[stubs] Simplify the non-function case of CallConstructStub.
authorbmeurer <bmeurer@chromium.org>
Fri, 11 Sep 2015 09:45:04 +0000 (02:45 -0700)
committerCommit bot <commit-bot@chromium.org>
Fri, 11 Sep 2015 09:45:21 +0000 (09:45 +0000)
Currently we do this dance between the CallConstructStub, the
CALL_* builtins and the %GetConstructorDelegate, %GetProxyTrap,
and %Apply runtime functions for every [[Construct]] operation on
non-function callables. This is complexity is unnecessary, and can
be simplified to work without any JS builtin. This will also make it
a lot easier to implement ES6 compliant [[Construct]] for proxies.

Also sanitize the invariant for CallConstructStub, which up until now
always restored the context itself, but that force us to always create
another copy of all arguments in case of proxies and other callables,
so we can relax that constraint by making the caller restore the context
(this only affects fullcodegen, since the optimizing compilers already
properly restore the context anyway).

R=mstarzinger@chromium.org

Review URL: https://codereview.chromium.org/1335723002

Cr-Commit-Position: refs/heads/master@{#30691}

14 files changed:
src/arm/code-stubs-arm.cc
src/arm64/code-stubs-arm64.cc
src/contexts.h
src/full-codegen/arm/full-codegen-arm.cc
src/full-codegen/arm64/full-codegen-arm64.cc
src/full-codegen/ia32/full-codegen-ia32.cc
src/full-codegen/mips/full-codegen-mips.cc
src/full-codegen/mips64/full-codegen-mips64.cc
src/full-codegen/x64/full-codegen-x64.cc
src/ia32/code-stubs-ia32.cc
src/mips/code-stubs-mips.cc
src/mips64/code-stubs-mips64.cc
src/runtime.js
src/x64/code-stubs-x64.cc

index ced550b..907bdac 100644 (file)
@@ -2528,22 +2528,30 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
   // r0: number of arguments
   // r1: called object
   // r5: object type
-  Label do_call;
   __ bind(&slow);
-  __ cmp(r5, Operand(JS_FUNCTION_PROXY_TYPE));
-  __ b(ne, &non_function_call);
-  __ GetBuiltinFunction(
-      r1, Context::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR_BUILTIN_INDEX);
-  __ jmp(&do_call);
-
-  __ bind(&non_function_call);
-  __ GetBuiltinFunction(
-      r1, Context::CALL_NON_FUNCTION_AS_CONSTRUCTOR_BUILTIN_INDEX);
-  __ bind(&do_call);
-  // Set expected number of arguments to zero (not changing r0).
-  __ mov(r2, Operand::Zero());
-  __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-          RelocInfo::CODE_TARGET);
+  {
+    __ cmp(r5, Operand(JS_FUNCTION_PROXY_TYPE));
+    __ b(ne, &non_function_call);
+    // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
+    __ ldr(r1, FieldMemOperand(r1, JSFunctionProxy::kConstructTrapOffset));
+    __ Jump(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
+
+    __ bind(&non_function_call);
+    {
+      // Determine the delegate for the target (if any).
+      FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
+      __ SmiTag(r0);
+      __ Push(r0, r1);
+      __ CallRuntime(Runtime::kGetConstructorDelegate, 1);
+      __ mov(r1, r0);
+      __ Pop(r0);
+      __ SmiUntag(r0);
+    }
+    // The delegate is always a regular function.
+    __ AssertFunction(r1);
+    __ Jump(masm->isolate()->builtins()->CallFunction(),
+            RelocInfo::CODE_TARGET);
+  }
 }
 
 
index 585d1c0..98dbb9c 100644 (file)
@@ -2904,23 +2904,30 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
   __ Add(cons_stub_code, cons_stub, Code::kHeaderSize - kHeapObjectTag);
   __ Br(cons_stub_code);
 
-  Label do_call;
   __ Bind(&slow);
