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