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 <set> | 7 #include <set> |
8 | 8 |
9 #include "src/accessors.h" | 9 #include "src/accessors.h" |
10 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
(...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
350 return false; | 350 return false; |
351 } | 351 } |
352 } | 352 } |
353 | 353 |
354 #ifdef DEBUG | 354 #ifdef DEBUG |
355 if (info->script_is_native() ? FLAG_print_builtin_scopes | 355 if (info->script_is_native() ? FLAG_print_builtin_scopes |
356 : FLAG_print_scopes) { | 356 : FLAG_print_scopes) { |
357 scope->Print(); | 357 scope->Print(); |
358 } | 358 } |
359 scope->CheckScopePositions(); | 359 scope->CheckScopePositions(); |
| 360 scope->CheckZones(); |
360 #endif | 361 #endif |
361 | 362 |
362 info->set_scope(scope); | 363 info->set_scope(scope); |
363 return true; | 364 return true; |
364 } | 365 } |
365 | 366 |
366 void Scope::DeclareThis(AstValueFactory* ast_value_factory) { | 367 void Scope::DeclareThis(AstValueFactory* ast_value_factory) { |
367 DCHECK(!already_resolved()); | 368 DCHECK(!already_resolved()); |
368 DCHECK(is_declaration_scope()); | 369 DCHECK(is_declaration_scope()); |
369 DCHECK(has_this_declaration()); | 370 DCHECK(has_this_declaration()); |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
573 AstNodeFactory* factory) { | 574 AstNodeFactory* factory) { |
574 if (function_ != NULL && function_->proxy()->raw_name() == name) { | 575 if (function_ != NULL && function_->proxy()->raw_name() == name) { |
575 return function_->proxy()->var(); | 576 return function_->proxy()->var(); |
576 } else if (!scope_info_.is_null()) { | 577 } else if (!scope_info_.is_null()) { |
577 // If we are backed by a scope info, try to lookup the variable there. | 578 // If we are backed by a scope info, try to lookup the variable there. |
578 VariableMode mode; | 579 VariableMode mode; |
579 int index = scope_info_->FunctionContextSlotIndex(*(name->string()), &mode); | 580 int index = scope_info_->FunctionContextSlotIndex(*(name->string()), &mode); |
580 if (index < 0) return NULL; | 581 if (index < 0) return NULL; |
581 Variable* var = new (zone()) | 582 Variable* var = new (zone()) |
582 Variable(this, name, mode, Variable::NORMAL, kCreatedInitialized); | 583 Variable(this, name, mode, Variable::NORMAL, kCreatedInitialized); |
| 584 DCHECK_NOT_NULL(factory); |
583 VariableProxy* proxy = factory->NewVariableProxy(var); | 585 VariableProxy* proxy = factory->NewVariableProxy(var); |
584 VariableDeclaration* declaration = | 586 VariableDeclaration* declaration = |
585 factory->NewVariableDeclaration(proxy, mode, this, kNoSourcePosition); | 587 factory->NewVariableDeclaration(proxy, mode, this, kNoSourcePosition); |
| 588 DCHECK_EQ(factory->zone(), zone()); |
586 DeclareFunctionVar(declaration); | 589 DeclareFunctionVar(declaration); |
587 var->AllocateTo(VariableLocation::CONTEXT, index); | 590 var->AllocateTo(VariableLocation::CONTEXT, index); |
588 return var; | 591 return var; |
589 } else { | 592 } else { |
590 return NULL; | 593 return NULL; |
591 } | 594 } |
592 } | 595 } |
593 | 596 |
594 | 597 |
595 Variable* Scope::Lookup(const AstRawString* name) { | 598 Variable* Scope::Lookup(const AstRawString* name) { |
(...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
960 if (proxy->is_resolved() && proxy->var()->IsStackAllocated()) continue; | 963 if (proxy->is_resolved() && proxy->var()->IsStackAllocated()) continue; |
961 Handle<String> name = proxy->name(); | 964 Handle<String> name = proxy->name(); |
962 non_locals = StringSet::Add(non_locals, name); | 965 non_locals = StringSet::Add(non_locals, name); |
963 } | 966 } |
964 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { | 967 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { |
965 non_locals = scope->CollectNonLocals(non_locals); | 968 non_locals = scope->CollectNonLocals(non_locals); |
966 } | 969 } |
967 return non_locals; | 970 return non_locals; |
968 } | 971 } |
969 | 972 |
| 973 void Scope::AnalyzePartially(Scope* migrate_to, |
| 974 AstNodeFactory* ast_node_factory) { |
| 975 // Gather info from inner scopes. |
| 976 PropagateScopeInfo(false); |
| 977 |
| 978 // Try to resolve unresolved variables for this Scope and migrate those which |
| 979 // cannot be resolved inside. It doesn't make sense to try to resolve them in |
| 980 // the outer Scopes here, because they are incomplete. |
| 981 MigrateUnresolvableLocals(migrate_to, ast_node_factory, this); |
| 982 |
| 983 // Push scope data up to migrate_to. Note that migrate_to and this Scope |
| 984 // describe the same Scope, just in different Zones. |
| 985 PropagateUsageFlagsToScope(migrate_to); |
| 986 if (inner_scope_calls_eval_) { |
| 987 migrate_to->inner_scope_calls_eval_ = true; |
| 988 } |
| 989 DCHECK(!force_eager_compilation_); |
| 990 migrate_to->set_start_position(start_position_); |
| 991 migrate_to->set_end_position(end_position_); |
| 992 migrate_to->language_mode_ = language_mode_; |
| 993 migrate_to->arity_ = arity_; |
| 994 migrate_to->force_context_allocation_ = force_context_allocation_; |
| 995 outer_scope_->RemoveInnerScope(this); |
| 996 DCHECK_EQ(outer_scope_, migrate_to->outer_scope_); |
| 997 DCHECK_EQ(outer_scope_->zone(), migrate_to->zone()); |
| 998 DCHECK_EQ(NeedsHomeObject(), migrate_to->NeedsHomeObject()); |
| 999 DCHECK_EQ(asm_function_, migrate_to->asm_function_); |
| 1000 DCHECK_EQ(arguments() != nullptr, migrate_to->arguments() != nullptr); |
| 1001 } |
970 | 1002 |
971 #ifdef DEBUG | 1003 #ifdef DEBUG |
972 static const char* Header(ScopeType scope_type, FunctionKind function_kind, | 1004 static const char* Header(ScopeType scope_type, FunctionKind function_kind, |
973 bool is_declaration_scope) { | 1005 bool is_declaration_scope) { |
974 switch (scope_type) { | 1006 switch (scope_type) { |
975 case EVAL_SCOPE: return "eval"; | 1007 case EVAL_SCOPE: return "eval"; |
976 // TODO(adamk): Should we print concise method scopes specially? | 1008 // TODO(adamk): Should we print concise method scopes specially? |
977 case FUNCTION_SCOPE: | 1009 case FUNCTION_SCOPE: |
978 if (IsGeneratorFunction(function_kind)) return "function*"; | 1010 if (IsGeneratorFunction(function_kind)) return "function*"; |
979 if (IsAsyncFunction(function_kind)) return "async function"; | 1011 if (IsAsyncFunction(function_kind)) return "async function"; |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1168 // A scope is allowed to have invalid positions if it is hidden and has no | 1200 // A scope is allowed to have invalid positions if it is hidden and has no |
1169 // inner scopes | 1201 // inner scopes |
1170 if (!is_hidden() && inner_scope_ == nullptr) { | 1202 if (!is_hidden() && inner_scope_ == nullptr) { |
1171 CHECK_NE(kNoSourcePosition, start_position()); | 1203 CHECK_NE(kNoSourcePosition, start_position()); |
1172 CHECK_NE(kNoSourcePosition, end_position()); | 1204 CHECK_NE(kNoSourcePosition, end_position()); |
1173 } | 1205 } |
1174 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { | 1206 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { |
1175 scope->CheckScopePositions(); | 1207 scope->CheckScopePositions(); |
1176 } | 1208 } |
1177 } | 1209 } |
| 1210 |
| 1211 void Scope::CheckZones() { |
| 1212 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { |
| 1213 CHECK_EQ(scope->zone(), zone()); |
| 1214 } |
| 1215 } |
1178 #endif // DEBUG | 1216 #endif // DEBUG |
1179 | 1217 |
1180 | 1218 |
1181 Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) { | 1219 Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) { |
1182 if (dynamics_ == NULL) dynamics_ = new (zone()) DynamicScopePart(zone()); | 1220 if (dynamics_ == NULL) dynamics_ = new (zone()) DynamicScopePart(zone()); |
1183 VariableMap* map = dynamics_->GetMap(mode); | 1221 VariableMap* map = dynamics_->GetMap(mode); |
1184 Variable* var = map->Lookup(name); | 1222 Variable* var = map->Lookup(name); |
1185 if (var == NULL) { | 1223 if (var == NULL) { |
1186 // Declare a new non-local. | 1224 // Declare a new non-local. |
1187 InitializationFlag init_flag = (mode == VAR) | 1225 InitializationFlag init_flag = (mode == VAR) |
1188 ? kCreatedInitialized : kNeedsInitialization; | 1226 ? kCreatedInitialized : kNeedsInitialization; |
1189 var = map->Declare(NULL, | 1227 var = map->Declare(NULL, |
1190 name, | 1228 name, |
1191 mode, | 1229 mode, |
1192 Variable::NORMAL, | 1230 Variable::NORMAL, |
1193 init_flag); | 1231 init_flag); |
1194 // Allocate it by giving it a dynamic lookup. | 1232 // Allocate it by giving it a dynamic lookup. |
1195 var->AllocateTo(VariableLocation::LOOKUP, -1); | 1233 var->AllocateTo(VariableLocation::LOOKUP, -1); |
1196 } | 1234 } |
1197 return var; | 1235 return var; |
1198 } | 1236 } |
1199 | 1237 |
1200 | |
1201 Variable* Scope::LookupRecursive(VariableProxy* proxy, | 1238 Variable* Scope::LookupRecursive(VariableProxy* proxy, |
1202 BindingKind* binding_kind, | 1239 BindingKind* binding_kind, |
1203 AstNodeFactory* factory) { | 1240 AstNodeFactory* factory, |
| 1241 Scope* max_outer_scope) { |
1204 DCHECK(binding_kind != NULL); | 1242 DCHECK(binding_kind != NULL); |
1205 if (already_resolved() && is_with_scope()) { | 1243 if (already_resolved() && is_with_scope()) { |
1206 // Short-cut: if the scope is deserialized from a scope info, variable | 1244 // Short-cut: if the scope is deserialized from a scope info, variable |
1207 // allocation is already fixed. We can simply return with dynamic lookup. | 1245 // allocation is already fixed. We can simply return with dynamic lookup. |
1208 *binding_kind = DYNAMIC_LOOKUP; | 1246 *binding_kind = DYNAMIC_LOOKUP; |
1209 return NULL; | 1247 return NULL; |
1210 } | 1248 } |
1211 | 1249 |
1212 // Try to find the variable in this scope. | 1250 // Try to find the variable in this scope. |
1213 Variable* var = LookupLocal(proxy->raw_name()); | 1251 Variable* var = LookupLocal(proxy->raw_name()); |
1214 | 1252 |
1215 // We found a variable and we are done. (Even if there is an 'eval' in | 1253 // We found a variable and we are done. (Even if there is an 'eval' in |
1216 // this scope which introduces the same variable again, the resulting | 1254 // this scope which introduces the same variable again, the resulting |
1217 // variable remains the same.) | 1255 // variable remains the same.) |
1218 if (var != NULL) { | 1256 if (var != NULL) { |
1219 *binding_kind = BOUND; | 1257 *binding_kind = BOUND; |
1220 return var; | 1258 return var; |
1221 } | 1259 } |
1222 | 1260 |
1223 // We did not find a variable locally. Check against the function variable, | 1261 // We did not find a variable locally. Check against the function variable, |
1224 // if any. We can do this for all scopes, since the function variable is | 1262 // if any. We can do this for all scopes, since the function variable is |
1225 // only present - if at all - for function scopes. | 1263 // only present - if at all - for function scopes. |
1226 *binding_kind = UNBOUND; | 1264 *binding_kind = UNBOUND; |
1227 var = LookupFunctionVar(proxy->raw_name(), factory); | 1265 var = LookupFunctionVar(proxy->raw_name(), factory); |
1228 if (var != NULL) { | 1266 if (var != NULL) { |
1229 *binding_kind = BOUND; | 1267 *binding_kind = BOUND; |
1230 } else if (outer_scope_ != NULL) { | 1268 } else if (outer_scope_ != nullptr && this != max_outer_scope) { |
1231 var = outer_scope_->LookupRecursive(proxy, binding_kind, factory); | 1269 var = outer_scope_->LookupRecursive(proxy, binding_kind, factory, |
| 1270 max_outer_scope); |
1232 if (*binding_kind == BOUND && (is_function_scope() || is_with_scope())) { | 1271 if (*binding_kind == BOUND && (is_function_scope() || is_with_scope())) { |
1233 var->ForceContextAllocation(); | 1272 var->ForceContextAllocation(); |
1234 } | 1273 } |
1235 } else { | 1274 } else { |
1236 DCHECK(is_script_scope()); | 1275 DCHECK(is_script_scope() || this == max_outer_scope); |
1237 } | 1276 } |
1238 | 1277 |
1239 // "this" can't be shadowed by "eval"-introduced bindings or by "with" scopes. | 1278 // "this" can't be shadowed by "eval"-introduced bindings or by "with" scopes. |
1240 // TODO(wingo): There are other variables in this category; add them. | 1279 // TODO(wingo): There are other variables in this category; add them. |
1241 bool name_can_be_shadowed = var == nullptr || !var->is_this(); | 1280 bool name_can_be_shadowed = var == nullptr || !var->is_this(); |
1242 | 1281 |
1243 if (is_with_scope() && name_can_be_shadowed) { | 1282 if (is_with_scope() && name_can_be_shadowed) { |
1244 DCHECK(!already_resolved()); | 1283 DCHECK(!already_resolved()); |
1245 // The current scope is a with scope, so the variable binding can not be | 1284 // The current scope is a with scope, so the variable binding can not be |
1246 // statically resolved. However, note that it was necessary to do a lookup | 1285 // 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... |
1359 } | 1398 } |
1360 | 1399 |
1361 // Resolve unresolved variables for inner scopes. | 1400 // Resolve unresolved variables for inner scopes. |
1362 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { | 1401 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { |
1363 if (!scope->ResolveVariablesRecursively(info, factory)) return false; | 1402 if (!scope->ResolveVariablesRecursively(info, factory)) return false; |
1364 } | 1403 } |
1365 | 1404 |
1366 return true; | 1405 return true; |
1367 } | 1406 } |
1368 | 1407 |
| 1408 void Scope::MigrateUnresolvableLocals(Scope* migrate_to, |
| 1409 AstNodeFactory* ast_node_factory, |
| 1410 Scope* max_outer_scope) { |
| 1411 BindingKind binding_kind; |
| 1412 for (VariableProxy *proxy = unresolved_, *next = nullptr; proxy != nullptr; |
| 1413 proxy = next) { |
| 1414 next = proxy->next_unresolved(); |
| 1415 // Note that we pass nullptr as AstNodeFactory: this phase should not create |
| 1416 // any new AstNodes, since none of the Scopes involved are backed up by |
| 1417 // ScopeInfo. |
| 1418 if (LookupRecursive(proxy, &binding_kind, nullptr, max_outer_scope) == |
| 1419 nullptr) { |
| 1420 // Re-create the VariableProxies in the right Zone and insert them into |
| 1421 // migrate_to. |
| 1422 DCHECK(!proxy->is_resolved()); |
| 1423 VariableProxy* copy = ast_node_factory->CopyVariableProxy(proxy); |
| 1424 migrate_to->AddUnresolved(copy); |
| 1425 } |
| 1426 } |
| 1427 |
| 1428 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { |
| 1429 scope->MigrateUnresolvableLocals(migrate_to, ast_node_factory, |
| 1430 max_outer_scope); |
| 1431 } |
| 1432 } |
1369 | 1433 |
1370 void Scope::PropagateScopeInfo(bool outer_scope_calls_sloppy_eval ) { | 1434 void Scope::PropagateScopeInfo(bool outer_scope_calls_sloppy_eval ) { |
1371 if (outer_scope_calls_sloppy_eval) { | 1435 if (outer_scope_calls_sloppy_eval) { |
1372 outer_scope_calls_sloppy_eval_ = true; | 1436 outer_scope_calls_sloppy_eval_ = true; |
1373 } | 1437 } |
1374 | 1438 |
1375 bool calls_sloppy_eval = | 1439 bool calls_sloppy_eval = |
1376 this->calls_sloppy_eval() || outer_scope_calls_sloppy_eval_; | 1440 this->calls_sloppy_eval() || outer_scope_calls_sloppy_eval_; |
1377 for (Scope* inner = inner_scope_; inner != nullptr; inner = inner->sibling_) { | 1441 for (Scope* inner = inner_scope_; inner != nullptr; inner = inner->sibling_) { |
1378 inner->PropagateScopeInfo(calls_sloppy_eval); | 1442 inner->PropagateScopeInfo(calls_sloppy_eval); |
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1654 function_ != NULL && function_->proxy()->var()->IsContextSlot(); | 1718 function_ != NULL && function_->proxy()->var()->IsContextSlot(); |
1655 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - num_global_slots() - | 1719 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - num_global_slots() - |
1656 (is_function_var_in_context ? 1 : 0); | 1720 (is_function_var_in_context ? 1 : 0); |
1657 } | 1721 } |
1658 | 1722 |
1659 | 1723 |
1660 int Scope::ContextGlobalCount() const { return num_global_slots(); } | 1724 int Scope::ContextGlobalCount() const { return num_global_slots(); } |
1661 | 1725 |
1662 } // namespace internal | 1726 } // namespace internal |
1663 } // namespace v8 | 1727 } // namespace v8 |
OLD | NEW |