-  __ Cmp(object_type, JS_FUNCTION_PROXY_TYPE);
-  __ B(ne, &non_function_call);
-  __ GetBuiltinFunction(
-      x1, Context::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR_BUILTIN_INDEX);
-  __ B(&do_call);
-
-  __ Bind(&non_function_call);
-  __ GetBuiltinFunction(
-      x1, Context::CALL_NON_FUNCTION_AS_CONSTRUCTOR_BUILTIN_INDEX);
-
-  __ Bind(&do_call);
-  // Set expected number of arguments to zero (not changing x0).
-  __ Mov(x2, 0);
-  __ Jump(isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-          RelocInfo::CODE_TARGET);
+  {
+    __ Cmp(object_type, JS_FUNCTION_PROXY_TYPE);
+    __ B(ne, &non_function_call);
+    // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
+    __ Ldr(x1, FieldMemOperand(x1, JSFunctionProxy::kConstructTrapOffset));
+    __ Jump(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
+
+    __ Bind(&non_function_call);
+    {
+      // Determine the delegate for the target (if any).
+      FrameScope scope(masm, StackFrame::INTERNAL);
+      __ SmiTag(x0);
+      __ Push(x0, x1);
+      __ CallRuntime(Runtime::kGetConstructorDelegate, 1);
+      __ Mov(x1, x0);
+      __ Pop(x0);
+      __ SmiUntag(x0);
+    }
+    // The delegate is always a regular function.
+    __ AssertFunction(x1);
+    __ Jump(masm->isolate()->builtins()->CallFunction(),
+            RelocInfo::CODE_TARGET);
+  }
 }
 
 
index 0e37489..01ce999 100644 (file)
@@ -92,10 +92,6 @@ enum BindingFlags {
 
 #define NATIVE_CONTEXT_JS_BUILTINS(V)                                   \
   V(APPLY_PREPARE_BUILTIN_INDEX, JSFunction, apply_prepare_builtin)     \
-  V(CALL_FUNCTION_PROXY_AS_CONSTRUCTOR_BUILTIN_INDEX, JSFunction,       \
-    call_function_proxy_as_constructor_builtin)                         \
-  V(CALL_NON_FUNCTION_AS_CONSTRUCTOR_BUILTIN_INDEX, JSFunction,         \
-    call_non_function_as_constructor_builtin)                           \
   V(COMPARE_BUILTIN_INDEX, JSFunction, compare_builtin)                 \
   V(COMPARE_STRONG_BUILTIN_INDEX, JSFunction, compare_strong_builtin)   \
   V(CONCAT_ITERABLE_TO_ARRAY_BUILTIN_INDEX, JSFunction,                 \
index a29ff82..7c7ec9f 100644 (file)
@@ -3203,6 +3203,8 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
   CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
   __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
   PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
+  // Restore context register.
+  __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
   context()->Plug(r0);
 }
 
@@ -3252,6 +3254,8 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
 
   RecordJSReturnSite(expr);
 
+  // Restore context register.
+  __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
   context()->Plug(r0);
 }
 
@@ -4154,9 +4158,10 @@ void FullCodeGenerator::EmitDefaultConstructorCallSuper(CallRuntime* expr) {
   CallConstructStub stub(isolate(), SUPER_CONSTRUCTOR_CALL);
   __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
 
-  __ Drop(1);
+  // Restore context register.
+  __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
 
-  context()->Plug(result_register());
+  context()->DropAndPlug(1, r0);
 }
 
 
index e460ac3..bcae556 100644 (file)
@@ -2910,6 +2910,8 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
   CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
   __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
   PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
+  // Restore context register.
+  __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
   context()->Plug(x0);
 }
 
@@ -2959,6 +2961,8 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
 
   RecordJSReturnSite(expr);
 
+  // Restore context register.
+  __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
   context()->Plug(x0);
 }
 
@@ -3883,9 +3887,10 @@ void FullCodeGenerator::EmitDefaultConstructorCallSuper(CallRuntime* expr) {
   CallConstructStub stub(isolate(), SUPER_CONSTRUCTOR_CALL);
   __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
 
-  __ Drop(1);
+  // Restore context register.
+  __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
 
-  context()->Plug(result_register());
+  context()->DropAndPlug(1, x0);
 }
 
 
