Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(57)

Unified Diff: src/compiler/ia32/code-generator-ia32.cc

Issue 1259203002: [turbofan] Implement tail calls with differing stack parameter counts (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Fix bugs in frameless tail calls Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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_);

Powered by Google App Engine
This is Rietveld 408576698