Chromium Code Reviews| Index: src/contexts.cc |
| diff --git a/src/contexts.cc b/src/contexts.cc |
| index 537d92d0f4032cf5be4d6db03b850d9f8c6beeb7..ed79e13ee815a3e1151315ceaecb25302123544f 100644 |
| --- a/src/contexts.cc |
| +++ b/src/contexts.cc |
| @@ -11,6 +11,44 @@ |
| namespace v8 { |
| namespace internal { |
| + |
| +Handle<GlobalContextTable> GlobalContextTable::Extend( |
| + Handle<GlobalContextTable> table, Handle<Context> global_context) { |
| + Isolate* isolate = global_context->GetIsolate(); |
| + Handle<GlobalContextTable> result; |
| + if (table.is_null()) { |
| + result = isolate->factory()->NewGlobalContextTable(1); |
| + } else { |
| + int length = table->length(); |
| + result = Handle<GlobalContextTable>::cast( |
| + FixedArray::CopySize(table, length + 1)); |
|
rossberg
2014/11/06 12:29:12
This should perhaps double the table size, pre-all
Dmitry Lomov (no reviews)
2014/11/06 17:26:58
Done.
|
| + } |
| + DCHECK(global_context->IsGlobalContext()); |
| + result->set(result->size() - 1, *global_context); |
| + return result; |
| +} |
| + |
| + |
| +bool GlobalContextTable::Lookup(Handle<GlobalContextTable> table, |
| + Handle<String> name, LookupResult* result) { |
| + for (int i = 0; i < table->size(); i++) { |
| + Handle<Context> context = GetContext(table, i); |
| + DCHECK(context->IsGlobalContext()); |
| + Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension())); |
| + int slot_index = ScopeInfo::ContextSlotIndex( |
| + scope_info, name, &result->mode_, &result->init_flag_, |
| + &result->maybe_assigned_flag_); |
| + |
| + if (slot_index >= 0) { |
| + result->context_index_ = i; |
| + result->slot_index_ = slot_index; |
| + return true; |
| + } |
| + } |
| + return false; |
| +} |
| + |
| + |
| Context* Context::declaration_context() { |
| Context* current = this; |
| while (!current->IsFunctionContext() && !current->IsNativeContext()) { |
| @@ -102,6 +140,53 @@ static Maybe<PropertyAttributes> UnscopableLookup(LookupIterator* it) { |
| return attrs; |
| } |
| +static void GetAttributesAndBindingFlags(VariableMode mode, |
| + InitializationFlag init_flag, |
| + PropertyAttributes* attributes, |
| + BindingFlags* binding_flags) { |
| + // Note: Fixed context slots are statically allocated by the compiler. |
|
rossberg
2014/11/06 12:29:12
Nit: why not move this comment next to the UNREACH
|
| + // Statically allocated variables always have a statically known mode, |
| + // which is the mode with which they were declared when added to the |
| + // scope. Thus, the DYNAMIC mode (which corresponds to dynamically |
| + // declared variables that were introduced through declaration nodes) |
| + // must not appear here. |
| + switch (mode) { |
| + case INTERNAL: // Fall through. |
| + case VAR: |
| + *attributes = NONE; |
| + *binding_flags = MUTABLE_IS_INITIALIZED; |
| + break; |
| + case LET: |
| + *attributes = NONE; |
| + *binding_flags = (init_flag == kNeedsInitialization) |
| + ? MUTABLE_CHECK_INITIALIZED |
| + : MUTABLE_IS_INITIALIZED; |
| + break; |
| + case CONST_LEGACY: |
| + *attributes = READ_ONLY; |
| + *binding_flags = (init_flag == kNeedsInitialization) |
| + ? IMMUTABLE_CHECK_INITIALIZED |
| + : IMMUTABLE_IS_INITIALIZED; |
| + break; |
| + case CONST: |
| + *attributes = READ_ONLY; |
| + *binding_flags = (init_flag == kNeedsInitialization) |
| + ? IMMUTABLE_CHECK_INITIALIZED_HARMONY |
| + : IMMUTABLE_IS_INITIALIZED_HARMONY; |
| + break; |
| + case MODULE: |
| + *attributes = READ_ONLY; |
| + *binding_flags = IMMUTABLE_IS_INITIALIZED_HARMONY; |
| + break; |
| + case DYNAMIC: |
| + case DYNAMIC_GLOBAL: |
| + case DYNAMIC_LOCAL: |
| + case TEMPORARY: |
| + UNREACHABLE(); |
| + break; |
| + } |
| +} |
| + |
| Handle<Object> Context::Lookup(Handle<String> name, |
| ContextLookupFlags flags, |
| @@ -122,8 +207,6 @@ Handle<Object> Context::Lookup(Handle<String> name, |
| PrintF(")\n"); |
| } |
| - bool visited_global_context = false; |
| - |
| do { |
| if (FLAG_trace_contexts) { |
| PrintF(" - looking in context %p", reinterpret_cast<void*>(*context)); |
| @@ -132,19 +215,6 @@ Handle<Object> Context::Lookup(Handle<String> name, |
| PrintF("\n"); |
| } |
| - if (follow_context_chain && FLAG_harmony_scoping && |
| - !visited_global_context && |
| - (context->IsGlobalContext() || context->IsNativeContext())) { |
| - // For lexical scoping, on a top level, we might resolve to the |
| - // lexical bindings introduced by later scrips. Therefore we need to |
| - // switch to the the last added global context during lookup here. |
| - context = Handle<Context>(context->global_object()->global_context()); |
| - visited_global_context = true; |
| - if (FLAG_trace_contexts) { |
| - PrintF(" - switching to current global context %p\n", |
| - reinterpret_cast<void*>(*context)); |
| - } |
| - } |
| // 1. Check global objects, subjects of with, and extension objects. |
| if (context->IsNativeContext() || |
| @@ -152,6 +222,30 @@ Handle<Object> Context::Lookup(Handle<String> name, |
| (context->IsFunctionContext() && context->has_extension())) { |
| Handle<JSReceiver> object( |
| JSReceiver::cast(context->extension()), isolate); |
| + |
| + if (context->IsNativeContext()) { |
| + if (FLAG_trace_contexts) { |
| + PrintF(" - trying other global contexts\n"); |
| + } |
| + // Try other global contexts. |
| + Handle<GlobalContextTable> global_contexts( |
| + context->global_object()->native_context()->global_context_table()); |
| + GlobalContextTable::LookupResult r; |
| + if (GlobalContextTable::Lookup(global_contexts, name, &r)) { |
| + if (FLAG_trace_contexts) { |
| + Handle<Context> c = GlobalContextTable::GetContext( |
| + global_contexts, r.context_index_); |
| + PrintF("=> found property in global context %d: %p\n", |
| + r.context_index_, reinterpret_cast<void*>(*c)); |
| + } |
| + *index = r.slot_index_; |
| + GetAttributesAndBindingFlags(r.mode_, r.init_flag_, attributes, |
| + binding_flags); |
| + return GlobalContextTable::GetContext(global_contexts, |
| + r.context_index_); |
| + } |
| + } |
| + |
| // 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. |
| @@ -206,45 +300,8 @@ Handle<Object> Context::Lookup(Handle<String> name, |
| slot_index, mode); |
| } |
| *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 |
| - // scope. Thus, the DYNAMIC mode (which corresponds to dynamically |
| - // declared variables that were introduced through declaration nodes) |
| - // must not appear here. |
| - switch (mode) { |
| - case INTERNAL: // Fall through. |
| - case VAR: |
| - *attributes = NONE; |
| - *binding_flags = MUTABLE_IS_INITIALIZED; |
| - break; |
| - case LET: |
| - *attributes = NONE; |
| - *binding_flags = (init_flag == kNeedsInitialization) |
| - ? MUTABLE_CHECK_INITIALIZED : MUTABLE_IS_INITIALIZED; |
| - break; |
| - case CONST_LEGACY: |
| - *attributes = READ_ONLY; |
| - *binding_flags = (init_flag == kNeedsInitialization) |
| - ? IMMUTABLE_CHECK_INITIALIZED : IMMUTABLE_IS_INITIALIZED; |
| - break; |
| - case CONST: |
| - *attributes = READ_ONLY; |
| - *binding_flags = (init_flag == kNeedsInitialization) |
| - ? IMMUTABLE_CHECK_INITIALIZED_HARMONY : |
| - IMMUTABLE_IS_INITIALIZED_HARMONY; |
| - break; |
| - case MODULE: |
| - *attributes = READ_ONLY; |
| - *binding_flags = IMMUTABLE_IS_INITIALIZED_HARMONY; |
| - break; |
| - case DYNAMIC: |
| - case DYNAMIC_GLOBAL: |
| - case DYNAMIC_LOCAL: |
| - case TEMPORARY: |
| - UNREACHABLE(); |
| - break; |
| - } |
| + GetAttributesAndBindingFlags(mode, init_flag, attributes, |
| + binding_flags); |
| return context; |
| } |