index 42c12b3..08a5a62 100644 (file)
@@ -3092,6 +3092,8 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
   CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
   __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
   PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
+  // Restore context register.
+  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
   context()->Plug(eax);
 }
 
@@ -3141,6 +3143,8 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
 
   RecordJSReturnSite(expr);
 
+  // Restore context register.
+  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
   context()->Plug(eax);
 }
 
@@ -4055,9 +4059,10 @@ void FullCodeGenerator::EmitDefaultConstructorCallSuper(CallRuntime* expr) {
   CallConstructStub stub(isolate(), SUPER_CONSTRUCTOR_CALL);
   __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
 
-  __ Drop(1);
+  // Restore context register.
+  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
 
-  context()->Plug(eax);
+  context()->DropAndPlug(1, eax);
 }
 
 
index 35747a6..2f35ef5 100644 (file)
@@ -3195,6 +3195,8 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
   CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
   __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
   PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
+  // Restore context register.
+  __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
   context()->Plug(v0);
 }
 
@@ -3244,6 +3246,8 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
 
   RecordJSReturnSite(expr);
 
+  // Restore context register.
+  __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
   context()->Plug(v0);
 }
 
@@ -4180,9 +4184,10 @@ void FullCodeGenerator::EmitDefaultConstructorCallSuper(CallRuntime* expr) {
   CallConstructStub stub(isolate(), SUPER_CONSTRUCTOR_CALL);
   __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
 
-  __ Drop(1);
+  // Restore context register.
+  __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
 
-  context()->Plug(result_register());
+  context()->DropAndPlug(1, result_register());
 }
 
 
index fa35b5f..bbc73d4 100644 (file)
@@ -3197,6 +3197,8 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
   CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
   __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
   PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
+  // Restore context register.
+  __ ld(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
   context()->Plug(v0);
 }
 
@@ -3246,6 +3248,8 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
 
   RecordJSReturnSite(expr);
 
+  // Restore context register.
+  __ ld(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
   context()->Plug(v0);
 }
 
@@ -4184,9 +4188,10 @@ void FullCodeGenerator::EmitDefaultConstructorCallSuper(CallRuntime* expr) {
   CallConstructStub stub(isolate(), SUPER_CONSTRUCTOR_CALL);
   __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
 
-  __ Drop(1);
+  // Restore context register.
+  __ ld(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
 
-  context()->Plug(result_register());
+  context()->DropAndPlug(1, result_register());
 }
 
 
index 3876eb3..a472456 100644 (file)
@@ -3120,6 +3120,8 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
   CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
   __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
   PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
+  // Restore context register.
+  __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
   context()->Plug(rax);
 }
 
@@ -3169,6 +3171,9 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
 
   RecordJSReturnSite(expr);
 
+  // Restore context register.
+  __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
+
   context()->Plug(rax);
 }
 
@@ -4081,9 +4086,10 @@ void FullCodeGenerator::EmitDefaultConstructorCallSuper(CallRuntime* expr) {
   CallConstructStub stub(isolate(), SUPER_CONSTRUCTOR_CALL);
   __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
 
-  __ Drop(1);
+  // Restore context register.
+  __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
 
-  context()->Plug(result_register());
+  context()->DropAndPlug(1, rax);
 }
 
 
index 9d7a668..c685d22 100644 (file)
@@ -2178,26 +2178,32 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
   // eax: number of arguments
   // ecx: object map
   // esp[0]: original receiver (for IsSuperConstructorCall)
-  Label do_call;
   __ bind(&slow);
