Index: src/compiler/ast-graph-builder.cc |
diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc |
index 805afc5a3c515c1d28118e2160c6bca6424807be..4eb72a6d66598d63c00200ca2f5d9db9c2897720 100644 |
--- a/src/compiler/ast-graph-builder.cc |
+++ b/src/compiler/ast-graph-builder.cc |
@@ -72,13 +72,22 @@ bool AstGraphBuilder::CreateGraph() { |
Environment env(this, scope, graph()->start()); |
set_environment(&env); |
+ // Initialize the incoming context. |
+ Node* outer_context = GetFunctionContext(); |
+ set_current_context(outer_context); |
+ |
+ // 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); |
+ |
// Build node to initialize local function context. |
Node* closure = GetFunctionClosure(); |
- Node* outer = GetFunctionContext(); |
- Node* inner = BuildLocalFunctionContext(outer, closure); |
+ Node* inner_context = BuildLocalFunctionContext(outer_context, closure); |
// Push top-level function scope for the function body. |
- ContextScope top_context(this, scope, inner); |
+ ContextScope top_context(this, scope, inner_context); |
// Build the arguments object if it is used. |
BuildArgumentsObject(scope->arguments()); |
@@ -1773,10 +1782,36 @@ Node* AstGraphBuilder::ProcessArguments(const Operator* op, int arity) { |
} |
+Node* AstGraphBuilder::BuildPatchReceiverToGlobalProxy(Node* receiver) { |
+ // Sloppy mode functions and builtins need to replace the receiver with the |
+ // global proxy when called as functions (without an explicit receiver |
+ // object). Otherwise there is nothing left to do here. |
+ if (info()->strict_mode() != SLOPPY || 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. |
+ if (!info()->scope()->uses_this() && !info()->scope()->inner_uses_this() && |
+ !info()->scope()->calls_sloppy_eval()) { |
+ return receiver; |
+ } |
+ |
+ IfBuilder receiver_check(this); |
+ Node* undefined = jsgraph()->UndefinedConstant(); |
+ Node* check = NewNode(javascript()->StrictEqual(), receiver, undefined); |
+ receiver_check.If(check); |
+ receiver_check.Then(); |
+ environment()->Push(BuildLoadGlobalProxy()); |
+ receiver_check.Else(); |
+ environment()->Push(receiver); |
+ receiver_check.End(); |
+ return environment()->Pop(); |
+} |
+ |
+ |
Node* AstGraphBuilder::BuildLocalFunctionContext(Node* context, Node* closure) { |
int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
if (heap_slots <= 0) return context; |
- set_current_context(context); |
// Allocate a new local context. |
const Operator* op = javascript()->CreateFunctionContext(); |
@@ -2069,6 +2104,14 @@ Node* AstGraphBuilder::BuildLoadGlobalObject() { |
} |
+Node* AstGraphBuilder::BuildLoadGlobalProxy() { |
+ Node* global = BuildLoadGlobalObject(); |
+ Node* proxy = |
+ BuildLoadObjectField(global, JSGlobalObject::kGlobalProxyOffset); |
+ return proxy; |
+} |
+ |
+ |
Node* AstGraphBuilder::BuildToBoolean(Node* input) { |
// TODO(titzer): this should be in a JSOperatorReducer. |
switch (input->opcode()) { |