OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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/scopes.h" | 7 #include "src/scopes.h" |
8 | 8 |
9 #include "src/accessors.h" | 9 #include "src/accessors.h" |
10 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
(...skipping 16 matching lines...) Expand all Loading... |
27 VariableMap::VariableMap(Zone* zone) | 27 VariableMap::VariableMap(Zone* zone) |
28 : ZoneHashMap(ZoneHashMap::PointersMatch, 8, ZoneAllocationPolicy(zone)), | 28 : ZoneHashMap(ZoneHashMap::PointersMatch, 8, ZoneAllocationPolicy(zone)), |
29 zone_(zone) {} | 29 zone_(zone) {} |
30 VariableMap::~VariableMap() {} | 30 VariableMap::~VariableMap() {} |
31 | 31 |
32 | 32 |
33 Variable* VariableMap::Declare(Scope* scope, const AstRawString* name, | 33 Variable* VariableMap::Declare(Scope* scope, const AstRawString* name, |
34 VariableMode mode, bool is_valid_lhs, | 34 VariableMode mode, bool is_valid_lhs, |
35 Variable::Kind kind, | 35 Variable::Kind kind, |
36 InitializationFlag initialization_flag, | 36 InitializationFlag initialization_flag, |
| 37 int position, |
37 MaybeAssignedFlag maybe_assigned_flag) { | 38 MaybeAssignedFlag maybe_assigned_flag) { |
38 // AstRawStrings are unambiguous, i.e., the same string is always represented | 39 // AstRawStrings are unambiguous, i.e., the same string is always represented |
39 // by the same AstRawString*. | 40 // by the same AstRawString*. |
40 // FIXME(marja): fix the type of Lookup. | 41 // FIXME(marja): fix the type of Lookup. |
41 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash(), | 42 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash(), |
42 true, ZoneAllocationPolicy(zone())); | 43 true, ZoneAllocationPolicy(zone())); |
43 if (p->value == NULL) { | 44 if (p->value == NULL) { |
44 // The variable has not been declared yet -> insert it. | 45 // The variable has not been declared yet -> insert it. |
45 DCHECK(p->key == name); | 46 DCHECK(p->key == name); |
46 p->value = new (zone()) Variable(scope, name, mode, is_valid_lhs, kind, | 47 Variable* variable = |
47 initialization_flag, maybe_assigned_flag); | 48 new (zone()) Variable(scope, name, mode, is_valid_lhs, kind, |
| 49 initialization_flag, maybe_assigned_flag); |
| 50 variable->set_initializer_position(position); |
| 51 p->value = variable; |
48 } | 52 } |
49 return reinterpret_cast<Variable*>(p->value); | 53 return reinterpret_cast<Variable*>(p->value); |
50 } | 54 } |
51 | 55 |
52 | 56 |
53 Variable* VariableMap::Lookup(const AstRawString* name) { | 57 Variable* VariableMap::Lookup(const AstRawString* name) { |
54 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash(), | 58 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash(), |
55 false, ZoneAllocationPolicy(NULL)); | 59 false, ZoneAllocationPolicy(NULL)); |
56 if (p != NULL) { | 60 if (p != NULL) { |
57 DCHECK(reinterpret_cast<const AstRawString*>(p->key) == name); | 61 DCHECK(reinterpret_cast<const AstRawString*>(p->key) == name); |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
256 // Traverse the scope tree up to the first unresolved scope or the global | 260 // Traverse the scope tree up to the first unresolved scope or the global |
257 // scope and start scope resolution and variable allocation from that scope. | 261 // scope and start scope resolution and variable allocation from that scope. |
258 while (!top->is_script_scope() && | 262 while (!top->is_script_scope() && |
259 !top->outer_scope()->already_resolved()) { | 263 !top->outer_scope()->already_resolved()) { |
260 top = top->outer_scope(); | 264 top = top->outer_scope(); |
261 } | 265 } |
262 | 266 |
263 // Allocate the variables. | 267 // Allocate the variables. |
264 { | 268 { |
265 AstNodeFactory ast_node_factory(info->ast_value_factory()); | 269 AstNodeFactory ast_node_factory(info->ast_value_factory()); |
266 if (!top->AllocateVariables(info, &ast_node_factory)) return false; | 270 if (!top->AllocateVariables(info, &ast_node_factory)) { |
| 271 DCHECK(top->pending_error_handler_.has_pending_error()); |
| 272 top->pending_error_handler_.ThrowPendingError(info->isolate(), |
| 273 info->script()); |
| 274 return false; |
| 275 } |
267 } | 276 } |
268 | 277 |
269 #ifdef DEBUG | 278 #ifdef DEBUG |
270 if (info->isolate()->bootstrapper()->IsActive() | 279 if (info->isolate()->bootstrapper()->IsActive() |
271 ? FLAG_print_builtin_scopes | 280 ? FLAG_print_builtin_scopes |
272 : FLAG_print_scopes) { | 281 : FLAG_print_scopes) { |
273 scope->Print(); | 282 scope->Print(); |
274 } | 283 } |
275 #endif | 284 #endif |
276 | 285 |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
395 | 404 |
396 mode = DYNAMIC; | 405 mode = DYNAMIC; |
397 location = Variable::LOOKUP; | 406 location = Variable::LOOKUP; |
398 init_flag = kCreatedInitialized; | 407 init_flag = kCreatedInitialized; |
399 // Be conservative and flag parameters as maybe assigned. Better information | 408 // Be conservative and flag parameters as maybe assigned. Better information |
400 // would require ScopeInfo to serialize the maybe_assigned bit also for | 409 // would require ScopeInfo to serialize the maybe_assigned bit also for |
401 // parameters. | 410 // parameters. |
402 maybe_assigned_flag = kMaybeAssigned; | 411 maybe_assigned_flag = kMaybeAssigned; |
403 } | 412 } |
404 | 413 |
405 Variable* var = variables_.Declare(this, name, mode, true, Variable::NORMAL, | 414 Variable* var = |
406 init_flag, maybe_assigned_flag); | 415 variables_.Declare(this, name, mode, true, Variable::NORMAL, init_flag, |
| 416 RelocInfo::kNoPosition, maybe_assigned_flag); |
407 var->AllocateTo(location, index); | 417 var->AllocateTo(location, index); |
408 return var; | 418 return var; |
409 } | 419 } |
410 | 420 |
411 | 421 |
412 Variable* Scope::LookupFunctionVar(const AstRawString* name, | 422 Variable* Scope::LookupFunctionVar(const AstRawString* name, |
413 AstNodeFactory* factory) { | 423 AstNodeFactory* factory) { |
414 if (function_ != NULL && function_->proxy()->raw_name() == name) { | 424 if (function_ != NULL && function_->proxy()->raw_name() == name) { |
415 return function_->proxy()->var(); | 425 return function_->proxy()->var(); |
416 } else if (!scope_info_.is_null()) { | 426 } else if (!scope_info_.is_null()) { |
417 // If we are backed by a scope info, try to lookup the variable there. | 427 // If we are backed by a scope info, try to lookup the variable there. |
418 VariableMode mode; | 428 VariableMode mode; |
419 int index = scope_info_->FunctionContextSlotIndex(*(name->string()), &mode); | 429 int index = scope_info_->FunctionContextSlotIndex(*(name->string()), &mode); |
420 if (index < 0) return NULL; | 430 if (index < 0) return NULL; |
421 Variable* var = new(zone()) Variable( | 431 Variable* var = |
422 this, name, mode, true /* is valid LHS */, | 432 new (zone()) Variable(this, name, mode, true /* is valid LHS */, |
423 Variable::NORMAL, kCreatedInitialized); | 433 Variable::NORMAL, kCreatedInitialized); |
424 VariableProxy* proxy = factory->NewVariableProxy(var); | 434 VariableProxy* proxy = factory->NewVariableProxy(var); |
425 VariableDeclaration* declaration = factory->NewVariableDeclaration( | 435 VariableDeclaration* declaration = factory->NewVariableDeclaration( |
426 proxy, mode, this, RelocInfo::kNoPosition); | 436 proxy, mode, this, RelocInfo::kNoPosition); |
427 DeclareFunctionVar(declaration); | 437 DeclareFunctionVar(declaration); |
428 var->AllocateTo(Variable::CONTEXT, index); | 438 var->AllocateTo(Variable::CONTEXT, index); |
429 return var; | 439 return var; |
430 } else { | 440 } else { |
431 return NULL; | 441 return NULL; |
432 } | 442 } |
433 } | 443 } |
(...skipping 20 matching lines...) Expand all Loading... |
454 DCHECK_NULL(rest_parameter_); | 464 DCHECK_NULL(rest_parameter_); |
455 rest_parameter_ = var; | 465 rest_parameter_ = var; |
456 rest_index_ = num_parameters(); | 466 rest_index_ = num_parameters(); |
457 } | 467 } |
458 params_.Add(var, zone()); | 468 params_.Add(var, zone()); |
459 return var; | 469 return var; |
460 } | 470 } |
461 | 471 |
462 | 472 |
463 Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode, | 473 Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode, |
464 InitializationFlag init_flag, | 474 InitializationFlag init_flag, int position, |
| 475 bool is_function, |
465 MaybeAssignedFlag maybe_assigned_flag) { | 476 MaybeAssignedFlag maybe_assigned_flag) { |
466 DCHECK(!already_resolved()); | 477 DCHECK(!already_resolved()); |
467 // This function handles VAR, LET, and CONST modes. DYNAMIC variables are | 478 // This function handles VAR, LET, and CONST modes. DYNAMIC variables are |
468 // introduces during variable allocation, INTERNAL variables are allocated | 479 // introduces during variable allocation, INTERNAL variables are allocated |
469 // explicitly, and TEMPORARY variables are allocated via NewTemporary(). | 480 // explicitly, and TEMPORARY variables are allocated via NewTemporary(). |
470 DCHECK(IsDeclaredVariableMode(mode)); | 481 DCHECK(IsDeclaredVariableMode(mode)); |
471 ++num_var_or_const_; | 482 ++num_var_or_const_; |
472 return variables_.Declare(this, name, mode, true, Variable::NORMAL, init_flag, | 483 return variables_.Declare(this, name, mode, true, |
473 maybe_assigned_flag); | 484 is_function ? Variable::FUNCTION : Variable::NORMAL, |
| 485 init_flag, position, maybe_assigned_flag); |
474 } | 486 } |
475 | 487 |
476 | 488 |
477 Variable* Scope::DeclareDynamicGlobal(const AstRawString* name) { | 489 Variable* Scope::DeclareDynamicGlobal(const AstRawString* name) { |
478 DCHECK(is_script_scope()); | 490 DCHECK(is_script_scope()); |
479 return variables_.Declare(this, | 491 return variables_.Declare(this, |
480 name, | 492 name, |
481 DYNAMIC_GLOBAL, | 493 DYNAMIC_GLOBAL, |
482 true, | 494 true, |
483 Variable::NORMAL, | 495 Variable::NORMAL, |
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
761 int end_pos = scope->end_position(); | 773 int end_pos = scope->end_position(); |
762 DCHECK(beg_pos >= 0 && end_pos >= 0); | 774 DCHECK(beg_pos >= 0 && end_pos >= 0); |
763 if (beg_pos <= position && position < end_pos) { | 775 if (beg_pos <= position && position < end_pos) { |
764 scope->GetNestedScopeChain(isolate, chain, position); | 776 scope->GetNestedScopeChain(isolate, chain, position); |
765 return; | 777 return; |
766 } | 778 } |
767 } | 779 } |
768 } | 780 } |
769 | 781 |
770 | 782 |
| 783 void Scope::ReportMessage(int start_position, int end_position, |
| 784 const char* message, const AstRawString* arg) { |
| 785 // Propagate the error to the topmost scope targeted by this scope analysis |
| 786 // phase. |
| 787 Scope* top = this; |
| 788 while (!top->is_script_scope() && !top->outer_scope()->already_resolved()) { |
| 789 top = top->outer_scope(); |
| 790 } |
| 791 |
| 792 top->pending_error_handler_.ReportMessageAt(start_position, end_position, |
| 793 message, arg, kReferenceError); |
| 794 } |
| 795 |
| 796 |
771 #ifdef DEBUG | 797 #ifdef DEBUG |
772 static const char* Header(ScopeType scope_type) { | 798 static const char* Header(ScopeType scope_type) { |
773 switch (scope_type) { | 799 switch (scope_type) { |
774 case EVAL_SCOPE: return "eval"; | 800 case EVAL_SCOPE: return "eval"; |
775 case FUNCTION_SCOPE: return "function"; | 801 case FUNCTION_SCOPE: return "function"; |
776 case MODULE_SCOPE: return "module"; | 802 case MODULE_SCOPE: return "module"; |
777 case SCRIPT_SCOPE: return "global"; | 803 case SCRIPT_SCOPE: return "global"; |
778 case CATCH_SCOPE: return "catch"; | 804 case CATCH_SCOPE: return "catch"; |
779 case BLOCK_SCOPE: return "block"; | 805 case BLOCK_SCOPE: return "block"; |
780 case WITH_SCOPE: return "with"; | 806 case WITH_SCOPE: return "with"; |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1043 // If the proxy is already resolved there's nothing to do | 1069 // If the proxy is already resolved there's nothing to do |
1044 // (functions and consts may be resolved by the parser). | 1070 // (functions and consts may be resolved by the parser). |
1045 if (proxy->is_resolved()) return true; | 1071 if (proxy->is_resolved()) return true; |
1046 | 1072 |
1047 // Otherwise, try to resolve the variable. | 1073 // Otherwise, try to resolve the variable. |
1048 BindingKind binding_kind; | 1074 BindingKind binding_kind; |
1049 Variable* var = LookupRecursive(proxy, &binding_kind, factory); | 1075 Variable* var = LookupRecursive(proxy, &binding_kind, factory); |
1050 switch (binding_kind) { | 1076 switch (binding_kind) { |
1051 case BOUND: | 1077 case BOUND: |
1052 // We found a variable binding. | 1078 // We found a variable binding. |
| 1079 if (is_strong(language_mode())) { |
| 1080 // Check for declaration-after use (for variables) in strong mode. Note |
| 1081 // that we can only do this in the case where we have seen the |
| 1082 // declaration. And we always allow referencing functions (for now). |
| 1083 |
| 1084 // If both the use and the declaration are inside an eval scope |
| 1085 // (possibly indirectly), or one of them is, we need to check whether |
| 1086 // they are inside the same eval scope or different |
| 1087 // ones. TODO(marja,rossberg): Detect errors across different evals |
| 1088 // (depends on the future of eval in strong mode). |
| 1089 const Scope* eval_for_use = NearestOuterEvalScope(); |
| 1090 const Scope* eval_for_declaration = |
| 1091 var->scope()->NearestOuterEvalScope(); |
| 1092 |
| 1093 if (proxy->position() != RelocInfo::kNoPosition && |
| 1094 proxy->position() < var->initializer_position() && |
| 1095 !var->is_function() && eval_for_use == eval_for_declaration) { |
| 1096 DCHECK(proxy->end_position() != RelocInfo::kNoPosition); |
| 1097 ReportMessage(proxy->position(), proxy->end_position(), |
| 1098 "strong_use_before_declaration", proxy->raw_name()); |
| 1099 return false; |
| 1100 } |
| 1101 } |
1053 break; | 1102 break; |
1054 | 1103 |
1055 case BOUND_EVAL_SHADOWED: | 1104 case BOUND_EVAL_SHADOWED: |
1056 // We either found a variable binding that might be shadowed by eval or | 1105 // We either found a variable binding that might be shadowed by eval or |
1057 // gave up on it (e.g. by encountering a local with the same in the outer | 1106 // gave up on it (e.g. by encountering a local with the same in the outer |
1058 // scope which was not promoted to a context, this can happen if we use | 1107 // scope which was not promoted to a context, this can happen if we use |
1059 // debugger to evaluate arbitrary expressions at a break point). | 1108 // debugger to evaluate arbitrary expressions at a break point). |
1060 if (var->IsGlobalObjectProperty()) { | 1109 if (var->IsGlobalObjectProperty()) { |
1061 var = NonLocal(proxy->raw_name(), DYNAMIC_GLOBAL); | 1110 var = NonLocal(proxy->raw_name(), DYNAMIC_GLOBAL); |
1062 } else if (var->is_dynamic()) { | 1111 } else if (var->is_dynamic()) { |
(...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1381 } | 1430 } |
1382 | 1431 |
1383 | 1432 |
1384 int Scope::ContextLocalCount() const { | 1433 int Scope::ContextLocalCount() const { |
1385 if (num_heap_slots() == 0) return 0; | 1434 if (num_heap_slots() == 0) return 0; |
1386 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - | 1435 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - |
1387 (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0); | 1436 (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0); |
1388 } | 1437 } |
1389 | 1438 |
1390 } } // namespace v8::internal | 1439 } } // namespace v8::internal |
OLD | NEW |