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/accessors.h" | 7 #include "src/accessors.h" |
8 #include "src/bootstrapper.h" | 8 #include "src/bootstrapper.h" |
9 #include "src/messages.h" | 9 #include "src/messages.h" |
10 #include "src/parser.h" | 10 #include "src/parser.h" |
(...skipping 14 matching lines...) Expand all Loading... | |
25 | 25 |
26 VariableMap::VariableMap(Zone* zone) | 26 VariableMap::VariableMap(Zone* zone) |
27 : ZoneHashMap(ZoneHashMap::PointersMatch, 8, ZoneAllocationPolicy(zone)), | 27 : ZoneHashMap(ZoneHashMap::PointersMatch, 8, ZoneAllocationPolicy(zone)), |
28 zone_(zone) {} | 28 zone_(zone) {} |
29 VariableMap::~VariableMap() {} | 29 VariableMap::~VariableMap() {} |
30 | 30 |
31 | 31 |
32 Variable* VariableMap::Declare(Scope* scope, const AstRawString* name, | 32 Variable* VariableMap::Declare(Scope* scope, const AstRawString* name, |
33 VariableMode mode, Variable::Kind kind, | 33 VariableMode mode, Variable::Kind kind, |
34 InitializationFlag initialization_flag, | 34 InitializationFlag initialization_flag, |
35 MaybeAssignedFlag maybe_assigned_flag) { | 35 MaybeAssignedFlag maybe_assigned_flag, |
36 int consecutive_declaration_group_start) { | |
36 // AstRawStrings are unambiguous, i.e., the same string is always represented | 37 // AstRawStrings are unambiguous, i.e., the same string is always represented |
37 // by the same AstRawString*. | 38 // by the same AstRawString*. |
38 // FIXME(marja): fix the type of Lookup. | 39 // FIXME(marja): fix the type of Lookup. |
39 Entry* p = | 40 Entry* p = |
40 ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name), name->hash(), | 41 ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name), name->hash(), |
41 ZoneAllocationPolicy(zone())); | 42 ZoneAllocationPolicy(zone())); |
42 if (p->value == NULL) { | 43 if (p->value == NULL) { |
43 // The variable has not been declared yet -> insert it. | 44 // The variable has not been declared yet -> insert it. |
44 DCHECK(p->key == name); | 45 DCHECK(p->key == name); |
45 p->value = new (zone()) Variable(scope, name, mode, kind, | 46 p->value = new (zone()) |
46 initialization_flag, maybe_assigned_flag); | 47 Variable(scope, name, mode, kind, initialization_flag, |
48 maybe_assigned_flag, consecutive_declaration_group_start); | |
47 } | 49 } |
48 return reinterpret_cast<Variable*>(p->value); | 50 return reinterpret_cast<Variable*>(p->value); |
49 } | 51 } |
50 | 52 |
51 | 53 |
52 Variable* VariableMap::Lookup(const AstRawString* name) { | 54 Variable* VariableMap::Lookup(const AstRawString* name) { |
53 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash()); | 55 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash()); |
54 if (p != NULL) { | 56 if (p != NULL) { |
55 DCHECK(reinterpret_cast<const AstRawString*>(p->key) == name); | 57 DCHECK(reinterpret_cast<const AstRawString*>(p->key) == name); |
56 DCHECK(p->value != NULL); | 58 DCHECK(p->value != NULL); |
(...skipping 12 matching lines...) Expand all Loading... | |
69 variables_(zone), | 71 variables_(zone), |
70 internals_(4, zone), | 72 internals_(4, zone), |
71 temps_(4, zone), | 73 temps_(4, zone), |
72 params_(4, zone), | 74 params_(4, zone), |
73 unresolved_(16, zone), | 75 unresolved_(16, zone), |
74 decls_(4, zone), | 76 decls_(4, zone), |
75 module_descriptor_( | 77 module_descriptor_( |
76 scope_type == MODULE_SCOPE ? ModuleDescriptor::New(zone) : NULL), | 78 scope_type == MODULE_SCOPE ? ModuleDescriptor::New(zone) : NULL), |
77 already_resolved_(false), | 79 already_resolved_(false), |
78 ast_value_factory_(ast_value_factory), | 80 ast_value_factory_(ast_value_factory), |
79 zone_(zone) { | 81 zone_(zone), |
82 consecutive_class_declaration_group_start_(-1) { | |
80 SetDefaults(scope_type, outer_scope, Handle<ScopeInfo>::null(), | 83 SetDefaults(scope_type, outer_scope, Handle<ScopeInfo>::null(), |
81 function_kind); | 84 function_kind); |
82 // The outermost scope must be a script scope. | 85 // The outermost scope must be a script scope. |
83 DCHECK(scope_type == SCRIPT_SCOPE || outer_scope != NULL); | 86 DCHECK(scope_type == SCRIPT_SCOPE || outer_scope != NULL); |
84 DCHECK(!HasIllegalRedeclaration()); | 87 DCHECK(!HasIllegalRedeclaration()); |
85 } | 88 } |
86 | 89 |
87 | 90 |
88 Scope::Scope(Zone* zone, Scope* inner_scope, ScopeType scope_type, | 91 Scope::Scope(Zone* zone, Scope* inner_scope, ScopeType scope_type, |
89 Handle<ScopeInfo> scope_info, AstValueFactory* value_factory) | 92 Handle<ScopeInfo> scope_info, AstValueFactory* value_factory) |
90 : inner_scopes_(4, zone), | 93 : inner_scopes_(4, zone), |
91 variables_(zone), | 94 variables_(zone), |
92 internals_(4, zone), | 95 internals_(4, zone), |
93 temps_(4, zone), | 96 temps_(4, zone), |
94 params_(4, zone), | 97 params_(4, zone), |
95 unresolved_(16, zone), | 98 unresolved_(16, zone), |
96 decls_(4, zone), | 99 decls_(4, zone), |
97 module_descriptor_(NULL), | 100 module_descriptor_(NULL), |
98 already_resolved_(true), | 101 already_resolved_(true), |
99 ast_value_factory_(value_factory), | 102 ast_value_factory_(value_factory), |
100 zone_(zone) { | 103 zone_(zone), |
104 consecutive_class_declaration_group_start_(-1) { | |
101 SetDefaults(scope_type, NULL, scope_info); | 105 SetDefaults(scope_type, NULL, scope_info); |
102 if (!scope_info.is_null()) { | 106 if (!scope_info.is_null()) { |
103 num_heap_slots_ = scope_info_->ContextLength(); | 107 num_heap_slots_ = scope_info_->ContextLength(); |
104 } | 108 } |
105 // Ensure at least MIN_CONTEXT_SLOTS to indicate a materialized context. | 109 // Ensure at least MIN_CONTEXT_SLOTS to indicate a materialized context. |
106 num_heap_slots_ = Max(num_heap_slots_, | 110 num_heap_slots_ = Max(num_heap_slots_, |
107 static_cast<int>(Context::MIN_CONTEXT_SLOTS)); | 111 static_cast<int>(Context::MIN_CONTEXT_SLOTS)); |
108 AddInnerScope(inner_scope); | 112 AddInnerScope(inner_scope); |
109 } | 113 } |
110 | 114 |
111 | 115 |
112 Scope::Scope(Zone* zone, Scope* inner_scope, | 116 Scope::Scope(Zone* zone, Scope* inner_scope, |
113 const AstRawString* catch_variable_name, | 117 const AstRawString* catch_variable_name, |
114 AstValueFactory* value_factory) | 118 AstValueFactory* value_factory) |
115 : inner_scopes_(1, zone), | 119 : inner_scopes_(1, zone), |
116 variables_(zone), | 120 variables_(zone), |
117 internals_(0, zone), | 121 internals_(0, zone), |
118 temps_(0, zone), | 122 temps_(0, zone), |
119 params_(0, zone), | 123 params_(0, zone), |
120 unresolved_(0, zone), | 124 unresolved_(0, zone), |
121 decls_(0, zone), | 125 decls_(0, zone), |
122 module_descriptor_(NULL), | 126 module_descriptor_(NULL), |
123 already_resolved_(true), | 127 already_resolved_(true), |
124 ast_value_factory_(value_factory), | 128 ast_value_factory_(value_factory), |
125 zone_(zone) { | 129 zone_(zone), |
130 consecutive_class_declaration_group_start_(-1) { | |
126 SetDefaults(CATCH_SCOPE, NULL, Handle<ScopeInfo>::null()); | 131 SetDefaults(CATCH_SCOPE, NULL, Handle<ScopeInfo>::null()); |
127 AddInnerScope(inner_scope); | 132 AddInnerScope(inner_scope); |
128 ++num_var_or_const_; | 133 ++num_var_or_const_; |
129 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS; | 134 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS; |
130 Variable* variable = variables_.Declare(this, | 135 Variable* variable = variables_.Declare(this, |
131 catch_variable_name, | 136 catch_variable_name, |
132 VAR, | 137 VAR, |
133 Variable::NORMAL, | 138 Variable::NORMAL, |
134 kCreatedInitialized); | 139 kCreatedInitialized); |
135 AllocateHeapSlot(variable); | 140 AllocateHeapSlot(variable); |
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
462 rest_parameter_ = var; | 467 rest_parameter_ = var; |
463 rest_index_ = num_parameters(); | 468 rest_index_ = num_parameters(); |
464 } | 469 } |
465 params_.Add(var, zone()); | 470 params_.Add(var, zone()); |
466 return var; | 471 return var; |
467 } | 472 } |
468 | 473 |
469 | 474 |
470 Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode, | 475 Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode, |
471 InitializationFlag init_flag, Variable::Kind kind, | 476 InitializationFlag init_flag, Variable::Kind kind, |
472 MaybeAssignedFlag maybe_assigned_flag) { | 477 MaybeAssignedFlag maybe_assigned_flag, |
478 int consecutive_declaration_group_start) { | |
473 DCHECK(!already_resolved()); | 479 DCHECK(!already_resolved()); |
474 // This function handles VAR, LET, and CONST modes. DYNAMIC variables are | 480 // This function handles VAR, LET, and CONST modes. DYNAMIC variables are |
475 // introduces during variable allocation, INTERNAL variables are allocated | 481 // introduces during variable allocation, INTERNAL variables are allocated |
476 // explicitly, and TEMPORARY variables are allocated via NewTemporary(). | 482 // explicitly, and TEMPORARY variables are allocated via NewTemporary(). |
477 DCHECK(IsDeclaredVariableMode(mode)); | 483 DCHECK(IsDeclaredVariableMode(mode)); |
478 ++num_var_or_const_; | 484 ++num_var_or_const_; |
479 return variables_.Declare(this, name, mode, kind, init_flag, | 485 return variables_.Declare(this, name, mode, kind, init_flag, |
480 maybe_assigned_flag); | 486 maybe_assigned_flag, |
487 consecutive_declaration_group_start); | |
481 } | 488 } |
482 | 489 |
483 | 490 |
484 Variable* Scope::DeclareDynamicGlobal(const AstRawString* name) { | 491 Variable* Scope::DeclareDynamicGlobal(const AstRawString* name) { |
485 DCHECK(is_script_scope()); | 492 DCHECK(is_script_scope()); |
486 return variables_.Declare(this, | 493 return variables_.Declare(this, |
487 name, | 494 name, |
488 DYNAMIC_GLOBAL, | 495 DYNAMIC_GLOBAL, |
489 Variable::NORMAL, | 496 Variable::NORMAL, |
490 kCreatedInitialized); | 497 kCreatedInitialized); |
(...skipping 641 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1132 | 1139 |
1133 // Allow referencing the class name from methods of that class, even though | 1140 // Allow referencing the class name from methods of that class, even though |
1134 // the initializer position for class names is only after the body. | 1141 // the initializer position for class names is only after the body. |
1135 Scope* scope = this; | 1142 Scope* scope = this; |
1136 while (scope) { | 1143 while (scope) { |
1137 if (scope->ClassVariableForMethod() == var) return true; | 1144 if (scope->ClassVariableForMethod() == var) return true; |
1138 scope = scope->outer_scope(); | 1145 scope = scope->outer_scope(); |
1139 } | 1146 } |
1140 | 1147 |
1141 // Allow references from methods to classes declared later, if we detect no | 1148 // Allow references from methods to classes declared later, if we detect no |
1142 // problematic dependency cycles. | 1149 // problematic dependency cycles. Note that we can be inside multiple methods |
1150 // at the same time, and it's enough if we find one where the reference is | |
1151 // allowed. | |
1152 scope = this; | |
1153 while (scope) { | |
rossberg
2015/04/21 13:30:02
A couple of observations:
- I shouldn't need to lo
marja
2015/04/23 09:52:37
I rewrote the code so that it's closer to what you
| |
1154 Variable* class_var = scope->ClassVariableForMethod(); | |
1155 if (class_var && var->is_class()) { | |
1156 // A method is referring to some other class, possibly declared | |
1157 // later. Referring to a class declared earlier is always OK and covered | |
1158 // by the code outside this if. Here we only need to allow special cases | |
1159 // for referring to a class which is declared later. | |
1143 | 1160 |
1144 if (ClassVariableForMethod() && var->is_class()) { | 1161 // Referring to a class C declared later is OK under the following |
1145 // A method is referring to some other class, possibly declared | 1162 // circumstances: |
1146 // later. Referring to a class declared earlier is always OK and covered by | |
1147 // the code outside this if. Here we only need to allow special cases for | |
1148 // referring to a class which is declared later. | |
1149 | 1163 |
1150 // Referring to a class C declared later is OK under the following | 1164 // 1. The class declarations are in a consecutive group with no other |
1151 // circumstances: | 1165 // declarations or statements in between, and |
1152 | 1166 |
1153 // 1. The class declarations are in a consecutive group with no other | 1167 // 2. There is no dependency cycle where the first edge is an |
1154 // declarations or statements in between, and | 1168 // initialization time dependency (computed property name or extends |
1169 // clause) from C to something that depends on this class directly or | |
1170 // transitively. | |
1155 | 1171 |
1156 // 2. There is no dependency cycle where the first edge is an initialization | 1172 // This is needed because a class ("class Name { }") creates two bindings |
1157 // time dependency (computed property name or extends clause) from C to | 1173 // (one in the outer scope, and one in the class scope). The method is a |
1158 // something that depends on this class directly or transitively. | 1174 // function scope inside the inner scope (class scope). The consecutive |
1175 // class declarations are in the outer scope. | |
1176 if (class_var->corresponding_outer_class_variable()) { | |
1177 class_var = class_var->corresponding_outer_class_variable(); | |
1178 } | |
1159 | 1179 |
1160 // TODO(marja,rossberg): implement these checks. Here we undershoot the | 1180 // TODO(marja,rossberg): implement the dependency cycle detection. Here we |
1161 // target and allow referring to any class. | 1181 // undershoot the target and allow referring to any class in the same |
1162 return true; | 1182 // consectuive declaration group. |
1183 if (class_var->consecutive_declaration_group_start() == | |
1184 var->consecutive_declaration_group_start() && | |
1185 class_var->consecutive_declaration_group_start() >= 0) { | |
1186 return true; | |
1187 } | |
1188 } | |
1189 scope = scope->outer_scope(); | |
1163 } | 1190 } |
1164 | 1191 |
1165 // If both the use and the declaration are inside an eval scope (possibly | 1192 // If both the use and the declaration are inside an eval scope (possibly |
1166 // indirectly), or one of them is, we need to check whether they are inside | 1193 // indirectly), or one of them is, we need to check whether they are inside |
1167 // the same eval scope or different ones. | 1194 // the same eval scope or different ones. |
1168 | 1195 |
1169 // TODO(marja,rossberg): Detect errors across different evals (depends on the | 1196 // TODO(marja,rossberg): Detect errors across different evals (depends on the |
1170 // future of eval in strong mode). | 1197 // future of eval in strong mode). |
1171 const Scope* eval_for_use = NearestOuterEvalScope(); | 1198 const Scope* eval_for_use = NearestOuterEvalScope(); |
1172 const Scope* eval_for_declaration = var->scope()->NearestOuterEvalScope(); | 1199 const Scope* eval_for_declaration = var->scope()->NearestOuterEvalScope(); |
1173 | 1200 |
1174 if (proxy->position() != RelocInfo::kNoPosition && | 1201 if (proxy->position() != RelocInfo::kNoPosition && |
1175 proxy->position() < var->initializer_position() && !var->is_function() && | 1202 proxy->position() < var->initializer_position() && !var->is_function() && |
1176 eval_for_use == eval_for_declaration) { | 1203 eval_for_use == eval_for_declaration) { |
1177 DCHECK(proxy->end_position() != RelocInfo::kNoPosition); | 1204 DCHECK(proxy->end_position() != RelocInfo::kNoPosition); |
1178 ReportMessage(proxy->position(), proxy->end_position(), | 1205 ReportMessage(proxy->position(), proxy->end_position(), |
1179 "strong_use_before_declaration", proxy->raw_name()); | 1206 "strong_use_before_declaration", proxy->raw_name()); |
1180 return false; | 1207 return false; |
1181 } | 1208 } |
1182 return true; | 1209 return true; |
1183 } | 1210 } |
1184 | 1211 |
1185 | 1212 |
1186 Variable* Scope::ClassVariableForMethod() const { | 1213 Variable* Scope::ClassVariableForMethod() const { |
1214 // TODO(marja, rossberg): This fails to find a class variable in the following | |
1215 // cases: | |
1216 // let A = class { ... } | |
1217 // It needs to be investigated whether this causes any practical problems. | |
1187 if (!is_function_scope()) return nullptr; | 1218 if (!is_function_scope()) return nullptr; |
1188 if (IsInObjectLiteral(function_kind_)) return nullptr; | 1219 if (IsInObjectLiteral(function_kind_)) return nullptr; |
1189 if (!IsConciseMethod(function_kind_) && !IsConstructor(function_kind_) && | 1220 if (!IsConciseMethod(function_kind_) && !IsConstructor(function_kind_) && |
1190 !IsAccessorFunction(function_kind_)) { | 1221 !IsAccessorFunction(function_kind_)) { |
1191 return nullptr; | 1222 return nullptr; |
1192 } | 1223 } |
1193 DCHECK_NOT_NULL(outer_scope_); | 1224 DCHECK_NOT_NULL(outer_scope_); |
1194 DCHECK(outer_scope_->is_class_scope()); | 1225 DCHECK(outer_scope_->is_class_scope()); |
1195 // The class scope contains at most one variable, the class name. | 1226 // The class scope contains at most one variable, the class name. |
1196 DCHECK(outer_scope_->variables_.occupancy() <= 1); | 1227 DCHECK(outer_scope_->variables_.occupancy() <= 1); |
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1488 (function_ != NULL && function_->proxy()->var()->IsStackLocal() ? 1 : 0); | 1519 (function_ != NULL && function_->proxy()->var()->IsStackLocal() ? 1 : 0); |
1489 } | 1520 } |
1490 | 1521 |
1491 | 1522 |
1492 int Scope::ContextLocalCount() const { | 1523 int Scope::ContextLocalCount() const { |
1493 if (num_heap_slots() == 0) return 0; | 1524 if (num_heap_slots() == 0) return 0; |
1494 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - | 1525 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - |
1495 (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0); | 1526 (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0); |
1496 } | 1527 } |
1497 } } // namespace v8::internal | 1528 } } // namespace v8::internal |
OLD | NEW |