 Chromium Code Reviews
 Chromium Code Reviews Issue 2230323004:
  Cleanup scope resolution  (Closed) 
  Base URL: https://chromium.googlesource.com/v8/v8.git@master
    
  
    Issue 2230323004:
  Cleanup scope resolution  (Closed) 
  Base URL: https://chromium.googlesource.com/v8/v8.git@master| 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 1252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1263 var = map->Declare(zone(), NULL, name, mode, Variable::NORMAL, init_flag); | 1263 var = map->Declare(zone(), NULL, name, mode, Variable::NORMAL, init_flag); | 
| 1264 // Allocate it by giving it a dynamic lookup. | 1264 // Allocate it by giving it a dynamic lookup. | 
| 1265 var->AllocateTo(VariableLocation::LOOKUP, -1); | 1265 var->AllocateTo(VariableLocation::LOOKUP, -1); | 
| 1266 } | 1266 } | 
| 1267 return var; | 1267 return var; | 
| 1268 } | 1268 } | 
| 1269 | 1269 | 
| 1270 Variable* Scope::LookupRecursive(VariableProxy* proxy, | 1270 Variable* Scope::LookupRecursive(VariableProxy* proxy, | 
| 1271 BindingKind* binding_kind, | 1271 BindingKind* binding_kind, | 
| 1272 AstNodeFactory* factory, | 1272 AstNodeFactory* factory, | 
| 1273 Scope* max_outer_scope) { | 1273 Scope* outer_scope_end) { | 
| 1274 DCHECK(binding_kind != NULL); | 1274 DCHECK_NE(outer_scope_end, this); | 
| 1275 DCHECK_NOT_NULL(binding_kind); | |
| 1276 DCHECK_EQ(UNBOUND, *binding_kind); | |
| 1275 if (already_resolved() && is_with_scope()) { | 1277 if (already_resolved() && is_with_scope()) { | 
| 1276 // Short-cut: if the scope is deserialized from a scope info, variable | 1278 // Short-cut: if the scope is deserialized from a scope info, variable | 
| 1277 // allocation is already fixed. We can simply return with dynamic lookup. | 1279 // allocation is already fixed. We can simply return with dynamic lookup. | 
| 1278 *binding_kind = DYNAMIC_LOOKUP; | 1280 *binding_kind = DYNAMIC_LOOKUP; | 
| 1279 return NULL; | 1281 return nullptr; | 
| 1280 } | 1282 } | 
| 1281 | 1283 | 
| 1282 // Try to find the variable in this scope. | 1284 // Try to find the variable in this scope. | 
| 1283 Variable* var = LookupLocal(proxy->raw_name()); | 1285 Variable* var = LookupLocal(proxy->raw_name()); | 
| 1284 | 1286 | 
| 1285 // We found a variable and we are done. (Even if there is an 'eval' in | 1287 // We found a variable and we are done. (Even if there is an 'eval' in | 
| 1286 // this scope which introduces the same variable again, the resulting | 1288 // this scope which introduces the same variable again, the resulting | 
| 1287 // variable remains the same.) | 1289 // variable remains the same.) | 
| 1288 if (var != NULL) { | 1290 if (var != nullptr) { | 
| 1289 *binding_kind = BOUND; | 1291 *binding_kind = BOUND; | 
| 1290 return var; | 1292 return var; | 
| 1291 } | 1293 } | 
| 1292 | 1294 | 
| 1293 // We did not find a variable locally. Check against the function variable, if | 1295 // We did not find a variable locally. Check against the function variable, if | 
| 1294 // any. | 1296 // any. | 
| 1295 *binding_kind = UNBOUND; | 1297 if (is_function_scope()) { | 
| 1296 var = | 1298 var = AsDeclarationScope()->LookupFunctionVar(proxy->raw_name(), factory); | 
| 1297 is_function_scope() | 1299 if (var != nullptr) { | 
| 1298 ? AsDeclarationScope()->LookupFunctionVar(proxy->raw_name(), factory) | 1300 *binding_kind = BOUND; | 
| 1299 : nullptr; | 1301 return var; | 
| 
marja
2016/08/11 09:37:35
As discussed offline, this changes the behavior wr
 | |
| 1300 if (var != NULL) { | 1302 } | 
| 1301 *binding_kind = BOUND; | 1303 } | 
| 1302 } else if (outer_scope_ != nullptr && this != max_outer_scope) { | 1304 | 
| 1305 if (outer_scope_ != outer_scope_end) { | |
| 1303 var = outer_scope_->LookupRecursive(proxy, binding_kind, factory, | 1306 var = outer_scope_->LookupRecursive(proxy, binding_kind, factory, | 
| 1304 max_outer_scope); | 1307 outer_scope_end); | 
| 1305 if (*binding_kind == BOUND && is_function_scope()) { | 1308 if (*binding_kind == BOUND && is_function_scope()) { | 
| 1306 var->ForceContextAllocation(); | 1309 var->ForceContextAllocation(); | 
| 1307 } | 1310 } | 
| 1311 // "this" can't be shadowed by "eval"-introduced bindings or by "with" | |
| 1312 // scopes. | |
| 1313 // TODO(wingo): There are other variables in this category; add them. | |
| 1314 if (var != nullptr && var->is_this()) return var; | |
| 1315 | |
| 1316 if (is_with_scope()) { | |
| 1317 DCHECK(!already_resolved()); | |
| 1318 // The current scope is a with scope, so the variable binding can not be | |
| 1319 // statically resolved. However, note that it was necessary to do a lookup | |
| 1320 // in the outer scope anyway, because if a binding exists in an outer | |
| 1321 // scope, | |
| 
marja
2016/08/11 09:37:35
pls re-wrap this
 | |
| 1322 // the associated variable has to be marked as potentially being accessed | |
| 1323 // from inside of an inner with scope (the property may not be in the | |
| 1324 // 'with' | |
| 1325 // object). | |
| 1326 if (var != nullptr) { | |
| 1327 var->set_is_used(); | |
| 1328 var->ForceContextAllocation(); | |
| 1329 if (proxy->is_assigned()) var->set_maybe_assigned(); | |
| 1330 } | |
| 1331 *binding_kind = DYNAMIC_LOOKUP; | |
| 1332 return nullptr; | |
| 1333 } | |
| 1308 } else { | 1334 } else { | 
| 1309 DCHECK(is_script_scope() || this == max_outer_scope); | 1335 DCHECK(is_function_scope() || is_script_scope() || is_eval_scope()); | 
| 1336 DCHECK(!is_with_scope()); | |
| 1310 } | 1337 } | 
| 1311 | 1338 | 
| 1312 // "this" can't be shadowed by "eval"-introduced bindings or by "with" scopes. | 1339 if (calls_sloppy_eval() && is_declaration_scope() && !is_script_scope()) { | 
| 1313 // TODO(wingo): There are other variables in this category; add them. | |
| 1314 bool name_can_be_shadowed = var == nullptr || !var->is_this(); | |
| 1315 | |
| 1316 if (is_with_scope() && name_can_be_shadowed) { | |
| 1317 DCHECK(!already_resolved()); | |
| 1318 // The current scope is a with scope, so the variable binding can not be | |
| 1319 // statically resolved. However, note that it was necessary to do a lookup | |
| 1320 // in the outer scope anyway, because if a binding exists in an outer scope, | |
| 1321 // the associated variable has to be marked as potentially being accessed | |
| 1322 // from inside of an inner with scope (the property may not be in the 'with' | |
| 1323 // object). | |
| 1324 if (var != NULL) { | |
| 1325 var->set_is_used(); | |
| 1326 var->ForceContextAllocation(); | |
| 1327 if (proxy->is_assigned()) var->set_maybe_assigned(); | |
| 1328 } | |
| 1329 *binding_kind = DYNAMIC_LOOKUP; | |
| 1330 return NULL; | |
| 1331 } else if (calls_sloppy_eval() && is_declaration_scope() && | |
| 1332 !is_script_scope() && name_can_be_shadowed) { | |
| 1333 // A variable binding may have been found in an outer scope, but the current | 1340 // A variable binding may have been found in an outer scope, but the current | 
| 1334 // scope makes a sloppy 'eval' call, so the found variable may not be | 1341 // scope makes a sloppy 'eval' call, so the found variable may not be the | 
| 1335 // the correct one (the 'eval' may introduce a binding with the same name). | 1342 // correct one (the 'eval' may introduce a binding with the same name). In | 
| 1336 // In that case, change the lookup result to reflect this situation. | 1343 // that case, change the lookup result to reflect this situation. Only | 
| 1337 // Only scopes that can host var bindings (declaration scopes) need be | 1344 // scopes that can host var bindings (declaration scopes) need be considered | 
| 1338 // considered here (this excludes block and catch scopes), and variable | 1345 // here (this excludes block and catch scopes), and variable lookups at | 
| 1339 // lookups at script scope are always dynamic. | 1346 // script scope are always dynamic. | 
| 1340 if (*binding_kind == BOUND) { | 1347 if (*binding_kind == BOUND) { | 
| 1341 *binding_kind = BOUND_EVAL_SHADOWED; | 1348 *binding_kind = BOUND_EVAL_SHADOWED; | 
| 1342 } else if (*binding_kind == UNBOUND) { | 1349 } else if (*binding_kind == UNBOUND) { | 
| 1343 *binding_kind = UNBOUND_EVAL_SHADOWED; | 1350 *binding_kind = UNBOUND_EVAL_SHADOWED; | 
| 1344 } | 1351 } | 
| 1345 } | 1352 } | 
| 1353 | |
| 1346 return var; | 1354 return var; | 
| 1347 } | 1355 } | 
| 1348 | 1356 | 
| 1349 void Scope::ResolveVariable(ParseInfo* info, VariableProxy* proxy, | 1357 void Scope::ResolveVariable(ParseInfo* info, VariableProxy* proxy, | 
| 1350 AstNodeFactory* factory) { | 1358 AstNodeFactory* factory) { | 
| 1351 DCHECK(info->script_scope()->is_script_scope()); | 1359 DCHECK(info->script_scope()->is_script_scope()); | 
| 1352 | 1360 | 
| 1353 // If the proxy is already resolved there's nothing to do | 1361 // If the proxy is already resolved there's nothing to do | 
| 1354 // (functions and consts may be resolved by the parser). | 1362 // (functions and consts may be resolved by the parser). | 
| 1355 if (proxy->is_resolved()) return; | 1363 if (proxy->is_resolved()) return; | 
| 1356 | 1364 | 
| 1357 // Otherwise, try to resolve the variable. | 1365 // Otherwise, try to resolve the variable. | 
| 1358 BindingKind binding_kind; | 1366 BindingKind binding_kind = UNBOUND; | 
| 1359 Variable* var = LookupRecursive(proxy, &binding_kind, factory); | 1367 Variable* var = LookupRecursive(proxy, &binding_kind, factory); | 
| 1360 | 1368 | 
| 1361 ResolveTo(info, binding_kind, proxy, var); | 1369 ResolveTo(info, binding_kind, proxy, var); | 
| 1362 } | 1370 } | 
| 1363 | 1371 | 
| 1364 void Scope::ResolveTo(ParseInfo* info, BindingKind binding_kind, | 1372 void Scope::ResolveTo(ParseInfo* info, BindingKind binding_kind, | 
| 1365 VariableProxy* proxy, Variable* var) { | 1373 VariableProxy* proxy, Variable* var) { | 
| 1366 #ifdef DEBUG | 1374 #ifdef DEBUG | 
| 1367 if (info->script_is_native()) { | 1375 if (info->script_is_native()) { | 
| 1368 // To avoid polluting the global object in native scripts | 1376 // To avoid polluting the global object in native scripts | 
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1438 | 1446 | 
| 1439 // Resolve unresolved variables for inner scopes. | 1447 // Resolve unresolved variables for inner scopes. | 
| 1440 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { | 1448 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { | 
| 1441 scope->ResolveVariablesRecursively(info, factory); | 1449 scope->ResolveVariablesRecursively(info, factory); | 
| 1442 } | 1450 } | 
| 1443 } | 1451 } | 
| 1444 | 1452 | 
| 1445 VariableProxy* Scope::FetchFreeVariables(DeclarationScope* max_outer_scope, | 1453 VariableProxy* Scope::FetchFreeVariables(DeclarationScope* max_outer_scope, | 
| 1446 ParseInfo* info, | 1454 ParseInfo* info, | 
| 1447 VariableProxy* stack) { | 1455 VariableProxy* stack) { | 
| 1448 BindingKind binding_kind = BOUND; | |
| 1449 for (VariableProxy *proxy = unresolved_, *next = nullptr; proxy != nullptr; | 1456 for (VariableProxy *proxy = unresolved_, *next = nullptr; proxy != nullptr; | 
| 1450 proxy = next) { | 1457 proxy = next) { | 
| 1451 next = proxy->next_unresolved(); | 1458 next = proxy->next_unresolved(); | 
| 1452 if (proxy->is_resolved()) continue; | 1459 if (proxy->is_resolved()) continue; | 
| 1453 // Note that we pass nullptr as AstNodeFactory: this phase should not create | 1460 // Note that we pass nullptr as AstNodeFactory: this phase should not create | 
| 1454 // any new AstNodes, since none of the Scopes involved are backed up by | 1461 // any new AstNodes, since none of the Scopes involved are backed up by | 
| 1455 // ScopeInfo. | 1462 // ScopeInfo. | 
| 1456 Variable* var = | 1463 BindingKind binding_kind = UNBOUND; | 
| 1457 LookupRecursive(proxy, &binding_kind, nullptr, max_outer_scope); | 1464 Variable* var = LookupRecursive(proxy, &binding_kind, nullptr, | 
| 1465 max_outer_scope->outer_scope()); | |
| 1458 // Anything that was bound | 1466 // Anything that was bound | 
| 
marja
2016/08/11 09:37:35
What is this comment? (Not introduced by this CL b
 | |
| 1459 if (var == nullptr) { | 1467 if (var == nullptr) { | 
| 1460 proxy->set_next_unresolved(stack); | 1468 proxy->set_next_unresolved(stack); | 
| 1461 stack = proxy; | 1469 stack = proxy; | 
| 1462 } else if (info != nullptr) { | 1470 } else if (info != nullptr) { | 
| 1463 DCHECK_NE(UNBOUND, binding_kind); | 1471 DCHECK_NE(UNBOUND, binding_kind); | 
| 1464 DCHECK_NE(UNBOUND_EVAL_SHADOWED, binding_kind); | 1472 DCHECK_NE(UNBOUND_EVAL_SHADOWED, binding_kind); | 
| 1465 ResolveTo(info, binding_kind, proxy, var); | 1473 ResolveTo(info, binding_kind, proxy, var); | 
| 1466 } | 1474 } | 
| 1467 } | 1475 } | 
| 1468 | 1476 | 
| (...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1791 function != NULL && function->proxy()->var()->IsContextSlot(); | 1799 function != NULL && function->proxy()->var()->IsContextSlot(); | 
| 1792 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - num_global_slots() - | 1800 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - num_global_slots() - | 
| 1793 (is_function_var_in_context ? 1 : 0); | 1801 (is_function_var_in_context ? 1 : 0); | 
| 1794 } | 1802 } | 
| 1795 | 1803 | 
| 1796 | 1804 | 
| 1797 int Scope::ContextGlobalCount() const { return num_global_slots(); } | 1805 int Scope::ContextGlobalCount() const { return num_global_slots(); } | 
| 1798 | 1806 | 
| 1799 } // namespace internal | 1807 } // namespace internal | 
| 1800 } // namespace v8 | 1808 } // namespace v8 | 
| OLD | NEW |