Reviewers: Jakob,
Description:
Merged r18286, r18289, r18291, r18292, r18299, r18327 into 3.23 branch.
Fix patching the receiver (global object -> global proxy) after the
interceptor.
Properly restore the receiver after the interceptor call.
Fix popping order on ARM.
Push receiver and holder separately, given that they can be the same.
Fixed global object leak caused by overwriting the global receiver (the
global
proxy) in the global object with the global object itself.
Move the receiver into r0 for PatchGlobalProxy. This fixes the ARM/android
bug
http://build.chromium.org/p/tryserver.chromium/builders/android_dbg_triggered_tests/builds/112686/steps/androidwebview_instrumentation_tests
[email protected]
BUG=324812
LOG=N
[email protected]
Please review this at https://codereview.chromium.org/137993018/
Index: include/v8.h
diff --git a/include/v8.h b/include/v8.h
index
815f43db7b2fb392ec521940c3b43821f190196b..9bf96081d5a4a3276bff5aa06892331055269c5b
100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -5150,20 +5150,16 @@ class V8_EXPORT ExtensionConfiguration {
class V8_EXPORT Context {
public:
/**
- * Returns the global proxy object or global object itself for
- * detached contexts.
+ * Returns the global proxy object.
*
- * Global proxy object is a thin wrapper whose prototype points to
- * actual context's global object with the properties like Object, etc.
- * This is done that way for security reasons (for more details see
+ * Global proxy object is a thin wrapper whose prototype points to actual
+ * context's global object with the properties like Object, etc. This is
done
+ * that way for security reasons (for more details see
* https://wiki.mozilla.org/Gecko:SplitWindow).
*
* Please note that changes to global proxy object prototype most
probably
- * would break VM---v8 expects only global object as a prototype of
- * global proxy object.
- *
- * If DetachGlobal() has been invoked, Global() would return actual
global
- * object until global is reattached with ReattachGlobal().
+ * would break VM---v8 expects only global object as a prototype of
global
+ * proxy object.
*/
Local<Object> Global();
@@ -5174,18 +5170,6 @@ class V8_EXPORT Context {
void DetachGlobal();
/**
- * Reattaches a global object to a context. This can be used to
- * restore the connection between a global object and a context
- * after DetachGlobal has been called.
- *
- * \param global_object The global object to reattach to the
- * context. For this to work, the global object must be the global
- * object that was associated with this context before a call to
- * DetachGlobal.
- */
- void ReattachGlobal(Handle<Object> global_object);
-
- /**
* Creates a new context and returns a handle to the newly allocated
* context.
*
Index: src/api.cc
diff --git a/src/api.cc b/src/api.cc
index
aee9e3a469eae454a9fdc7b241142050044a730a..d7c76d5a13db453d2c2510041effc573acb69c1f
100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -5410,6 +5410,12 @@ v8::Local<v8::Object> Context::Global() {
i::Handle<i::Context> context = Utils::OpenHandle(this);
i::Isolate* isolate = context->GetIsolate();
i::Handle<i::Object> global(context->global_proxy(), isolate);
+ // TODO(dcarney): This should always return the global proxy
+ // but can't presently as calls to GetProtoype will return the wrong
result.
+ if (i::Handle<i::JSGlobalProxy>::cast(
+ global)->IsDetachedFrom(context->global_object())) {
+ global = i::Handle<i::Object>(context->global_object(), isolate);
+ }
return Utils::ToLocal(i::Handle<i::JSObject>::cast(global));
}
@@ -5422,16 +5428,6 @@ void Context::DetachGlobal() {
}
-void Context::ReattachGlobal(Handle<Object> global_object) {
- i::Handle<i::Context> context = Utils::OpenHandle(this);
- i::Isolate* isolate = context->GetIsolate();
- ENTER_V8(isolate);
- i::Handle<i::JSGlobalProxy> global_proxy =
- i::Handle<i::JSGlobalProxy>::cast(Utils::OpenHandle(*global_object));
- isolate->bootstrapper()->ReattachGlobal(context, global_proxy);
-}
-
-
void Context::AllowCodeGenerationFromStrings(bool allow) {
i::Handle<i::Context> context = Utils::OpenHandle(this);
i::Isolate* isolate = context->GetIsolate();
Index: src/arm/stub-cache-arm.cc
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index
265265d591002ade05f68d778702faf41bc1b84f..4ca5e27ed712392f34d777dae6132a08fff5dfd4
100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -1021,7 +1021,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
// holder haven't changed and thus we can use cached constant function.
if (*interceptor_holder != lookup->holder()) {
stub_compiler_->CheckPrototypes(
- IC::CurrentTypeOf(interceptor_holder, masm->isolate()), receiver,
+ IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder,
handle(lookup->holder()), scratch1, scratch2, scratch3,
name, depth2, miss);
} else {
@@ -1038,7 +1038,8 @@ class CallInterceptorCompiler BASE_EMBEDDED {
masm, optimization, arguments_.immediate(), false);
} else {
Handle<JSFunction> function = optimization.constant_function();
- stub_compiler_->GenerateJumpFunctionIgnoreReceiver(function);
+ __ Move(r0, receiver);
+ stub_compiler_->GenerateJumpFunction(object, function);
}
// Deferred code for fast API call case---clean preallocated space.
@@ -1091,12 +1092,14 @@ class CallInterceptorCompiler BASE_EMBEDDED {
Label* interceptor_succeeded) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
+ __ Push(receiver);
__ Push(holder, name_);
CompileCallLoadPropertyWithInterceptor(
masm, receiver, holder, name_, holder_obj,
IC::kLoadPropertyWithInterceptorOnly);
- __ pop(name_); // Restore the name.
- __ pop(receiver); // Restore the holder.
+ __ pop(name_);
+ __ pop(holder);
+ __ pop(receiver);
}
// If interceptor returns no-result sentinel, call the constant
function.
__ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
Index: src/bootstrapper.cc
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index
4d69f8407f4fb4e9bff20bd174b8cb848d824fe6..2b2f7c7193122f6b082025190b72b11af3b6e8e9
100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -339,17 +339,6 @@ void Bootstrapper::DetachGlobal(Handle<Context> env) {
Handle<JSGlobalProxy>
global_proxy(JSGlobalProxy::cast(env->global_proxy()));
global_proxy->set_native_context(*factory->null_value());
SetObjectPrototype(global_proxy, factory->null_value());
- env->set_global_proxy(env->global_object());
- env->global_object()->set_global_receiver(env->global_object());
-}
-
-
-void Bootstrapper::ReattachGlobal(Handle<Context> env,
- Handle<JSGlobalProxy> global_proxy) {
- env->global_object()->set_global_receiver(*global_proxy);
- env->set_global_proxy(*global_proxy);
- SetObjectPrototype(global_proxy, Handle<JSObject>(env->global_object()));
- global_proxy->set_native_context(*env);
}
Index: src/bootstrapper.h
diff --git a/src/bootstrapper.h b/src/bootstrapper.h
index
bac9f40372d9039041014cd6ba84209057d70223..4f63c87163f0e512c2fbc6b3bbb35c1d19605e9a
100644
--- a/src/bootstrapper.h
+++ b/src/bootstrapper.h
@@ -105,9 +105,6 @@ class Bootstrapper {
// Detach the environment from its outer global object.
void DetachGlobal(Handle<Context> env);
- // Reattach an outer global object to an environment.
- void ReattachGlobal(Handle<Context> env, Handle<JSGlobalProxy>
global_proxy);
-
// Traverses the pointers for memory management.
void Iterate(ObjectVisitor* v);
Index: src/ia32/stub-cache-ia32.cc
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index
f4f3b2bed3430fba38796b61d2ede5d775c114b6..9efedc67325065b134dffb12e4a17e4cc99c0421
100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -740,7 +740,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
// holder haven't changed and thus we can use cached constant function.
if (*interceptor_holder != lookup->holder()) {
stub_compiler_->CheckPrototypes(
- IC::CurrentTypeOf(interceptor_holder, masm->isolate()), receiver,
+ IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder,
handle(lookup->holder()), scratch1, scratch2, scratch3,
name, depth2, miss);
} else {
@@ -756,7 +756,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
GenerateFastApiCall(masm, optimization, arguments_.immediate());
} else {
Handle<JSFunction> fun = optimization.constant_function();
- stub_compiler_->GenerateJumpFunctionIgnoreReceiver(fun);
+ stub_compiler_->GenerateJumpFunction(object, fun);
}
// Deferred code for fast API call case---clean preallocated space.
@@ -808,15 +808,17 @@ class CallInterceptorCompiler BASE_EMBEDDED {
Label* interceptor_succeeded) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
- __ push(holder); // Save the holder.
- __ push(name_); // Save the name.
+ __ push(receiver);
+ __ push(holder);
+ __ push(name_);
CompileCallLoadPropertyWithInterceptor(
masm, receiver, holder, name_, holder_obj,
IC::kLoadPropertyWithInterceptorOnly);
- __ pop(name_); // Restore the name.
- __ pop(receiver); // Restore the holder.
+ __ pop(name_);
+ __ pop(holder);
+ __ pop(receiver);
// Leave the internal frame.
}
Index: src/objects-inl.h
diff --git a/src/objects-inl.h b/src/objects-inl.h
index
8406a6ad681bfa33e6a7cc0a449d2f40b5b0d3db..02e3160c9364326c0d027ad1c8a57873319a27fa
100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -5907,16 +5907,13 @@ PropertyAttributes
JSReceiver::GetElementAttribute(uint32_t index) {
}
-// TODO(504): this may be useful in other places too where JSGlobalProxy
-// is used.
-Object* JSObject::BypassGlobalProxy() {
- if (IsJSGlobalProxy()) {
- Object* proto = GetPrototype();
- if (proto->IsNull()) return GetHeap()->undefined_value();
- ASSERT(proto->IsJSGlobalObject());
- return proto;
- }
- return this;
+bool JSGlobalObject::IsDetached() {
+ return JSGlobalProxy::cast(global_receiver())->IsDetachedFrom(this);
+}
+
+
+bool JSGlobalProxy::IsDetachedFrom(GlobalObject* global) {
+ return GetPrototype() != global;
}
Index: src/objects.h
diff --git a/src/objects.h b/src/objects.h
index
09a1c7cfb43c824d61574a3f4207aea70f8a4597..5216657347936a09038d2e6527fdcbdc3329d1fa
100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -878,6 +878,7 @@ class DictionaryElementsAccessor;
class ElementsAccessor;
class Failure;
class FixedArrayBase;
+class GlobalObject;
class ObjectVisitor;
class StringStream;
class Type;
@@ -7424,6 +7425,8 @@ class JSGlobalProxy : public JSObject {
// Casting.
static inline JSGlobalProxy* cast(Object* obj);
+ inline bool IsDetachedFrom(GlobalObject* global);
+
// Dispatched behavior.
DECLARE_PRINTER(JSGlobalProxy)
DECLARE_VERIFIER(JSGlobalProxy)
@@ -7493,6 +7496,8 @@ class JSGlobalObject: public GlobalObject {
static Handle<PropertyCell> EnsurePropertyCell(Handle<JSGlobalObject>
global,
Handle<Name> name);
+ inline bool IsDetached();
+
// Dispatched behavior.
DECLARE_PRINTER(JSGlobalObject)
DECLARE_VERIFIER(JSGlobalObject)
Index: src/runtime.cc
diff --git a/src/runtime.cc b/src/runtime.cc
index
7dc96f201970eec90466b79f20fa2823271fe737..c909f34db17f9cbb687ace5eb1f165c764af2752
100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -9646,6 +9646,16 @@ RUNTIME_FUNCTION(MaybeObject*,
Runtime_GlobalReceiver) {
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_IsAttachedGlobal) {
+ SealHandleScope shs(isolate);
+ ASSERT(args.length() == 1);
+ Object* global = args[0];
+ if (!global->IsJSGlobalObject()) return isolate->heap()->false_value();
+ return isolate->heap()->ToBoolean(
+ !JSGlobalObject::cast(global)->IsDetached());
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
HandleScope scope(isolate);
ASSERT_EQ(1, args.length());
Index: src/runtime.h
diff --git a/src/runtime.h b/src/runtime.h
index
0f920c7259eba9fc3521013d3fe2027f24c8f461..6a0358399d1a26340779eb587af046ac09212a77
100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -278,6 +278,7 @@ namespace internal {
\
/* Eval */ \
F(GlobalReceiver, 1, 1) \
+ F(IsAttachedGlobal, 1, 1) \
F(ResolvePossiblyDirectEval, 5, 2) \
\
F(SetProperty, -1 /* 4 or 5 */, 1) \
Index: src/v8natives.js
diff --git a/src/v8natives.js b/src/v8natives.js
index
b715e8923ff26184b43d2f5f432e9e5a3cf778d3..96b88c5285c9962d479fa75d0e71031cd0c35b6c
100644
--- a/src/v8natives.js
+++ b/src/v8natives.js
@@ -170,19 +170,18 @@ function GlobalParseFloat(string) {
function GlobalEval(x) {
if (!IS_STRING(x)) return x;
- var global_receiver = %GlobalReceiver(global);
- var global_is_detached = (global === global_receiver);
-
// For consistency with JSC we require the global object passed to
// eval to be the global object from which 'eval' originated. This
// is not mandated by the spec.
// We only throw if the global has been detached, since we need the
// receiver as this-value for the call.
- if (global_is_detached) {
+ if (!%IsAttachedGlobal(global)) {
throw new $EvalError('The "this" value passed to eval must ' +
'be the global object from which eval
originated');
}
+ var global_receiver = %GlobalReceiver(global);
+
var f = %CompileString(x, false);
if (!IS_FUNCTION(f)) return f;
Index: src/version.cc
diff --git a/src/version.cc b/src/version.cc
index
c0a940ae07cd63b4e52c4f6e520ffed703a29df6..70b626e1aed9317c3e50c08aabc63034f999c703
100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -35,7 +35,7 @@
#define MAJOR_VERSION 3
#define MINOR_VERSION 23
#define BUILD_NUMBER 17
-#define PATCH_LEVEL 6
+#define PATCH_LEVEL 7
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 0
Index: src/x64/stub-cache-x64.cc
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index
9bf6e9f2fb34d2ec94d52a3067d33092ff7a2995..c87f00fc4dbc2cfa6d0379f78dbe797bbad039bb
100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -733,7 +733,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
// holder haven't changed and thus we can use cached constant function.
if (*interceptor_holder != lookup->holder()) {
stub_compiler_->CheckPrototypes(
- IC::CurrentTypeOf(interceptor_holder, masm->isolate()), receiver,
+ IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder,
handle(lookup->holder()), scratch1, scratch2, scratch3,
name, depth2, miss);
} else {
@@ -749,7 +749,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
GenerateFastApiCall(masm, optimization, arguments_.immediate());
} else {
Handle<JSFunction> fun = optimization.constant_function();
- stub_compiler_->GenerateJumpFunctionIgnoreReceiver(fun);
+ stub_compiler_->GenerateJumpFunction(object, fun);
}
// Deferred code for fast API call case---clean preallocated space.
@@ -801,15 +801,17 @@ class CallInterceptorCompiler BASE_EMBEDDED {
Label* interceptor_succeeded) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
- __ push(holder); // Save the holder.
- __ push(name_); // Save the name.
+ __ push(receiver);
+ __ push(holder);
+ __ push(name_);
CompileCallLoadPropertyWithInterceptor(
masm, receiver, holder, name_, holder_obj,
IC::kLoadPropertyWithInterceptorOnly);
- __ pop(name_); // Restore the name.
- __ pop(receiver); // Restore the holder.
+ __ pop(name_);
+ __ pop(holder);
+ __ pop(receiver);
// Leave the internal frame.
}
Index: test/cctest/test-api.cc
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index
2e457d0e8e5cb8006be69d735fc068730a3aa2d4..57c98d06dd557a51f1e458d5929e26842b532a91
100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -8502,8 +8502,6 @@ TEST(ContextDetachGlobal) {
// Detach env2's global, and reuse the global object of env2
env2->Exit();
env2->DetachGlobal();
- // env2 has a new global object.
- CHECK(!env2->Global()->Equals(global2));
v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
0,
@@ -8538,7 +8536,7 @@ TEST(ContextDetachGlobal) {
}
-TEST(DetachAndReattachGlobal) {
+TEST(DetachGlobal) {
LocalContext env1;
v8::HandleScope scope(env1->GetIsolate());
@@ -8603,16 +8601,58 @@ TEST(DetachAndReattachGlobal) {
// so access should be blocked.
result = CompileRun("other.p");
CHECK(result->IsUndefined());
+}
- // Detach the global for env3 and reattach it to env2.
- env3->DetachGlobal();
- env2->ReattachGlobal(global2);
- // Check that we have access to other.p again in env1. |other| is now
- // the global object for env2 which has the same security token as env1.
- result = CompileRun("other.p");
- CHECK(result->IsInt32());
- CHECK_EQ(42, result->Int32Value());
+TEST(DetachedAccesses) {
+ LocalContext env1;
+ v8::HandleScope scope(env1->GetIsolate());
+
+ // Create second environment.
+ v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
+
+ Local<Value> foo = v8_str("foo");
+
+ // Set same security token for env1 and env2.
+ env1->SetSecurityToken(foo);
+ env2->SetSecurityToken(foo);
+
+ {
+ v8::Context::Scope scope(env2);
+ CompileRun(
+ "var x = 'x';"
+ "function get_x() { return this.x; }"
+ "function get_x_w() { return get_x(); }"
+ "");
+ env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
+ env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
+ }
+
+ Local<Object> env2_global = env2->Global();
+ env2_global->TurnOnAccessCheck();
+ env2->DetachGlobal();
+
+ Local<Value> result;
+ result = CompileRun("get_x()");
+ CHECK(result->IsUndefined());
+ result = CompileRun("get_x_w()");
+ CHECK(result->IsUndefined());
+
+ // Reattach env2's proxy
+ env2 = Context::New(env1->GetIsolate(),
+ 0,
+ v8::Handle<v8::ObjectTemplate>(),
+ env2_global);
+ env2->SetSecurityToken(foo);
+ {
+ v8::Context::Scope scope(env2);
+ CompileRun("var x = 'x2';");
+ }
+
+ result = CompileRun("get_x()");
+ CHECK(result->IsUndefined());
+ result = CompileRun("get_x_w()");
+ CHECK_EQ(v8_str("x2"), result);
}
@@ -14230,8 +14270,10 @@ THREADED_TEST(TurnOnAccessCheck) {
}
// Detach the global and turn on access check.
+ Local<Object> hidden_global = Local<Object>::Cast(
+ context->Global()->GetPrototype());
context->DetachGlobal();
- context->Global()->TurnOnAccessCheck();
+ hidden_global->TurnOnAccessCheck();
// Failing access check to property get results in undefined.
CHECK(f1->Call(global, 0, NULL)->IsUndefined());
@@ -14315,8 +14357,10 @@ THREADED_TEST(TurnOnAccessCheckAndRecompile) {
// Detach the global and turn on access check now blocking access to
property
// a and function h.
+ Local<Object> hidden_global = Local<Object>::Cast(
+ context->Global()->GetPrototype());
context->DetachGlobal();
- context->Global()->TurnOnAccessCheck();
+ hidden_global->TurnOnAccessCheck();
// Failing access check to property get results in undefined.
CHECK(f1->Call(global, 0, NULL)->IsUndefined());
@@ -14332,11 +14376,11 @@ THREADED_TEST(TurnOnAccessCheckAndRecompile) {
// Now compile the source again. And get the newly compiled functions,
except
// for h for which access is blocked.
CompileRun(source);
- f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
- f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
- g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
- g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
- CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
+ f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
+ f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
+ g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
+ g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
+ CHECK(hidden_global->Get(v8_str("h"))->IsUndefined());
// Failing access check to property get results in undefined.
CHECK(f1->Call(global, 0, NULL)->IsUndefined());
@@ -15203,23 +15247,6 @@ THREADED_TEST(ReplaceConstantFunction) {
}
-// Regression test for http://crbug.com/16276.
-THREADED_TEST(Regress16276) {
- LocalContext context;
- v8::HandleScope scope(context->GetIsolate());
- // Force the IC in f to be a dictionary load IC.
- CompileRun("function f(obj) { return obj.x; }\n"
- "var obj = { x: { foo: 42 }, y: 87 };\n"
- "var x = obj.x;\n"
- "delete obj.y;\n"
- "for (var i = 0; i < 5; i++) f(obj);");
- // Detach the global object to make 'this' refer directly to the
- // global object (not the proxy), and make sure that the dictionary
- // load IC doesn't mess up loading directly from the global object.
- context->DetachGlobal();
- CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
-}
-
static void CheckElementValue(i::Isolate* isolate,
int expected,
i::Handle<i::Object> obj,
Index: test/cctest/test-decls.cc
diff --git a/test/cctest/test-decls.cc b/test/cctest/test-decls.cc
index
c3bd5c4494f396f30d2b809a16e4373ca297843c..de0d745c7f75b264171cb04c88dd623f2506f6d2
100644
--- a/test/cctest/test-decls.cc
+++ b/test/cctest/test-decls.cc
@@ -648,9 +648,9 @@ class ExistsInHiddenPrototypeContext: public
DeclarationContext {
virtual void PostInitializeContext(Handle<Context> context) {
Local<Object> global_object = context->Global();
Local<Object> hidden_proto =
hidden_proto_->GetFunction()->NewInstance();
- context->DetachGlobal();
- context->Global()->SetPrototype(hidden_proto);
- context->ReattachGlobal(global_object);
+ Local<Object> inner_global =
+ Local<Object>::Cast(global_object->GetPrototype());
+ inner_global->SetPrototype(hidden_proto);
}
// Use the hidden prototype as the holder for the interceptors.
Index: test/cctest/test-object-observe.cc
diff --git a/test/cctest/test-object-observe.cc
b/test/cctest/test-object-observe.cc
index
4c32d44dcb3fa5d4c624068327b593b76c840e77..b4e7c697412139f555deb042fa2e6287c9b9db4f
100644
--- a/test/cctest/test-object-observe.cc
+++ b/test/cctest/test-object-observe.cc
@@ -242,7 +242,6 @@ TEST(GlobalObjectObservation) {
LocalContext context(isolate.GetIsolate());
HandleScope scope(isolate.GetIsolate());
Handle<Object> global_proxy = context->Global();
- Handle<Object> inner_global = global_proxy->GetPrototype().As<Object>();
CompileRun(
"var records = [];"
"var global = this;"
@@ -255,33 +254,26 @@ TEST(GlobalObjectObservation) {
context->DetachGlobal();
CompileRun("global.bar = 'goodbye';");
CHECK_EQ(1, CompileRun("records.length")->Int32Value());
-
- // Mutating the global object directly still has an effect...
- CompileRun("this.bar = 'goodbye';");
- CHECK_EQ(2, CompileRun("records.length")->Int32Value());
- CHECK(inner_global->StrictEquals(CompileRun("records[1].object")));
-
- // Reattached, back to global proxy.
- context->ReattachGlobal(global_proxy);
- CompileRun("global.baz = 'again';");
- CHECK_EQ(3, CompileRun("records.length")->Int32Value());
- CHECK(global_proxy->StrictEquals(CompileRun("records[2].object")));
+ CompileRun("this.baz = 'goodbye';");
+ CHECK_EQ(1, CompileRun("records.length")->Int32Value());
// Attached to a different context, should not leak mutations
// to the old context.
context->DetachGlobal();
{
LocalContext context2(isolate.GetIsolate());
- context2->DetachGlobal();
- context2->ReattachGlobal(global_proxy);
CompileRun(
"var records2 = [];"
+ "var global = this;"
"Object.observe(this, function(r) { [].push.apply(records2, r) });"
- "this.bat = 'context2';");
+ "this.v1 = 'context2';");
+ context2->DetachGlobal();
+ CompileRun(
+ "global.v2 = 'context2';"
+ "this.v3 = 'context2';");
CHECK_EQ(1, CompileRun("records2.length")->Int32Value());
- CHECK(global_proxy->StrictEquals(CompileRun("records2[0].object")));
}
- CHECK_EQ(3, CompileRun("records.length")->Int32Value());
+ CHECK_EQ(1, CompileRun("records.length")->Int32Value());
// Attaching by passing to Context::New
{
@@ -295,7 +287,7 @@ TEST(GlobalObjectObservation) {
CHECK_EQ(1, CompileRun("records3.length")->Int32Value());
CHECK(global_proxy->StrictEquals(CompileRun("records3[0].object")));
}
- CHECK_EQ(3, CompileRun("records.length")->Int32Value());
+ CHECK_EQ(1, CompileRun("records.length")->Int32Value());
}
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.