Index: src/x64/macro-assembler-x64.cc |
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc |
index e72d40b4aec743f4db9f5a27a81d25c2d5657010..a7fb0dc742f27c3d184846e4538f49d89550c1ed 100644 |
--- a/src/x64/macro-assembler-x64.cc |
+++ b/src/x64/macro-assembler-x64.cc |
@@ -4094,6 +4094,77 @@ void MacroAssembler::DebugBreak() { |
Call(ces.GetCode(), RelocInfo::DEBUGGER_STATEMENT); |
} |
+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()) { |
+ subp(caller_args_count_reg, callee_args_count.reg()); |
+ leap(new_sp_reg, Operand(rbp, caller_args_count_reg, times_pointer_size, |
+ StandardFrameConstants::kCallerPCOffset)); |
+ } else { |
+ leap(new_sp_reg, Operand(rbp, caller_args_count_reg, times_pointer_size, |
+ StandardFrameConstants::kCallerPCOffset - |
+ callee_args_count.immediate() * kPointerSize)); |
+ } |
+ |
+ if (FLAG_debug_code) { |
+ cmpp(rsp, 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) { |
+ movp(tmp_reg, Operand(rbp, StandardFrameConstants::kCallerPCOffset)); |
+ movp(Operand(rsp, 0), tmp_reg); |
+ } else { |
+ DCHECK(ReturnAddressState::kNotOnStack == ra_state); |
+ Push(Operand(rbp, StandardFrameConstants::kCallerPCOffset)); |
+ } |
+ |
+ // Restore caller's frame pointer now as it could be overwritten by |
+ // the copying loop. |
+ movp(rbp, Operand(rbp, 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()) { |
+ leap(count_reg, Operand(callee_args_count.reg(), 2)); |
+ } else { |
+ movp(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); |
+ decp(count_reg); |
+ movp(tmp_reg, Operand(rsp, count_reg, times_pointer_size, 0)); |
+ movp(Operand(new_sp_reg, count_reg, times_pointer_size, 0), tmp_reg); |
+ bind(&entry); |
+ cmpp(count_reg, Immediate(0)); |
+ j(not_equal, &loop, Label::kNear); |
+ |
+ // Leave current frame. |
+ movp(rsp, new_sp_reg); |
+} |
void MacroAssembler::InvokeFunction(Register function, |
Register new_target, |