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/ast/scopeinfo.h" | 8 #include "src/ast/scopeinfo.h" |
9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
10 #include "src/messages.h" | 10 #include "src/messages.h" |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
273 return false; | 273 return false; |
274 } | 274 } |
275 } | 275 } |
276 | 276 |
277 #ifdef DEBUG | 277 #ifdef DEBUG |
278 if (info->script_is_native() ? FLAG_print_builtin_scopes | 278 if (info->script_is_native() ? FLAG_print_builtin_scopes |
279 : FLAG_print_scopes) { | 279 : FLAG_print_scopes) { |
280 scope->Print(); | 280 scope->Print(); |
281 } | 281 } |
282 scope->CheckScopePositions(); | 282 scope->CheckScopePositions(); |
283 scope->CheckZones(); | |
283 #endif | 284 #endif |
284 | 285 |
285 info->set_scope(scope); | 286 info->set_scope(scope); |
286 return true; | 287 return true; |
287 } | 288 } |
288 | 289 |
289 void Scope::DeclareThis(AstValueFactory* ast_value_factory) { | 290 void Scope::DeclareThis(AstValueFactory* ast_value_factory) { |
290 DCHECK(!already_resolved()); | 291 DCHECK(!already_resolved()); |
291 DCHECK(is_declaration_scope()); | 292 DCHECK(is_declaration_scope()); |
292 DCHECK(has_this_declaration()); | 293 DCHECK(has_this_declaration()); |
(...skipping 202 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 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
883 if (proxy->is_resolved() && proxy->var()->IsStackAllocated()) continue; | 886 if (proxy->is_resolved() && proxy->var()->IsStackAllocated()) continue; |
884 Handle<String> name = proxy->name(); | 887 Handle<String> name = proxy->name(); |
885 non_locals = StringSet::Add(non_locals, name); | 888 non_locals = StringSet::Add(non_locals, name); |
886 } | 889 } |
887 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { | 890 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { |
888 non_locals = scope->CollectNonLocals(non_locals); | 891 non_locals = scope->CollectNonLocals(non_locals); |
889 } | 892 } |
890 return non_locals; | 893 return non_locals; |
891 } | 894 } |
892 | 895 |
896 void Scope::CollectUnresolvableLocals(VariableProxy** still_unresolved, | |
897 Scope* max_outer_scope) { | |
898 BindingKind binding_kind; | |
899 for (VariableProxy *proxy = unresolved_, *next = nullptr; proxy != nullptr; | |
900 proxy = next) { | |
901 next = proxy->next_unresolved(); | |
902 // Note that we pass nullptr as AstNodeFactory: this phase should not create | |
903 // any new AstNodes, since none of the Scopes involved are backed up by | |
904 // ScopeInfo. | |
905 if (LookupRecursive(proxy, &binding_kind, nullptr, max_outer_scope) == | |
906 nullptr) { | |
907 proxy->set_next_unresolved(*still_unresolved); | |
908 *still_unresolved = proxy; | |
909 } | |
910 } | |
911 | |
912 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { | |
913 scope->CollectUnresolvableLocals(still_unresolved, max_outer_scope); | |
914 } | |
915 } | |
916 | |
917 void Scope::AnalyzePartially(Scope* migrate_to, | |
918 AstNodeFactory* ast_node_factory) { | |
919 // Gather info from inner scopes. | |
920 PropagateScopeInfo(false); | |
921 | |
922 // Try to resolve unresolved variables for this Scope and collect those which | |
923 // cannot be resolved inside. It doesn't make sense to try to resolve them in | |
924 // the outer Scopes here, because they are incomplete. | |
925 VariableProxy* still_unresolved = nullptr; | |
926 CollectUnresolvableLocals(&still_unresolved, this); | |
927 | |
928 // Re-create the VariableProxies in the right Zone and insert them into | |
929 // migrate_to. | |
930 for (VariableProxy* proxy = still_unresolved; proxy != nullptr; | |
931 proxy = proxy->next_unresolved()) { | |
932 // Recrate the VariableProxy. | |
adamk
2016/08/01 18:34:33
s/Recrate/Recreate/
marja
2016/08/02 07:42:37
Done.
| |
933 DCHECK_EQ(proxy->is_resolved(), false); | |
adamk
2016/08/01 18:34:33
Nit: I'd prefer DCHECK(!proxy->is_resolved()) :)
marja
2016/08/02 07:42:37
Ha, I'm only using this form because some code rev
adamk
2016/08/02 16:13:09
CHECK_EQ makes sense to me if we want to know what
| |
934 VariableProxy* clone = ast_node_factory->CloneVariableProxy(proxy); | |
935 migrate_to->AddUnresolved(clone); | |
936 } | |
937 | |
938 // Push scope data up to migrate_to. Note that migrate_to and this Scope | |
939 // describe the same Scope, just in different Zones. | |
940 PropagateUsageFlagsToScope(migrate_to); | |
941 if (inner_scope_calls_eval_) { | |
942 migrate_to->inner_scope_calls_eval_ = true; | |
943 } | |
944 DCHECK(!force_eager_compilation_); | |
945 migrate_to->set_start_position(start_position_); | |
946 migrate_to->set_end_position(end_position_); | |
947 migrate_to->language_mode_ = language_mode_; | |
948 outer_scope_->RemoveInnerScope(this); | |
949 DCHECK_EQ(outer_scope_, migrate_to->outer_scope_); | |
950 DCHECK_EQ(outer_scope_->zone(), migrate_to->zone()); | |
951 } | |
893 | 952 |
894 #ifdef DEBUG | 953 #ifdef DEBUG |
895 static const char* Header(ScopeType scope_type, FunctionKind function_kind, | 954 static const char* Header(ScopeType scope_type, FunctionKind function_kind, |
896 bool is_declaration_scope) { | 955 bool is_declaration_scope) { |
897 switch (scope_type) { | 956 switch (scope_type) { |
898 case EVAL_SCOPE: return "eval"; | 957 case EVAL_SCOPE: return "eval"; |
899 // TODO(adamk): Should we print concise method scopes specially? | 958 // TODO(adamk): Should we print concise method scopes specially? |
900 case FUNCTION_SCOPE: | 959 case FUNCTION_SCOPE: |
901 if (IsGeneratorFunction(function_kind)) return "function*"; | 960 if (IsGeneratorFunction(function_kind)) return "function*"; |
902 if (IsAsyncFunction(function_kind)) return "async function"; | 961 if (IsAsyncFunction(function_kind)) return "async function"; |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1091 // A scope is allowed to have invalid positions if it is hidden and has no | 1150 // A scope is allowed to have invalid positions if it is hidden and has no |
1092 // inner scopes | 1151 // inner scopes |
1093 if (!is_hidden() && inner_scope_ == nullptr) { | 1152 if (!is_hidden() && inner_scope_ == nullptr) { |
1094 CHECK_NE(kNoSourcePosition, start_position()); | 1153 CHECK_NE(kNoSourcePosition, start_position()); |
1095 CHECK_NE(kNoSourcePosition, end_position()); | 1154 CHECK_NE(kNoSourcePosition, end_position()); |
1096 } | 1155 } |
1097 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { | 1156 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { |
1098 scope->CheckScopePositions(); | 1157 scope->CheckScopePositions(); |
1099 } | 1158 } |
1100 } | 1159 } |
1160 | |
1161 void Scope::CheckZones() { | |
1162 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { | |
1163 CHECK_EQ(scope->zone(), zone()); | |
1164 } | |
1165 } | |
1101 #endif // DEBUG | 1166 #endif // DEBUG |
1102 | 1167 |
1103 | 1168 |
1104 Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) { | 1169 Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) { |
1105 if (dynamics_ == NULL) dynamics_ = new (zone()) DynamicScopePart(zone()); | 1170 if (dynamics_ == NULL) dynamics_ = new (zone()) DynamicScopePart(zone()); |
1106 VariableMap* map = dynamics_->GetMap(mode); | 1171 VariableMap* map = dynamics_->GetMap(mode); |
1107 Variable* var = map->Lookup(name); | 1172 Variable* var = map->Lookup(name); |
1108 if (var == NULL) { | 1173 if (var == NULL) { |
1109 // Declare a new non-local. | 1174 // Declare a new non-local. |
1110 InitializationFlag init_flag = (mode == VAR) | 1175 InitializationFlag init_flag = (mode == VAR) |
1111 ? kCreatedInitialized : kNeedsInitialization; | 1176 ? kCreatedInitialized : kNeedsInitialization; |
1112 var = map->Declare(NULL, | 1177 var = map->Declare(NULL, |
1113 name, | 1178 name, |
1114 mode, | 1179 mode, |
1115 Variable::NORMAL, | 1180 Variable::NORMAL, |
1116 init_flag); | 1181 init_flag); |
1117 // Allocate it by giving it a dynamic lookup. | 1182 // Allocate it by giving it a dynamic lookup. |
1118 var->AllocateTo(VariableLocation::LOOKUP, -1); | 1183 var->AllocateTo(VariableLocation::LOOKUP, -1); |
1119 } | 1184 } |
1120 return var; | 1185 return var; |
1121 } | 1186 } |
1122 | 1187 |
1123 | |
1124 Variable* Scope::LookupRecursive(VariableProxy* proxy, | 1188 Variable* Scope::LookupRecursive(VariableProxy* proxy, |
1125 BindingKind* binding_kind, | 1189 BindingKind* binding_kind, |
1126 AstNodeFactory* factory) { | 1190 AstNodeFactory* factory, |
1191 Scope* max_outer_scope) { | |
1127 DCHECK(binding_kind != NULL); | 1192 DCHECK(binding_kind != NULL); |
1128 if (already_resolved() && is_with_scope()) { | 1193 if (already_resolved() && is_with_scope()) { |
1129 // Short-cut: if the scope is deserialized from a scope info, variable | 1194 // Short-cut: if the scope is deserialized from a scope info, variable |
1130 // allocation is already fixed. We can simply return with dynamic lookup. | 1195 // allocation is already fixed. We can simply return with dynamic lookup. |
1131 *binding_kind = DYNAMIC_LOOKUP; | 1196 *binding_kind = DYNAMIC_LOOKUP; |
1132 return NULL; | 1197 return NULL; |
1133 } | 1198 } |
1134 | 1199 |
1135 // Try to find the variable in this scope. | 1200 // Try to find the variable in this scope. |
1136 Variable* var = LookupLocal(proxy->raw_name()); | 1201 Variable* var = LookupLocal(proxy->raw_name()); |
1137 | 1202 |
1138 // We found a variable and we are done. (Even if there is an 'eval' in | 1203 // We found a variable and we are done. (Even if there is an 'eval' in |
1139 // this scope which introduces the same variable again, the resulting | 1204 // this scope which introduces the same variable again, the resulting |
1140 // variable remains the same.) | 1205 // variable remains the same.) |
1141 if (var != NULL) { | 1206 if (var != NULL) { |
1142 *binding_kind = BOUND; | 1207 *binding_kind = BOUND; |
1143 return var; | 1208 return var; |
1144 } | 1209 } |
1145 | 1210 |
1146 // We did not find a variable locally. Check against the function variable, | 1211 // We did not find a variable locally. Check against the function variable, |
1147 // if any. We can do this for all scopes, since the function variable is | 1212 // if any. We can do this for all scopes, since the function variable is |
1148 // only present - if at all - for function scopes. | 1213 // only present - if at all - for function scopes. |
1149 *binding_kind = UNBOUND; | 1214 *binding_kind = UNBOUND; |
1150 var = LookupFunctionVar(proxy->raw_name(), factory); | 1215 var = LookupFunctionVar(proxy->raw_name(), factory); |
1151 if (var != NULL) { | 1216 if (var != NULL) { |
1152 *binding_kind = BOUND; | 1217 *binding_kind = BOUND; |
1153 } else if (outer_scope_ != NULL) { | 1218 } else if (outer_scope_ != nullptr && this != max_outer_scope) { |
1154 var = outer_scope_->LookupRecursive(proxy, binding_kind, factory); | 1219 var = outer_scope_->LookupRecursive(proxy, binding_kind, factory, |
1220 max_outer_scope); | |
1155 if (*binding_kind == BOUND && (is_function_scope() || is_with_scope())) { | 1221 if (*binding_kind == BOUND && (is_function_scope() || is_with_scope())) { |
1156 var->ForceContextAllocation(); | 1222 var->ForceContextAllocation(); |
1157 } | 1223 } |
1158 } else { | 1224 } else { |
1159 DCHECK(is_script_scope()); | 1225 DCHECK(is_script_scope() || this == max_outer_scope); |
1160 } | 1226 } |
1161 | 1227 |
1162 // "this" can't be shadowed by "eval"-introduced bindings or by "with" scopes. | 1228 // "this" can't be shadowed by "eval"-introduced bindings or by "with" scopes. |
1163 // TODO(wingo): There are other variables in this category; add them. | 1229 // TODO(wingo): There are other variables in this category; add them. |
1164 bool name_can_be_shadowed = var == nullptr || !var->is_this(); | 1230 bool name_can_be_shadowed = var == nullptr || !var->is_this(); |
1165 | 1231 |
1166 if (is_with_scope() && name_can_be_shadowed) { | 1232 if (is_with_scope() && name_can_be_shadowed) { |
1167 DCHECK(!already_resolved()); | 1233 DCHECK(!already_resolved()); |
1168 // The current scope is a with scope, so the variable binding can not be | 1234 // The current scope is a with scope, so the variable binding can not be |
1169 // statically resolved. However, note that it was necessary to do a lookup | 1235 // statically resolved. However, note that it was necessary to do a lookup |
(...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1577 function_ != NULL && function_->proxy()->var()->IsContextSlot(); | 1643 function_ != NULL && function_->proxy()->var()->IsContextSlot(); |
1578 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - num_global_slots() - | 1644 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - num_global_slots() - |
1579 (is_function_var_in_context ? 1 : 0); | 1645 (is_function_var_in_context ? 1 : 0); |
1580 } | 1646 } |
1581 | 1647 |
1582 | 1648 |
1583 int Scope::ContextGlobalCount() const { return num_global_slots(); } | 1649 int Scope::ContextGlobalCount() const { return num_global_slots(); } |
1584 | 1650 |
1585 } // namespace internal | 1651 } // namespace internal |
1586 } // namespace v8 | 1652 } // namespace v8 |
OLD | NEW |