| 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 |