| 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(); | |
| 283 #endif | 282 #endif |
| 284 | 283 |
| 285 info->set_scope(scope); | 284 info->set_scope(scope); |
| 286 return true; | 285 return true; |
| 287 } | 286 } |
| 288 | 287 |
| 289 void Scope::DeclareThis(AstValueFactory* ast_value_factory) { | 288 void Scope::DeclareThis(AstValueFactory* ast_value_factory) { |
| 290 DCHECK(!already_resolved()); | 289 DCHECK(!already_resolved()); |
| 291 DCHECK(is_declaration_scope()); | 290 DCHECK(is_declaration_scope()); |
| 292 DCHECK(has_this_declaration()); | 291 DCHECK(has_this_declaration()); |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 496 AstNodeFactory* factory) { | 495 AstNodeFactory* factory) { |
| 497 if (function_ != NULL && function_->proxy()->raw_name() == name) { | 496 if (function_ != NULL && function_->proxy()->raw_name() == name) { |
| 498 return function_->proxy()->var(); | 497 return function_->proxy()->var(); |
| 499 } else if (!scope_info_.is_null()) { | 498 } else if (!scope_info_.is_null()) { |
| 500 // If we are backed by a scope info, try to lookup the variable there. | 499 // If we are backed by a scope info, try to lookup the variable there. |
| 501 VariableMode mode; | 500 VariableMode mode; |
| 502 int index = scope_info_->FunctionContextSlotIndex(*(name->string()), &mode); | 501 int index = scope_info_->FunctionContextSlotIndex(*(name->string()), &mode); |
| 503 if (index < 0) return NULL; | 502 if (index < 0) return NULL; |
| 504 Variable* var = new (zone()) | 503 Variable* var = new (zone()) |
| 505 Variable(this, name, mode, Variable::NORMAL, kCreatedInitialized); | 504 Variable(this, name, mode, Variable::NORMAL, kCreatedInitialized); |
| 506 DCHECK_NOT_NULL(factory); | |
| 507 VariableProxy* proxy = factory->NewVariableProxy(var); | 505 VariableProxy* proxy = factory->NewVariableProxy(var); |
| 508 VariableDeclaration* declaration = | 506 VariableDeclaration* declaration = |
| 509 factory->NewVariableDeclaration(proxy, mode, this, kNoSourcePosition); | 507 factory->NewVariableDeclaration(proxy, mode, this, kNoSourcePosition); |
| 510 DCHECK_EQ(factory->zone(), zone()); | |
| 511 DeclareFunctionVar(declaration); | 508 DeclareFunctionVar(declaration); |
| 512 var->AllocateTo(VariableLocation::CONTEXT, index); | 509 var->AllocateTo(VariableLocation::CONTEXT, index); |
| 513 return var; | 510 return var; |
| 514 } else { | 511 } else { |
| 515 return NULL; | 512 return NULL; |
| 516 } | 513 } |
| 517 } | 514 } |
| 518 | 515 |
| 519 | 516 |
| 520 Variable* Scope::Lookup(const AstRawString* name) { | 517 Variable* Scope::Lookup(const AstRawString* name) { |
| (...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 885 if (proxy->is_resolved() && proxy->var()->IsStackAllocated()) continue; | 882 if (proxy->is_resolved() && proxy->var()->IsStackAllocated()) continue; |
| 886 Handle<String> name = proxy->name(); | 883 Handle<String> name = proxy->name(); |
| 887 non_locals = StringSet::Add(non_locals, name); | 884 non_locals = StringSet::Add(non_locals, name); |
| 888 } | 885 } |
| 889 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { | 886 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { |
| 890 non_locals = scope->CollectNonLocals(non_locals); | 887 non_locals = scope->CollectNonLocals(non_locals); |
| 891 } | 888 } |
| 892 return non_locals; | 889 return non_locals; |
| 893 } | 890 } |
| 894 | 891 |
| 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 } | |
| 930 | 892 |
| 931 #ifdef DEBUG | 893 #ifdef DEBUG |
| 932 static const char* Header(ScopeType scope_type, FunctionKind function_kind, | 894 static const char* Header(ScopeType scope_type, FunctionKind function_kind, |
| 933 bool is_declaration_scope) { | 895 bool is_declaration_scope) { |
| 934 switch (scope_type) { | 896 switch (scope_type) { |
| 935 case EVAL_SCOPE: return "eval"; | 897 case EVAL_SCOPE: return "eval"; |
| 936 // TODO(adamk): Should we print concise method scopes specially? | 898 // TODO(adamk): Should we print concise method scopes specially? |
| 937 case FUNCTION_SCOPE: | 899 case FUNCTION_SCOPE: |
| 938 if (IsGeneratorFunction(function_kind)) return "function*"; | 900 if (IsGeneratorFunction(function_kind)) return "function*"; |
| 939 if (IsAsyncFunction(function_kind)) return "async function"; | 901 if (IsAsyncFunction(function_kind)) return "async function"; |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1128 // A scope is allowed to have invalid positions if it is hidden and has no | 1090 // A scope is allowed to have invalid positions if it is hidden and has no |
| 1129 // inner scopes | 1091 // inner scopes |
| 1130 if (!is_hidden() && inner_scope_ == nullptr) { | 1092 if (!is_hidden() && inner_scope_ == nullptr) { |
| 1131 CHECK_NE(kNoSourcePosition, start_position()); | 1093 CHECK_NE(kNoSourcePosition, start_position()); |
| 1132 CHECK_NE(kNoSourcePosition, end_position()); | 1094 CHECK_NE(kNoSourcePosition, end_position()); |
| 1133 } | 1095 } |
| 1134 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { | 1096 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { |
| 1135 scope->CheckScopePositions(); | 1097 scope->CheckScopePositions(); |
| 1136 } | 1098 } |
| 1137 } | 1099 } |
| 1138 | |
| 1139 void Scope::CheckZones() { | |
| 1140 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { | |
| 1141 CHECK_EQ(scope->zone(), zone()); | |
| 1142 } | |
| 1143 } | |
| 1144 #endif // DEBUG | 1100 #endif // DEBUG |
| 1145 | 1101 |
| 1146 | 1102 |
| 1147 Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) { | 1103 Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) { |
| 1148 if (dynamics_ == NULL) dynamics_ = new (zone()) DynamicScopePart(zone()); | 1104 if (dynamics_ == NULL) dynamics_ = new (zone()) DynamicScopePart(zone()); |
| 1149 VariableMap* map = dynamics_->GetMap(mode); | 1105 VariableMap* map = dynamics_->GetMap(mode); |
| 1150 Variable* var = map->Lookup(name); | 1106 Variable* var = map->Lookup(name); |
| 1151 if (var == NULL) { | 1107 if (var == NULL) { |
| 1152 // Declare a new non-local. | 1108 // Declare a new non-local. |
| 1153 InitializationFlag init_flag = (mode == VAR) | 1109 InitializationFlag init_flag = (mode == VAR) |
| 1154 ? kCreatedInitialized : kNeedsInitialization; | 1110 ? kCreatedInitialized : kNeedsInitialization; |
| 1155 var = map->Declare(NULL, | 1111 var = map->Declare(NULL, |
| 1156 name, | 1112 name, |
| 1157 mode, | 1113 mode, |
| 1158 Variable::NORMAL, | 1114 Variable::NORMAL, |
| 1159 init_flag); | 1115 init_flag); |
| 1160 // Allocate it by giving it a dynamic lookup. | 1116 // Allocate it by giving it a dynamic lookup. |
| 1161 var->AllocateTo(VariableLocation::LOOKUP, -1); | 1117 var->AllocateTo(VariableLocation::LOOKUP, -1); |
| 1162 } | 1118 } |
| 1163 return var; | 1119 return var; |
| 1164 } | 1120 } |
| 1165 | 1121 |
| 1122 |
| 1166 Variable* Scope::LookupRecursive(VariableProxy* proxy, | 1123 Variable* Scope::LookupRecursive(VariableProxy* proxy, |
| 1167 BindingKind* binding_kind, | 1124 BindingKind* binding_kind, |
| 1168 AstNodeFactory* factory, | 1125 AstNodeFactory* factory) { |
| 1169 Scope* max_outer_scope) { | |
| 1170 DCHECK(binding_kind != NULL); | 1126 DCHECK(binding_kind != NULL); |
| 1171 if (already_resolved() && is_with_scope()) { | 1127 if (already_resolved() && is_with_scope()) { |
| 1172 // Short-cut: if the scope is deserialized from a scope info, variable | 1128 // Short-cut: if the scope is deserialized from a scope info, variable |
| 1173 // allocation is already fixed. We can simply return with dynamic lookup. | 1129 // allocation is already fixed. We can simply return with dynamic lookup. |
| 1174 *binding_kind = DYNAMIC_LOOKUP; | 1130 *binding_kind = DYNAMIC_LOOKUP; |
| 1175 return NULL; | 1131 return NULL; |
| 1176 } | 1132 } |
| 1177 | 1133 |
| 1178 // Try to find the variable in this scope. | 1134 // Try to find the variable in this scope. |
| 1179 Variable* var = LookupLocal(proxy->raw_name()); | 1135 Variable* var = LookupLocal(proxy->raw_name()); |
| 1180 | 1136 |
| 1181 // We found a variable and we are done. (Even if there is an 'eval' in | 1137 // We found a variable and we are done. (Even if there is an 'eval' in |
| 1182 // this scope which introduces the same variable again, the resulting | 1138 // this scope which introduces the same variable again, the resulting |
| 1183 // variable remains the same.) | 1139 // variable remains the same.) |
| 1184 if (var != NULL) { | 1140 if (var != NULL) { |
| 1185 *binding_kind = BOUND; | 1141 *binding_kind = BOUND; |
| 1186 return var; | 1142 return var; |
| 1187 } | 1143 } |
| 1188 | 1144 |
| 1189 // We did not find a variable locally. Check against the function variable, | 1145 // We did not find a variable locally. Check against the function variable, |
| 1190 // if any. We can do this for all scopes, since the function variable is | 1146 // if any. We can do this for all scopes, since the function variable is |
| 1191 // only present - if at all - for function scopes. | 1147 // only present - if at all - for function scopes. |
| 1192 *binding_kind = UNBOUND; | 1148 *binding_kind = UNBOUND; |
| 1193 var = LookupFunctionVar(proxy->raw_name(), factory); | 1149 var = LookupFunctionVar(proxy->raw_name(), factory); |
| 1194 if (var != NULL) { | 1150 if (var != NULL) { |
| 1195 *binding_kind = BOUND; | 1151 *binding_kind = BOUND; |
| 1196 } else if (outer_scope_ != nullptr && this != max_outer_scope) { | 1152 } else if (outer_scope_ != NULL) { |
| 1197 var = outer_scope_->LookupRecursive(proxy, binding_kind, factory, | 1153 var = outer_scope_->LookupRecursive(proxy, binding_kind, factory); |
| 1198 max_outer_scope); | |
| 1199 if (*binding_kind == BOUND && (is_function_scope() || is_with_scope())) { | 1154 if (*binding_kind == BOUND && (is_function_scope() || is_with_scope())) { |
| 1200 var->ForceContextAllocation(); | 1155 var->ForceContextAllocation(); |
| 1201 } | 1156 } |
| 1202 } else { | 1157 } else { |
| 1203 DCHECK(is_script_scope() || this == max_outer_scope); | 1158 DCHECK(is_script_scope()); |
| 1204 } | 1159 } |
| 1205 | 1160 |
| 1206 // "this" can't be shadowed by "eval"-introduced bindings or by "with" scopes. | 1161 // "this" can't be shadowed by "eval"-introduced bindings or by "with" scopes. |
| 1207 // TODO(wingo): There are other variables in this category; add them. | 1162 // TODO(wingo): There are other variables in this category; add them. |
| 1208 bool name_can_be_shadowed = var == nullptr || !var->is_this(); | 1163 bool name_can_be_shadowed = var == nullptr || !var->is_this(); |
| 1209 | 1164 |
| 1210 if (is_with_scope() && name_can_be_shadowed) { | 1165 if (is_with_scope() && name_can_be_shadowed) { |
| 1211 DCHECK(!already_resolved()); | 1166 DCHECK(!already_resolved()); |
| 1212 // The current scope is a with scope, so the variable binding can not be | 1167 // The current scope is a with scope, so the variable binding can not be |
| 1213 // statically resolved. However, note that it was necessary to do a lookup | 1168 // 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... |
| 1326 } | 1281 } |
| 1327 | 1282 |
| 1328 // Resolve unresolved variables for inner scopes. | 1283 // Resolve unresolved variables for inner scopes. |
| 1329 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { | 1284 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { |
| 1330 if (!scope->ResolveVariablesRecursively(info, factory)) return false; | 1285 if (!scope->ResolveVariablesRecursively(info, factory)) return false; |
| 1331 } | 1286 } |
| 1332 | 1287 |
| 1333 return true; | 1288 return true; |
| 1334 } | 1289 } |
| 1335 | 1290 |
| 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 } | |
| 1356 | 1291 |
| 1357 void Scope::PropagateScopeInfo(bool outer_scope_calls_sloppy_eval ) { | 1292 void Scope::PropagateScopeInfo(bool outer_scope_calls_sloppy_eval ) { |
| 1358 if (outer_scope_calls_sloppy_eval) { | 1293 if (outer_scope_calls_sloppy_eval) { |
| 1359 outer_scope_calls_sloppy_eval_ = true; | 1294 outer_scope_calls_sloppy_eval_ = true; |
| 1360 } | 1295 } |
| 1361 | 1296 |
| 1362 bool calls_sloppy_eval = | 1297 bool calls_sloppy_eval = |
| 1363 this->calls_sloppy_eval() || outer_scope_calls_sloppy_eval_; | 1298 this->calls_sloppy_eval() || outer_scope_calls_sloppy_eval_; |
| 1364 for (Scope* inner = inner_scope_; inner != nullptr; inner = inner->sibling_) { | 1299 for (Scope* inner = inner_scope_; inner != nullptr; inner = inner->sibling_) { |
| 1365 inner->PropagateScopeInfo(calls_sloppy_eval); | 1300 inner->PropagateScopeInfo(calls_sloppy_eval); |
| (...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1641 function_ != NULL && function_->proxy()->var()->IsContextSlot(); | 1576 function_ != NULL && function_->proxy()->var()->IsContextSlot(); |
| 1642 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - num_global_slots() - | 1577 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - num_global_slots() - |
| 1643 (is_function_var_in_context ? 1 : 0); | 1578 (is_function_var_in_context ? 1 : 0); |
| 1644 } | 1579 } |
| 1645 | 1580 |
| 1646 | 1581 |
| 1647 int Scope::ContextGlobalCount() const { return num_global_slots(); } | 1582 int Scope::ContextGlobalCount() const { return num_global_slots(); } |
| 1648 | 1583 |
| 1649 } // namespace internal | 1584 } // namespace internal |
| 1650 } // namespace v8 | 1585 } // namespace v8 |
| OLD | NEW |