Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(180)

Side by Side Diff: src/ast/scopes.cc

Issue 2230323004: Cleanup scope resolution (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: rebase Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/ast/scopes.h ('k') | test/mjsunit/function-name-eval-shadowed.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « src/ast/scopes.h ('k') | test/mjsunit/function-name-eval-shadowed.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698