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 |