Index: src/ia32/macro-assembler-ia32.cc |
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc |
index 12daec8285c79fea84149f25660fb1f593978118..44029ea618a7c8385806a6d870ac763c4f5a09af 100644 |
--- a/src/ia32/macro-assembler-ia32.cc |
+++ b/src/ia32/macro-assembler-ia32.cc |
@@ -2086,6 +2086,77 @@ void MacroAssembler::JumpToExternalReference(const ExternalReference& ext) { |
jmp(ces.GetCode(), RelocInfo::CODE_TARGET); |
} |
+void MacroAssembler::PrepareForTailCall(const ParameterCount& callee_args_count, |
+ Register caller_args_count_reg, |
+ Register scratch0, Register scratch1, |
+ ReturnAddressState ra_state) { |
+#if DEBUG |
+ if (callee_args_count.is_reg()) { |
+ DCHECK(!AreAliased(callee_args_count.reg(), caller_args_count_reg, scratch0, |
+ scratch1)); |
+ } else { |
+ DCHECK(!AreAliased(caller_args_count_reg, scratch0, scratch1)); |
+ } |
+#endif |
+ |
+ // Calculate the destination address where we will put the return address |
+ // after we drop current frame. |
+ Register new_sp_reg = scratch0; |
+ if (callee_args_count.is_reg()) { |
+ sub(caller_args_count_reg, callee_args_count.reg()); |
+ lea(new_sp_reg, Operand(ebp, caller_args_count_reg, times_pointer_size, |
+ StandardFrameConstants::kCallerPCOffset)); |
+ } else { |
+ lea(new_sp_reg, Operand(ebp, caller_args_count_reg, times_pointer_size, |
+ StandardFrameConstants::kCallerPCOffset - |
+ callee_args_count.immediate() * kPointerSize)); |
+ } |
+ |
+ if (FLAG_debug_code) { |
+ cmp(esp, new_sp_reg); |
+ Check(below, kStackAccessBelowStackPointer); |
+ } |
+ |
+ // Copy return address from caller's frame to current frame's return address |
+ // to avoid its trashing and let the following loop copy it to the right |
+ // place. |
+ Register tmp_reg = scratch1; |
+ if (ra_state == ReturnAddressState::kOnStack) { |
+ mov(tmp_reg, Operand(ebp, StandardFrameConstants::kCallerPCOffset)); |
+ mov(Operand(esp, 0), tmp_reg); |
+ } else { |
+ DCHECK(ReturnAddressState::kNotOnStack == ra_state); |
+ Push(Operand(ebp, StandardFrameConstants::kCallerPCOffset)); |
+ } |
+ |
+ // Restore caller's frame pointer now as it could be overwritten by |
+ // the copying loop. |
+ mov(ebp, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); |
+ |
+ // +2 here is to copy both receiver and return address. |
+ Register count_reg = caller_args_count_reg; |
+ if (callee_args_count.is_reg()) { |
+ lea(count_reg, Operand(callee_args_count.reg(), 2)); |
+ } else { |
+ mov(count_reg, Immediate(callee_args_count.immediate() + 2)); |
+ // TODO(ishell): Unroll copying loop for small immediate values. |
+ } |
+ |
+ // Now copy callee arguments to the caller frame going backwards to avoid |
+ // callee arguments corruption (source and destination areas could overlap). |
+ Label loop, entry; |
+ jmp(&entry, Label::kNear); |
+ bind(&loop); |
+ dec(count_reg); |
+ mov(tmp_reg, Operand(esp, count_reg, times_pointer_size, 0)); |
+ mov(Operand(new_sp_reg, count_reg, times_pointer_size, 0), tmp_reg); |
+ bind(&entry); |
+ cmp(count_reg, Immediate(0)); |
+ j(not_equal, &loop, Label::kNear); |
+ |
+ // Leave current frame. |
+ mov(esp, new_sp_reg); |
+} |
void MacroAssembler::InvokePrologue(const ParameterCount& expected, |
const ParameterCount& actual, |