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 b16e2b68c0c8cfd4738123951f1a4bf15bd71d67..b1a5cccb2dc1602675c29c03313bdd0a7abf36aa 100644 | 
| --- a/src/builtins/ia32/builtins-ia32.cc | 
| +++ b/src/builtins/ia32/builtins-ia32.cc | 
| @@ -704,19 +704,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); | 
| } | 
| @@ -742,7 +743,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. | 
| @@ -760,40 +762,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)); | 
| 
 
mythria
2016/09/01 08:42:24
This is the only change on the top of the earlier
 
 | 
| + | 
| + // 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) { |