| 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);
|
|
|