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 |