Index: src/x64/code-stubs-x64.cc |
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc |
index e56fc4a5702f3662125b6b911d8bd61d88418c0c..5b8745f583ba60e4291180f98290a103df9bf783 100644 |
--- a/src/x64/code-stubs-x64.cc |
+++ b/src/x64/code-stubs-x64.cc |
@@ -1884,14 +1884,17 @@ static void EmitSlowCase(Isolate* isolate, |
MacroAssembler* masm, |
StackArgumentsAccessor* args, |
int argc, |
- Label* non_function) { |
+ Label* non_function, |
+ bool is_spread = false) { |
// Check for function proxy. |
__ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE); |
__ j(not_equal, non_function); |
__ PopReturnAddressTo(rcx); |
__ Push(rdi); // put proxy as additional argument under return address |
__ PushReturnAddressFrom(rcx); |
- __ Set(rax, argc + 1); |
+ if (!is_spread) { |
+ __ Set(rax, argc + 1); |
+ } |
__ Set(rbx, 0); |
__ GetBuiltinEntry(rdx, Builtins::CALL_FUNCTION_PROXY); |
{ |
@@ -1904,7 +1907,9 @@ static void EmitSlowCase(Isolate* isolate, |
// of the original receiver from the call site). |
__ bind(non_function); |
__ movp(args->GetReceiverOperand(), rdi); |
- __ Set(rax, argc); |
+ if (!is_spread) { |
+ __ Set(rax, argc); |
+ } |
__ Set(rbx, 0); |
__ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION); |
Handle<Code> adaptor = |
@@ -1915,29 +1920,40 @@ static void EmitSlowCase(Isolate* isolate, |
static void EmitWrapCase(MacroAssembler* masm, |
StackArgumentsAccessor* args, |
- Label* cont) { |
+ Label* cont, bool is_spread = false) { |
// Wrap the receiver and patch it back onto the stack. |
{ FrameScope frame_scope(masm, StackFrame::INTERNAL); |
+ // If is_spread is true, dynamic argument count is in $r8 temporarily |
+ if (is_spread) __ Push(r8); |
__ Push(rdi); |
__ Push(rax); |
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
__ Pop(rdi); |
+ if (is_spread) __ Pop(r8); |
+ } |
+ if (is_spread) { |
+ DCHECK(args->argument_count_reg().is(rax)); |
+ __ xchgp(rax, r8); |
+ __ movp(args->GetReceiverOperand(), r8); |
+ } else { |
+ __ movp(args->GetReceiverOperand(), rax); |
} |
- __ movp(args->GetReceiverOperand(), rax); |
__ jmp(cont); |
} |
static void CallFunctionNoFeedback(MacroAssembler* masm, |
int argc, bool needs_checks, |
- bool call_as_method) { |
+ bool call_as_method, |
+ bool is_spread = false) { |
// rdi : the function to call |
+ // rcx : the dynamic argument count (if is_spread is true) |
// wrap_and_call can only be true if we are compiling a monomorphic method. |
Isolate* isolate = masm->isolate(); |
Label slow, non_function, wrap, cont; |
- StackArgumentsAccessor args(rsp, argc); |
- |
+ StackArgumentsAccessor args = is_spread ? |
+ StackArgumentsAccessor(rsp, rax) : StackArgumentsAccessor(rsp, argc); |
if (needs_checks) { |
// Check that the function really is a JavaScript function. |
__ JumpIfSmi(rdi, &non_function); |
@@ -1948,14 +1964,19 @@ static void CallFunctionNoFeedback(MacroAssembler* masm, |
} |
// Fast-case: Just invoke the function. |
- ParameterCount actual(argc); |
+ ParameterCount actual = is_spread ? |
+ ParameterCount(rax) : ParameterCount(argc); |
if (call_as_method) { |
+ // If is_spread is true, preserve dynamic argument count in r8 |
+ if (is_spread) __ xchgp(r8, rax); |
+ |
if (needs_checks) { |
EmitContinueIfStrictOrNative(masm, &cont); |
} |
- // Load the receiver from the stack. |
+ // Load the receiver from the stack. If is_spread is true, args is now |
+ // broken. |
__ movp(rax, args.GetReceiverOperand()); |
if (needs_checks) { |
@@ -1975,18 +1996,19 @@ static void CallFunctionNoFeedback(MacroAssembler* masm, |
if (needs_checks) { |
// Slow-case: Non-function called. |
__ bind(&slow); |
- EmitSlowCase(isolate, masm, &args, argc, &non_function); |
+ EmitSlowCase(isolate, masm, &args, argc, &non_function, is_spread); |
} |
if (call_as_method) { |
__ bind(&wrap); |
- EmitWrapCase(masm, &args, &cont); |
+ EmitWrapCase(masm, &args, &cont, is_spread); |
} |
} |
void CallFunctionStub::Generate(MacroAssembler* masm) { |
- CallFunctionNoFeedback(masm, argc(), NeedsChecks(), CallAsMethod()); |
+ CallFunctionNoFeedback(masm, argc(), NeedsChecks(), CallAsMethod(), |
+ is_spread()); |
} |
@@ -2113,6 +2135,7 @@ void CallIC_ArrayStub::Generate(MacroAssembler* masm) { |
void CallICStub::Generate(MacroAssembler* masm) { |
+ // rax - argument count (only if call is a spread call) |
// rdi - function |
// rdx - slot id |
// rbx - vector |
@@ -2125,8 +2148,10 @@ void CallICStub::Generate(MacroAssembler* masm) { |
Label slow, non_function, wrap, cont; |
Label have_js_function; |
int argc = arg_count(); |
- StackArgumentsAccessor args(rsp, argc); |
- ParameterCount actual(argc); |
+ StackArgumentsAccessor args = is_spread() ? |
+ StackArgumentsAccessor(rsp, rax) : StackArgumentsAccessor(rsp, argc); |
+ ParameterCount actual = is_spread() ? |
+ ParameterCount(rax) : ParameterCount(argc); |
// The checks. First, does rdi match the recorded monomorphic target? |
__ SmiToInteger32(rdx, rdx); |