Commit c1753f5c authored by zhengxing.li's avatar zhengxing.li Committed by Commit bot

X87: [turbofan] Support variable size argument removal in TF-generated functions.

  port 5319b50c (r40678)

  original commit message:
  This is preparation for using TF to create builtins that handle variable number of
  arguments and have to remove these arguments dynamically from the stack upon
  return.

  The gist of the changes:
  - Added a second argument to the Return node which specifies the number of stack
    slots to pop upon return in addition to those specified by the Linkage of the
    compiled function.
  - Removed Tail -> Non-Tail fallback in the instruction selector. Since TF now should
    handles all tail-call cases except where the return value type differs, this fallback
    was not really useful and in fact caused unexpected behavior with variable
    sized argument popping, since it wasn't possible to materialize a Return node
    with the right pop count from the TailCall without additional context.
  - Modified existing Return generation to pass a constant zero as the additional
    pop argument since the variable pop functionality

BUG=

Review-Url: https://codereview.chromium.org/2469623002
Cr-Commit-Position: refs/heads/master@{#40684}
parent a1381990
...@@ -746,7 +746,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( ...@@ -746,7 +746,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break; break;
} }
case kArchRet: case kArchRet:
AssembleReturn(); AssembleReturn(instr->InputAt(0));
break; break;
case kArchFramePointer: case kArchFramePointer:
__ mov(i.OutputRegister(), ebp); __ mov(i.OutputRegister(), ebp);
...@@ -2444,8 +2444,7 @@ void CodeGenerator::AssembleConstructFrame() { ...@@ -2444,8 +2444,7 @@ void CodeGenerator::AssembleConstructFrame() {
} }
} }
void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
void CodeGenerator::AssembleReturn() {
CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
// Clear the FPU stack only if there is no return value in the stack. // Clear the FPU stack only if there is no return value in the stack.
...@@ -2463,7 +2462,6 @@ void CodeGenerator::AssembleReturn() { ...@@ -2463,7 +2462,6 @@ void CodeGenerator::AssembleReturn() {
} }
if (clear_stack) __ fstp(0); if (clear_stack) __ fstp(0);
int pop_count = static_cast<int>(descriptor->StackParameterCount());
const RegList saves = descriptor->CalleeSavedRegisters(); const RegList saves = descriptor->CalleeSavedRegisters();
// Restore registers. // Restore registers.
if (saves != 0) { if (saves != 0) {
...@@ -2473,22 +2471,40 @@ void CodeGenerator::AssembleReturn() { ...@@ -2473,22 +2471,40 @@ void CodeGenerator::AssembleReturn() {
} }
} }
// Might need ecx for scratch if pop_size is too big or if there is a variable
// pop count.
DCHECK_EQ(0u, descriptor->CalleeSavedRegisters() & ecx.bit());
size_t pop_size = descriptor->StackParameterCount() * kPointerSize;
X87OperandConverter g(this, nullptr);
if (descriptor->IsCFunctionCall()) { if (descriptor->IsCFunctionCall()) {
AssembleDeconstructFrame(); AssembleDeconstructFrame();
} else if (frame_access_state()->has_frame()) { } else if (frame_access_state()->has_frame()) {
// Canonicalize JSFunction return sites for now. // Canonicalize JSFunction return sites for now if they always have the same
if (return_label_.is_bound()) { // number of return args.
__ jmp(&return_label_); if (pop->IsImmediate() && g.ToConstant(pop).ToInt32() == 0) {
return; if (return_label_.is_bound()) {
__ jmp(&return_label_);
return;
} else {
__ bind(&return_label_);
AssembleDeconstructFrame();
}
} else { } else {
__ bind(&return_label_);
AssembleDeconstructFrame(); AssembleDeconstructFrame();
} }
} }
if (pop_count == 0) { DCHECK_EQ(0u, descriptor->CalleeSavedRegisters() & edx.bit());
__ ret(0); DCHECK_EQ(0u, descriptor->CalleeSavedRegisters() & ecx.bit());
if (pop->IsImmediate()) {
DCHECK_EQ(Constant::kInt32, g.ToConstant(pop).type());
pop_size += g.ToConstant(pop).ToInt32() * kPointerSize;
__ Ret(static_cast<int>(pop_size), ecx);
} else { } else {
__ Ret(pop_count * kPointerSize, ebx); Register pop_reg = g.ToRegister(pop);
Register scratch_reg = pop_reg.is(ecx) ? edx : ecx;
__ pop(scratch_reg);
__ lea(esp, Operand(esp, pop_reg, times_4, static_cast<int>(pop_size)));
__ jmp(scratch_reg);
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment