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/bootstrapper.h" | 8 #include "src/bootstrapper.h" |
9 #include "src/messages.h" | 9 #include "src/messages.h" |
10 #include "src/parsing/parser.h" // for ParseInfo | 10 #include "src/parsing/parser.h" // for ParseInfo |
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
272 return false; | 272 return false; |
273 } | 273 } |
274 } | 274 } |
275 | 275 |
276 #ifdef DEBUG | 276 #ifdef DEBUG |
277 if (info->script_is_native() ? FLAG_print_builtin_scopes | 277 if (info->script_is_native() ? FLAG_print_builtin_scopes |
278 : FLAG_print_scopes) { | 278 : FLAG_print_scopes) { |
279 scope->Print(); | 279 scope->Print(); |
280 } | 280 } |
281 scope->CheckScopePositions(); | 281 scope->CheckScopePositions(); |
| 282 scope->CheckZones(); |
282 #endif | 283 #endif |
283 | 284 |
284 info->set_scope(scope); | 285 info->set_scope(scope); |
285 return true; | 286 return true; |
286 } | 287 } |
287 | 288 |
288 void Scope::DeclareThis(AstValueFactory* ast_value_factory) { | 289 void Scope::DeclareThis(AstValueFactory* ast_value_factory) { |
289 DCHECK(!already_resolved()); | 290 DCHECK(!already_resolved()); |
290 DCHECK(is_declaration_scope()); | 291 DCHECK(is_declaration_scope()); |
291 DCHECK(has_this_declaration()); | 292 DCHECK(has_this_declaration()); |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
495 AstNodeFactory* factory) { | 496 AstNodeFactory* factory) { |
496 if (function_ != NULL && function_->proxy()->raw_name() == name) { | 497 if (function_ != NULL && function_->proxy()->raw_name() == name) { |
497 return function_->proxy()->var(); | 498 return function_->proxy()->var(); |
498 } else if (!scope_info_.is_null()) { | 499 } else if (!scope_info_.is_null()) { |
499 // If we are backed by a scope info, try to lookup the variable there. | 500 // If we are backed by a scope info, try to lookup the variable there. |
500 VariableMode mode; | 501 VariableMode mode; |
501 int index = scope_info_->FunctionContextSlotIndex(*(name->string()), &mode); | 502 int index = scope_info_->FunctionContextSlotIndex(*(name->string()), &mode); |
502 if (index < 0) return NULL; | 503 if (index < 0) return NULL; |
503 Variable* var = new (zone()) | 504 Variable* var = new (zone()) |
504 Variable(this, name, mode, Variable::NORMAL, kCreatedInitialized); | 505 Variable(this, name, mode, Variable::NORMAL, kCreatedInitialized); |
| 506 DCHECK_NOT_NULL(factory); |
505 VariableProxy* proxy = factory->NewVariableProxy(var); | 507 VariableProxy* proxy = factory->NewVariableProxy(var); |
506 VariableDeclaration* declaration = | 508 VariableDeclaration* declaration = |
507 factory->NewVariableDeclaration(proxy, mode, this, kNoSourcePosition); | 509 factory->NewVariableDeclaration(proxy, mode, this, kNoSourcePosition); |
| 510 DCHECK_EQ(factory->zone(), zone()); |
508 DeclareFunctionVar(declaration); | 511 DeclareFunctionVar(declaration); |
509 var->AllocateTo(VariableLocation::CONTEXT, index); | 512 var->AllocateTo(VariableLocation::CONTEXT, index); |
510 return var; | 513 return var; |
511 } else { | 514 } else { |
512 return NULL; | 515 return NULL; |
513 } | 516 } |
514 } | 517 } |
515 | 518 |
516 | 519 |
517 Variable* Scope::Lookup(const AstRawString* name) { | 520 Variable* Scope::Lookup(const AstRawString* name) { |
(...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
882 if (proxy->is_resolved() && proxy->var()->IsStackAllocated()) continue; | 885 if (proxy->is_resolved() && proxy->var()->IsStackAllocated()) continue; |
883 Handle<String> name = proxy->name(); | 886 Handle<String> name = proxy->name(); |
884 non_locals = StringSet::Add(non_locals, name); | 887 non_locals = StringSet::Add(non_locals, name); |
885 } | 888 } |
886 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { | 889 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { |
887 non_locals = scope->CollectNonLocals(non_locals); | 890 non_locals = scope->CollectNonLocals(non_locals); |
888 } | 891 } |
889 return non_locals; | 892 return non_locals; |
890 } | 893 } |
891 | 894 |
| 895 void Scope::AnalyzePartially(Scope* migrate_to, |
| 896 AstNodeFactory* ast_node_factory) { |
| 897 // Gather info from inner scopes. |
| 898 PropagateScopeInfo(false); |
| 899 |
| 900 // Try to resolve unresolved variables for this Scope and collect those which |
| 901 // cannot be resolved inside. It doesn't make sense to try to resolve them in |
| 902 // the outer Scopes here, because they are incomplete. |
| 903 VariableProxy* still_unresolved = nullptr; |
| 904 CollectUnresolvableLocals(&still_unresolved, this); |
| 905 |
| 906 // Re-create the VariableProxies in the right Zone and insert them into |
| 907 // migrate_to. |
| 908 for (VariableProxy* proxy = still_unresolved; proxy != nullptr; |
| 909 proxy = proxy->next_unresolved()) { |
| 910 // Recreate the VariableProxy. |
| 911 DCHECK(!proxy->is_resolved()); |
| 912 VariableProxy* copy = ast_node_factory->CopyVariableProxy(proxy); |
| 913 migrate_to->AddUnresolved(copy); |
| 914 } |
| 915 |
| 916 // Push scope data up to migrate_to. Note that migrate_to and this Scope |
| 917 // describe the same Scope, just in different Zones. |
| 918 PropagateUsageFlagsToScope(migrate_to); |
| 919 if (inner_scope_calls_eval_) { |
| 920 migrate_to->inner_scope_calls_eval_ = true; |
| 921 } |
| 922 DCHECK(!force_eager_compilation_); |
| 923 migrate_to->set_start_position(start_position_); |
| 924 migrate_to->set_end_position(end_position_); |
| 925 migrate_to->language_mode_ = language_mode_; |
| 926 outer_scope_->RemoveInnerScope(this); |
| 927 DCHECK_EQ(outer_scope_, migrate_to->outer_scope_); |
| 928 DCHECK_EQ(outer_scope_->zone(), migrate_to->zone()); |
| 929 } |
892 | 930 |
893 #ifdef DEBUG | 931 #ifdef DEBUG |
894 static const char* Header(ScopeType scope_type, FunctionKind function_kind, | 932 static const char* Header(ScopeType scope_type, FunctionKind function_kind, |
895 bool is_declaration_scope) { | 933 bool is_declaration_scope) { |
896 switch (scope_type) { | 934 switch (scope_type) { |
897 case EVAL_SCOPE: return "eval"; | 935 case EVAL_SCOPE: return "eval"; |
898 // TODO(adamk): Should we print concise method scopes specially? | 936 // TODO(adamk): Should we print concise method scopes specially? |
899 case FUNCTION_SCOPE: | 937 case FUNCTION_SCOPE: |
900 if (IsGeneratorFunction(function_kind)) return "function*"; | 938 if (IsGeneratorFunction(function_kind)) return "function*"; |
901 if (IsAsyncFunction(function_kind)) return "async function"; | 939 if (IsAsyncFunction(function_kind)) return "async function"; |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1090 // A scope is allowed to have invalid positions if it is hidden and has no | 1128 // A scope is allowed to have invalid positions if it is hidden and has no |
1091 // inner scopes | 1129 // inner scopes |
1092 if (!is_hidden() && inner_scope_ == nullptr) { | 1130 if (!is_hidden() && inner_scope_ == nullptr) { |
1093 CHECK_NE(kNoSourcePosition, start_position()); | 1131 CHECK_NE(kNoSourcePosition, start_position()); |
1094 CHECK_NE(kNoSourcePosition, end_position()); | 1132 CHECK_NE(kNoSourcePosition, end_position()); |
1095 } | 1133 } |
1096 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { | 1134 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { |
1097 scope->CheckScopePositions(); | 1135 scope->CheckScopePositions(); |
1098 } | 1136 } |
1099 } | 1137 } |
| 1138 |
| 1139 void Scope::CheckZones() { |
| 1140 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { |
| 1141 CHECK_EQ(scope->zone(), zone()); |
| 1142 } |
| 1143 } |
1100 #endif // DEBUG | 1144 #endif // DEBUG |
1101 | 1145 |
1102 | 1146 |
1103 Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) { | 1147 Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) { |
1104 if (dynamics_ == NULL) dynamics_ = new (zone()) DynamicScopePart(zone()); | 1148 if (dynamics_ == NULL) dynamics_ = new (zone()) DynamicScopePart(zone()); |
1105 VariableMap* map = dynamics_->GetMap(mode); | 1149 VariableMap* map = dynamics_->GetMap(mode); |
1106 Variable* var = map->Lookup(name); | 1150 Variable* var = map->Lookup(name); |
1107 if (var == NULL) { | 1151 if (var == NULL) { |
1108 // Declare a new non-local. | 1152 // Declare a new non-local. |
1109 InitializationFlag init_flag = (mode == VAR) | 1153 InitializationFlag init_flag = (mode == VAR) |
1110 ? kCreatedInitialized : kNeedsInitialization; | 1154 ? kCreatedInitialized : kNeedsInitialization; |
1111 var = map->Declare(NULL, | 1155 var = map->Declare(NULL, |
1112 name, | 1156 name, |
1113 mode, | 1157 mode, |
1114 Variable::NORMAL, | 1158 Variable::NORMAL, |
1115 init_flag); | 1159 init_flag); |
1116 // Allocate it by giving it a dynamic lookup. | 1160 // Allocate it by giving it a dynamic lookup. |
1117 var->AllocateTo(VariableLocation::LOOKUP, -1); | 1161 var->AllocateTo(VariableLocation::LOOKUP, -1); |
1118 } | 1162 } |
1119 return var; | 1163 return var; |
1120 } | 1164 } |
1121 | 1165 |
1122 | |
1123 Variable* Scope::LookupRecursive(VariableProxy* proxy, | 1166 Variable* Scope::LookupRecursive(VariableProxy* proxy, |
1124 BindingKind* binding_kind, | 1167 BindingKind* binding_kind, |
1125 AstNodeFactory* factory) { | 1168 AstNodeFactory* factory, |
| 1169 Scope* max_outer_scope) { |
1126 DCHECK(binding_kind != NULL); | 1170 DCHECK(binding_kind != NULL); |
1127 if (already_resolved() && is_with_scope()) { | 1171 if (already_resolved() && is_with_scope()) { |
1128 // Short-cut: if the scope is deserialized from a scope info, variable | 1172 // Short-cut: if the scope is deserialized from a scope info, variable |
1129 // allocation is already fixed. We can simply return with dynamic lookup. | 1173 // allocation is already fixed. We can simply return with dynamic lookup. |
1130 *binding_kind = DYNAMIC_LOOKUP; | 1174 *binding_kind = DYNAMIC_LOOKUP; |
1131 return NULL; | 1175 return NULL; |
1132 } | 1176 } |
1133 | 1177 |
1134 // Try to find the variable in this scope. | 1178 // Try to find the variable in this scope. |
1135 Variable* var = LookupLocal(proxy->raw_name()); | 1179 Variable* var = LookupLocal(proxy->raw_name()); |
1136 | 1180 |
1137 // We found a variable and we are done. (Even if there is an 'eval' in | 1181 // We found a variable and we are done. (Even if there is an 'eval' in |
1138 // this scope which introduces the same variable again, the resulting | 1182 // this scope which introduces the same variable again, the resulting |
1139 // variable remains the same.) | 1183 // variable remains the same.) |
1140 if (var != NULL) { | 1184 if (var != NULL) { |
1141 *binding_kind = BOUND; | 1185 *binding_kind = BOUND; |
1142 return var; | 1186 return var; |
1143 } | 1187 } |
1144 | 1188 |
1145 // We did not find a variable locally. Check against the function variable, | 1189 // We did not find a variable locally. Check against the function variable, |
1146 // if any. We can do this for all scopes, since the function variable is | 1190 // if any. We can do this for all scopes, since the function variable is |
1147 // only present - if at all - for function scopes. | 1191 // only present - if at all - for function scopes. |
1148 *binding_kind = UNBOUND; | 1192 *binding_kind = UNBOUND; |
1149 var = LookupFunctionVar(proxy->raw_name(), factory); | 1193 var = LookupFunctionVar(proxy->raw_name(), factory); |
1150 if (var != NULL) { | 1194 if (var != NULL) { |
1151 *binding_kind = BOUND; | 1195 *binding_kind = BOUND; |
1152 } else if (outer_scope_ != NULL) { | 1196 } else if (outer_scope_ != nullptr && this != max_outer_scope) { |
1153 var = outer_scope_->LookupRecursive(proxy, binding_kind, factory); | 1197 var = outer_scope_->LookupRecursive(proxy, binding_kind, factory, |
| 1198 max_outer_scope); |
1154 if (*binding_kind == BOUND && (is_function_scope() || is_with_scope())) { | 1199 if (*binding_kind == BOUND && (is_function_scope() || is_with_scope())) { |
1155 var->ForceContextAllocation(); | 1200 var->ForceContextAllocation(); |
1156 } | 1201 } |
1157 } else { | 1202 } else { |
1158 DCHECK(is_script_scope()); | 1203 DCHECK(is_script_scope() || this == max_outer_scope); |
1159 } | 1204 } |
1160 | 1205 |
1161 // "this" can't be shadowed by "eval"-introduced bindings or by "with" scopes. | 1206 // "this" can't be shadowed by "eval"-introduced bindings or by "with" scopes. |
1162 // TODO(wingo): There are other variables in this category; add them. | 1207 // TODO(wingo): There are other variables in this category; add them. |
1163 bool name_can_be_shadowed = var == nullptr || !var->is_this(); | 1208 bool name_can_be_shadowed = var == nullptr || !var->is_this(); |
1164 | 1209 |
1165 if (is_with_scope() && name_can_be_shadowed) { | 1210 if (is_with_scope() && name_can_be_shadowed) { |
1166 DCHECK(!already_resolved()); | 1211 DCHECK(!already_resolved()); |
1167 // The current scope is a with scope, so the variable binding can not be | 1212 // The current scope is a with scope, so the variable binding can not be |
1168 // statically resolved. However, note that it was necessary to do a lookup | 1213 // statically resolved. However, note that it was necessary to do a lookup |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1281 } | 1326 } |
1282 | 1327 |
1283 // Resolve unresolved variables for inner scopes. | 1328 // Resolve unresolved variables for inner scopes. |
1284 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { | 1329 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { |
1285 if (!scope->ResolveVariablesRecursively(info, factory)) return false; | 1330 if (!scope->ResolveVariablesRecursively(info, factory)) return false; |
1286 } | 1331 } |
1287 | 1332 |
1288 return true; | 1333 return true; |
1289 } | 1334 } |
1290 | 1335 |
| 1336 void Scope::CollectUnresolvableLocals(VariableProxy** still_unresolved, |
| 1337 Scope* max_outer_scope) { |
| 1338 BindingKind binding_kind; |
| 1339 for (VariableProxy *proxy = unresolved_, *next = nullptr; proxy != nullptr; |
| 1340 proxy = next) { |
| 1341 next = proxy->next_unresolved(); |
| 1342 // Note that we pass nullptr as AstNodeFactory: this phase should not create |
| 1343 // any new AstNodes, since none of the Scopes involved are backed up by |
| 1344 // ScopeInfo. |
| 1345 if (LookupRecursive(proxy, &binding_kind, nullptr, max_outer_scope) == |
| 1346 nullptr) { |
| 1347 proxy->set_next_unresolved(*still_unresolved); |
| 1348 *still_unresolved = proxy; |
| 1349 } |
| 1350 } |
| 1351 |
| 1352 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { |
| 1353 scope->CollectUnresolvableLocals(still_unresolved, max_outer_scope); |
| 1354 } |
| 1355 } |
1291 | 1356 |
1292 void Scope::PropagateScopeInfo(bool outer_scope_calls_sloppy_eval ) { | 1357 void Scope::PropagateScopeInfo(bool outer_scope_calls_sloppy_eval ) { |
1293 if (outer_scope_calls_sloppy_eval) { | 1358 if (outer_scope_calls_sloppy_eval) { |
1294 outer_scope_calls_sloppy_eval_ = true; | 1359 outer_scope_calls_sloppy_eval_ = true; |
1295 } | 1360 } |
1296 | 1361 |
1297 bool calls_sloppy_eval = | 1362 bool calls_sloppy_eval = |
1298 this->calls_sloppy_eval() || outer_scope_calls_sloppy_eval_; | 1363 this->calls_sloppy_eval() || outer_scope_calls_sloppy_eval_; |
1299 for (Scope* inner = inner_scope_; inner != nullptr; inner = inner->sibling_) { | 1364 for (Scope* inner = inner_scope_; inner != nullptr; inner = inner->sibling_) { |
1300 inner->PropagateScopeInfo(calls_sloppy_eval); | 1365 inner->PropagateScopeInfo(calls_sloppy_eval); |
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1576 function_ != NULL && function_->proxy()->var()->IsContextSlot(); | 1641 function_ != NULL && function_->proxy()->var()->IsContextSlot(); |
1577 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - num_global_slots() - | 1642 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - num_global_slots() - |
1578 (is_function_var_in_context ? 1 : 0); | 1643 (is_function_var_in_context ? 1 : 0); |
1579 } | 1644 } |
1580 | 1645 |
1581 | 1646 |
1582 int Scope::ContextGlobalCount() const { return num_global_slots(); } | 1647 int Scope::ContextGlobalCount() const { return num_global_slots(); } |
1583 | 1648 |
1584 } // namespace internal | 1649 } // namespace internal |
1585 } // namespace v8 | 1650 } // namespace v8 |
OLD | NEW |