| 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/ast/scopes.h" | 5 #include "src/ast/scopes.h" |
| 6 | 6 |
| 7 #include "src/accessors.h" | 7 #include "src/accessors.h" |
| 8 #include "src/ast/scopeinfo.h" | 8 #include "src/ast/scopeinfo.h" |
| 9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
| 10 #include "src/messages.h" | 10 #include "src/messages.h" |
| 11 #include "src/parsing/parser.h" // for ParseInfo | 11 #include "src/parsing/parser.h" // for ParseInfo |
| 12 | 12 |
| 13 namespace v8 { | 13 namespace v8 { |
| 14 namespace internal { | 14 namespace internal { |
| 15 | 15 |
| 16 // ---------------------------------------------------------------------------- | 16 // ---------------------------------------------------------------------------- |
| 17 // Implementation of LocalsMap | 17 // Implementation of LocalsMap |
| 18 // | 18 // |
| 19 // Note: We are storing the handle locations as key values in the hash map. | 19 // Note: We are storing the handle locations as key values in the hash map. |
| 20 // When inserting a new variable via Declare(), we rely on the fact that | 20 // When inserting a new variable via Declare(), we rely on the fact that |
| 21 // the handle location remains alive for the duration of that variable | 21 // the handle location remains alive for the duration of that variable |
| 22 // use. Because a Variable holding a handle with the same location exists | 22 // use. Because a Variable holding a handle with the same location exists |
| 23 // this is ensured. | 23 // this is ensured. |
| 24 | 24 |
| 25 VariableMap::VariableMap(Zone* zone) | 25 VariableMap::VariableMap(Zone* zone) |
| 26 : ZoneHashMap(ZoneHashMap::PointersMatch, 8, ZoneAllocationPolicy(zone)), | 26 : ZoneHashMap(ZoneHashMap::PointersMatch, 8, ZoneAllocationPolicy(zone)), |
| 27 zone_(zone) {} | 27 zone_(zone) {} |
| 28 VariableMap::~VariableMap() {} | 28 VariableMap::~VariableMap() {} |
| 29 | 29 |
| 30 | |
| 31 Variable* VariableMap::Declare(Scope* scope, const AstRawString* name, | 30 Variable* VariableMap::Declare(Scope* scope, const AstRawString* name, |
| 32 VariableMode mode, Variable::Kind kind, | 31 VariableMode mode, Variable::Kind kind, |
| 33 InitializationFlag initialization_flag, | 32 InitializationFlag initialization_flag, |
| 34 MaybeAssignedFlag maybe_assigned_flag, | 33 MaybeAssignedFlag maybe_assigned_flag) { |
| 35 int declaration_group_start) { | |
| 36 // AstRawStrings are unambiguous, i.e., the same string is always represented | 34 // AstRawStrings are unambiguous, i.e., the same string is always represented |
| 37 // by the same AstRawString*. | 35 // by the same AstRawString*. |
| 38 // FIXME(marja): fix the type of Lookup. | 36 // FIXME(marja): fix the type of Lookup. |
| 39 Entry* p = | 37 Entry* p = |
| 40 ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name), name->hash(), | 38 ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name), name->hash(), |
| 41 ZoneAllocationPolicy(zone())); | 39 ZoneAllocationPolicy(zone())); |
| 42 if (p->value == NULL) { | 40 if (p->value == NULL) { |
| 43 // The variable has not been declared yet -> insert it. | 41 // The variable has not been declared yet -> insert it. |
| 44 DCHECK(p->key == name); | 42 DCHECK(p->key == name); |
| 45 if (kind == Variable::CLASS) { | 43 p->value = new (zone()) Variable(scope, name, mode, kind, |
| 46 p->value = new (zone()) | 44 initialization_flag, maybe_assigned_flag); |
| 47 ClassVariable(scope, name, mode, initialization_flag, | |
| 48 maybe_assigned_flag, declaration_group_start); | |
| 49 } else { | |
| 50 p->value = new (zone()) Variable( | |
| 51 scope, name, mode, kind, initialization_flag, maybe_assigned_flag); | |
| 52 } | |
| 53 } | 45 } |
| 54 return reinterpret_cast<Variable*>(p->value); | 46 return reinterpret_cast<Variable*>(p->value); |
| 55 } | 47 } |
| 56 | 48 |
| 57 | 49 |
| 58 Variable* VariableMap::Lookup(const AstRawString* name) { | 50 Variable* VariableMap::Lookup(const AstRawString* name) { |
| 59 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash()); | 51 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash()); |
| 60 if (p != NULL) { | 52 if (p != NULL) { |
| 61 DCHECK(reinterpret_cast<const AstRawString*>(p->key) == name); | 53 DCHECK(reinterpret_cast<const AstRawString*>(p->key) == name); |
| 62 DCHECK(p->value != NULL); | 54 DCHECK(p->value != NULL); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 96 variables_(zone), | 88 variables_(zone), |
| 97 temps_(4, zone), | 89 temps_(4, zone), |
| 98 params_(4, zone), | 90 params_(4, zone), |
| 99 unresolved_(16, zone), | 91 unresolved_(16, zone), |
| 100 decls_(4, zone), | 92 decls_(4, zone), |
| 101 module_descriptor_( | 93 module_descriptor_( |
| 102 scope_type == MODULE_SCOPE ? ModuleDescriptor::New(zone) : NULL), | 94 scope_type == MODULE_SCOPE ? ModuleDescriptor::New(zone) : NULL), |
| 103 sloppy_block_function_map_(zone), | 95 sloppy_block_function_map_(zone), |
| 104 already_resolved_(false), | 96 already_resolved_(false), |
| 105 ast_value_factory_(ast_value_factory), | 97 ast_value_factory_(ast_value_factory), |
| 106 zone_(zone), | 98 zone_(zone) { |
| 107 class_declaration_group_start_(-1) { | |
| 108 SetDefaults(scope_type, outer_scope, Handle<ScopeInfo>::null(), | 99 SetDefaults(scope_type, outer_scope, Handle<ScopeInfo>::null(), |
| 109 function_kind); | 100 function_kind); |
| 110 // The outermost scope must be a script scope. | 101 // The outermost scope must be a script scope. |
| 111 DCHECK(scope_type == SCRIPT_SCOPE || outer_scope != NULL); | 102 DCHECK(scope_type == SCRIPT_SCOPE || outer_scope != NULL); |
| 112 DCHECK(!HasIllegalRedeclaration()); | 103 DCHECK(!HasIllegalRedeclaration()); |
| 113 } | 104 } |
| 114 | 105 |
| 115 | |
| 116 Scope::Scope(Zone* zone, Scope* inner_scope, ScopeType scope_type, | 106 Scope::Scope(Zone* zone, Scope* inner_scope, ScopeType scope_type, |
| 117 Handle<ScopeInfo> scope_info, AstValueFactory* value_factory) | 107 Handle<ScopeInfo> scope_info, AstValueFactory* value_factory) |
| 118 : inner_scopes_(4, zone), | 108 : inner_scopes_(4, zone), |
| 119 variables_(zone), | 109 variables_(zone), |
| 120 temps_(4, zone), | 110 temps_(4, zone), |
| 121 params_(4, zone), | 111 params_(4, zone), |
| 122 unresolved_(16, zone), | 112 unresolved_(16, zone), |
| 123 decls_(4, zone), | 113 decls_(4, zone), |
| 124 module_descriptor_(NULL), | 114 module_descriptor_(NULL), |
| 125 sloppy_block_function_map_(zone), | 115 sloppy_block_function_map_(zone), |
| 126 already_resolved_(true), | 116 already_resolved_(true), |
| 127 ast_value_factory_(value_factory), | 117 ast_value_factory_(value_factory), |
| 128 zone_(zone), | 118 zone_(zone) { |
| 129 class_declaration_group_start_(-1) { | |
| 130 SetDefaults(scope_type, NULL, scope_info); | 119 SetDefaults(scope_type, NULL, scope_info); |
| 131 if (!scope_info.is_null()) { | 120 if (!scope_info.is_null()) { |
| 132 num_heap_slots_ = scope_info_->ContextLength(); | 121 num_heap_slots_ = scope_info_->ContextLength(); |
| 133 } | 122 } |
| 134 // Ensure at least MIN_CONTEXT_SLOTS to indicate a materialized context. | 123 // Ensure at least MIN_CONTEXT_SLOTS to indicate a materialized context. |
| 135 num_heap_slots_ = Max(num_heap_slots_, | 124 num_heap_slots_ = Max(num_heap_slots_, |
| 136 static_cast<int>(Context::MIN_CONTEXT_SLOTS)); | 125 static_cast<int>(Context::MIN_CONTEXT_SLOTS)); |
| 137 AddInnerScope(inner_scope); | 126 AddInnerScope(inner_scope); |
| 138 } | 127 } |
| 139 | 128 |
| 140 | |
| 141 Scope::Scope(Zone* zone, Scope* inner_scope, | 129 Scope::Scope(Zone* zone, Scope* inner_scope, |
| 142 const AstRawString* catch_variable_name, | 130 const AstRawString* catch_variable_name, |
| 143 AstValueFactory* value_factory) | 131 AstValueFactory* value_factory) |
| 144 : inner_scopes_(1, zone), | 132 : inner_scopes_(1, zone), |
| 145 variables_(zone), | 133 variables_(zone), |
| 146 temps_(0, zone), | 134 temps_(0, zone), |
| 147 params_(0, zone), | 135 params_(0, zone), |
| 148 unresolved_(0, zone), | 136 unresolved_(0, zone), |
| 149 decls_(0, zone), | 137 decls_(0, zone), |
| 150 module_descriptor_(NULL), | 138 module_descriptor_(NULL), |
| 151 sloppy_block_function_map_(zone), | 139 sloppy_block_function_map_(zone), |
| 152 already_resolved_(true), | 140 already_resolved_(true), |
| 153 ast_value_factory_(value_factory), | 141 ast_value_factory_(value_factory), |
| 154 zone_(zone), | 142 zone_(zone) { |
| 155 class_declaration_group_start_(-1) { | |
| 156 SetDefaults(CATCH_SCOPE, NULL, Handle<ScopeInfo>::null()); | 143 SetDefaults(CATCH_SCOPE, NULL, Handle<ScopeInfo>::null()); |
| 157 AddInnerScope(inner_scope); | 144 AddInnerScope(inner_scope); |
| 158 ++num_var_or_const_; | 145 ++num_var_or_const_; |
| 159 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS; | 146 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS; |
| 160 Variable* variable = variables_.Declare(this, | 147 Variable* variable = variables_.Declare(this, |
| 161 catch_variable_name, | 148 catch_variable_name, |
| 162 VAR, | 149 VAR, |
| 163 Variable::NORMAL, | 150 Variable::NORMAL, |
| 164 kCreatedInitialized); | 151 kCreatedInitialized); |
| 165 AllocateHeapSlot(variable); | 152 AllocateHeapSlot(variable); |
| (...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 521 } | 508 } |
| 522 if (is_rest) { | 509 if (is_rest) { |
| 523 DCHECK_NULL(rest_parameter_); | 510 DCHECK_NULL(rest_parameter_); |
| 524 rest_parameter_ = var; | 511 rest_parameter_ = var; |
| 525 rest_index_ = num_parameters(); | 512 rest_index_ = num_parameters(); |
| 526 } | 513 } |
| 527 params_.Add(var, zone()); | 514 params_.Add(var, zone()); |
| 528 return var; | 515 return var; |
| 529 } | 516 } |
| 530 | 517 |
| 531 | |
| 532 Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode, | 518 Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode, |
| 533 InitializationFlag init_flag, Variable::Kind kind, | 519 InitializationFlag init_flag, Variable::Kind kind, |
| 534 MaybeAssignedFlag maybe_assigned_flag, | 520 MaybeAssignedFlag maybe_assigned_flag) { |
| 535 int declaration_group_start) { | |
| 536 DCHECK(!already_resolved()); | 521 DCHECK(!already_resolved()); |
| 537 // This function handles VAR, LET, and CONST modes. DYNAMIC variables are | 522 // This function handles VAR, LET, and CONST modes. DYNAMIC variables are |
| 538 // introduces during variable allocation, and TEMPORARY variables are | 523 // introduces during variable allocation, and TEMPORARY variables are |
| 539 // allocated via NewTemporary(). | 524 // allocated via NewTemporary(). |
| 540 DCHECK(IsDeclaredVariableMode(mode)); | 525 DCHECK(IsDeclaredVariableMode(mode)); |
| 541 ++num_var_or_const_; | 526 ++num_var_or_const_; |
| 542 return variables_.Declare(this, name, mode, kind, init_flag, | 527 return variables_.Declare(this, name, mode, kind, init_flag, |
| 543 maybe_assigned_flag, declaration_group_start); | 528 maybe_assigned_flag); |
| 544 } | 529 } |
| 545 | 530 |
| 546 | 531 |
| 547 Variable* Scope::DeclareDynamicGlobal(const AstRawString* name) { | 532 Variable* Scope::DeclareDynamicGlobal(const AstRawString* name) { |
| 548 DCHECK(is_script_scope()); | 533 DCHECK(is_script_scope()); |
| 549 return variables_.Declare(this, | 534 return variables_.Declare(this, |
| 550 name, | 535 name, |
| 551 DYNAMIC_GLOBAL, | 536 DYNAMIC_GLOBAL, |
| 552 Variable::NORMAL, | 537 Variable::NORMAL, |
| 553 kCreatedInitialized); | 538 kCreatedInitialized); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 653 int order() const { return order_; } | 638 int order() const { return order_; } |
| 654 static int Compare(const VarAndOrder* a, const VarAndOrder* b) { | 639 static int Compare(const VarAndOrder* a, const VarAndOrder* b) { |
| 655 return a->order_ - b->order_; | 640 return a->order_ - b->order_; |
| 656 } | 641 } |
| 657 | 642 |
| 658 private: | 643 private: |
| 659 Variable* var_; | 644 Variable* var_; |
| 660 int order_; | 645 int order_; |
| 661 }; | 646 }; |
| 662 | 647 |
| 663 | 648 void Scope::CollectStackAndContextLocals(ZoneList<Variable*>* stack_locals, |
| 664 void Scope::CollectStackAndContextLocals( | 649 ZoneList<Variable*>* context_locals, |
| 665 ZoneList<Variable*>* stack_locals, ZoneList<Variable*>* context_locals, | 650 ZoneList<Variable*>* context_globals) { |
| 666 ZoneList<Variable*>* context_globals, | |
| 667 ZoneList<Variable*>* strong_mode_free_variables) { | |
| 668 DCHECK(stack_locals != NULL); | 651 DCHECK(stack_locals != NULL); |
| 669 DCHECK(context_locals != NULL); | 652 DCHECK(context_locals != NULL); |
| 670 DCHECK(context_globals != NULL); | 653 DCHECK(context_globals != NULL); |
| 671 | 654 |
| 672 // Collect temporaries which are always allocated on the stack, unless the | 655 // Collect temporaries which are always allocated on the stack, unless the |
| 673 // context as a whole has forced context allocation. | 656 // context as a whole has forced context allocation. |
| 674 for (int i = 0; i < temps_.length(); i++) { | 657 for (int i = 0; i < temps_.length(); i++) { |
| 675 Variable* var = temps_[i]; | 658 Variable* var = temps_[i]; |
| 676 if (var->is_used()) { | 659 if (var->is_used()) { |
| 677 if (var->IsContextSlot()) { | 660 if (var->IsContextSlot()) { |
| 678 DCHECK(has_forced_context_allocation()); | 661 DCHECK(has_forced_context_allocation()); |
| 679 context_locals->Add(var, zone()); | 662 context_locals->Add(var, zone()); |
| 680 } else if (var->IsStackLocal()) { | 663 } else if (var->IsStackLocal()) { |
| 681 stack_locals->Add(var, zone()); | 664 stack_locals->Add(var, zone()); |
| 682 } else { | 665 } else { |
| 683 DCHECK(var->IsParameter()); | 666 DCHECK(var->IsParameter()); |
| 684 } | 667 } |
| 685 } | 668 } |
| 686 } | 669 } |
| 687 | 670 |
| 688 // Collect declared local variables. | 671 // Collect declared local variables. |
| 689 ZoneList<VarAndOrder> vars(variables_.occupancy(), zone()); | 672 ZoneList<VarAndOrder> vars(variables_.occupancy(), zone()); |
| 690 for (VariableMap::Entry* p = variables_.Start(); | 673 for (VariableMap::Entry* p = variables_.Start(); |
| 691 p != NULL; | 674 p != NULL; |
| 692 p = variables_.Next(p)) { | 675 p = variables_.Next(p)) { |
| 693 Variable* var = reinterpret_cast<Variable*>(p->value); | 676 Variable* var = reinterpret_cast<Variable*>(p->value); |
| 694 if (strong_mode_free_variables && var->has_strong_mode_reference() && | |
| 695 var->mode() == DYNAMIC_GLOBAL) { | |
| 696 strong_mode_free_variables->Add(var, zone()); | |
| 697 } | |
| 698 | |
| 699 if (var->is_used()) { | 677 if (var->is_used()) { |
| 700 vars.Add(VarAndOrder(var, p->order), zone()); | 678 vars.Add(VarAndOrder(var, p->order), zone()); |
| 701 } | 679 } |
| 702 } | 680 } |
| 703 vars.Sort(VarAndOrder::Compare); | 681 vars.Sort(VarAndOrder::Compare); |
| 704 int var_count = vars.length(); | 682 int var_count = vars.length(); |
| 705 for (int i = 0; i < var_count; i++) { | 683 for (int i = 0; i < var_count; i++) { |
| 706 Variable* var = vars[i].var(); | 684 Variable* var = vars[i].var(); |
| 707 if (var->IsStackLocal()) { | 685 if (var->IsStackLocal()) { |
| 708 stack_locals->Add(var, zone()); | 686 stack_locals->Add(var, zone()); |
| (...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1010 if (function_ != NULL) { | 988 if (function_ != NULL) { |
| 1011 Indent(n1, "// (local) function name: "); | 989 Indent(n1, "// (local) function name: "); |
| 1012 PrintName(function_->proxy()->raw_name()); | 990 PrintName(function_->proxy()->raw_name()); |
| 1013 PrintF("\n"); | 991 PrintF("\n"); |
| 1014 } | 992 } |
| 1015 | 993 |
| 1016 // Scope info. | 994 // Scope info. |
| 1017 if (HasTrivialOuterContext()) { | 995 if (HasTrivialOuterContext()) { |
| 1018 Indent(n1, "// scope has trivial outer context\n"); | 996 Indent(n1, "// scope has trivial outer context\n"); |
| 1019 } | 997 } |
| 1020 if (is_strong(language_mode())) { | 998 if (is_strict(language_mode())) { |
| 1021 Indent(n1, "// strong mode scope\n"); | |
| 1022 } else if (is_strict(language_mode())) { | |
| 1023 Indent(n1, "// strict mode scope\n"); | 999 Indent(n1, "// strict mode scope\n"); |
| 1024 } | 1000 } |
| 1025 if (scope_inside_with_) Indent(n1, "// scope inside 'with'\n"); | 1001 if (scope_inside_with_) Indent(n1, "// scope inside 'with'\n"); |
| 1026 if (scope_contains_with_) Indent(n1, "// scope contains 'with'\n"); | 1002 if (scope_contains_with_) Indent(n1, "// scope contains 'with'\n"); |
| 1027 if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n"); | 1003 if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n"); |
| 1028 if (scope_uses_arguments_) Indent(n1, "// scope uses 'arguments'\n"); | 1004 if (scope_uses_arguments_) Indent(n1, "// scope uses 'arguments'\n"); |
| 1029 if (scope_uses_super_property_) | 1005 if (scope_uses_super_property_) |
| 1030 Indent(n1, "// scope uses 'super' property\n"); | 1006 Indent(n1, "// scope uses 'super' property\n"); |
| 1031 if (outer_scope_calls_sloppy_eval_) { | 1007 if (outer_scope_calls_sloppy_eval_) { |
| 1032 Indent(n1, "// outer scope calls 'eval' in sloppy context\n"); | 1008 Indent(n1, "// outer scope calls 'eval' in sloppy context\n"); |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1197 VariableLocation location = var->location(); | 1173 VariableLocation location = var->location(); |
| 1198 CHECK(location == VariableLocation::LOCAL || | 1174 CHECK(location == VariableLocation::LOCAL || |
| 1199 location == VariableLocation::CONTEXT || | 1175 location == VariableLocation::CONTEXT || |
| 1200 location == VariableLocation::PARAMETER || | 1176 location == VariableLocation::PARAMETER || |
| 1201 location == VariableLocation::UNALLOCATED); | 1177 location == VariableLocation::UNALLOCATED); |
| 1202 } | 1178 } |
| 1203 #endif | 1179 #endif |
| 1204 | 1180 |
| 1205 switch (binding_kind) { | 1181 switch (binding_kind) { |
| 1206 case BOUND: | 1182 case BOUND: |
| 1207 // We found a variable binding. | |
| 1208 if (is_strong(language_mode())) { | |
| 1209 if (!CheckStrongModeDeclaration(proxy, var)) return false; | |
| 1210 } | |
| 1211 break; | 1183 break; |
| 1212 | 1184 |
| 1213 case BOUND_EVAL_SHADOWED: | 1185 case BOUND_EVAL_SHADOWED: |
| 1214 // We either found a variable binding that might be shadowed by eval or | 1186 // We either found a variable binding that might be shadowed by eval or |
| 1215 // gave up on it (e.g. by encountering a local with the same in the outer | 1187 // gave up on it (e.g. by encountering a local with the same in the outer |
| 1216 // scope which was not promoted to a context, this can happen if we use | 1188 // scope which was not promoted to a context, this can happen if we use |
| 1217 // debugger to evaluate arbitrary expressions at a break point). | 1189 // debugger to evaluate arbitrary expressions at a break point). |
| 1218 if (var->IsGlobalObjectProperty()) { | 1190 if (var->IsGlobalObjectProperty()) { |
| 1219 var = NonLocal(proxy->raw_name(), DYNAMIC_GLOBAL); | 1191 var = NonLocal(proxy->raw_name(), DYNAMIC_GLOBAL); |
| 1220 } else if (var->is_dynamic()) { | 1192 } else if (var->is_dynamic()) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1238 | 1210 |
| 1239 case DYNAMIC_LOOKUP: | 1211 case DYNAMIC_LOOKUP: |
| 1240 // The variable could not be resolved statically. | 1212 // The variable could not be resolved statically. |
| 1241 var = NonLocal(proxy->raw_name(), DYNAMIC); | 1213 var = NonLocal(proxy->raw_name(), DYNAMIC); |
| 1242 break; | 1214 break; |
| 1243 } | 1215 } |
| 1244 | 1216 |
| 1245 DCHECK(var != NULL); | 1217 DCHECK(var != NULL); |
| 1246 if (proxy->is_assigned()) var->set_maybe_assigned(); | 1218 if (proxy->is_assigned()) var->set_maybe_assigned(); |
| 1247 | 1219 |
| 1248 if (is_strong(language_mode())) { | |
| 1249 // Record that the variable is referred to from strong mode. Also, record | |
| 1250 // the position. | |
| 1251 var->RecordStrongModeReference(proxy->position(), proxy->end_position()); | |
| 1252 } | |
| 1253 | |
| 1254 proxy->BindTo(var); | 1220 proxy->BindTo(var); |
| 1255 | 1221 |
| 1256 return true; | 1222 return true; |
| 1257 } | 1223 } |
| 1258 | 1224 |
| 1259 | 1225 |
| 1260 bool Scope::CheckStrongModeDeclaration(VariableProxy* proxy, Variable* var) { | |
| 1261 // Check for declaration-after use (for variables) in strong mode. Note that | |
| 1262 // we can only do this in the case where we have seen the declaration. And we | |
| 1263 // always allow referencing functions (for now). | |
| 1264 | |
| 1265 // This might happen during lazy compilation; we don't keep track of | |
| 1266 // initializer positions for variables stored in ScopeInfo, so we cannot check | |
| 1267 // bindings against them. TODO(marja, rossberg): remove this hack. | |
| 1268 if (var->initializer_position() == RelocInfo::kNoPosition) return true; | |
| 1269 | |
| 1270 // Allow referencing the class name from methods of that class, even though | |
| 1271 // the initializer position for class names is only after the body. | |
| 1272 Scope* scope = this; | |
| 1273 while (scope) { | |
| 1274 if (scope->ClassVariableForMethod() == var) return true; | |
| 1275 scope = scope->outer_scope(); | |
| 1276 } | |
| 1277 | |
| 1278 // Allow references from methods to classes declared later, if we detect no | |
| 1279 // problematic dependency cycles. Note that we can be inside multiple methods | |
| 1280 // at the same time, and it's enough if we find one where the reference is | |
| 1281 // allowed. | |
| 1282 if (var->is_class() && | |
| 1283 var->AsClassVariable()->declaration_group_start() >= 0) { | |
| 1284 for (scope = this; scope && scope != var->scope(); | |
| 1285 scope = scope->outer_scope()) { | |
| 1286 ClassVariable* class_var = scope->ClassVariableForMethod(); | |
| 1287 // A method is referring to some other class, possibly declared | |
| 1288 // later. Referring to a class declared earlier is always OK and covered | |
| 1289 // by the code outside this if. Here we only need to allow special cases | |
| 1290 // for referring to a class which is declared later. | |
| 1291 | |
| 1292 // Referring to a class C declared later is OK under the following | |
| 1293 // circumstances: | |
| 1294 | |
| 1295 // 1. The class declarations are in a consecutive group with no other | |
| 1296 // declarations or statements in between, and | |
| 1297 | |
| 1298 // 2. There is no dependency cycle where the first edge is an | |
| 1299 // initialization time dependency (computed property name or extends | |
| 1300 // clause) from C to something that depends on this class directly or | |
| 1301 // transitively. | |
| 1302 if (class_var && | |
| 1303 class_var->declaration_group_start() == | |
| 1304 var->AsClassVariable()->declaration_group_start()) { | |
| 1305 return true; | |
| 1306 } | |
| 1307 | |
| 1308 // TODO(marja,rossberg): implement the dependency cycle detection. Here we | |
| 1309 // undershoot the target and allow referring to any class in the same | |
| 1310 // consectuive declaration group. | |
| 1311 | |
| 1312 // The cycle detection can work roughly like this: 1) detect init-time | |
| 1313 // references here (they are free variables which are inside the class | |
| 1314 // scope but not inside a method scope - no parser changes needed to | |
| 1315 // detect them) 2) if we encounter an init-time reference here, allow it, | |
| 1316 // but record it for a later dependency cycle check 3) also record | |
| 1317 // non-init-time references here 4) after scope analysis is done, analyse | |
| 1318 // the dependency cycles: an illegal cycle is one starting with an | |
| 1319 // init-time reference and leading back to the starting point with either | |
| 1320 // non-init-time and init-time references. | |
| 1321 } | |
| 1322 } | |
| 1323 | |
| 1324 // If both the use and the declaration are inside an eval scope (possibly | |
| 1325 // indirectly), or one of them is, we need to check whether they are inside | |
| 1326 // the same eval scope or different ones. | |
| 1327 | |
| 1328 // TODO(marja,rossberg): Detect errors across different evals (depends on the | |
| 1329 // future of eval in strong mode). | |
| 1330 const Scope* eval_for_use = NearestOuterEvalScope(); | |
| 1331 const Scope* eval_for_declaration = var->scope()->NearestOuterEvalScope(); | |
| 1332 | |
| 1333 if (proxy->position() != RelocInfo::kNoPosition && | |
| 1334 proxy->position() < var->initializer_position() && !var->is_function() && | |
| 1335 eval_for_use == eval_for_declaration) { | |
| 1336 DCHECK(proxy->end_position() != RelocInfo::kNoPosition); | |
| 1337 ReportMessage(proxy->position(), proxy->end_position(), | |
| 1338 MessageTemplate::kStrongUseBeforeDeclaration, | |
| 1339 proxy->raw_name()); | |
| 1340 return false; | |
| 1341 } | |
| 1342 return true; | |
| 1343 } | |
| 1344 | |
| 1345 | |
| 1346 ClassVariable* Scope::ClassVariableForMethod() const { | |
| 1347 // TODO(marja, rossberg): This fails to find a class variable in the following | |
| 1348 // cases: | |
| 1349 // let A = class { ... } | |
| 1350 // It needs to be investigated whether this causes any practical problems. | |
| 1351 if (!is_function_scope()) return nullptr; | |
| 1352 if (IsInObjectLiteral(function_kind_)) return nullptr; | |
| 1353 if (!IsConciseMethod(function_kind_) && !IsClassConstructor(function_kind_) && | |
| 1354 !IsAccessorFunction(function_kind_)) { | |
| 1355 return nullptr; | |
| 1356 } | |
| 1357 DCHECK_NOT_NULL(outer_scope_); | |
| 1358 // The class scope contains at most one variable, the class name. | |
| 1359 DCHECK(outer_scope_->variables_.occupancy() <= 1); | |
| 1360 if (outer_scope_->variables_.occupancy() == 0) return nullptr; | |
| 1361 VariableMap::Entry* p = outer_scope_->variables_.Start(); | |
| 1362 Variable* var = reinterpret_cast<Variable*>(p->value); | |
| 1363 if (!var->is_class()) return nullptr; | |
| 1364 return var->AsClassVariable(); | |
| 1365 } | |
| 1366 | |
| 1367 | |
| 1368 bool Scope::ResolveVariablesRecursively(ParseInfo* info, | 1226 bool Scope::ResolveVariablesRecursively(ParseInfo* info, |
| 1369 AstNodeFactory* factory) { | 1227 AstNodeFactory* factory) { |
| 1370 DCHECK(info->script_scope()->is_script_scope()); | 1228 DCHECK(info->script_scope()->is_script_scope()); |
| 1371 | 1229 |
| 1372 // Resolve unresolved variables for this scope. | 1230 // Resolve unresolved variables for this scope. |
| 1373 for (int i = 0; i < unresolved_.length(); i++) { | 1231 for (int i = 0; i < unresolved_.length(); i++) { |
| 1374 if (!ResolveVariable(info, unresolved_[i], factory)) return false; | 1232 if (!ResolveVariable(info, unresolved_[i], factory)) return false; |
| 1375 } | 1233 } |
| 1376 | 1234 |
| 1377 // Resolve unresolved variables for inner scopes. | 1235 // Resolve unresolved variables for inner scopes. |
| (...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1689 function_ != NULL && function_->proxy()->var()->IsContextSlot(); | 1547 function_ != NULL && function_->proxy()->var()->IsContextSlot(); |
| 1690 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - num_global_slots() - | 1548 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - num_global_slots() - |
| 1691 (is_function_var_in_context ? 1 : 0); | 1549 (is_function_var_in_context ? 1 : 0); |
| 1692 } | 1550 } |
| 1693 | 1551 |
| 1694 | 1552 |
| 1695 int Scope::ContextGlobalCount() const { return num_global_slots(); } | 1553 int Scope::ContextGlobalCount() const { return num_global_slots(); } |
| 1696 | 1554 |
| 1697 } // namespace internal | 1555 } // namespace internal |
| 1698 } // namespace v8 | 1556 } // namespace v8 |
| OLD | NEW |