Chromium Code Reviews| Index: src/compiler/ia32/code-generator-ia32.cc |
| diff --git a/src/compiler/ia32/code-generator-ia32.cc b/src/compiler/ia32/code-generator-ia32.cc |
| index 4690a8cc05d869893778ed9f12c229b2b10f88c5..edc73a3e4745c6b41938fe9bec5e655a2c1bdffd 100644 |
| --- a/src/compiler/ia32/code-generator-ia32.cc |
| +++ b/src/compiler/ia32/code-generator-ia32.cc |
| @@ -284,13 +284,123 @@ class OutOfLineTruncateDoubleToI final : public OutOfLineCode { |
| } while (false) |
| -void CodeGenerator::AssembleDeconstructActivationRecord() { |
| - CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); |
| - int stack_slots = frame()->GetSpillSlotCount(); |
| - if (descriptor->IsJSFunctionCall() || stack_slots > 0) { |
| - __ mov(esp, ebp); |
| - __ pop(ebp); |
| +void CodeGenerator::AssembleTailCallSetup(Instruction* instr) { |
|
Benedikt Meurer
2015/07/30 06:47:24
This is quite a lot of (complex) per-architecture
|
| + IA32OperandConverter i(this, instr); |
| + size_t current_argument = instr->InputCount() - 1; |
| + int stack_delta = ImmediateOperand::cast(instr->InputAt(current_argument--)) |
| + ->inline_value(); |
| + int pushed_parameters = |
| + ImmediateOperand::cast(instr->InputAt(current_argument--)) |
| + ->inline_value(); |
| + int base_offset = pushed_parameters * kPointerSize; |
| + int frame_size = (StandardFrameConstants::kCallerPCOffset - |
| + StandardFrameConstants::kMarkerOffset) + |
| + frame()->GetFrameSlotCount() * kPointerSize; |
| + if (frame()->NeedsFrame()) { |
| + base_offset += frame_size; |
| + } |
| + |
| + if (frame()->NeedsFrame() && stack_delta != 0) { |
| + __ mov(ebp, Operand(ebp, 0)); |
| } |
| + |
| + bool done = false; |
| + Register return_reg = no_reg; |
| + while (!done) { |
| + TailCallOpcode opcode = static_cast<TailCallOpcode>( |
| + ImmediateOperand::cast(instr->InputAt(current_argument--)) |
| + ->inline_value()); |
| + switch (opcode) { |
| + case kPopAndStore: { |
| + int location = |
| + ImmediateOperand::cast(instr->InputAt(current_argument--)) |
| + ->inline_value(); |
| + DCHECK(location != 0); |
| + DCHECK(frame()->NeedsFrame()); // Tail calls from elided frames that |
| + // require pushing arguments are not |
| + // supported. |
| + base_offset -= kPointerSize; |
| + __ pop(Operand(esp, base_offset + location * kPointerSize)); |
| + break; |
| + } |
| + case kStore: { |
| + size_t arg = current_argument--; |
| + if (HasImmediateInput(instr, arg)) { |
| + Immediate value_immediate = i.InputImmediate(arg); |
| + int location = |
| + ImmediateOperand::cast(instr->InputAt(current_argument--)) |
| + ->inline_value(); |
| + DCHECK(location != 0); |
| + __ mov(Operand(esp, base_offset + location * kPointerSize), |
| + value_immediate); |
| + } else { |
| + Register value_reg = i.InputRegister(arg); |
| + int location = |
| + ImmediateOperand::cast(instr->InputAt(current_argument--)) |
| + ->inline_value(); |
| + DCHECK(location != 0); |
| + __ mov(Operand(esp, base_offset + location * kPointerSize), |
| + value_reg); |
| + } |
| + break; |
| + } |
| + case kReplaceReturn: { |
| + return_reg = i.InputRegister(current_argument--); |
| + DCHECK(return_reg.is_valid()); |
| + __ xchg(return_reg, Operand(esp, base_offset)); |
| + break; |
| + } |
| + case kDeconstructFrame: { |
| + if (stack_delta > 0) { |
| + int delta = (frame()->NeedsFrame() ? frame_size : 0) - |
| + (stack_delta - 1) * kPointerSize; |
| + if (delta != 0) { |
| + if (delta < 0) { |
| + __ sub(esp, Immediate(-delta)); |
| + } else { |
| + __ add(esp, Immediate(delta)); |
| + } |
| + base_offset -= delta; |
| + } |
| + } else if (stack_delta < 0) { |
| + if (frame()->NeedsFrame()) { |
| + __ add(esp, Immediate(frame_size)); |
| + base_offset -= frame_size; |
| + } |
| + int delta = (-stack_delta - 1) * kPointerSize; |
| + base_offset -= kPointerSize; |
| + __ pop(Operand(esp, delta)); |
| + if (stack_delta != -1) { |
| + if (delta < 0) { |
| + __ sub(esp, Immediate(-delta)); |
| + } else { |
| + __ add(esp, Immediate(delta)); |
| + } |
| + base_offset -= delta; |
| + } |
| + } else { |
| + if (frame()->NeedsFrame()) { |
| + __ mov(esp, ebp); |
| + __ pop(ebp); |
| + base_offset -= frame_size; |
| + } |
| + } |
| + break; |
| + } |
| + case kParametersReady: { |
| + if (stack_delta > 0) { |
| + __ push(return_reg); |
| + base_offset += kPointerSize; |
| + } |
| + done = true; |
| + break; |
| + } |
| + } |
| + } |
| + |
| + // Ensure all of the stack tracking math ends up at the end matching the |
| + // predicted delta. |
| + DCHECK_EQ(stack_delta * kPointerSize, base_offset); |
| } |
| @@ -312,7 +422,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { |
| break; |
| } |
| case kArchTailCallCodeObject: { |
| - AssembleDeconstructActivationRecord(); |
| + AssembleTailCallSetup(instr); |
| if (HasImmediateInput(instr, 0)) { |
| Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0)); |
| __ jmp(code, RelocInfo::CODE_TARGET); |
| @@ -341,7 +451,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { |
| __ cmp(esi, FieldOperand(func, JSFunction::kContextOffset)); |
| __ Assert(equal, kWrongFunctionContext); |
| } |
| - AssembleDeconstructActivationRecord(); |
| + AssembleTailCallSetup(instr); |
| __ jmp(FieldOperand(func, JSFunction::kCodeEntryOffset)); |
| break; |
| } |
| @@ -873,6 +983,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { |
| break; |
| } |
| case kIA32Push: |
| + // Pushes and pops require a frame, otherwise parameter access, which is |
| + // esp-relative would be off. |
| + DCHECK(frame()->NeedsFrame()); |
| if (HasImmediateInput(instr, 0)) { |
| __ push(i.InputImmediate(0)); |
| } else { |
| @@ -1255,7 +1368,7 @@ void CodeGenerator::AssembleDeoptimizerCall( |
| void CodeGenerator::AssemblePrologue() { |
| CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); |
| - int stack_slots = frame()->GetSpillSlotCount(); |
| + int stack_slots = frame()->GetFrameSlotCount(); |
| if (descriptor->kind() == CallDescriptor::kCallAddress) { |
| // Assemble a prologue similar the to cdecl calling convention. |
| __ push(ebp); |
| @@ -1270,15 +1383,15 @@ void CodeGenerator::AssemblePrologue() { |
| } |
| frame()->SetRegisterSaveAreaSize(register_save_area_size); |
| } |
| - } else if (descriptor->IsJSFunctionCall()) { |
| + } else if (frame()->NeedsFrame()) { |
| // TODO(turbofan): this prologue is redundant with OSR, but needed for |
| // code aging. |
| CompilationInfo* info = this->info(); |
| - __ Prologue(info->IsCodePreAgingActive()); |
| - frame()->SetRegisterSaveAreaSize( |
| - StandardFrameConstants::kFixedFrameSizeFromFp); |
| - } else if (needs_frame_) { |
| - __ StubPrologue(); |
| + if (descriptor->IsJSFunctionCall()) { |
| + __ Prologue(info->IsCodePreAgingActive()); |
| + } else { |
| + __ StubPrologue(); |
| + } |
| frame()->SetRegisterSaveAreaSize( |
| StandardFrameConstants::kFixedFrameSizeFromFp); |
| } |
| @@ -1308,7 +1421,7 @@ void CodeGenerator::AssemblePrologue() { |
| void CodeGenerator::AssembleReturn() { |
| CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); |
| - int stack_slots = frame()->GetSpillSlotCount(); |
| + int stack_slots = frame()->GetFrameSlotCount(); |
| if (descriptor->kind() == CallDescriptor::kCallAddress) { |
| const RegList saves = descriptor->CalleeSavedRegisters(); |
| if (frame()->GetRegisterSaveAreaSize() > 0) { |
| @@ -1331,7 +1444,7 @@ void CodeGenerator::AssembleReturn() { |
| __ pop(ebp); // Pop caller's frame pointer. |
| __ ret(0); |
| } |
| - } else if (descriptor->IsJSFunctionCall() || needs_frame_) { |
| + } else if (frame()->NeedsFrame()) { |
| // Canonicalize JSFunction return sites for now. |
| if (return_label_.is_bound()) { |
| __ jmp(&return_label_); |