From 99eab9444305dfdf01133f6b253bf10488abc029 Mon Sep 17 00:00:00 2001 From: "kmillikin@chromium.org" Date: Wed, 21 Sep 2011 08:51:44 +0000 Subject: [PATCH] Reapply "Clean up Context::Lookup and its uses." The threading test failures seem to be due to a GC-unsafe place, that mixed handles and raw pointers, in the runtime code for context lookup. R=fschneider@chromium.org BUG= TEST= Review URL: http://codereview.chromium.org/7890002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9356 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/contexts.cc | 100 +++++++++---------- src/contexts.h | 38 +++----- src/hydrogen.cc | 1 - src/runtime.cc | 291 ++++++++++++++++++++++++-------------------------------- 4 files changed, 183 insertions(+), 247 deletions(-) diff --git a/src/contexts.cc b/src/contexts.cc index 4f93abd..007d30d 100644 --- a/src/contexts.cc +++ b/src/contexts.cc @@ -86,14 +86,14 @@ void Context::set_global_proxy(JSObject* object) { Handle Context::Lookup(Handle name, ContextLookupFlags flags, - int* index_, + int* index, PropertyAttributes* attributes, BindingFlags* binding_flags) { Isolate* isolate = GetIsolate(); Handle context(this, isolate); bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0; - *index_ = -1; + *index = -1; *attributes = ABSENT; *binding_flags = MISSING_BINDING; @@ -110,70 +110,50 @@ Handle Context::Lookup(Handle name, PrintF("\n"); } - // Check extension/with/global object. - if (!context->IsBlockContext() && context->has_extension()) { - if (context->IsCatchContext()) { - // Catch contexts have the variable name in the extension slot. - if (name->Equals(String::cast(context->extension()))) { - if (FLAG_trace_contexts) { - PrintF("=> found in catch context\n"); - } - *index_ = Context::THROWN_OBJECT_INDEX; - *attributes = NONE; - *binding_flags = MUTABLE_IS_INITIALIZED; - return context; - } + // 1. Check global objects, subjects of with, and extension objects. + if (context->IsGlobalContext() || + context->IsWithContext() || + (context->IsFunctionContext() && context->has_extension())) { + Handle object(JSObject::cast(context->extension()), isolate); + // Context extension objects needs to behave as if they have no + // prototype. So even if we want to follow prototype chains, we need + // to only do a local lookup for context extension objects. + if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 || + object->IsJSContextExtensionObject()) { + *attributes = object->GetLocalPropertyAttribute(*name); } else { - ASSERT(context->IsGlobalContext() || - context->IsFunctionContext() || - context->IsWithContext()); - // Global, function, and with contexts may have an object in the - // extension slot. - Handle extension(JSObject::cast(context->extension()), - isolate); - // Context extension objects needs to behave as if they have no - // prototype. So even if we want to follow prototype chains, we - // need to only do a local lookup for context extension objects. - if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 || - extension->IsJSContextExtensionObject()) { - *attributes = extension->GetLocalPropertyAttribute(*name); - } else { - *attributes = extension->GetPropertyAttribute(*name); - } - if (*attributes != ABSENT) { - // property found - if (FLAG_trace_contexts) { - PrintF("=> found property in context object %p\n", - reinterpret_cast(*extension)); - } - return extension; + *attributes = object->GetPropertyAttribute(*name); + } + if (*attributes != ABSENT) { + if (FLAG_trace_contexts) { + PrintF("=> found property in context object %p\n", + reinterpret_cast(*object)); } + return object; } } - // Check serialized scope information of functions and blocks. Only - // functions can have parameters, and a function name. + // 2. Check the context proper if it has slots. if (context->IsFunctionContext() || context->IsBlockContext()) { - // We may have context-local slots. Check locals in the context. + // Use serialized scope information of functions and blocks to search + // for the context index. Handle scope_info; if (context->IsFunctionContext()) { scope_info = Handle( context->closure()->shared()->scope_info(), isolate); } else { - ASSERT(context->IsBlockContext()); scope_info = Handle( SerializedScopeInfo::cast(context->extension()), isolate); } - Variable::Mode mode; - int index = scope_info->ContextSlotIndex(*name, &mode); - ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS); - if (index >= 0) { + int slot_index = scope_info->ContextSlotIndex(*name, &mode); + ASSERT(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS); + if (slot_index >= 0) { if (FLAG_trace_contexts) { PrintF("=> found local in context slot %d (mode = %d)\n", - index, mode); + slot_index, mode); } - *index_ = index; + *index = slot_index; // Note: Fixed context slots are statically allocated by the compiler. // Statically allocated variables always have a statically known mode, // which is the mode with which they were declared when added to the @@ -206,22 +186,34 @@ Handle Context::Lookup(Handle name, // Check the slot corresponding to the intermediate context holding // only the function name variable. - if (follow_context_chain) { - int index = scope_info->FunctionContextSlotIndex(*name); - if (index >= 0) { + if (follow_context_chain && context->IsFunctionContext()) { + int function_index = scope_info->FunctionContextSlotIndex(*name); + if (function_index >= 0) { if (FLAG_trace_contexts) { PrintF("=> found intermediate function in context slot %d\n", - index); + function_index); } - *index_ = index; + *index = function_index; *attributes = READ_ONLY; *binding_flags = IMMUTABLE_IS_INITIALIZED; return context; } } + + } else if (context->IsCatchContext()) { + // Catch contexts have the variable name in the extension slot. + if (name->Equals(String::cast(context->extension()))) { + if (FLAG_trace_contexts) { + PrintF("=> found in catch context\n"); + } + *index = Context::THROWN_OBJECT_INDEX; + *attributes = NONE; + *binding_flags = MUTABLE_IS_INITIALIZED; + return context; + } } - // Proceed with the previous context. + // 3. Prepare to continue with the previous (next outermost) context. if (context->IsGlobalContext()) { follow_context_chain = false; } else { diff --git a/src/contexts.h b/src/contexts.h index 505f86c..0facc9a 100644 --- a/src/contexts.h +++ b/src/contexts.h @@ -330,12 +330,6 @@ class Context: public FixedArray { // Mark the global context with out of memory. inline void mark_out_of_memory(); - // The exception holder is the object used as a with object in - // the implementation of a catch block. - bool is_exception_holder(Object* object) { - return IsCatchContext() && extension() == object; - } - // A global context hold a list of all functions which have been optimized. void AddOptimizedFunction(JSFunction* function); void RemoveOptimizedFunction(JSFunction* function); @@ -355,29 +349,25 @@ class Context: public FixedArray { #undef GLOBAL_CONTEXT_FIELD_ACCESSORS // Lookup the the slot called name, starting with the current context. - // There are 4 possible outcomes: - // - // 1) index_ >= 0 && result->IsContext(): - // most common case, the result is a Context, and index is the - // context slot index, and the slot exists. - // attributes == READ_ONLY for the function name variable, NONE otherwise. + // There are three possibilities: // - // 2) index_ >= 0 && result->IsJSObject(): - // the result is the JSObject arguments object, the index is the parameter - // index, i.e., key into the arguments object, and the property exists. - // attributes != ABSENT. + // 1) result->IsContext(): + // The binding was found in a context. *index is always the + // non-negative slot index. *attributes is NONE for var and let + // declarations, READ_ONLY for const declarations (never ABSENT). // - // 3) index_ < 0 && result->IsJSObject(): - // the result is the JSObject extension context or the global object, - // and the name is the property name, and the property exists. - // attributes != ABSENT. + // 2) result->IsJSObject(): + // The binding was found as a named property in a context extension + // object (i.e., was introduced via eval), as a property on the subject + // of with, or as a property of the global object. *index is -1 and + // *attributes is not ABSENT. // - // 4) index_ < 0 && result.is_null(): - // there was no context found with the corresponding property. - // attributes == ABSENT. + // 3) result.is_null(): + // There was no binding found, *index is always -1 and *attributes is + // always ABSENT. Handle Lookup(Handle name, ContextLookupFlags flags, - int* index_, + int* index, PropertyAttributes* attributes, BindingFlags* binding_flags); diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 3b8007c..b22ba13 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -4942,7 +4942,6 @@ void HGraphBuilder::VisitCall(Call* expr) { } else { VariableProxy* proxy = expr->expression()->AsVariableProxy(); - // FIXME. bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); if (global_call) { diff --git a/src/runtime.cc b/src/runtime.cc index 7f68d61..4dd3667 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -1292,15 +1292,17 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) { HandleScope scope(isolate); ASSERT(args.length() == 4); - CONVERT_ARG_CHECKED(Context, context, 0); + // Declarations are always made in a function or global context. In the + // case of eval code, the context passed is the context of the caller, + // which may be some nested context and not the declaration context. + RUNTIME_ASSERT(args[0]->IsContext()); + Handle context(Context::cast(args[0])->declaration_context()); + Handle name(String::cast(args[1])); PropertyAttributes mode = static_cast(args.smi_at(2)); RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE); Handle initial_value(args[3], isolate); - // Declarations are always done in a function or global context. - context = Handle(context->declaration_context()); - int index; PropertyAttributes attributes; ContextLookupFlags flags = DONT_FOLLOW_CHAINS; @@ -1309,9 +1311,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) { context->Lookup(name, flags, &index, &attributes, &binding_flags); if (attributes != ABSENT) { - // The name was declared before; check for conflicting - // re-declarations: This is similar to the code in parser.cc in - // the AstBuildingParser::Declare function. + // The name was declared before; check for conflicting re-declarations. if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) { // Functions are not read-only. ASSERT(mode != READ_ONLY || initial_value->IsTheHole()); @@ -1322,53 +1322,41 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) { // Initialize it if necessary. if (*initial_value != NULL) { if (index >= 0) { - // The variable or constant context slot should always be in - // the function context or the arguments object. - if (holder->IsContext()) { - ASSERT(holder.is_identical_to(context)); - if (((attributes & READ_ONLY) == 0) || - context->get(index)->IsTheHole()) { - context->set(index, *initial_value); - } - } else { - // The holder is an arguments object. - Handle arguments(Handle::cast(holder)); - Handle result = SetElement(arguments, index, initial_value, - kNonStrictMode); - if (result.is_null()) return Failure::Exception(); + ASSERT(holder.is_identical_to(context)); + if (((attributes & READ_ONLY) == 0) || + context->get(index)->IsTheHole()) { + context->set(index, *initial_value); } } else { - // Slow case: The property is not in the FixedArray part of the context. - Handle context_ext = Handle::cast(holder); + // Slow case: The property is in the context extension object of a + // function context or the global object of a global context. + Handle object = Handle::cast(holder); RETURN_IF_EMPTY_HANDLE( isolate, - SetProperty(context_ext, name, initial_value, - mode, kNonStrictMode)); + SetProperty(object, name, initial_value, mode, kNonStrictMode)); } } } else { // The property is not in the function context. It needs to be - // "declared" in the function context's extension context, or in the - // global context. - Handle context_ext; + // "declared" in the function context's extension context or as a + // property of the the global object. + Handle object; if (context->has_extension()) { - // The function context's extension context exists - use it. - context_ext = Handle(JSObject::cast(context->extension())); + object = Handle(JSObject::cast(context->extension())); } else { - // The function context's extension context does not exists - allocate - // it. - context_ext = isolate->factory()->NewJSObject( + // Context extension objects are allocated lazily. + ASSERT(context->IsFunctionContext()); + object = isolate->factory()->NewJSObject( isolate->context_extension_function()); - // And store it in the extension slot. - context->set_extension(*context_ext); + context->set_extension(*object); } - ASSERT(*context_ext != NULL); + ASSERT(*object != NULL); // Declare the property by setting it to the initial value if provided, // or undefined, and use the correct mode (e.g. READ_ONLY attribute for // constant declarations). - ASSERT(!context_ext->HasLocalProperty(*name)); + ASSERT(!object->HasLocalProperty(*name)); Handle value(isolate->heap()->undefined_value(), isolate); if (*initial_value != NULL) value = initial_value; // Declaring a const context slot is a conflicting declaration if @@ -1378,15 +1366,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) { // SetProperty and no setters are invoked for those since they are // not real JSObjects. if (initial_value->IsTheHole() && - !context_ext->IsJSContextExtensionObject()) { + !object->IsJSContextExtensionObject()) { LookupResult lookup; - context_ext->Lookup(*name, &lookup); + object->Lookup(*name, &lookup); if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) { return ThrowRedeclarationError(isolate, "const", name); } } RETURN_IF_EMPTY_HANDLE(isolate, - SetProperty(context_ext, name, value, mode, + SetProperty(object, name, value, mode, kNonStrictMode)); } @@ -1537,11 +1525,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) { Handle value(args[0], isolate); ASSERT(!value->IsTheHole()); - CONVERT_ARG_CHECKED(Context, context, 1); - Handle name(String::cast(args[2])); // Initializations are always done in a function or global context. - context = Handle(context->declaration_context()); + RUNTIME_ASSERT(args[1]->IsContext()); + Handle context(Context::cast(args[1])->declaration_context()); + + Handle name(String::cast(args[2])); int index; PropertyAttributes attributes; @@ -1550,39 +1539,19 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) { Handle holder = context->Lookup(name, flags, &index, &attributes, &binding_flags); - // In most situations, the property introduced by the const - // declaration should be present in the context extension object. - // However, because declaration and initialization are separate, the - // property might have been deleted (if it was introduced by eval) - // before we reach the initialization point. - // - // Example: - // - // function f() { eval("delete x; const x;"); } - // - // In that case, the initialization behaves like a normal assignment - // to property 'x'. if (index >= 0) { - if (holder->IsContext()) { - // Property was found in a context. Perform the assignment if we - // found some non-constant or an uninitialized constant. - Handle context = Handle::cast(holder); - if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) { - context->set(index, *value); - } - } else { - // The holder is an arguments object. - ASSERT((attributes & READ_ONLY) == 0); - Handle arguments(Handle::cast(holder)); - RETURN_IF_EMPTY_HANDLE( - isolate, - SetElement(arguments, index, value, kNonStrictMode)); + ASSERT(holder->IsContext()); + // Property was found in a context. Perform the assignment if we + // found some non-constant or an uninitialized constant. + Handle context = Handle::cast(holder); + if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) { + context->set(index, *value); } return *value; } - // The property could not be found, we introduce it in the global - // context. + // The property could not be found, we introduce it as a property of the + // global object. if (attributes == ABSENT) { Handle global = Handle( isolate->context()->global()); @@ -1593,29 +1562,41 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) { return *value; } - // The property was present in a context extension object. - Handle context_ext = Handle::cast(holder); + // The property was present in some function's context extension object, + // as a property on the subject of a with, or as a property of the global + // object. + // + // In most situations, eval-introduced consts should still be present in + // the context extension object. However, because declaration and + // initialization are separate, the property might have been deleted + // before we reach the initialization point. + // + // Example: + // + // function f() { eval("delete x; const x;"); } + // + // In that case, the initialization behaves like a normal assignment. + Handle object = Handle::cast(holder); - if (*context_ext == context->extension()) { - // This is the property that was introduced by the const - // declaration. Set it if it hasn't been set before. NOTE: We - // cannot use GetProperty() to get the current value as it - // 'unholes' the value. + if (*object == context->extension()) { + // This is the property that was introduced by the const declaration. + // Set it if it hasn't been set before. NOTE: We cannot use + // GetProperty() to get the current value as it 'unholes' the value. LookupResult lookup; - context_ext->LocalLookupRealNamedProperty(*name, &lookup); + object->LocalLookupRealNamedProperty(*name, &lookup); ASSERT(lookup.IsProperty()); // the property was declared ASSERT(lookup.IsReadOnly()); // and it was declared as read-only PropertyType type = lookup.type(); if (type == FIELD) { - FixedArray* properties = context_ext->properties(); + FixedArray* properties = object->properties(); int index = lookup.GetFieldIndex(); if (properties->get(index)->IsTheHole()) { properties->set(index, *value); } } else if (type == NORMAL) { - if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) { - context_ext->SetNormalizedProperty(&lookup, *value); + if (object->GetNormalizedProperty(&lookup)->IsTheHole()) { + object->SetNormalizedProperty(&lookup, *value); } } else { // We should not reach here. Any real, named property should be @@ -1623,13 +1604,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) { UNREACHABLE(); } } else { - // The property was found in a different context extension object. - // Set it if it is not a read-only property. + // The property was found on some other object. Set it if it is not a + // read-only property. if ((attributes & READ_ONLY) == 0) { // Strict mode not needed (const disallowed in strict mode). RETURN_IF_EMPTY_HANDLE( isolate, - SetProperty(context_ext, name, value, attributes, kNonStrictMode)); + SetProperty(object, name, value, attributes, kNonStrictMode)); } } @@ -8557,18 +8538,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) { } // The slot was found in a JSObject, either a context extension object, - // the global object, or an arguments object. Try to delete it - // (respecting DONT_DELETE). For consistency with V8's usual behavior, - // which allows deleting all parameters in functions that mention - // 'arguments', we do this even for the case of slots found on an - // arguments object. The slot was found on an arguments object if the - // index is non-negative. + // the global object, or the subject of a with. Try to delete it + // (respecting DONT_DELETE). Handle object = Handle::cast(holder); - if (index >= 0) { - return object->DeleteElement(index, JSReceiver::NORMAL_DELETION); - } else { - return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION); - } + return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION); } @@ -8653,24 +8626,19 @@ static ObjectPair LoadContextSlotHelper(Arguments args, &attributes, &binding_flags); - // If the index is non-negative, the slot has been found in a local - // variable or a parameter. Read it from the context object or the - // arguments object. + // If the index is non-negative, the slot has been found in a context. if (index >= 0) { - // If the "property" we were looking for is a local variable or an - // argument in a context, the receiver is the global object; see - // ECMA-262, 3rd., 10.1.6 and 10.2.3. + ASSERT(holder->IsContext()); + // If the "property" we were looking for is a local variable, the + // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3. // - // Use the hole as the receiver to signal that the receiver is - // implicit and that the global receiver should be used. + // Use the hole as the receiver to signal that the receiver is implicit + // and that the global receiver should be used (as distinguished from an + // explicit receiver that happens to be a global object). Handle receiver = isolate->factory()->the_hole_value(); - MaybeObject* value = (holder->IsContext()) - ? Context::cast(*holder)->get(index) - : JSObject::cast(*holder)->GetElement(index); + Object* value = Context::cast(*holder)->get(index); // Check for uninitialized bindings. - if (holder->IsContext() && - binding_flags == MUTABLE_CHECK_INITIALIZED && - value->IsTheHole()) { + if (binding_flags == MUTABLE_CHECK_INITIALIZED && value->IsTheHole()) { Handle reference_error = isolate->factory()->NewReferenceError("not_defined", HandleVector(&name, 1)); @@ -8680,25 +8648,18 @@ static ObjectPair LoadContextSlotHelper(Arguments args, } } - // If the holder is found, we read the property from it. - if (!holder.is_null() && holder->IsJSObject()) { - ASSERT(Handle::cast(holder)->HasProperty(*name)); - JSObject* object = JSObject::cast(*holder); - Object* receiver; - if (object->IsGlobalObject()) { - receiver = GlobalObject::cast(object)->global_receiver(); - } else if (context->is_exception_holder(*holder)) { - // Use the hole as the receiver to signal that the receiver is - // implicit and that the global receiver should be used. - receiver = isolate->heap()->the_hole_value(); - } else { - receiver = ComputeReceiverForNonGlobal(isolate, object); - } - + // Otherwise, if the slot was found the holder is a context extension + // object, subject of a with, or a global object. We read the named + // property from it. + if (!holder.is_null()) { + Handle object = Handle::cast(holder); + ASSERT(object->HasProperty(*name)); // GetProperty below can cause GC. - Handle receiver_handle(receiver); + Handle receiver_handle(object->IsGlobalObject() + ? GlobalObject::cast(*object)->global_receiver() + : ComputeReceiverForNonGlobal(isolate, object)); - // No need to unhole the value here. This is taken care of by the + // No need to unhole the value here. This is taken care of by the // GetProperty function. MaybeObject* value = object->GetProperty(*name); return MakePair(value, *receiver_handle); @@ -8751,45 +8712,37 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) { &binding_flags); if (index >= 0) { - if (holder->IsContext()) { - Handle context = Handle::cast(holder); - if (binding_flags == MUTABLE_CHECK_INITIALIZED && - context->get(index)->IsTheHole()) { - Handle error = - isolate->factory()->NewReferenceError("not_defined", - HandleVector(&name, 1)); - return isolate->Throw(*error); - } - // Ignore if read_only variable. - if ((attributes & READ_ONLY) == 0) { - // Context is a fixed array and set cannot fail. - context->set(index, *value); - } else if (strict_mode == kStrictMode) { - // Setting read only property in strict mode. - Handle error = - isolate->factory()->NewTypeError("strict_cannot_assign", - HandleVector(&name, 1)); - return isolate->Throw(*error); - } - } else { - ASSERT((attributes & READ_ONLY) == 0); - Handle result = - SetElement(Handle::cast(holder), index, value, strict_mode); - if (result.is_null()) { - ASSERT(isolate->has_pending_exception()); - return Failure::Exception(); - } + // The property was found in a context slot. + Handle context = Handle::cast(holder); + if (binding_flags == MUTABLE_CHECK_INITIALIZED && + context->get(index)->IsTheHole()) { + Handle error = + isolate->factory()->NewReferenceError("not_defined", + HandleVector(&name, 1)); + return isolate->Throw(*error); + } + // Ignore if read_only variable. + if ((attributes & READ_ONLY) == 0) { + // Context is a fixed array and set cannot fail. + context->set(index, *value); + } else if (strict_mode == kStrictMode) { + // Setting read only property in strict mode. + Handle error = + isolate->factory()->NewTypeError("strict_cannot_assign", + HandleVector(&name, 1)); + return isolate->Throw(*error); } return *value; } - // Slow case: The property is not in a FixedArray context. - // It is either in an JSObject extension context or it was not found. - Handle context_ext; + // Slow case: The property is not in a context slot. It is either in a + // context extension object, a property of the subject of a with, or a + // property of the global object. + Handle object; if (!holder.is_null()) { - // The property exists in the extension context. - context_ext = Handle::cast(holder); + // The property exists on the holder. + object = Handle::cast(holder); } else { // The property was not found. ASSERT(attributes == ABSENT); @@ -8797,22 +8750,21 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) { if (strict_mode == kStrictMode) { // Throw in strict mode (assignment to undefined variable). Handle error = - isolate->factory()->NewReferenceError( - "not_defined", HandleVector(&name, 1)); + isolate->factory()->NewReferenceError( + "not_defined", HandleVector(&name, 1)); return isolate->Throw(*error); } - // In non-strict mode, the property is stored in the global context. + // In non-strict mode, the property is added to the global object. attributes = NONE; - context_ext = Handle(isolate->context()->global()); + object = Handle(isolate->context()->global()); } - // Set the property, but ignore if read_only variable on the context - // extension object itself. + // Set the property if it's not read only or doesn't yet exist. if ((attributes & READ_ONLY) == 0 || - (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) { + (object->GetLocalPropertyAttribute(*name) == ABSENT)) { RETURN_IF_EMPTY_HANDLE( isolate, - SetProperty(context_ext, name, value, NONE, strict_mode)); + SetProperty(object, name, value, NONE, strict_mode)); } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) { // Setting read only property in strict mode. Handle error = @@ -9217,6 +9169,9 @@ RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) { PropertyAttributes attributes = ABSENT; BindingFlags binding_flags; while (true) { + // Don't follow context chains in Context::Lookup and implement the loop + // up the context chain here, so that we can know the context where eval + // was found. receiver = context->Lookup(isolate->factory()->eval_symbol(), FOLLOW_PROTOTYPE_CHAIN, &index, -- 2.7.4