Index: src/builtins/x64/builtins-x64.cc |
diff --git a/src/builtins/x64/builtins-x64.cc b/src/builtins/x64/builtins-x64.cc |
index 401fadb3efb73e943b561b119411fae6e5b35372..8ec2efecf1ac3c61fe09f38ce14a4f5494969526 100644 |
--- a/src/builtins/x64/builtins-x64.cc |
+++ b/src/builtins/x64/builtins-x64.cc |
@@ -720,24 +720,23 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { |
__ jmp(rcx); |
} |
-static void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args, |
- Register scratch1, Register scratch2, |
- Label* stack_overflow) { |
+static void Generate_StackOverflowCheck( |
+ MacroAssembler* masm, Register num_args, Register scratch, |
+ Label* stack_overflow, |
+ Label::Distance stack_overflow_distance = Label::kFar) { |
// Check the stack for overflow. We are not trying to catch |
// interruptions (e.g. debug break and preemption) here, so the "real stack |
// limit" is checked. |
- __ LoadRoot(scratch1, Heap::kRealStackLimitRootIndex); |
- __ movp(scratch2, rsp); |
- // Make scratch2 the space we have left. The stack might already be overflowed |
- // here which will cause scratch2 to become negative. |
- __ subp(scratch2, scratch1); |
- // Make scratch1 the space we need for the array when it is unrolled onto the |
- // stack. |
- __ movp(scratch1, num_args); |
- __ shlp(scratch1, Immediate(kPointerSizeLog2)); |
+ __ LoadRoot(kScratchRegister, Heap::kRealStackLimitRootIndex); |
+ __ movp(scratch, rsp); |
+ // Make scratch the space we have left. The stack might already be overflowed |
+ // here which will cause scratch to become negative. |
+ __ subp(scratch, kScratchRegister); |
+ __ sarp(scratch, Immediate(kPointerSizeLog2)); |
// Check if the arguments will overflow the stack. |
- __ cmpp(scratch2, scratch1); |
- __ j(less_equal, stack_overflow); // Signed comparison. |
+ __ cmpp(scratch, num_args); |
+ // Signed comparison. |
+ __ j(less_equal, stack_overflow, stack_overflow_distance); |
} |
static void Generate_InterpreterPushArgs(MacroAssembler* masm, |
@@ -779,7 +778,7 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl( |
__ addp(rcx, Immediate(1)); // Add one for receiver. |
// Add a stack check before pushing arguments. |
- Generate_StackOverflowCheck(masm, rcx, rdx, r8, &stack_overflow); |
+ Generate_StackOverflowCheck(masm, rcx, rdx, &stack_overflow); |
// Pop return address to allow tail-call after pushing arguments. |
__ PopReturnAddressTo(kScratchRegister); |
@@ -828,7 +827,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl( |
Label stack_overflow; |
// Add a stack check before pushing arguments. |
- Generate_StackOverflowCheck(masm, rax, r8, r9, &stack_overflow); |
+ Generate_StackOverflowCheck(masm, rax, r8, &stack_overflow); |
// Pop return address to allow tail-call after pushing arguments. |
__ PopReturnAddressTo(kScratchRegister); |
@@ -890,7 +889,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructArray( |
__ addp(r8, Immediate(1)); // Add one for receiver. |
// Add a stack check before pushing arguments. |
- Generate_StackOverflowCheck(masm, r8, rdi, r9, &stack_overflow); |
+ Generate_StackOverflowCheck(masm, r8, rdi, &stack_overflow); |
// Pop return address to allow tail-call after pushing arguments. |
__ PopReturnAddressTo(kScratchRegister); |
@@ -2147,7 +2146,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { |
__ bind(&enough); |
EnterArgumentsAdaptorFrame(masm); |
// The registers rcx and r8 will be modified. The register rbx is only read. |
- Generate_StackOverflowCheck(masm, rbx, rcx, r8, &stack_overflow); |
+ Generate_StackOverflowCheck(masm, rbx, rcx, &stack_overflow); |
// Copy receiver and all expected arguments. |
const int offset = StandardFrameConstants::kCallerSPOffset; |
@@ -2169,7 +2168,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { |
EnterArgumentsAdaptorFrame(masm); |
// The registers rcx and r8 will be modified. The register rbx is only read. |
- Generate_StackOverflowCheck(masm, rbx, rcx, r8, &stack_overflow); |
+ Generate_StackOverflowCheck(masm, rbx, rcx, &stack_overflow); |
// Copy receiver and all actual arguments. |
const int offset = StandardFrameConstants::kCallerSPOffset; |
@@ -2376,6 +2375,72 @@ void Builtins::Generate_Apply(MacroAssembler* masm) { |
} |
} |
+// static |
+void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm, |
+ Handle<Code> code) { |
+ // ----------- S t a t e ------------- |
+ // -- rdi : the target to call (can be any Object) |
+ // -- rcx : start index (to support rest parameters) |
+ // -- rsp[0] : return address. |
+ // -- rsp[8] : thisArgument |
+ // ----------------------------------- |
+ |
+ // Check if we have an arguments adaptor frame below the function frame. |
+ Label arguments_adaptor, arguments_done; |
+ __ movp(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
+ __ Cmp(Operand(rbx, CommonFrameConstants::kContextOrFrameTypeOffset), |
+ Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
+ __ j(equal, &arguments_adaptor, Label::kNear); |
+ { |
+ __ movp(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
+ __ movp(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset)); |
+ __ LoadSharedFunctionInfoSpecialField( |
+ rax, rax, SharedFunctionInfo::kFormalParameterCountOffset); |
+ __ movp(rbx, rbp); |
+ } |
+ __ jmp(&arguments_done, Label::kNear); |
+ __ bind(&arguments_adaptor); |
+ { |
+ __ SmiToInteger32( |
+ rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
+ } |
+ __ bind(&arguments_done); |
+ |
+ Label stack_empty, stack_done, stack_overflow; |
+ __ subl(rax, rcx); |
+ __ j(less_equal, &stack_empty); |
+ { |
+ // Check for stack overflow. |
+ Generate_StackOverflowCheck(masm, rax, rcx, &stack_overflow, Label::kNear); |
+ |
+ // Forward the arguments from the caller frame. |
+ { |
+ Label loop; |
+ __ movl(rcx, rax); |
+ __ Pop(r8); |
+ __ bind(&loop); |
+ { |
+ StackArgumentsAccessor args(rbx, rcx, ARGUMENTS_DONT_CONTAIN_RECEIVER); |
+ __ Push(args.GetArgumentOperand(0)); |
+ __ decl(rcx); |
+ __ j(not_zero, &loop); |
+ } |
+ __ Push(r8); |
+ } |
+ } |
+ __ jmp(&stack_done, Label::kNear); |
+ __ bind(&stack_overflow); |
+ __ TailCallRuntime(Runtime::kThrowStackOverflow); |
+ __ bind(&stack_empty); |
+ { |
+ // We just pass the receiver, which is already on the stack. |
+ __ Set(rax, 0); |
+ } |
+ __ bind(&stack_done); |
+ |
+ __ Jump(code, RelocInfo::CODE_TARGET); |
+} |
+ |
namespace { |
// Drops top JavaScript frame and an arguments adaptor frame below it (if |