Chromium Code Reviews| Index: src/builtins/ia32/builtins-ia32.cc |
| diff --git a/src/builtins/ia32/builtins-ia32.cc b/src/builtins/ia32/builtins-ia32.cc |
| index b1a5cccb2dc1602675c29c03313bdd0a7abf36aa..b099c6ba4980ed08ff15262458bc279a6e37b79a 100644 |
| --- a/src/builtins/ia32/builtins-ia32.cc |
| +++ b/src/builtins/ia32/builtins-ia32.cc |
| @@ -761,42 +761,40 @@ 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. reg1 and reg2 are used as temporary registers. Their original |
| +// values are restored after the use. reg1 and reg2 will be pushed onto the |
| +// stack, so they should either have an Smi or a tagged pointer. |
|
rmcilroy
2016/09/07 10:57:39
Do reg1/reg2 need to be tagged? They are pushed, b
mythria
2016/09/07 13:11:15
As mentioned offline, I was thinking about interru
|
| +void Generate_InterpreterPushArgsAndReturnAddress(MacroAssembler* masm, |
| + Register num_args, |
| + Register start_addr, |
| + Register reg1, Register reg2, |
|
rmcilroy
2016/09/07 10:57:39
nit - reg1 / reg2 -> scratch1 / scratch2 (also upd
mythria
2016/09/07 13:11:16
Done.
|
| + bool receiver_in_args) { |
| + // Store reg2, reg1 onto the stack. We need to restore the original values |
| + // so store reg2, reg1 temporarily on stack. |
| + __ Push(reg2); |
| + __ Push(reg1); |
| // 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) |
| + // | | | reg1 | (2) <-- esp(1) |
| + // | | | reg2 | (3) |
| // | | | return addr | (4) |
| // | | | arg N | (5) |
| - // | edx | <-- esp | .... | |
| - // | edi | | arg 0 | |
| + // | reg1 | <-- esp | .... | |
| + // | reg2 | | 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(reg1, num_args); |
| + __ shl(reg1, kPointerSizeLog2); |
| + __ add(reg1, Immediate(kPointerSize)); |
| #ifdef _MSC_VER |
| // TODO(mythria): Move it to macro assembler. |
| @@ -807,12 +805,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(reg1, 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(reg1, Immediate(page_size)); |
| __ jmp(&check_offset); |
| __ bind(&update_stack_pointer); |
| #endif |
| @@ -820,44 +818,71 @@ 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, reg1); |
| - // 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 reg1 to the correct location. Move reg1 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(reg1, Operand(esp, num_args, times_pointer_size, 1 * kPointerSize)); |
| + __ mov(Operand(esp, 0), reg1); |
| - // 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 reg2 to the correct location |
| + __ mov(reg1, Operand(esp, num_args, times_pointer_size, 2 * kPointerSize)); |
| + __ mov(Operand(esp, 1 * kPointerSize), reg1); |
| // 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(reg1, Operand(esp, num_args, times_pointer_size, 3 * kPointerSize)); |
| + __ mov(Operand(esp, 2 * kPointerSize), reg1); |
| // Step 5 copy arguments to correct locations. |
| - __ mov(edx, eax); |
| + if (receiver_in_args) { |
| + __ mov(reg1, num_args); |
| + __ add(reg1, 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(reg1, 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(reg2, Operand(start_addr, 0)); |
| + __ mov(Operand(esp, reg1, times_pointer_size, 2 * kPointerSize), reg2); |
| + __ sub(start_addr, Immediate(kPointerSize)); |
| + __ sub(reg1, Immediate(1)); |
| __ bind(&loop_check); |
| - __ cmp(edx, Immediate(0)); |
| + __ cmp(reg1, Immediate(0)); |
| __ j(greater, &loop_header, Label::kNear); |
| - // Restore edi and edx. |
| - __ Pop(edx); |
| - __ Pop(edi); |
| + // Restore reg1 and reg2. |
| + __ Pop(reg1); |
| + __ Pop(reg2); |
| +} |
| + |
| +} // 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. |
| + // eax is readonly. ecx will be modified. edx and edi will be modified but |
|
rmcilroy
2016/09/07 10:57:39
Capitalize start of sentences (e.g., do "The eax r
mythria
2016/09/07 13:11:15
Done.
|
| + // restored to their original values. edx and edi will be pushed onto the |
| + // stack, so ensure they have an Smi or tagged pointer. |
| + Generate_InterpreterPushArgsAndReturnAddress(masm, eax, ecx, edx, edi, false); |
| __ AssertUndefinedOrAllocationSite(ebx); |
| if (construct_type == CallableType::kJSFunction) { |
| @@ -877,6 +902,31 @@ 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. |
| + // eax is readonly. ecx will be modified. edx and ebx will be modified but |
| + // restored to their original values. edx and ebx will be pushed onto the |
| + // stack, so ensure they have an Smi or tagged pointer. |
| + 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. |