| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #include "src/bootstrapper.h" | 7 #include "src/bootstrapper.h" |
| 8 #include "src/debug.h" | 8 #include "src/debug.h" |
| 9 #include "src/scopeinfo.h" | 9 #include "src/scopeinfo.h" |
| 10 | 10 |
| 11 namespace v8 { | 11 namespace v8 { |
| 12 namespace internal { | 12 namespace internal { |
| 13 | 13 |
| 14 |
| 15 Handle<GlobalContextTable> GlobalContextTable::Extend( |
| 16 Handle<GlobalContextTable> table, Handle<Context> global_context) { |
| 17 Handle<GlobalContextTable> result; |
| 18 int used = table->used(); |
| 19 int length = table->length(); |
| 20 CHECK(used >= 0 && length > 0 && used < length); |
| 21 if (used + 1 == length) { |
| 22 CHECK(length < Smi::kMaxValue / 2); |
| 23 result = Handle<GlobalContextTable>::cast( |
| 24 FixedArray::CopySize(table, length * 2)); |
| 25 } else { |
| 26 result = table; |
| 27 } |
| 28 result->set_used(used + 1); |
| 29 |
| 30 DCHECK(global_context->IsGlobalContext()); |
| 31 result->set(used + 1, *global_context); |
| 32 return result; |
| 33 } |
| 34 |
| 35 |
| 36 bool GlobalContextTable::Lookup(Handle<GlobalContextTable> table, |
| 37 Handle<String> name, LookupResult* result) { |
| 38 for (int i = 0; i < table->used(); i++) { |
| 39 Handle<Context> context = GetContext(table, i); |
| 40 DCHECK(context->IsGlobalContext()); |
| 41 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension())); |
| 42 int slot_index = ScopeInfo::ContextSlotIndex( |
| 43 scope_info, name, &result->mode, &result->init_flag, |
| 44 &result->maybe_assigned_flag); |
| 45 |
| 46 if (slot_index >= 0) { |
| 47 result->context_index = i; |
| 48 result->slot_index = slot_index; |
| 49 return true; |
| 50 } |
| 51 } |
| 52 return false; |
| 53 } |
| 54 |
| 55 |
| 14 Context* Context::declaration_context() { | 56 Context* Context::declaration_context() { |
| 15 Context* current = this; | 57 Context* current = this; |
| 16 while (!current->IsFunctionContext() && !current->IsNativeContext()) { | 58 while (!current->IsFunctionContext() && !current->IsNativeContext()) { |
| 17 current = current->previous(); | 59 current = current->previous(); |
| 18 DCHECK(current->closure() == closure()); | 60 DCHECK(current->closure() == closure()); |
| 19 } | 61 } |
| 20 return current; | 62 return current; |
| 21 } | 63 } |
| 22 | 64 |
| 23 | 65 |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 95 Maybe<bool> blacklist = JSReceiver::HasProperty( | 137 Maybe<bool> blacklist = JSReceiver::HasProperty( |
| 96 Handle<JSReceiver>::cast(unscopables), it->name()); | 138 Handle<JSReceiver>::cast(unscopables), it->name()); |
| 97 if (!blacklist.has_value) { | 139 if (!blacklist.has_value) { |
| 98 DCHECK(isolate->has_pending_exception()); | 140 DCHECK(isolate->has_pending_exception()); |
| 99 return Maybe<PropertyAttributes>(); | 141 return Maybe<PropertyAttributes>(); |
| 100 } | 142 } |
| 101 if (blacklist.value) return maybe(ABSENT); | 143 if (blacklist.value) return maybe(ABSENT); |
| 102 return attrs; | 144 return attrs; |
| 103 } | 145 } |
| 104 | 146 |
| 147 static void GetAttributesAndBindingFlags(VariableMode mode, |
| 148 InitializationFlag init_flag, |
| 149 PropertyAttributes* attributes, |
| 150 BindingFlags* binding_flags) { |
| 151 switch (mode) { |
| 152 case INTERNAL: // Fall through. |
| 153 case VAR: |
| 154 *attributes = NONE; |
| 155 *binding_flags = MUTABLE_IS_INITIALIZED; |
| 156 break; |
| 157 case LET: |
| 158 *attributes = NONE; |
| 159 *binding_flags = (init_flag == kNeedsInitialization) |
| 160 ? MUTABLE_CHECK_INITIALIZED |
| 161 : MUTABLE_IS_INITIALIZED; |
| 162 break; |
| 163 case CONST_LEGACY: |
| 164 *attributes = READ_ONLY; |
| 165 *binding_flags = (init_flag == kNeedsInitialization) |
| 166 ? IMMUTABLE_CHECK_INITIALIZED |
| 167 : IMMUTABLE_IS_INITIALIZED; |
| 168 break; |
| 169 case CONST: |
| 170 *attributes = READ_ONLY; |
| 171 *binding_flags = (init_flag == kNeedsInitialization) |
| 172 ? IMMUTABLE_CHECK_INITIALIZED_HARMONY |
| 173 : IMMUTABLE_IS_INITIALIZED_HARMONY; |
| 174 break; |
| 175 case MODULE: |
| 176 *attributes = READ_ONLY; |
| 177 *binding_flags = IMMUTABLE_IS_INITIALIZED_HARMONY; |
| 178 break; |
| 179 case DYNAMIC: |
| 180 case DYNAMIC_GLOBAL: |
| 181 case DYNAMIC_LOCAL: |
| 182 case TEMPORARY: |
| 183 // Note: Fixed context slots are statically allocated by the compiler. |
| 184 // Statically allocated variables always have a statically known mode, |
| 185 // which is the mode with which they were declared when added to the |
| 186 // scope. Thus, the DYNAMIC mode (which corresponds to dynamically |
| 187 // declared variables that were introduced through declaration nodes) |
| 188 // must not appear here. |
| 189 UNREACHABLE(); |
| 190 break; |
| 191 } |
| 192 } |
| 193 |
| 105 | 194 |
| 106 Handle<Object> Context::Lookup(Handle<String> name, | 195 Handle<Object> Context::Lookup(Handle<String> name, |
| 107 ContextLookupFlags flags, | 196 ContextLookupFlags flags, |
| 108 int* index, | 197 int* index, |
| 109 PropertyAttributes* attributes, | 198 PropertyAttributes* attributes, |
| 110 BindingFlags* binding_flags) { | 199 BindingFlags* binding_flags) { |
| 111 Isolate* isolate = GetIsolate(); | 200 Isolate* isolate = GetIsolate(); |
| 112 Handle<Context> context(this, isolate); | 201 Handle<Context> context(this, isolate); |
| 113 | 202 |
| 114 bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0; | 203 bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0; |
| 115 *index = -1; | 204 *index = -1; |
| 116 *attributes = ABSENT; | 205 *attributes = ABSENT; |
| 117 *binding_flags = MISSING_BINDING; | 206 *binding_flags = MISSING_BINDING; |
| 118 | 207 |
| 119 if (FLAG_trace_contexts) { | 208 if (FLAG_trace_contexts) { |
| 120 PrintF("Context::Lookup("); | 209 PrintF("Context::Lookup("); |
| 121 name->ShortPrint(); | 210 name->ShortPrint(); |
| 122 PrintF(")\n"); | 211 PrintF(")\n"); |
| 123 } | 212 } |
| 124 | 213 |
| 125 bool visited_global_context = false; | |
| 126 | |
| 127 do { | 214 do { |
| 128 if (FLAG_trace_contexts) { | 215 if (FLAG_trace_contexts) { |
| 129 PrintF(" - looking in context %p", reinterpret_cast<void*>(*context)); | 216 PrintF(" - looking in context %p", reinterpret_cast<void*>(*context)); |
| 130 if (context->IsGlobalContext()) PrintF(" (global context)"); | 217 if (context->IsGlobalContext()) PrintF(" (global context)"); |
| 131 if (context->IsNativeContext()) PrintF(" (native context)"); | 218 if (context->IsNativeContext()) PrintF(" (native context)"); |
| 132 PrintF("\n"); | 219 PrintF("\n"); |
| 133 } | 220 } |
| 134 | 221 |
| 135 if (follow_context_chain && FLAG_harmony_scoping && | |
| 136 !visited_global_context && | |
| 137 (context->IsGlobalContext() || context->IsNativeContext())) { | |
| 138 // For lexical scoping, on a top level, we might resolve to the | |
| 139 // lexical bindings introduced by later scrips. Therefore we need to | |
| 140 // switch to the the last added global context during lookup here. | |
| 141 context = Handle<Context>(context->global_object()->global_context()); | |
| 142 visited_global_context = true; | |
| 143 if (FLAG_trace_contexts) { | |
| 144 PrintF(" - switching to current global context %p\n", | |
| 145 reinterpret_cast<void*>(*context)); | |
| 146 } | |
| 147 } | |
| 148 | 222 |
| 149 // 1. Check global objects, subjects of with, and extension objects. | 223 // 1. Check global objects, subjects of with, and extension objects. |
| 150 if (context->IsNativeContext() || | 224 if (context->IsNativeContext() || |
| 151 context->IsWithContext() || | 225 context->IsWithContext() || |
| 152 (context->IsFunctionContext() && context->has_extension())) { | 226 (context->IsFunctionContext() && context->has_extension())) { |
| 153 Handle<JSReceiver> object( | 227 Handle<JSReceiver> object( |
| 154 JSReceiver::cast(context->extension()), isolate); | 228 JSReceiver::cast(context->extension()), isolate); |
| 229 |
| 230 if (context->IsNativeContext()) { |
| 231 if (FLAG_trace_contexts) { |
| 232 PrintF(" - trying other global contexts\n"); |
| 233 } |
| 234 // Try other global contexts. |
| 235 Handle<GlobalContextTable> global_contexts( |
| 236 context->global_object()->native_context()->global_context_table()); |
| 237 GlobalContextTable::LookupResult r; |
| 238 if (GlobalContextTable::Lookup(global_contexts, name, &r)) { |
| 239 if (FLAG_trace_contexts) { |
| 240 Handle<Context> c = GlobalContextTable::GetContext(global_contexts, |
| 241 r.context_index); |
| 242 PrintF("=> found property in global context %d: %p\n", |
| 243 r.context_index, reinterpret_cast<void*>(*c)); |
| 244 } |
| 245 *index = r.slot_index; |
| 246 GetAttributesAndBindingFlags(r.mode, r.init_flag, attributes, |
| 247 binding_flags); |
| 248 return GlobalContextTable::GetContext(global_contexts, |
| 249 r.context_index); |
| 250 } |
| 251 } |
| 252 |
| 155 // Context extension objects needs to behave as if they have no | 253 // Context extension objects needs to behave as if they have no |
| 156 // prototype. So even if we want to follow prototype chains, we need | 254 // prototype. So even if we want to follow prototype chains, we need |
| 157 // to only do a local lookup for context extension objects. | 255 // to only do a local lookup for context extension objects. |
| 158 Maybe<PropertyAttributes> maybe; | 256 Maybe<PropertyAttributes> maybe; |
| 159 if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 || | 257 if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 || |
| 160 object->IsJSContextExtensionObject()) { | 258 object->IsJSContextExtensionObject()) { |
| 161 maybe = JSReceiver::GetOwnPropertyAttributes(object, name); | 259 maybe = JSReceiver::GetOwnPropertyAttributes(object, name); |
| 162 } else if (context->IsWithContext()) { | 260 } else if (context->IsWithContext()) { |
| 163 LookupIterator it(object, name); | 261 LookupIterator it(object, name); |
| 164 maybe = UnscopableLookup(&it); | 262 maybe = UnscopableLookup(&it); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 199 MaybeAssignedFlag maybe_assigned_flag; | 297 MaybeAssignedFlag maybe_assigned_flag; |
| 200 int slot_index = ScopeInfo::ContextSlotIndex( | 298 int slot_index = ScopeInfo::ContextSlotIndex( |
| 201 scope_info, name, &mode, &init_flag, &maybe_assigned_flag); | 299 scope_info, name, &mode, &init_flag, &maybe_assigned_flag); |
| 202 DCHECK(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS); | 300 DCHECK(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS); |
| 203 if (slot_index >= 0) { | 301 if (slot_index >= 0) { |
| 204 if (FLAG_trace_contexts) { | 302 if (FLAG_trace_contexts) { |
| 205 PrintF("=> found local in context slot %d (mode = %d)\n", | 303 PrintF("=> found local in context slot %d (mode = %d)\n", |
| 206 slot_index, mode); | 304 slot_index, mode); |
| 207 } | 305 } |
| 208 *index = slot_index; | 306 *index = slot_index; |
| 209 // Note: Fixed context slots are statically allocated by the compiler. | 307 GetAttributesAndBindingFlags(mode, init_flag, attributes, |
| 210 // Statically allocated variables always have a statically known mode, | 308 binding_flags); |
| 211 // which is the mode with which they were declared when added to the | |
| 212 // scope. Thus, the DYNAMIC mode (which corresponds to dynamically | |
| 213 // declared variables that were introduced through declaration nodes) | |
| 214 // must not appear here. | |
| 215 switch (mode) { | |
| 216 case INTERNAL: // Fall through. | |
| 217 case VAR: | |
| 218 *attributes = NONE; | |
| 219 *binding_flags = MUTABLE_IS_INITIALIZED; | |
| 220 break; | |
| 221 case LET: | |
| 222 *attributes = NONE; | |
| 223 *binding_flags = (init_flag == kNeedsInitialization) | |
| 224 ? MUTABLE_CHECK_INITIALIZED : MUTABLE_IS_INITIALIZED; | |
| 225 break; | |
| 226 case CONST_LEGACY: | |
| 227 *attributes = READ_ONLY; | |
| 228 *binding_flags = (init_flag == kNeedsInitialization) | |
| 229 ? IMMUTABLE_CHECK_INITIALIZED : IMMUTABLE_IS_INITIALIZED; | |
| 230 break; | |
| 231 case CONST: | |
| 232 *attributes = READ_ONLY; | |
| 233 *binding_flags = (init_flag == kNeedsInitialization) | |
| 234 ? IMMUTABLE_CHECK_INITIALIZED_HARMONY : | |
| 235 IMMUTABLE_IS_INITIALIZED_HARMONY; | |
| 236 break; | |
| 237 case MODULE: | |
| 238 *attributes = READ_ONLY; | |
| 239 *binding_flags = IMMUTABLE_IS_INITIALIZED_HARMONY; | |
| 240 break; | |
| 241 case DYNAMIC: | |
| 242 case DYNAMIC_GLOBAL: | |
| 243 case DYNAMIC_LOCAL: | |
| 244 case TEMPORARY: | |
| 245 UNREACHABLE(); | |
| 246 break; | |
| 247 } | |
| 248 return context; | 309 return context; |
| 249 } | 310 } |
| 250 | 311 |
| 251 // Check the slot corresponding to the intermediate context holding | 312 // Check the slot corresponding to the intermediate context holding |
| 252 // only the function name variable. | 313 // only the function name variable. |
| 253 if (follow_context_chain && context->IsFunctionContext()) { | 314 if (follow_context_chain && context->IsFunctionContext()) { |
| 254 VariableMode mode; | 315 VariableMode mode; |
| 255 int function_index = scope_info->FunctionContextSlotIndex(*name, &mode); | 316 int function_index = scope_info->FunctionContextSlotIndex(*name, &mode); |
| 256 if (function_index >= 0) { | 317 if (function_index >= 0) { |
| 257 if (FLAG_trace_contexts) { | 318 if (FLAG_trace_contexts) { |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 427 bool Context::IsBootstrappingOrGlobalObject(Isolate* isolate, Object* object) { | 488 bool Context::IsBootstrappingOrGlobalObject(Isolate* isolate, Object* object) { |
| 428 // During bootstrapping we allow all objects to pass as global | 489 // During bootstrapping we allow all objects to pass as global |
| 429 // objects. This is necessary to fix circular dependencies. | 490 // objects. This is necessary to fix circular dependencies. |
| 430 return isolate->heap()->gc_state() != Heap::NOT_IN_GC || | 491 return isolate->heap()->gc_state() != Heap::NOT_IN_GC || |
| 431 isolate->bootstrapper()->IsActive() || | 492 isolate->bootstrapper()->IsActive() || |
| 432 object->IsGlobalObject(); | 493 object->IsGlobalObject(); |
| 433 } | 494 } |
| 434 #endif | 495 #endif |
| 435 | 496 |
| 436 } } // namespace v8::internal | 497 } } // namespace v8::internal |
| OLD | NEW |