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/contexts.h" | 5 #include "src/contexts.h" |
6 | 6 |
7 #include "src/bootstrapper.h" | 7 #include "src/bootstrapper.h" |
8 #include "src/debug/debug.h" | 8 #include "src/debug/debug.h" |
9 #include "src/isolate-inl.h" | 9 #include "src/isolate-inl.h" |
10 | 10 |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
169 if (!unscopables->IsJSReceiver()) return Just(true); | 169 if (!unscopables->IsJSReceiver()) return Just(true); |
170 Handle<Object> blacklist; | 170 Handle<Object> blacklist; |
171 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 171 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
172 isolate, blacklist, | 172 isolate, blacklist, |
173 JSReceiver::GetProperty(Handle<JSReceiver>::cast(unscopables), | 173 JSReceiver::GetProperty(Handle<JSReceiver>::cast(unscopables), |
174 it->name()), | 174 it->name()), |
175 Nothing<bool>()); | 175 Nothing<bool>()); |
176 return Just(!blacklist->BooleanValue()); | 176 return Just(!blacklist->BooleanValue()); |
177 } | 177 } |
178 | 178 |
179 static void GetAttributesAndBindingFlags(VariableMode mode, | 179 static PropertyAttributes GetAttributesForMode(VariableMode mode) { |
180 InitializationFlag init_flag, | 180 DCHECK(IsDeclaredVariableMode(mode)); |
181 PropertyAttributes* attributes, | 181 return IsImmutableVariableMode(mode) ? READ_ONLY : NONE; |
182 BindingFlags* binding_flags) { | |
183 switch (mode) { | |
184 case VAR: | |
185 *attributes = NONE; | |
186 *binding_flags = BINDING_IS_INITIALIZED; | |
187 break; | |
188 case LET: | |
189 *attributes = NONE; | |
190 *binding_flags = (init_flag == kNeedsInitialization) | |
191 ? BINDING_CHECK_INITIALIZED | |
192 : BINDING_IS_INITIALIZED; | |
193 break; | |
194 case CONST_LEGACY: | |
195 DCHECK_EQ(kCreatedInitialized, init_flag); | |
196 *attributes = READ_ONLY; | |
197 *binding_flags = BINDING_IS_INITIALIZED; | |
198 break; | |
199 case CONST: | |
200 *attributes = READ_ONLY; | |
201 *binding_flags = (init_flag == kNeedsInitialization) | |
202 ? BINDING_CHECK_INITIALIZED | |
203 : BINDING_IS_INITIALIZED; | |
204 break; | |
205 case IMPORT: // TODO(neis): Make sure this is what we want for IMPORT. | |
206 case DYNAMIC: | |
207 case DYNAMIC_GLOBAL: | |
208 case DYNAMIC_LOCAL: | |
209 case TEMPORARY: | |
210 // Note: Fixed context slots are statically allocated by the compiler. | |
211 // Statically allocated variables always have a statically known mode, | |
212 // which is the mode with which they were declared when added to the | |
213 // scope. Thus, the DYNAMIC mode (which corresponds to dynamically | |
214 // declared variables that were introduced through declaration nodes) | |
215 // must not appear here. | |
216 UNREACHABLE(); | |
217 break; | |
218 } | |
219 } | 182 } |
220 | 183 |
221 Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags, | 184 Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags, |
222 int* index, PropertyAttributes* attributes, | 185 int* index, PropertyAttributes* attributes, |
223 BindingFlags* binding_flags, | 186 InitializationFlag* init_flag, |
224 VariableMode* variable_mode) { | 187 VariableMode* variable_mode) { |
225 Isolate* isolate = GetIsolate(); | 188 Isolate* isolate = GetIsolate(); |
226 Handle<Context> context(this, isolate); | 189 Handle<Context> context(this, isolate); |
227 | 190 |
228 bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0; | 191 bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0; |
229 bool failed_whitelist = false; | 192 bool failed_whitelist = false; |
230 *index = kNotFound; | 193 *index = kNotFound; |
231 *attributes = ABSENT; | 194 *attributes = ABSENT; |
232 *binding_flags = MISSING_BINDING; | 195 *init_flag = kCreatedInitialized; |
233 *variable_mode = VAR; | 196 *variable_mode = VAR; |
234 | 197 |
235 if (FLAG_trace_contexts) { | 198 if (FLAG_trace_contexts) { |
236 PrintF("Context::Lookup("); | 199 PrintF("Context::Lookup("); |
237 name->ShortPrint(); | 200 name->ShortPrint(); |
238 PrintF(")\n"); | 201 PrintF(")\n"); |
239 } | 202 } |
240 | 203 |
241 do { | 204 do { |
242 if (FLAG_trace_contexts) { | 205 if (FLAG_trace_contexts) { |
(...skipping 20 matching lines...) Expand all Loading... |
263 ScriptContextTable::LookupResult r; | 226 ScriptContextTable::LookupResult r; |
264 if (ScriptContextTable::Lookup(script_contexts, name, &r)) { | 227 if (ScriptContextTable::Lookup(script_contexts, name, &r)) { |
265 if (FLAG_trace_contexts) { | 228 if (FLAG_trace_contexts) { |
266 Handle<Context> c = ScriptContextTable::GetContext(script_contexts, | 229 Handle<Context> c = ScriptContextTable::GetContext(script_contexts, |
267 r.context_index); | 230 r.context_index); |
268 PrintF("=> found property in script context %d: %p\n", | 231 PrintF("=> found property in script context %d: %p\n", |
269 r.context_index, reinterpret_cast<void*>(*c)); | 232 r.context_index, reinterpret_cast<void*>(*c)); |
270 } | 233 } |
271 *index = r.slot_index; | 234 *index = r.slot_index; |
272 *variable_mode = r.mode; | 235 *variable_mode = r.mode; |
273 GetAttributesAndBindingFlags(r.mode, r.init_flag, attributes, | 236 *attributes = GetAttributesForMode(r.mode); |
274 binding_flags); | |
275 return ScriptContextTable::GetContext(script_contexts, | 237 return ScriptContextTable::GetContext(script_contexts, |
276 r.context_index); | 238 r.context_index); |
277 } | 239 } |
278 } | 240 } |
279 | 241 |
280 // Context extension objects needs to behave as if they have no | 242 // Context extension objects needs to behave as if they have no |
281 // prototype. So even if we want to follow prototype chains, we need | 243 // prototype. So even if we want to follow prototype chains, we need |
282 // to only do a local lookup for context extension objects. | 244 // to only do a local lookup for context extension objects. |
283 Maybe<PropertyAttributes> maybe = Nothing<PropertyAttributes>(); | 245 Maybe<PropertyAttributes> maybe = Nothing<PropertyAttributes>(); |
284 if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 || | 246 if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 || |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
319 | 281 |
320 // 2. Check the context proper if it has slots. | 282 // 2. Check the context proper if it has slots. |
321 if (context->IsFunctionContext() || context->IsBlockContext() || | 283 if (context->IsFunctionContext() || context->IsBlockContext() || |
322 context->IsScriptContext()) { | 284 context->IsScriptContext()) { |
323 // Use serialized scope information of functions and blocks to search | 285 // Use serialized scope information of functions and blocks to search |
324 // for the context index. | 286 // for the context index. |
325 Handle<ScopeInfo> scope_info(context->IsFunctionContext() | 287 Handle<ScopeInfo> scope_info(context->IsFunctionContext() |
326 ? context->closure()->shared()->scope_info() | 288 ? context->closure()->shared()->scope_info() |
327 : context->scope_info()); | 289 : context->scope_info()); |
328 VariableMode mode; | 290 VariableMode mode; |
329 InitializationFlag init_flag; | 291 InitializationFlag flag; |
330 // TODO(sigurds) Figure out whether maybe_assigned_flag should | |
331 // be used to compute binding_flags. | |
332 MaybeAssignedFlag maybe_assigned_flag; | 292 MaybeAssignedFlag maybe_assigned_flag; |
333 int slot_index = ScopeInfo::ContextSlotIndex( | 293 int slot_index = ScopeInfo::ContextSlotIndex(scope_info, name, &mode, |
334 scope_info, name, &mode, &init_flag, &maybe_assigned_flag); | 294 &flag, &maybe_assigned_flag); |
335 DCHECK(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS); | 295 DCHECK(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS); |
336 if (slot_index >= 0) { | 296 if (slot_index >= 0) { |
337 if (FLAG_trace_contexts) { | 297 if (FLAG_trace_contexts) { |
338 PrintF("=> found local in context slot %d (mode = %d)\n", | 298 PrintF("=> found local in context slot %d (mode = %d)\n", |
339 slot_index, mode); | 299 slot_index, mode); |
340 } | 300 } |
341 *index = slot_index; | 301 *index = slot_index; |
342 *variable_mode = mode; | 302 *variable_mode = mode; |
343 GetAttributesAndBindingFlags(mode, init_flag, attributes, | 303 *init_flag = flag; |
344 binding_flags); | 304 *attributes = GetAttributesForMode(mode); |
345 return context; | 305 return context; |
346 } | 306 } |
347 | 307 |
348 // Check the slot corresponding to the intermediate context holding | 308 // Check the slot corresponding to the intermediate context holding |
349 // only the function name variable. | 309 // only the function name variable. |
350 if (follow_context_chain && context->IsFunctionContext()) { | 310 if (follow_context_chain && context->IsFunctionContext()) { |
351 VariableMode mode; | 311 VariableMode mode; |
352 int function_index = scope_info->FunctionContextSlotIndex(*name, &mode); | 312 int function_index = scope_info->FunctionContextSlotIndex(*name, &mode); |
353 if (function_index >= 0) { | 313 if (function_index >= 0) { |
354 if (FLAG_trace_contexts) { | 314 if (FLAG_trace_contexts) { |
355 PrintF("=> found intermediate function in context slot %d\n", | 315 PrintF("=> found intermediate function in context slot %d\n", |
356 function_index); | 316 function_index); |
357 } | 317 } |
358 *index = function_index; | 318 *index = function_index; |
359 *attributes = READ_ONLY; | 319 *attributes = READ_ONLY; |
360 DCHECK(mode == CONST_LEGACY || mode == CONST); | 320 DCHECK(mode == CONST_LEGACY || mode == CONST); |
361 *binding_flags = BINDING_IS_INITIALIZED; | 321 *init_flag = kCreatedInitialized; |
362 *variable_mode = mode; | 322 *variable_mode = mode; |
363 return context; | 323 return context; |
364 } | 324 } |
365 } | 325 } |
366 | 326 |
367 } else if (context->IsCatchContext()) { | 327 } else if (context->IsCatchContext()) { |
368 // Catch contexts have the variable name in the extension slot. | 328 // Catch contexts have the variable name in the extension slot. |
369 if (String::Equals(name, handle(context->catch_name()))) { | 329 if (String::Equals(name, handle(context->catch_name()))) { |
370 if (FLAG_trace_contexts) { | 330 if (FLAG_trace_contexts) { |
371 PrintF("=> found in catch context\n"); | 331 PrintF("=> found in catch context\n"); |
372 } | 332 } |
373 *index = Context::THROWN_OBJECT_INDEX; | 333 *index = Context::THROWN_OBJECT_INDEX; |
374 *attributes = NONE; | 334 *attributes = NONE; |
375 *binding_flags = BINDING_IS_INITIALIZED; | 335 *init_flag = kCreatedInitialized; |
376 *variable_mode = VAR; | 336 *variable_mode = VAR; |
377 return context; | 337 return context; |
378 } | 338 } |
379 } else if (context->IsDebugEvaluateContext()) { | 339 } else if (context->IsDebugEvaluateContext()) { |
380 // Check materialized locals. | 340 // Check materialized locals. |
381 Object* obj = context->get(EXTENSION_INDEX); | 341 Object* obj = context->get(EXTENSION_INDEX); |
382 if (obj->IsJSReceiver()) { | 342 if (obj->IsJSReceiver()) { |
383 Handle<JSReceiver> extension(JSReceiver::cast(obj)); | 343 Handle<JSReceiver> extension(JSReceiver::cast(obj)); |
384 LookupIterator it(extension, name, extension); | 344 LookupIterator it(extension, name, extension); |
385 Maybe<bool> found = JSReceiver::HasProperty(&it); | 345 Maybe<bool> found = JSReceiver::HasProperty(&it); |
386 if (found.FromMaybe(false)) { | 346 if (found.FromMaybe(false)) { |
387 *attributes = NONE; | 347 *attributes = NONE; |
388 return extension; | 348 return extension; |
389 } | 349 } |
390 } | 350 } |
391 // Check the original context, but do not follow its context chain. | 351 // Check the original context, but do not follow its context chain. |
392 obj = context->get(WRAPPED_CONTEXT_INDEX); | 352 obj = context->get(WRAPPED_CONTEXT_INDEX); |
393 if (obj->IsContext()) { | 353 if (obj->IsContext()) { |
394 Handle<Object> result = Context::cast(obj)->Lookup( | 354 Handle<Object> result = |
395 name, DONT_FOLLOW_CHAINS, index, attributes, binding_flags, | 355 Context::cast(obj)->Lookup(name, DONT_FOLLOW_CHAINS, index, |
396 variable_mode); | 356 attributes, init_flag, variable_mode); |
397 if (!result.is_null()) return result; | 357 if (!result.is_null()) return result; |
398 } | 358 } |
399 // Check whitelist. Names that do not pass whitelist shall only resolve | 359 // Check whitelist. Names that do not pass whitelist shall only resolve |
400 // to with, script or native contexts up the context chain. | 360 // to with, script or native contexts up the context chain. |
401 obj = context->get(WHITE_LIST_INDEX); | 361 obj = context->get(WHITE_LIST_INDEX); |
402 if (obj->IsStringSet()) { | 362 if (obj->IsStringSet()) { |
403 failed_whitelist = failed_whitelist || !StringSet::cast(obj)->Has(name); | 363 failed_whitelist = failed_whitelist || !StringSet::cast(obj)->Has(name); |
404 } | 364 } |
405 } | 365 } |
406 | 366 |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
613 | 573 |
614 int previous_value = errors_thrown()->value(); | 574 int previous_value = errors_thrown()->value(); |
615 set_errors_thrown(Smi::FromInt(previous_value + 1)); | 575 set_errors_thrown(Smi::FromInt(previous_value + 1)); |
616 } | 576 } |
617 | 577 |
618 | 578 |
619 int Context::GetErrorsThrown() { return errors_thrown()->value(); } | 579 int Context::GetErrorsThrown() { return errors_thrown()->value(); } |
620 | 580 |
621 } // namespace internal | 581 } // namespace internal |
622 } // namespace v8 | 582 } // namespace v8 |
OLD | NEW |