| Index: src/scopes.cc
|
| diff --git a/src/scopes.cc b/src/scopes.cc
|
| index 0dec5b0ede6c6d4dfd9101988a6796d4d432c888..8b623f90ce908ac548bfd8ea46bdcf088121bbcf 100644
|
| --- a/src/scopes.cc
|
| +++ b/src/scopes.cc
|
| @@ -165,6 +165,7 @@ void Scope::SetDefaults(ScopeType scope_type, Scope* outer_scope,
|
| scope_calls_eval_ = false;
|
| scope_uses_arguments_ = false;
|
| scope_uses_super_property_ = false;
|
| + scope_uses_this_ = false;
|
| asm_module_ = false;
|
| asm_function_ = outer_scope != NULL && outer_scope->asm_module_;
|
| // Inherit the language mode from the parent scope.
|
| @@ -172,6 +173,7 @@ void Scope::SetDefaults(ScopeType scope_type, Scope* outer_scope,
|
| outer_scope_calls_sloppy_eval_ = false;
|
| inner_scope_calls_eval_ = false;
|
| inner_scope_uses_arguments_ = false;
|
| + inner_scope_uses_this_ = false;
|
| inner_scope_uses_super_property_ = false;
|
| force_eager_compilation_ = false;
|
| force_context_allocation_ = (outer_scope != NULL && !is_function_scope())
|
| @@ -307,16 +309,22 @@ void Scope::Initialize() {
|
| scope_inside_with_ = is_with_scope();
|
| }
|
|
|
| - // Declare convenience variables and the receiver.
|
| + // Declare convenience variables.
|
| + // Declare and allocate receiver (even for the script scope, and even
|
| + // if naccesses_ == 0).
|
| + // NOTE: When loading parameters in the script scope, we must take
|
| + // care not to access them as properties of the global object, but
|
| + // instead load them directly from the stack. Currently, the only
|
| + // such parameter is 'this' which is passed on the stack when
|
| + // invoking scripts
|
| if (is_declaration_scope()) {
|
| DCHECK(!subclass_constructor || is_function_scope());
|
| - if (has_this_declaration()) {
|
| - Variable* var = variables_.Declare(
|
| - this, ast_value_factory_->this_string(),
|
| - subclass_constructor ? CONST : VAR, Variable::THIS,
|
| - subclass_constructor ? kNeedsInitialization : kCreatedInitialized);
|
| - receiver_ = var;
|
| - }
|
| + Variable* var = variables_.Declare(
|
| + this, ast_value_factory_->this_string(),
|
| + subclass_constructor ? CONST : VAR, Variable::THIS,
|
| + subclass_constructor ? kNeedsInitialization : kCreatedInitialized);
|
| + var->AllocateTo(Variable::PARAMETER, -1);
|
| + receiver_ = var;
|
|
|
| if (subclass_constructor) {
|
| new_target_ =
|
| @@ -325,6 +333,9 @@ void Scope::Initialize() {
|
| new_target_->AllocateTo(Variable::PARAMETER, -2);
|
| new_target_->set_is_used();
|
| }
|
| + } else {
|
| + DCHECK(outer_scope() != NULL);
|
| + receiver_ = outer_scope()->receiver();
|
| }
|
|
|
| if (is_function_scope() && !is_arrow_scope()) {
|
| @@ -369,6 +380,7 @@ Scope* Scope::FinalizeBlockScope() {
|
| // Propagate usage flags to outer scope.
|
| if (uses_arguments()) outer_scope_->RecordArgumentsUsage();
|
| if (uses_super_property()) outer_scope_->RecordSuperPropertyUsage();
|
| + if (uses_this()) outer_scope_->RecordThisUsage();
|
| if (scope_calls_eval_) outer_scope_->RecordEvalCall();
|
|
|
| return NULL;
|
| @@ -918,11 +930,13 @@ void Scope::Print(int n) {
|
| if (scope_uses_arguments_) Indent(n1, "// scope uses 'arguments'\n");
|
| if (scope_uses_super_property_)
|
| Indent(n1, "// scope uses 'super' property\n");
|
| + if (scope_uses_this_) Indent(n1, "// scope uses 'this'\n");
|
| if (inner_scope_uses_arguments_) {
|
| Indent(n1, "// inner scope uses 'arguments'\n");
|
| }
|
| if (inner_scope_uses_super_property_)
|
| Indent(n1, "// inner scope uses 'super' property\n");
|
| + if (inner_scope_uses_this_) Indent(n1, "// inner scope uses 'this'\n");
|
| if (outer_scope_calls_sloppy_eval_) {
|
| Indent(n1, "// outer scope calls 'eval' in sloppy context\n");
|
| }
|
| @@ -1035,11 +1049,7 @@ Variable* Scope::LookupRecursive(VariableProxy* proxy,
|
| DCHECK(is_script_scope());
|
| }
|
|
|
| - // "this" can't be shadowed by "eval"-introduced bindings or by "with" scopes.
|
| - // TODO(wingo): There are other variables in this category; add them.
|
| - bool name_can_be_shadowed = var == nullptr || !var->is_this();
|
| -
|
| - if (is_with_scope() && name_can_be_shadowed) {
|
| + if (is_with_scope()) {
|
| DCHECK(!already_resolved());
|
| // The current scope is a with scope, so the variable binding can not be
|
| // statically resolved. However, note that it was necessary to do a lookup
|
| @@ -1050,7 +1060,7 @@ Variable* Scope::LookupRecursive(VariableProxy* proxy,
|
| if (var != NULL && proxy->is_assigned()) var->set_maybe_assigned();
|
| *binding_kind = DYNAMIC_LOOKUP;
|
| return NULL;
|
| - } else if (calls_sloppy_eval() && name_can_be_shadowed) {
|
| + } else if (calls_sloppy_eval()) {
|
| // A variable binding may have been found in an outer scope, but the current
|
| // scope makes a sloppy 'eval' call, so the found variable may not be
|
| // the correct one (the 'eval' may introduce a binding with the same name).
|
| @@ -1282,6 +1292,9 @@ void Scope::PropagateScopeInfo(bool outer_scope_calls_sloppy_eval ) {
|
| inner->inner_scope_uses_super_property_) {
|
| inner_scope_uses_super_property_ = true;
|
| }
|
| + if (inner->scope_uses_this_ || inner->inner_scope_uses_this_) {
|
| + inner_scope_uses_this_ = true;
|
| + }
|
| }
|
| if (inner->force_eager_compilation_) {
|
| force_eager_compilation_ = true;
|
| @@ -1402,40 +1415,24 @@ void Scope::AllocateParameterLocals(Isolate* isolate) {
|
| // Force context allocation of the parameter.
|
| var->ForceContextAllocation();
|
| }
|
| - AllocateParameter(var, i);
|
| - }
|
| -}
|
|
|
| -
|
| -void Scope::AllocateParameter(Variable* var, int index) {
|
| - if (MustAllocate(var)) {
|
| - if (MustAllocateInContext(var)) {
|
| - DCHECK(var->IsUnallocated() || var->IsContextSlot());
|
| - if (var->IsUnallocated()) {
|
| - AllocateHeapSlot(var);
|
| - }
|
| - } else {
|
| - DCHECK(var->IsUnallocated() || var->IsParameter());
|
| - if (var->IsUnallocated()) {
|
| - var->AllocateTo(Variable::PARAMETER, index);
|
| + if (MustAllocate(var)) {
|
| + if (MustAllocateInContext(var)) {
|
| + DCHECK(var->IsUnallocated() || var->IsContextSlot());
|
| + if (var->IsUnallocated()) {
|
| + AllocateHeapSlot(var);
|
| + }
|
| + } else {
|
| + DCHECK(var->IsUnallocated() || var->IsParameter());
|
| + if (var->IsUnallocated()) {
|
| + var->AllocateTo(Variable::PARAMETER, i);
|
| + }
|
| }
|
| }
|
| }
|
| }
|
|
|
|
|
| -void Scope::AllocateReceiver() {
|
| - DCHECK_NOT_NULL(receiver());
|
| - DCHECK_EQ(receiver()->scope(), this);
|
| -
|
| - if (has_forced_context_allocation()) {
|
| - // Force context allocation of the receiver.
|
| - receiver()->ForceContextAllocation();
|
| - }
|
| - AllocateParameter(receiver(), -1);
|
| -}
|
| -
|
| -
|
| void Scope::AllocateNonParameterLocal(Isolate* isolate, Variable* var) {
|
| DCHECK(var->scope() == this);
|
| DCHECK(!var->IsVariable(isolate->factory()->dot_result_string()) ||
|
| @@ -1505,7 +1502,6 @@ void Scope::AllocateVariablesRecursively(Isolate* isolate) {
|
| // Allocate variables for this scope.
|
| // Parameters must be allocated first, if any.
|
| if (is_function_scope()) AllocateParameterLocals(isolate);
|
| - if (has_this_declaration()) AllocateReceiver();
|
| AllocateNonParameterLocals(isolate);
|
|
|
| // Force allocation of a context for this scope if necessary. For a 'with'
|
|
|