Index: src/contexts.cc |
diff --git a/src/contexts.cc b/src/contexts.cc |
index 537d92d0f4032cf5be4d6db03b850d9f8c6beeb7..37db84d04bd0e97cf2ef83b5aca9ce45da01712b 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 used = table->used(); |
+ int length = table->length(); |
+ CHECK(used >= 0 && length > 0 && used < length); |
+ if (used + 1 == length) { |
+ CHECK(length < Smi::kMaxValue / 2); |
+ result = Handle<GlobalContextTable>::cast( |
+ FixedArray::CopySize(table, length * 2)); |
+ } else { |
+ result = table; |
+ } |
+ result->set_used(used + 1); |
+ |
+ DCHECK(global_context->IsGlobalContext()); |
+ result->set(used + 1, *global_context); |
+ return result; |
+} |
+ |
+ |
+bool GlobalContextTable::Lookup(Handle<GlobalContextTable> table, |
+ Handle<String> name, LookupResult* result) { |
+ for (int i = 0; i < table->used(); 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) { |
+ 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: |
+ // 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. |
+ 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; |
} |