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 1243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1254 var = map->Declare(zone(), NULL, name, mode, Variable::NORMAL, init_flag); | 1254 var = map->Declare(zone(), NULL, name, mode, Variable::NORMAL, init_flag); |
1255 // Allocate it by giving it a dynamic lookup. | 1255 // Allocate it by giving it a dynamic lookup. |
1256 var->AllocateTo(VariableLocation::LOOKUP, -1); | 1256 var->AllocateTo(VariableLocation::LOOKUP, -1); |
1257 } | 1257 } |
1258 return var; | 1258 return var; |
1259 } | 1259 } |
1260 | 1260 |
1261 Variable* Scope::LookupRecursive(VariableProxy* proxy, | 1261 Variable* Scope::LookupRecursive(VariableProxy* proxy, |
1262 BindingKind* binding_kind, | 1262 BindingKind* binding_kind, |
1263 AstNodeFactory* factory, | 1263 AstNodeFactory* factory, |
1264 Scope* max_outer_scope) { | 1264 Scope* outer_scope_end) { |
1265 DCHECK(binding_kind != NULL); | 1265 DCHECK_NE(outer_scope_end, this); |
1266 DCHECK_NOT_NULL(binding_kind); | |
1267 DCHECK_EQ(UNBOUND, *binding_kind); | |
1266 if (already_resolved() && is_with_scope()) { | 1268 if (already_resolved() && is_with_scope()) { |
1267 // Short-cut: if the scope is deserialized from a scope info, variable | 1269 // Short-cut: if the scope is deserialized from a scope info, variable |
1268 // allocation is already fixed. We can simply return with dynamic lookup. | 1270 // allocation is already fixed. We can simply return with dynamic lookup. |
1269 *binding_kind = DYNAMIC_LOOKUP; | 1271 *binding_kind = DYNAMIC_LOOKUP; |
1270 return NULL; | 1272 return nullptr; |
1271 } | 1273 } |
1272 | 1274 |
1273 // Try to find the variable in this scope. | 1275 // Try to find the variable in this scope. |
1274 Variable* var = LookupLocal(proxy->raw_name()); | 1276 Variable* var = LookupLocal(proxy->raw_name()); |
1275 | 1277 |
1276 // We found a variable and we are done. (Even if there is an 'eval' in | 1278 // We found a variable and we are done. (Even if there is an 'eval' in this |
1277 // this scope which introduces the same variable again, the resulting | 1279 // scope which introduces the same variable again, the resulting variable |
1278 // variable remains the same.) | 1280 // remains the same.) |
1279 if (var != NULL) { | 1281 if (var != nullptr) { |
1280 *binding_kind = BOUND; | 1282 *binding_kind = BOUND; |
1281 return var; | 1283 return var; |
1282 } | 1284 } |
1283 | 1285 |
1284 // We did not find a variable locally. Check against the function variable, if | 1286 // We did not find a variable locally. Check against the function variable, if |
1285 // any. | 1287 // any. |
1286 *binding_kind = UNBOUND; | 1288 if (is_function_scope()) { |
1287 var = is_function_scope() | 1289 var = AsDeclarationScope()->LookupFunctionVar(proxy->raw_name()); |
1288 ? AsDeclarationScope()->LookupFunctionVar(proxy->raw_name()) | 1290 if (var != nullptr) { |
1289 : nullptr; | 1291 *binding_kind = calls_sloppy_eval() ? BOUND_EVAL_SHADOWED : BOUND; |
1290 if (var != NULL) { | 1292 return var; |
1291 *binding_kind = BOUND; | 1293 } |
1292 } else if (outer_scope_ != nullptr && this != max_outer_scope) { | 1294 } |
1295 | |
1296 if (outer_scope_ != outer_scope_end) { | |
1293 var = outer_scope_->LookupRecursive(proxy, binding_kind, factory, | 1297 var = outer_scope_->LookupRecursive(proxy, binding_kind, factory, |
1294 max_outer_scope); | 1298 outer_scope_end); |
1295 if (*binding_kind == BOUND && is_function_scope()) { | 1299 if (*binding_kind == BOUND && is_function_scope()) { |
1296 var->ForceContextAllocation(); | 1300 var->ForceContextAllocation(); |
1297 } | 1301 } |
1302 // "this" can't be shadowed by "eval"-introduced bindings or by "with" | |
1303 // scopes. | |
1304 // TODO(wingo): There are other variables in this category; add them. | |
1305 if (var != nullptr && var->is_this()) return var; | |
1306 | |
1307 if (is_with_scope()) { | |
1308 DCHECK(!already_resolved()); | |
1309 // The current scope is a with scope, so the variable binding can not be | |
1310 // statically resolved. However, note that it was necessary to do a lookup | |
1311 // in the outer scope anyway, because if a binding exists in an outer | |
1312 // scope, the associated variable has to be marked as potentially being | |
1313 // accessed from inside of an inner with scope (the property may not be in | |
1314 // the 'with' object). | |
1315 if (var != nullptr) { | |
1316 var->set_is_used(); | |
1317 var->ForceContextAllocation(); | |
1318 if (proxy->is_assigned()) var->set_maybe_assigned(); | |
1319 } | |
1320 *binding_kind = DYNAMIC_LOOKUP; | |
1321 return nullptr; | |
1322 } | |
1298 } else { | 1323 } else { |
1299 DCHECK(is_script_scope() || this == max_outer_scope); | 1324 DCHECK(is_function_scope() || is_script_scope() || is_eval_scope()); |
1325 DCHECK(!is_with_scope()); | |
adamk
2016/08/11 18:19:19
If you want this DCHECK to be useful it's gotta go
Toon Verwaest
2016/08/12 05:16:58
I don't see the issue with checking both? I can re
adamk
2016/08/15 17:45:00
What I mean is that a with scope will fail on the
| |
1300 } | 1326 } |
1301 | 1327 |
1302 // "this" can't be shadowed by "eval"-introduced bindings or by "with" scopes. | 1328 if (calls_sloppy_eval() && is_declaration_scope() && !is_script_scope()) { |
adamk
2016/08/11 18:19:19
This is no longer guarded by "name_can_be_shadowed
Toon Verwaest
2016/08/12 05:16:58
It is. Either we have a var null since outer scope
adamk
2016/08/15 17:45:00
Point taken :)
| |
1303 // TODO(wingo): There are other variables in this category; add them. | |
1304 bool name_can_be_shadowed = var == nullptr || !var->is_this(); | |
1305 | |
1306 if (is_with_scope() && name_can_be_shadowed) { | |
1307 DCHECK(!already_resolved()); | |
1308 // The current scope is a with scope, so the variable binding can not be | |
1309 // statically resolved. However, note that it was necessary to do a lookup | |
1310 // in the outer scope anyway, because if a binding exists in an outer scope, | |
1311 // the associated variable has to be marked as potentially being accessed | |
1312 // from inside of an inner with scope (the property may not be in the 'with' | |
1313 // object). | |
1314 if (var != NULL) { | |
1315 var->set_is_used(); | |
1316 var->ForceContextAllocation(); | |
1317 if (proxy->is_assigned()) var->set_maybe_assigned(); | |
1318 } | |
1319 *binding_kind = DYNAMIC_LOOKUP; | |
1320 return NULL; | |
1321 } else if (calls_sloppy_eval() && is_declaration_scope() && | |
1322 !is_script_scope() && name_can_be_shadowed) { | |
1323 // A variable binding may have been found in an outer scope, but the current | 1329 // A variable binding may have been found in an outer scope, but the current |
1324 // scope makes a sloppy 'eval' call, so the found variable may not be | 1330 // scope makes a sloppy 'eval' call, so the found variable may not be the |
1325 // the correct one (the 'eval' may introduce a binding with the same name). | 1331 // correct one (the 'eval' may introduce a binding with the same name). In |
1326 // In that case, change the lookup result to reflect this situation. | 1332 // that case, change the lookup result to reflect this situation. Only |
1327 // Only scopes that can host var bindings (declaration scopes) need be | 1333 // scopes that can host var bindings (declaration scopes) need be considered |
1328 // considered here (this excludes block and catch scopes), and variable | 1334 // here (this excludes block and catch scopes), and variable lookups at |
1329 // lookups at script scope are always dynamic. | 1335 // script scope are always dynamic. |
1330 if (*binding_kind == BOUND) { | 1336 if (*binding_kind == BOUND) { |
1331 *binding_kind = BOUND_EVAL_SHADOWED; | 1337 *binding_kind = BOUND_EVAL_SHADOWED; |
1332 } else if (*binding_kind == UNBOUND) { | 1338 } else if (*binding_kind == UNBOUND) { |
1333 *binding_kind = UNBOUND_EVAL_SHADOWED; | 1339 *binding_kind = UNBOUND_EVAL_SHADOWED; |
1334 } | 1340 } |
1335 } | 1341 } |
1342 | |
1336 return var; | 1343 return var; |
1337 } | 1344 } |
1338 | 1345 |
1339 void Scope::ResolveVariable(ParseInfo* info, VariableProxy* proxy, | 1346 void Scope::ResolveVariable(ParseInfo* info, VariableProxy* proxy, |
1340 AstNodeFactory* factory) { | 1347 AstNodeFactory* factory) { |
1341 DCHECK(info->script_scope()->is_script_scope()); | 1348 DCHECK(info->script_scope()->is_script_scope()); |
1342 | 1349 |
1343 // If the proxy is already resolved there's nothing to do | 1350 // If the proxy is already resolved there's nothing to do |
1344 // (functions and consts may be resolved by the parser). | 1351 // (functions and consts may be resolved by the parser). |
1345 if (proxy->is_resolved()) return; | 1352 if (proxy->is_resolved()) return; |
1346 | 1353 |
1347 // Otherwise, try to resolve the variable. | 1354 // Otherwise, try to resolve the variable. |
1348 BindingKind binding_kind; | 1355 BindingKind binding_kind = UNBOUND; |
1349 Variable* var = LookupRecursive(proxy, &binding_kind, factory); | 1356 Variable* var = LookupRecursive(proxy, &binding_kind, factory); |
1350 | 1357 |
1351 ResolveTo(info, binding_kind, proxy, var); | 1358 ResolveTo(info, binding_kind, proxy, var); |
1352 } | 1359 } |
1353 | 1360 |
1354 void Scope::ResolveTo(ParseInfo* info, BindingKind binding_kind, | 1361 void Scope::ResolveTo(ParseInfo* info, BindingKind binding_kind, |
1355 VariableProxy* proxy, Variable* var) { | 1362 VariableProxy* proxy, Variable* var) { |
1356 #ifdef DEBUG | 1363 #ifdef DEBUG |
1357 if (info->script_is_native()) { | 1364 if (info->script_is_native()) { |
1358 // To avoid polluting the global object in native scripts | 1365 // To avoid polluting the global object in native scripts |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1428 | 1435 |
1429 // Resolve unresolved variables for inner scopes. | 1436 // Resolve unresolved variables for inner scopes. |
1430 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { | 1437 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { |
1431 scope->ResolveVariablesRecursively(info, factory); | 1438 scope->ResolveVariablesRecursively(info, factory); |
1432 } | 1439 } |
1433 } | 1440 } |
1434 | 1441 |
1435 VariableProxy* Scope::FetchFreeVariables(DeclarationScope* max_outer_scope, | 1442 VariableProxy* Scope::FetchFreeVariables(DeclarationScope* max_outer_scope, |
1436 ParseInfo* info, | 1443 ParseInfo* info, |
1437 VariableProxy* stack) { | 1444 VariableProxy* stack) { |
1438 BindingKind binding_kind = BOUND; | |
1439 for (VariableProxy *proxy = unresolved_, *next = nullptr; proxy != nullptr; | 1445 for (VariableProxy *proxy = unresolved_, *next = nullptr; proxy != nullptr; |
1440 proxy = next) { | 1446 proxy = next) { |
1441 next = proxy->next_unresolved(); | 1447 next = proxy->next_unresolved(); |
1442 if (proxy->is_resolved()) continue; | 1448 if (proxy->is_resolved()) continue; |
1443 // Note that we pass nullptr as AstNodeFactory: this phase should not create | 1449 // Note that we pass nullptr as AstNodeFactory: this phase should not create |
1444 // any new AstNodes, since none of the Scopes involved are backed up by | 1450 // any new AstNodes, since none of the Scopes involved are backed up by |
1445 // ScopeInfo. | 1451 // ScopeInfo. |
1446 Variable* var = | 1452 BindingKind binding_kind = UNBOUND; |
1447 LookupRecursive(proxy, &binding_kind, nullptr, max_outer_scope); | 1453 Variable* var = LookupRecursive(proxy, &binding_kind, nullptr, |
1448 // Anything that was bound | 1454 max_outer_scope->outer_scope()); |
1449 if (var == nullptr) { | 1455 if (var == nullptr) { |
1450 proxy->set_next_unresolved(stack); | 1456 proxy->set_next_unresolved(stack); |
1451 stack = proxy; | 1457 stack = proxy; |
1452 } else if (info != nullptr) { | 1458 } else if (info != nullptr) { |
1453 DCHECK_NE(UNBOUND, binding_kind); | 1459 DCHECK_NE(UNBOUND, binding_kind); |
1454 DCHECK_NE(UNBOUND_EVAL_SHADOWED, binding_kind); | 1460 DCHECK_NE(UNBOUND_EVAL_SHADOWED, binding_kind); |
1455 ResolveTo(info, binding_kind, proxy, var); | 1461 ResolveTo(info, binding_kind, proxy, var); |
1456 } | 1462 } |
1457 } | 1463 } |
1458 | 1464 |
(...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1781 function != nullptr && function->IsContextSlot(); | 1787 function != nullptr && function->IsContextSlot(); |
1782 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - num_global_slots() - | 1788 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - num_global_slots() - |
1783 (is_function_var_in_context ? 1 : 0); | 1789 (is_function_var_in_context ? 1 : 0); |
1784 } | 1790 } |
1785 | 1791 |
1786 | 1792 |
1787 int Scope::ContextGlobalCount() const { return num_global_slots(); } | 1793 int Scope::ContextGlobalCount() const { return num_global_slots(); } |
1788 | 1794 |
1789 } // namespace internal | 1795 } // namespace internal |
1790 } // namespace v8 | 1796 } // namespace v8 |
OLD | NEW |