| 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,
|
|
|