Index: src/builtins/x87/builtins-x87.cc |
diff --git a/src/builtins/x87/builtins-x87.cc b/src/builtins/x87/builtins-x87.cc |
index 5cc72ee64061153dd5b68818292f7849cf2eb777..2b7dfdd46ed262ce2bdac870e61d1a80e3bffbfb 100644 |
--- a/src/builtins/x87/builtins-x87.cc |
+++ b/src/builtins/x87/builtins-x87.cc |
@@ -705,19 +705,20 @@ void Builtins::Generate_InterpreterMarkBaselineOnReturn(MacroAssembler* masm) { |
} |
static void Generate_InterpreterPushArgs(MacroAssembler* masm, |
- Register array_limit) { |
+ Register array_limit, |
+ Register start_address) { |
// ----------- S t a t e ------------- |
- // -- ebx : Pointer to the last argument in the args array. |
+ // -- start_address : Pointer to the last argument in the args array. |
// -- array_limit : Pointer to one before the first argument in the |
// args array. |
// ----------------------------------- |
Label loop_header, loop_check; |
__ jmp(&loop_check); |
__ bind(&loop_header); |
- __ Push(Operand(ebx, 0)); |
- __ sub(ebx, Immediate(kPointerSize)); |
+ __ Push(Operand(start_address, 0)); |
+ __ sub(start_address, Immediate(kPointerSize)); |
__ bind(&loop_check); |
- __ cmp(ebx, array_limit); |
+ __ cmp(start_address, array_limit); |
__ j(greater, &loop_header, Label::kNear); |
} |
@@ -743,7 +744,8 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl( |
__ neg(ecx); |
__ add(ecx, ebx); |
- Generate_InterpreterPushArgs(masm, ecx); |
+ // TODO(mythria): Add a stack check before pushing the arguments. |
+ Generate_InterpreterPushArgs(masm, ecx, ebx); |
// Call the target. |
__ Push(edx); // Re-push return address. |
@@ -761,40 +763,119 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl( |
} |
// static |
-void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { |
+void Builtins::Generate_InterpreterPushArgsAndConstructImpl( |
+ MacroAssembler* masm, CallableType construct_type) { |
// ----------- S t a t e ------------- |
// -- eax : the number of arguments (not including the receiver) |
// -- edx : the new target |
// -- edi : the constructor |
- // -- ebx : the address of the first argument to be pushed. Subsequent |
+ // -- ebx : allocation site feedback (if available or undefined) |
+ // -- ecx : the address of the first argument to be pushed. Subsequent |
// arguments should be consecutive above this, in the same order as |
// they are to be pushed onto the stack. |
// ----------------------------------- |
- // Pop return address to allow tail-call after pushing arguments. |
- __ Pop(ecx); |
- |
- // Push edi in the slot meant for receiver. We need an extra register |
- // so store edi temporarily on stack. |
+ // Store edi, edx onto the stack. We need two extra registers |
+ // so store edi, edx temporarily on stack. |
__ Push(edi); |
+ __ Push(edx); |
- // Find the address of the last argument. |
- __ mov(edi, eax); |
- __ neg(edi); |
- __ shl(edi, kPointerSizeLog2); |
- __ add(edi, ebx); |
- |
- Generate_InterpreterPushArgs(masm, edi); |
+ // We have to pop return address and the two temporary registers before we |
+ // can push arguments onto the stack. we do not have any free registers so |
+ // update the stack and copy them into the correct places on the stack. |
+ // current stack =====> required stack layout |
+ // | | | edx | (2) <-- esp(1) |
+ // | | | edi | (3) |
+ // | | | return addr | (4) |
+ // | | | arg N | (5) |
+ // | edx | <-- esp | .... | |
+ // | edi | | arg 0 | |
+ // | return addr | | receiver slot | |
+ |
+ // First increment the stack pointer to the correct location. |
+ // we need additional slots for arguments and the receiver. |
+ // Step 1 - compute the required increment to the stack. |
+ __ mov(edx, eax); |
+ __ shl(edx, kPointerSizeLog2); |
+ __ add(edx, Immediate(kPointerSize)); |
+ |
+#ifdef _MSC_VER |
+ // TODO(mythria): Move it to macro assembler. |
+ // In windows, we cannot increment the stack size by more than one page |
+ // (mimimum page size is 4KB) without accessing at least one byte on the |
+ // page. Check this: |
+ // https://msdn.microsoft.com/en-us/library/aa227153(v=vs.60).aspx. |
+ const int page_size = 4 * 1024; |
+ Label check_offset, update_stack_pointer; |
+ __ bind(&check_offset); |
+ __ cmp(edx, page_size); |
+ __ j(less, &update_stack_pointer); |
+ __ sub(esp, Immediate(page_size)); |
+ // Just to touch the page, before we increment further. |
+ __ mov(Operand(esp, 0), Immediate(0)); |
+ __ sub(edx, Immediate(page_size)); |
+ __ jmp(&check_offset); |
+ __ bind(&update_stack_pointer); |
+#endif |
+ |
+ // TODO(mythria): Add a stack check before updating the stack pointer. |
+ |
+ // Step 1 - Update the stack pointer. |
+ __ sub(esp, edx); |
+ |
+ // Step 2 move edx to the correct location. Move edx first otherwise |
+ // we may overwrite when eax = 0 or 1, basically when the source and |
+ // destination overlap. We at least need one extra slot for receiver, |
+ // so no extra checks are required to avoid copy. |
+ __ mov(edi, Operand(esp, eax, times_pointer_size, 1 * kPointerSize)); |
+ __ mov(Operand(esp, 0), edi); |
+ |
+ // Step 3 move edi to the correct location |
+ __ mov(edi, Operand(esp, eax, times_pointer_size, 2 * kPointerSize)); |
+ __ mov(Operand(esp, 1 * kPointerSize), edi); |
+ |
+ // Step 4 move return address to the correct location |
+ __ mov(edi, Operand(esp, eax, times_pointer_size, 3 * kPointerSize)); |
+ __ mov(Operand(esp, 2 * kPointerSize), edi); |
+ |
+ // Slot meant for receiver contains return address. Reset it so that |
+ // we will not incorrectly interpret return address as an object. |
+ __ mov(Operand(esp, eax, times_pointer_size, 3 * kPointerSize), Immediate(0)); |
+ |
+ // Step 5 copy arguments to correct locations. |
+ __ mov(edx, eax); |
- // Restore the constructor from slot on stack. It was pushed at the slot |
- // meant for receiver. |
- __ mov(edi, Operand(esp, eax, times_pointer_size, 0)); |
+ Label loop_header, loop_check; |
+ __ jmp(&loop_check); |
+ __ bind(&loop_header); |
+ __ mov(edi, Operand(ecx, 0)); |
+ __ mov(Operand(esp, edx, times_pointer_size, 2 * kPointerSize), edi); |
+ __ sub(ecx, Immediate(kPointerSize)); |
+ __ sub(edx, Immediate(1)); |
+ __ bind(&loop_check); |
+ __ cmp(edx, Immediate(0)); |
+ __ j(greater, &loop_header, Label::kNear); |
- // Re-push return address. |
- __ Push(ecx); |
+ // Restore edi and edx. |
+ __ Pop(edx); |
+ __ Pop(edi); |
+ |
+ __ AssertUndefinedOrAllocationSite(ebx); |
+ if (construct_type == CallableType::kJSFunction) { |
+ // Tail call to the function-specific construct stub (still in the caller |
+ // context at this point). |
+ __ AssertFunction(edi); |
+ |
+ __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
+ __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset)); |
+ __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); |
+ __ jmp(ecx); |
+ } else { |
+ DCHECK_EQ(construct_type, CallableType::kAny); |
- // Call the constructor with unmodified eax, edi, ebi values. |
- __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); |
+ // Call the constructor with unmodified eax, edi, edx values. |
+ __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); |
+ } |
} |
void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { |