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 458 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
469 this_function_ = | 469 this_function_ = |
470 Declare(zone(), this, ast_value_factory->this_function_string(), CONST, | 470 Declare(zone(), this, ast_value_factory->this_function_string(), CONST, |
471 Variable::NORMAL, kCreatedInitialized); | 471 Variable::NORMAL, kCreatedInitialized); |
472 } | 472 } |
473 } | 473 } |
474 | 474 |
475 Variable* DeclarationScope::DeclareFunctionVar(const AstRawString* name) { | 475 Variable* DeclarationScope::DeclareFunctionVar(const AstRawString* name) { |
476 DCHECK(is_function_scope()); | 476 DCHECK(is_function_scope()); |
477 DCHECK_NULL(function_); | 477 DCHECK_NULL(function_); |
478 VariableMode mode = is_strict(language_mode()) ? CONST : CONST_LEGACY; | 478 VariableMode mode = is_strict(language_mode()) ? CONST : CONST_LEGACY; |
479 function_ = new (zone()) | 479 bool preexists = variables_.Lookup(name); |
480 Variable(this, name, mode, Variable::NORMAL, kCreatedInitialized); | 480 if (preexists || calls_sloppy_eval()) { |
adamk
2016/08/24 18:15:49
This logic is pretty tricky (I find it trickier th
| |
481 function_ = new (zone()) | |
adamk
2016/08/24 20:22:48
Maybe we should just skip creating the function_ v
| |
482 Variable(this, name, mode, Variable::NORMAL, kCreatedInitialized); | |
483 if (!preexists) NonLocal(name, DYNAMIC); | |
484 } else { | |
485 function_ = variables_.Declare(zone(), this, name, mode, Variable::NORMAL, | |
486 kCreatedInitialized); | |
487 } | |
481 return function_; | 488 return function_; |
482 } | 489 } |
483 | 490 |
484 Scope* Scope::FinalizeBlockScope() { | 491 Scope* Scope::FinalizeBlockScope() { |
485 DCHECK(is_block_scope()); | 492 DCHECK(is_block_scope()); |
486 | 493 |
487 if (variables_.occupancy() > 0 || | 494 if (variables_.occupancy() > 0 || |
488 (is_declaration_scope() && calls_sloppy_eval())) { | 495 (is_declaration_scope() && calls_sloppy_eval())) { |
489 return this; | 496 return this; |
490 } | 497 } |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
611 int index = ScopeInfo::ContextSlotIndex(scope_info_, name_handle, &mode, | 618 int index = ScopeInfo::ContextSlotIndex(scope_info_, name_handle, &mode, |
612 &init_flag, &maybe_assigned_flag); | 619 &init_flag, &maybe_assigned_flag); |
613 if (index < 0) { | 620 if (index < 0) { |
614 location = VariableLocation::GLOBAL; | 621 location = VariableLocation::GLOBAL; |
615 index = ScopeInfo::ContextGlobalSlotIndex(scope_info_, name_handle, &mode, | 622 index = ScopeInfo::ContextGlobalSlotIndex(scope_info_, name_handle, &mode, |
616 &init_flag, &maybe_assigned_flag); | 623 &init_flag, &maybe_assigned_flag); |
617 } | 624 } |
618 if (index < 0) { | 625 if (index < 0) { |
619 // Check parameters. | 626 // Check parameters. |
620 index = scope_info_->ParameterIndex(*name_handle); | 627 index = scope_info_->ParameterIndex(*name_handle); |
621 if (index < 0) return NULL; | 628 if (index < 0) { |
629 index = scope_info_->FunctionContextSlotIndex(*name_handle, &mode); | |
630 if (index < 0) return nullptr; | |
631 Variable* var = AsDeclarationScope()->DeclareFunctionVar(name); | |
632 DCHECK_EQ(mode, var->mode()); | |
633 var->AllocateTo(VariableLocation::CONTEXT, index); | |
634 return variables_.Lookup(name); | |
635 } | |
622 | 636 |
623 mode = DYNAMIC; | 637 mode = DYNAMIC; |
624 location = VariableLocation::LOOKUP; | 638 location = VariableLocation::LOOKUP; |
625 init_flag = kCreatedInitialized; | 639 init_flag = kCreatedInitialized; |
626 // Be conservative and flag parameters as maybe assigned. Better information | 640 // Be conservative and flag parameters as maybe assigned. Better information |
627 // would require ScopeInfo to serialize the maybe_assigned bit also for | 641 // would require ScopeInfo to serialize the maybe_assigned bit also for |
628 // parameters. | 642 // parameters. |
629 maybe_assigned_flag = kMaybeAssigned; | 643 maybe_assigned_flag = kMaybeAssigned; |
630 } else { | 644 } else { |
631 DCHECK(location != VariableLocation::GLOBAL || | 645 DCHECK(location != VariableLocation::GLOBAL || |
632 (is_script_scope() && IsDeclaredVariableMode(mode) && | 646 (is_script_scope() && IsDeclaredVariableMode(mode) && |
633 !IsLexicalVariableMode(mode))); | 647 !IsLexicalVariableMode(mode))); |
634 } | 648 } |
635 | 649 |
636 Variable::Kind kind = Variable::NORMAL; | 650 Variable::Kind kind = Variable::NORMAL; |
637 if (location == VariableLocation::CONTEXT && | 651 if (location == VariableLocation::CONTEXT && |
638 index == scope_info_->ReceiverContextSlotIndex()) { | 652 index == scope_info_->ReceiverContextSlotIndex()) { |
639 kind = Variable::THIS; | 653 kind = Variable::THIS; |
640 } | 654 } |
641 // TODO(marja, rossberg): Correctly declare FUNCTION, CLASS, NEW_TARGET, and | 655 // TODO(marja, rossberg): Correctly declare FUNCTION, CLASS, NEW_TARGET, and |
642 // ARGUMENTS bindings as their corresponding Variable::Kind. | 656 // ARGUMENTS bindings as their corresponding Variable::Kind. |
643 | 657 |
644 Variable* var = variables_.Declare(zone(), this, name, mode, kind, init_flag, | 658 Variable* var = variables_.Declare(zone(), this, name, mode, kind, init_flag, |
645 maybe_assigned_flag); | 659 maybe_assigned_flag); |
646 var->AllocateTo(location, index); | 660 var->AllocateTo(location, index); |
647 return var; | 661 return var; |
648 } | 662 } |
649 | 663 |
650 Variable* DeclarationScope::LookupFunctionVar(const AstRawString* name) { | |
651 if (function_ != nullptr && function_->raw_name() == name) { | |
652 return function_; | |
653 } else if (!scope_info_.is_null()) { | |
654 // If we are backed by a scope info, try to lookup the variable there. | |
655 VariableMode mode; | |
656 int index = scope_info_->FunctionContextSlotIndex(*(name->string()), &mode); | |
657 if (index < 0) return nullptr; | |
658 Variable* var = DeclareFunctionVar(name); | |
659 DCHECK_EQ(mode, var->mode()); | |
660 var->AllocateTo(VariableLocation::CONTEXT, index); | |
661 return var; | |
662 } else { | |
663 return nullptr; | |
664 } | |
665 } | |
666 | |
667 | |
668 Variable* Scope::Lookup(const AstRawString* name) { | 664 Variable* Scope::Lookup(const AstRawString* name) { |
669 for (Scope* scope = this; | 665 for (Scope* scope = this; |
670 scope != NULL; | 666 scope != NULL; |
671 scope = scope->outer_scope()) { | 667 scope = scope->outer_scope()) { |
672 Variable* var = scope->LookupLocal(name); | 668 Variable* var = scope->LookupLocal(name); |
673 if (var != NULL) return var; | 669 if (var != NULL) return var; |
674 } | 670 } |
675 return NULL; | 671 return NULL; |
676 } | 672 } |
677 | 673 |
(...skipping 560 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1238 } | 1234 } |
1239 | 1235 |
1240 // Try to find the variable in this scope. | 1236 // Try to find the variable in this scope. |
1241 Variable* var = LookupLocal(proxy->raw_name()); | 1237 Variable* var = LookupLocal(proxy->raw_name()); |
1242 | 1238 |
1243 // We found a variable and we are done. (Even if there is an 'eval' in this | 1239 // We found a variable and we are done. (Even if there is an 'eval' in this |
1244 // scope which introduces the same variable again, the resulting variable | 1240 // scope which introduces the same variable again, the resulting variable |
1245 // remains the same.) | 1241 // remains the same.) |
1246 if (var != nullptr) return var; | 1242 if (var != nullptr) return var; |
1247 | 1243 |
1248 // We did not find a variable locally. Check against the function variable, if | |
1249 // any. | |
1250 if (is_function_scope()) { | |
1251 var = AsDeclarationScope()->LookupFunctionVar(proxy->raw_name()); | |
1252 if (var != nullptr) { | |
1253 if (calls_sloppy_eval()) return NonLocal(proxy->raw_name(), DYNAMIC); | |
1254 return var; | |
1255 } | |
1256 } | |
1257 | |
1258 if (outer_scope_ == outer_scope_end) { | 1244 if (outer_scope_ == outer_scope_end) { |
1259 if (!declare_free) return nullptr; | 1245 if (!declare_free) return nullptr; |
1260 DCHECK(is_script_scope()); | 1246 DCHECK(is_script_scope()); |
1261 // No binding has been found. Declare a variable on the global object. | 1247 // No binding has been found. Declare a variable on the global object. |
1262 return AsDeclarationScope()->DeclareDynamicGlobal(proxy->raw_name(), | 1248 return AsDeclarationScope()->DeclareDynamicGlobal(proxy->raw_name(), |
1263 Variable::NORMAL); | 1249 Variable::NORMAL); |
1264 } | 1250 } |
1265 | 1251 |
1266 DCHECK(!is_script_scope()); | 1252 DCHECK(!is_script_scope()); |
1267 | 1253 |
(...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1673 function != nullptr && function->IsContextSlot(); | 1659 function != nullptr && function->IsContextSlot(); |
1674 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - num_global_slots() - | 1660 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - num_global_slots() - |
1675 (is_function_var_in_context ? 1 : 0); | 1661 (is_function_var_in_context ? 1 : 0); |
1676 } | 1662 } |
1677 | 1663 |
1678 | 1664 |
1679 int Scope::ContextGlobalCount() const { return num_global_slots(); } | 1665 int Scope::ContextGlobalCount() const { return num_global_slots(); } |
1680 | 1666 |
1681 } // namespace internal | 1667 } // namespace internal |
1682 } // namespace v8 | 1668 } // namespace v8 |
OLD | NEW |