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 |