Index: src/compiler/ast-graph-builder.cc |
diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc |
index 3d725a1262e9c1cf02a9993b72e315e93b1e4950..e1f9667412c2dccd02ea56aca0be9d1d385fc78f 100644 |
--- a/src/compiler/ast-graph-builder.cc |
+++ b/src/compiler/ast-graph-builder.cc |
@@ -512,15 +512,21 @@ bool AstGraphBuilder::CreateGraph(bool constant_context, bool stack_check) { |
// Build receiver check for sloppy mode if necessary. |
// TODO(mstarzinger/verwaest): Should this be moved back into the CallIC? |
- Node* original_receiver = env.Lookup(scope->receiver()); |
- Node* patched_receiver = BuildPatchReceiverToGlobalProxy(original_receiver); |
- env.Bind(scope->receiver(), patched_receiver); |
+ Node* patched_receiver = nullptr; |
+ if (scope->has_this_declaration()) { |
+ Node* original_receiver = NewNode(common()->Parameter(0), graph()->start()); |
+ patched_receiver = BuildPatchReceiverToGlobalProxy(original_receiver); |
+ if (scope->receiver()->IsStackAllocated()) { |
+ env.Bind(scope->receiver(), patched_receiver); |
+ } |
+ } |
// Build function context only if there are context allocated variables. |
int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
if (heap_slots > 0) { |
// Push a new inner context scope for the function. |
- Node* inner_context = BuildLocalFunctionContext(function_context_.get()); |
+ Node* inner_context = |
+ BuildLocalFunctionContext(function_context_.get(), patched_receiver); |
ContextScope top_context(this, scope, inner_context); |
CreateGraphBody(stack_check); |
} else { |
@@ -2251,7 +2257,23 @@ void AstGraphBuilder::VisitCall(Call* expr) { |
// Create node to ask for help resolving potential eval call. This will |
// provide a fully resolved callee and the corresponding receiver. |
Node* function = GetFunctionClosure(); |
- Node* receiver = environment()->Lookup(info()->scope()->receiver()); |
+ // TODO(wingo): ResolvePossibleDirectEval doesn't really need a receiver, |
+ // now that eval scopes don't have "this" declarations. Remove this hack |
+ // once ResolvePossibleDirectEval changes. |
+ Node* receiver; |
+ { |
+ Variable* variable = info()->scope()->LookupThis(); |
+ if (variable->IsStackAllocated()) { |
+ receiver = environment()->Lookup(variable); |
+ } else { |
+ DCHECK(variable->IsContextSlot()); |
+ int depth = current_scope()->ContextChainLength(variable->scope()); |
+ bool immutable = variable->maybe_assigned() == kNotAssigned; |
+ const Operator* op = |
+ javascript()->LoadContext(depth, variable->index(), immutable); |
+ receiver = NewNode(op, current_context()); |
+ } |
+ } |
Node* language = jsgraph()->Constant(language_mode()); |
Node* position = jsgraph()->Constant(info()->scope()->start_position()); |
const Operator* op = |
@@ -2731,9 +2753,7 @@ Node* AstGraphBuilder::BuildPatchReceiverToGlobalProxy(Node* receiver) { |
// object). Otherwise there is nothing left to do here. |
if (is_strict(language_mode()) || info()->is_native()) return receiver; |
- // There is no need to perform patching if the receiver is never used. Note |
- // that scope predicates are purely syntactical, a call to eval might still |
- // inspect the receiver value. |
+ // There is no need to perform patching if the receiver will never be used. |
if (!info()->MayUseThis()) return receiver; |
IfBuilder receiver_check(this); |
@@ -2750,25 +2770,36 @@ Node* AstGraphBuilder::BuildPatchReceiverToGlobalProxy(Node* receiver) { |
} |
-Node* AstGraphBuilder::BuildLocalFunctionContext(Node* context) { |
+Node* AstGraphBuilder::BuildLocalFunctionContext(Node* context, |
+ Node* patched_receiver) { |
+ Scope* scope = info()->scope(); |
Node* closure = GetFunctionClosure(); |
// Allocate a new local context. |
Node* local_context = |
- info()->scope()->is_script_scope() |
- ? BuildLocalScriptContext(info()->scope()) |
+ scope->is_script_scope() |
+ ? BuildLocalScriptContext(scope) |
: NewNode(javascript()->CreateFunctionContext(), closure); |
+ if (scope->has_this_declaration() && scope->receiver()->IsContextSlot()) { |
+ DCHECK_NOT_NULL(patched_receiver); |
+ // Context variable (at bottom of the context chain). |
+ Variable* variable = scope->receiver(); |
+ DCHECK_EQ(0, scope->ContextChainLength(variable->scope())); |
+ const Operator* op = javascript()->StoreContext(0, variable->index()); |
+ NewNode(op, local_context, patched_receiver); |
+ } |
+ |
// Copy parameters into context if necessary. |
- int num_parameters = info()->scope()->num_parameters(); |
+ int num_parameters = scope->num_parameters(); |
for (int i = 0; i < num_parameters; i++) { |
- Variable* variable = info()->scope()->parameter(i); |
+ Variable* variable = scope->parameter(i); |
if (!variable->IsContextSlot()) continue; |
// Temporary parameter node. The parameter indices are shifted by 1 |
// (receiver is parameter index -1 but environment index 0). |
Node* parameter = NewNode(common()->Parameter(i + 1), graph()->start()); |
// Context variable (at bottom of the context chain). |
- DCHECK_EQ(0, info()->scope()->ContextChainLength(variable->scope())); |
+ DCHECK_EQ(0, scope->ContextChainLength(variable->scope())); |
const Operator* op = javascript()->StoreContext(0, variable->index()); |
NewNode(op, local_context, parameter); |
} |