| Index: src/builtins/x87/builtins-x87.cc
|
| diff --git a/src/builtins/x87/builtins-x87.cc b/src/builtins/x87/builtins-x87.cc
|
| index 2b7dfdd46ed262ce2bdac870e61d1a80e3bffbfb..169b9f2ac5e37527344bd7aae306ce18dc56bdbc 100644
|
| --- a/src/builtins/x87/builtins-x87.cc
|
| +++ b/src/builtins/x87/builtins-x87.cc
|
| @@ -762,42 +762,38 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
|
| }
|
| }
|
|
|
| -// static
|
| -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 : 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.
|
| - // -----------------------------------
|
| +namespace {
|
|
|
| - // Store edi, edx onto the stack. We need two extra registers
|
| - // so store edi, edx temporarily on stack.
|
| - __ Push(edi);
|
| - __ Push(edx);
|
| +// This function modified start_addr, and only reads the contents of num_args
|
| +// register. scratch1 and scratch2 are used as temporary registers. Their
|
| +// original values are restored after the use.
|
| +void Generate_InterpreterPushArgsAndReturnAddress(
|
| + MacroAssembler* masm, Register num_args, Register start_addr,
|
| + Register scratch1, Register scratch2, bool receiver_in_args) {
|
| + // Store scratch2, scratch1 onto the stack. We need to restore the original
|
| + // values
|
| + // so store scratch2, scratch1 temporarily on stack.
|
| + __ Push(scratch2);
|
| + __ Push(scratch1);
|
|
|
| // 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)
|
| + // | | | scratch1 | (2) <-- esp(1)
|
| + // | | | scratch2 | (3)
|
| // | | | return addr | (4)
|
| // | | | arg N | (5)
|
| - // | edx | <-- esp | .... |
|
| - // | edi | | arg 0 |
|
| + // | scratch1 | <-- esp | .... |
|
| + // | scratch2 | | 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));
|
| + __ mov(scratch1, num_args);
|
| + __ shl(scratch1, kPointerSizeLog2);
|
| + __ add(scratch1, Immediate(kPointerSize));
|
|
|
| #ifdef _MSC_VER
|
| // TODO(mythria): Move it to macro assembler.
|
| @@ -808,12 +804,12 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
|
| const int page_size = 4 * 1024;
|
| Label check_offset, update_stack_pointer;
|
| __ bind(&check_offset);
|
| - __ cmp(edx, page_size);
|
| + __ cmp(scratch1, 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));
|
| + __ sub(scratch1, Immediate(page_size));
|
| __ jmp(&check_offset);
|
| __ bind(&update_stack_pointer);
|
| #endif
|
| @@ -821,44 +817,74 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
|
| // TODO(mythria): Add a stack check before updating the stack pointer.
|
|
|
| // Step 1 - Update the stack pointer.
|
| - __ sub(esp, edx);
|
| + __ sub(esp, scratch1);
|
|
|
| - // 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
|
| + // Step 2 move scratch1 to the correct location. Move scratch1 first otherwise
|
| + // we may overwrite when num_args = 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);
|
| + __ mov(scratch1,
|
| + Operand(esp, num_args, times_pointer_size, 1 * kPointerSize));
|
| + __ mov(Operand(esp, 0), scratch1);
|
|
|
| - // 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 3 move scratch2 to the correct location
|
| + __ mov(scratch1,
|
| + Operand(esp, num_args, times_pointer_size, 2 * kPointerSize));
|
| + __ mov(Operand(esp, 1 * kPointerSize), scratch1);
|
|
|
| // 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));
|
| + __ mov(scratch1,
|
| + Operand(esp, num_args, times_pointer_size, 3 * kPointerSize));
|
| + __ mov(Operand(esp, 2 * kPointerSize), scratch1);
|
|
|
| // Step 5 copy arguments to correct locations.
|
| - __ mov(edx, eax);
|
| + if (receiver_in_args) {
|
| + __ mov(scratch1, num_args);
|
| + __ add(scratch1, Immediate(1));
|
| + } else {
|
| + // Slot meant for receiver contains return address. Reset it so that
|
| + // we will not incorrectly interpret return address as an object.
|
| + __ mov(Operand(esp, num_args, times_pointer_size, 3 * kPointerSize),
|
| + Immediate(0));
|
| + __ mov(scratch1, num_args);
|
| + }
|
|
|
| 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));
|
| + __ mov(scratch2, Operand(start_addr, 0));
|
| + __ mov(Operand(esp, scratch1, times_pointer_size, 2 * kPointerSize),
|
| + scratch2);
|
| + __ sub(start_addr, Immediate(kPointerSize));
|
| + __ sub(scratch1, Immediate(1));
|
| __ bind(&loop_check);
|
| - __ cmp(edx, Immediate(0));
|
| + __ cmp(scratch1, Immediate(0));
|
| __ j(greater, &loop_header, Label::kNear);
|
|
|
| - // Restore edi and edx.
|
| - __ Pop(edx);
|
| - __ Pop(edi);
|
| + // Restore scratch1 and scratch2.
|
| + __ Pop(scratch1);
|
| + __ Pop(scratch2);
|
| +}
|
| +
|
| +} // end anonymous namespace
|
| +
|
| +// static
|
| +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 : 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.
|
| + // -----------------------------------
|
| +
|
| + // Push arguments and move return address to the top of stack.
|
| + // The eax register is readonly. The ecx register will be modified. The edx
|
| + // and edi registers will be modified but restored to their original values.
|
| + Generate_InterpreterPushArgsAndReturnAddress(masm, eax, ecx, edx, edi, false);
|
|
|
| __ AssertUndefinedOrAllocationSite(ebx);
|
| if (construct_type == CallableType::kJSFunction) {
|
| @@ -878,6 +904,30 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
|
| }
|
| }
|
|
|
| +// static
|
| +void Builtins::Generate_InterpreterPushArgsAndConstructArray(
|
| + MacroAssembler* masm) {
|
| + // ----------- S t a t e -------------
|
| + // -- eax : the number of arguments (not including the receiver)
|
| + // -- edx : the target to call checked to be Array function.
|
| + // -- ebx : the allocation site feedback
|
| + // -- 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.
|
| + // -----------------------------------
|
| +
|
| + // Push arguments and move return address to the top of stack.
|
| + // The eax register is readonly. The ecx register will be modified. The edx
|
| + // and edi registers will be modified but restored to their original values.
|
| + Generate_InterpreterPushArgsAndReturnAddress(masm, eax, ecx, edx, ebx, true);
|
| +
|
| + // Array constructor expects constructor in edi. It is same as edx here.
|
| + __ Move(edi, edx);
|
| +
|
| + ArrayConstructorStub stub(masm->isolate());
|
| + __ TailCallStub(&stub);
|
| +}
|
| +
|
| void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) {
|
| // Set the return address to the correct point in the interpreter entry
|
| // trampoline.
|
|
|