-  __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
-  __ j(not_equal, &non_function_call);
-  __ GetBuiltinEntry(edx,
-                     Context::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR_BUILTIN_INDEX);
-  __ jmp(&do_call);
-
-  __ bind(&non_function_call);
-  __ GetBuiltinEntry(edx,
-                     Context::CALL_NON_FUNCTION_AS_CONSTRUCTOR_BUILTIN_INDEX);
-  __ bind(&do_call);
-  if (IsSuperConstructorCall()) {
-    __ Drop(1);
+  {
+    __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
+    __ j(not_equal, &non_function_call, Label::kNear);
+    if (IsSuperConstructorCall()) __ Drop(1);
+    // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
+    __ mov(edi, FieldOperand(edi, JSFunctionProxy::kConstructTrapOffset));
+    __ Jump(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
+
+    __ bind(&non_function_call);
+    if (IsSuperConstructorCall()) __ Drop(1);
+    {
+      // Determine the delegate for the target (if any).
+      FrameScope scope(masm, StackFrame::INTERNAL);
+      __ SmiTag(eax);
+      __ Push(eax);
+      __ Push(edi);
+      __ CallRuntime(Runtime::kGetConstructorDelegate, 1);
+      __ mov(edi, eax);
+      __ Pop(eax);
+      __ SmiUntag(eax);
+    }
+    // The delegate is always a regular function.
+    __ AssertFunction(edi);
+    __ Jump(isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
   }
-  // Set expected number of arguments to zero (not changing eax).
-  __ Move(ebx, Immediate(0));
-  Handle<Code> arguments_adaptor =
-      isolate()->builtins()->ArgumentsAdaptorTrampoline();
-  __ jmp(arguments_adaptor, RelocInfo::CODE_TARGET);
 }
 
 
index 52c37f8..2580081 100644 (file)
@@ -2660,21 +2660,29 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
   // a0: number of arguments
   // a1: called object
   // t1: object type
-  Label do_call;
   __ bind(&slow);
-  __ Branch(&non_function_call, ne, t1, Operand(JS_FUNCTION_PROXY_TYPE));
-  __ GetBuiltinFunction(
-      a1, Context::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR_BUILTIN_INDEX);
-  __ jmp(&do_call);
-
-  __ bind(&non_function_call);
-  __ GetBuiltinFunction(
-      a1, Context::CALL_NON_FUNCTION_AS_CONSTRUCTOR_BUILTIN_INDEX);
-  __ bind(&do_call);
-  // Set expected number of arguments to zero (not changing r0).
-  __ li(a2, Operand(0, RelocInfo::NONE32));
-  __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-           RelocInfo::CODE_TARGET);
+  {
+    __ Branch(&non_function_call, ne, t1, Operand(JS_FUNCTION_PROXY_TYPE));
+    // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
+    __ lw(a1, FieldMemOperand(a1, JSFunctionProxy::kConstructTrapOffset));
+    __ Jump(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
+
+    __ bind(&non_function_call);
+    {
+      // Determine the delegate for the target (if any).
+      FrameScope scope(masm, StackFrame::INTERNAL);
+      __ sll(a0, a0, kSmiTagSize);  // Smi tagged.
+      __ Push(a0, a1);
+      __ CallRuntime(Runtime::kGetConstructorDelegate, 1);
+      __ mov(a1, v0);
+      __ Pop(a0);
+      __ sra(a0, a0, kSmiTagSize);  // Un-tag.
+    }
+    // The delegate is always a regular function.
+    __ AssertFunction(a1);
+    __ Jump(masm->isolate()->builtins()->CallFunction(),
+            RelocInfo::CODE_TARGET);
+  }
 }
 
 
index ed2029d..f2e751a 100644 (file)
@@ -2696,21 +2696,29 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
   // a0: number of arguments
   // a1: called object
   // a5: object type
-  Label do_call;
   __ bind(&slow);
-  __ Branch(&non_function_call, ne, a5, Operand(JS_FUNCTION_PROXY_TYPE));
-  __ GetBuiltinFunction(
-      a1, Context::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR_BUILTIN_INDEX);
-  __ jmp(&do_call);
-
-  __ bind(&non_function_call);
-  __ GetBuiltinFunction(
-      a1, Context::CALL_NON_FUNCTION_AS_CONSTRUCTOR_BUILTIN_INDEX);
-  __ bind(&do_call);
-  // Set expected number of arguments to zero (not changing r0).
-  __ li(a2, Operand(0, RelocInfo::NONE32));
-  __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-           RelocInfo::CODE_TARGET);
+  {
+    __ Branch(&non_function_call, ne, a5, Operand(JS_FUNCTION_PROXY_TYPE));
+    // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
+    __ ld(a1, FieldMemOperand(a1, JSFunctionProxy::kConstructTrapOffset));
+    __ Jump(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
+
+    __ bind(&non_function_call);
+    {
+      // Determine the delegate for the target (if any).
+      FrameScope scope(masm, StackFrame::INTERNAL);
+      __ SmiTag(a0);
+      __ Push(a0, a1);
+      __ CallRuntime(Runtime::kGetConstructorDelegate, 1);
+      __ mov(a1, v0);
+      __ Pop(a0);
+      __ SmiUntag(a0);
+    }
+    // The delegate is always a regular function.
+    __ AssertFunction(a1);
+    __ Jump(masm->isolate()->builtins()->CallFunction(),
+            RelocInfo::CODE_TARGET);
+  }
 }
 
 
index 098551a..749feb6 100644 (file)
@@ -192,19 +192,6 @@ function STRING_ADD_RIGHT(y) {
    -----------------------------
 */
 
-function CALL_NON_FUNCTION_AS_CONSTRUCTOR() {
-  var delegate = %GetConstructorDelegate(this);
-  return %Apply(delegate, this, arguments, 0, %_ArgumentsLength());
-}
-
-
-function CALL_FUNCTION_PROXY_AS_CONSTRUCTOR () {
-  var proxy = this;
-  var trap = %GetConstructTrap(proxy);
-  return %Apply(trap, this, arguments, 0, %_ArgumentsLength());
-}
-
-
 function APPLY_PREPARE(args) {
   var length;
 
@@ -550,8 +537,6 @@ $toString = ToString;
 
 %InstallToContext([
   "apply_prepare_builtin", APPLY_PREPARE,
-  "call_function_proxy_as_constructor_builtin", CALL_FUNCTION_PROXY_AS_CONSTRUCTOR,
-  "call_non_function_as_constructor_builtin", CALL_NON_FUNCTION_AS_CONSTRUCTOR,
   "compare_builtin", COMPARE,
   "compare_strong_builtin", COMPARE_STRONG,
   "concat_iterable_to_array_builtin", CONCAT_ITERABLE_TO_ARRAY,
index 38c8602..ff8d4be 100644 (file)
@@ -2041,22 +2041,31 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
   // rdi: called object
   // rax: number of arguments
   // r11: object map
-  Label do_call;
   __ bind(&slow);
-  __ CmpInstanceType(r11, JS_FUNCTION_PROXY_TYPE);
-  __ j(not_equal, &non_function_call);
-  __ GetBuiltinEntry(rdx,
-                     Context::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR_BUILTIN_INDEX);
-  __ jmp(&do_call);
-
-  __ bind(&non_function_call);
-  __ GetBuiltinEntry(rdx,
-                     Context::CALL_NON_FUNCTION_AS_CONSTRUCTOR_BUILTIN_INDEX);
-  __ bind(&do_call);
-  // Set expected number of arguments to zero (not changing rax).
-  __ Set(rbx, 0);
-  __ Jump(isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-          RelocInfo::CODE_TARGET);
+  {
+    __ CmpInstanceType(r11, JS_FUNCTION_PROXY_TYPE);
+    __ j(not_equal, &non_function_call, Label::kNear);
+
+    // TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
+    __ movp(rdi, FieldOperand(rdi, JSFunctionProxy::kConstructTrapOffset));
+    __ Jump(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
+
+    __ bind(&non_function_call);
+    {
+      // Determine the delegate for the target (if any).
+      FrameScope scope(masm, StackFrame::INTERNAL);
+      __ Integer32ToSmi(rax, rax);
+      __ Push(rax);
+      __ Push(rdi);
+      __ CallRuntime(Runtime::kGetConstructorDelegate, 1);
+      __ movp(rdi, rax);
+      __ Pop(rax);
+      __ SmiToInteger32(rax, rax);
+    }
+    // The delegate is always a regular function.
+    __ AssertFunction(rdi);
+    __ Jump(isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
+  }
 }