Chromium Code Reviews| Index: src/contexts.cc |
| diff --git a/src/contexts.cc b/src/contexts.cc |
| index 537d92d0f4032cf5be4d6db03b850d9f8c6beeb7..cbabccaaf63bebe2bcf973021fd96d6a07b17e39 100644 |
| --- a/src/contexts.cc |
| +++ b/src/contexts.cc |
| @@ -11,6 +11,48 @@ |
| namespace v8 { |
| namespace internal { |
| + |
| +Handle<GlobalContextTable> GlobalContextTable::Extend( |
| + Handle<GlobalContextTable> table, Handle<Context> global_context) { |
| + Handle<GlobalContextTable> result; |
| + int size = table->size(); |
| + int length = table->length(); |
| + CHECK(size >= 0 && length > 0 && size < length); |
|
adamk
2014/11/06 20:18:05
This looks like the sort of check I'd expect in ob
Dmitry Lomov (no reviews)
2014/11/07 10:18:47
This check is here for int-overflow protection.
V
|
| + if (size + 1 == length) { |
| + CHECK(length < Smi::kMaxValue / 2); |
|
adamk
2014/11/06 20:18:05
This is basically a crash-if-OOM sort of check, ri
Dmitry Lomov (no reviews)
2014/11/07 10:18:47
No this is a sanity/correctness check to make sure
|
| + result = Handle<GlobalContextTable>::cast( |
| + FixedArray::CopySize(table, length * 2)); |
| + } else { |
| + result = table; |
| + } |
| + result->set(kSizeSlot, Smi::FromInt(size + 1)); |
| + |
| + DCHECK(global_context->IsGlobalContext()); |
| + result->set(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 +144,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. |
| + // 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 +211,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 +219,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 +226,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 +304,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; |
| } |