Commit 53d51c52 authored by mtrofin's avatar mtrofin Committed by Commit bot

[turbofan] Frame elision for code stubs.

Removed Frame::needs_frame and the function-wide logic using it in
favor of FrameAccessState::has_frame, which can be set on a more
granular level, and driving it block by block.

BUG= v8:4533
LOG=N

Review URL: https://codereview.chromium.org/1775323002

Cr-Commit-Position: refs/heads/master@{#35139}
parent a549d4a7
......@@ -230,7 +230,8 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
value_(value),
scratch0_(scratch0),
scratch1_(scratch1),
mode_(mode) {}
mode_(mode),
must_save_lr_(!gen->frame_access_state()->has_frame()) {}
void Generate() final {
if (mode_ > RecordWriteMode::kValueIsPointer) {
......@@ -244,7 +245,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
: OMIT_REMEMBERED_SET;
SaveFPRegsMode const save_fp_mode =
frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
if (!frame()->needs_frame()) {
if (must_save_lr_) {
// We need to save and restore lr if the frame was elided.
__ Push(lr);
}
......@@ -257,7 +258,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
__ add(scratch1_, object_, Operand(index_));
}
__ CallStub(&stub);
if (!frame()->needs_frame()) {
if (must_save_lr_) {
__ Pop(lr);
}
}
......@@ -270,6 +271,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
Register const scratch0_;
Register const scratch1_;
RecordWriteMode const mode_;
bool must_save_lr_;
};
......@@ -386,6 +388,11 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
DCHECK_EQ(LeaveCC, i.OutputSBit()); \
} while (0)
void CodeGenerator::AssembleDeconstructFrame() {
__ LeaveFrame(StackFrame::MANUAL);
}
void CodeGenerator::AssembleSetupStackPointer() {}
void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) {
int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
......@@ -402,7 +409,7 @@ void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) {
__ sub(sp, sp, Operand(-sp_slot_delta * kPointerSize));
frame_access_state()->IncreaseSPDelta(-sp_slot_delta);
}
if (frame()->needs_frame()) {
if (frame_access_state()->has_frame()) {
if (FLAG_enable_embedded_constant_pool) {
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kConstantPoolOffset));
}
......@@ -580,7 +587,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArchParentFramePointer:
if (frame_access_state()->frame()->needs_frame()) {
if (frame_access_state()->has_frame()) {
__ ldr(i.OutputRegister(), MemOperand(fp, 0));
} else {
__ mov(i.OutputRegister(), fp);
......@@ -1271,7 +1278,7 @@ void CodeGenerator::AssembleDeoptimizerCall(
void CodeGenerator::AssemblePrologue() {
CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
if (frame()->needs_frame()) {
if (frame_access_state()->has_frame()) {
if (descriptor->IsCFunctionCall()) {
if (FLAG_enable_embedded_constant_pool) {
__ Push(lr, fp, pp);
......@@ -1286,10 +1293,7 @@ void CodeGenerator::AssemblePrologue() {
} else {
__ StubPrologue(info()->GetOutputStackFrameType());
}
} else {
frame()->SetElidedFrameSizeInSlots(0);
}
frame_access_state()->SetFrameAccessToDefault();
int stack_shrink_slots = frame()->GetSpillSlotCount();
if (info()->is_osr()) {
......@@ -1359,15 +1363,15 @@ void CodeGenerator::AssembleReturn() {
}
if (descriptor->IsCFunctionCall()) {
__ LeaveFrame(StackFrame::MANUAL);
} else if (frame()->needs_frame()) {
AssembleDeconstructFrame();
} else if (frame_access_state()->has_frame()) {
// Canonicalize JSFunction return sites for now.
if (return_label_.is_bound()) {
__ b(&return_label_);
return;
} else {
__ bind(&return_label_);
__ LeaveFrame(StackFrame::MANUAL);
AssembleDeconstructFrame();
}
}
__ Ret(pop_count);
......
......@@ -279,7 +279,8 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
value_(value),
scratch0_(scratch0),
scratch1_(scratch1),
mode_(mode) {}
mode_(mode),
must_save_lr_(!gen->frame_access_state()->has_frame()) {}
void Generate() final {
if (mode_ > RecordWriteMode::kValueIsPointer) {
......@@ -293,7 +294,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
: OMIT_REMEMBERED_SET;
SaveFPRegsMode const save_fp_mode =
frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
if (!frame()->needs_frame()) {
if (must_save_lr_) {
// We need to save and restore lr if the frame was elided.
__ Push(lr);
}
......@@ -301,7 +302,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
remembered_set_action, save_fp_mode);
__ Add(scratch1_, object_, index_);
__ CallStub(&stub);
if (!frame()->needs_frame()) {
if (must_save_lr_) {
__ Pop(lr);
}
}
......@@ -313,6 +314,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
Register const scratch0_;
Register const scratch1_;
RecordWriteMode const mode_;
bool must_save_lr_;
};
......@@ -466,6 +468,15 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
} \
} while (0)
void CodeGenerator::AssembleDeconstructFrame() {
const CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
if (descriptor->IsCFunctionCall() || descriptor->UseNativeStack()) {
__ Mov(csp, fp);
} else {
__ Mov(jssp, fp);
}
__ Pop(fp, lr);
}
void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) {
int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
......@@ -482,7 +493,7 @@ void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) {
__ Claim(-sp_slot_delta);
frame_access_state()->IncreaseSPDelta(-sp_slot_delta);
}
if (frame()->needs_frame()) {
if (frame_access_state()->has_frame()) {
__ Ldr(lr, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
__ Ldr(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
}
......@@ -672,7 +683,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
__ mov(i.OutputRegister(), fp);
break;
case kArchParentFramePointer:
if (frame_access_state()->frame()->needs_frame()) {
if (frame_access_state()->has_frame()) {
__ ldr(i.OutputRegister(), MemOperand(fp, 0));
} else {
__ mov(i.OutputRegister(), fp);
......@@ -1492,6 +1503,14 @@ void CodeGenerator::AssembleDeoptimizerCall(
__ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
}
void CodeGenerator::AssembleSetupStackPointer() {
const CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
if (descriptor->UseNativeStack() || descriptor->IsCFunctionCall()) {
__ SetStackPointer(csp);
} else {
__ SetStackPointer(jssp);
}
}
void CodeGenerator::AssemblePrologue() {
CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
......@@ -1499,19 +1518,12 @@ void CodeGenerator::AssemblePrologue() {
__ AssertCspAligned();
}
frame()->AlignFrame(16);
int stack_shrink_slots = frame()->GetSpillSlotCount();
if (frame()->needs_frame()) {
if (frame_access_state()->has_frame()) {
if (descriptor->IsJSFunctionCall()) {
DCHECK(!descriptor->UseNativeStack());
__ SetStackPointer(jssp);
__ Prologue(this->info()->GeneratePreagedPrologue());
} else {
if (descriptor->UseNativeStack() || descriptor->IsCFunctionCall()) {
__ SetStackPointer(csp);
} else {
__ SetStackPointer(jssp);
}
if (descriptor->IsCFunctionCall()) {
__ Push(lr, fp);
__ Mov(fp, masm_.StackPointer());
......@@ -1521,15 +1533,8 @@ void CodeGenerator::AssemblePrologue() {
frame()->GetTotalFrameSlotCount());
}
}
} else {
if (descriptor->UseNativeStack()) {
__ SetStackPointer(csp);
} else {
__ SetStackPointer(jssp);
}
frame()->SetElidedFrameSizeInSlots(0);
}
frame_access_state()->SetFrameAccessToDefault();
if (info()->is_osr()) {
// TurboFan OSR-compiled functions cannot be entered directly.
__ Abort(kShouldNotDirectlyEnterOsrFunction);
......@@ -1590,22 +1595,18 @@ void CodeGenerator::AssembleReturn() {
int pop_count = static_cast<int>(descriptor->StackParameterCount());
if (descriptor->IsCFunctionCall()) {
__ Mov(csp, fp);
__ Pop(fp, lr);
} else if (frame()->needs_frame()) {
AssembleDeconstructFrame();
} else if (frame_access_state()->has_frame()) {
// Canonicalize JSFunction return sites for now.
if (return_label_.is_bound()) {
__ B(&return_label_);
return;
} else {
__ Bind(&return_label_);
AssembleDeconstructFrame();
if (descriptor->UseNativeStack()) {
__ Mov(csp, fp);
pop_count += (pop_count & 1); // align
} else {
__ Mov(jssp, fp);
}
__ Pop(fp, lr);
}
} else if (descriptor->UseNativeStack()) {
pop_count += (pop_count & 1); // align
......
......@@ -56,12 +56,8 @@ CodeGenerator::CodeGenerator(Frame* frame, Linkage* linkage,
for (int i = 0; i < code->InstructionBlockCount(); ++i) {
new (&labels_[i]) Label;
}
if (code->ContainsCall()) {
frame->MarkNeedsFrame();
}
}
Handle<Code> CodeGenerator::GenerateCode() {
CompilationInfo* info = this->info();
......@@ -80,10 +76,6 @@ Handle<Code> CodeGenerator::GenerateCode() {
}
// Architecture-specific, linkage-specific prologue.
info->set_prologue_offset(masm()->pc_offset());
AssemblePrologue();
if (linkage()->GetIncomingDescriptor()->InitializeRootRegister()) {
masm()->InitializeRootRegister();
}
// Define deoptimization literals for all inlined functions.
DCHECK_EQ(0u, deoptimization_literals_.size());
......@@ -104,6 +96,9 @@ Handle<Code> CodeGenerator::GenerateCode() {
}
}
// Finish the Frame
frame()->AlignFrame(kFrameAlignmentInBytes);
AssembleSetupStackPointer();
// Assemble all non-deferred blocks, followed by deferred ones.
for (int deferred = 0; deferred < 2; ++deferred) {
for (const InstructionBlock* block : code()->instruction_blocks()) {
......@@ -143,9 +138,24 @@ Handle<Code> CodeGenerator::GenerateCode() {
SNPrintF(buffer, " --");
masm()->RecordComment(buffer_start);
}
frame_access_state()->MarkHasFrame(block->needs_frame());
masm()->bind(GetLabel(current_block_));
if (block->must_construct_frame()) {
AssemblePrologue();
// We need to setup the root register after we assemble the prologue, to
// avoid clobbering callee saved registers in case of C linkage and
// using the roots.
// TODO(mtrofin): investigate how we can avoid doing this repeatedly.
if (linkage()->GetIncomingDescriptor()->InitializeRootRegister()) {
masm()->InitializeRootRegister();
}
}
for (int i = block->code_start(); i < block->code_end(); ++i) {
AssembleInstruction(code()->InstructionAt(i));
Instruction* instr = code()->InstructionAt(i);
AssembleInstruction(instr, block);
}
}
}
......@@ -290,9 +300,12 @@ bool CodeGenerator::IsMaterializableFromRoot(
return false;
}
void CodeGenerator::AssembleInstruction(Instruction* instr) {
void CodeGenerator::AssembleInstruction(Instruction* instr,
const InstructionBlock* block) {
AssembleGaps(instr);
if (instr->IsJump() && block->must_deconstruct_frame()) {
AssembleDeconstructFrame();
}
AssembleSourcePosition(instr);
// Assemble architecture-specific code for the instruction.
AssembleArchInstruction(instr);
......@@ -761,13 +774,11 @@ DeoptimizationExit* CodeGenerator::AddDeoptimizationExit(
}
int CodeGenerator::TailCallFrameStackSlotDelta(int stack_param_delta) {
CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
int spill_slots = frame()->GetSpillSlotCount();
bool has_frame = descriptor->IsJSFunctionCall() || spill_slots > 0;
// Leave the PC on the stack on platforms that have that as part of their ABI
int pc_slots = V8_TARGET_ARCH_STORES_RETURN_ADDRESS_ON_STACK ? 1 : 0;
int sp_slot_delta =
has_frame ? (frame()->GetTotalFrameSlotCount() - pc_slots) : 0;
int sp_slot_delta = frame_access_state()->has_frame()
? (frame()->GetTotalFrameSlotCount() - pc_slots)
: 0;
// Discard only slots that won't be used by new parameters.
sp_slot_delta += stack_param_delta;
return sp_slot_delta;
......
......@@ -85,7 +85,7 @@ class CodeGenerator final : public GapResolver::Assembler {
Heap::RootListIndex* index_return);
// Assemble code for the specified instruction.
void AssembleInstruction(Instruction* instr);
void AssembleInstruction(Instruction* instr, const InstructionBlock* block);
void AssembleSourcePosition(Instruction* instr);
void AssembleGaps(Instruction* instr);
......@@ -106,6 +106,9 @@ class CodeGenerator final : public GapResolver::Assembler {
// Generates an architecture-specific, descriptor-specific prologue
// to set up a stack frame.
void AssemblePrologue();
void AssembleSetupStackPointer();
// Generates an architecture-specific, descriptor-specific return sequence
// to tear down a stack frame.
void AssembleReturn();
......@@ -113,6 +116,8 @@ class CodeGenerator final : public GapResolver::Assembler {
// Generates code to deconstruct a the caller's frame, including arguments.
void AssembleDeconstructActivationRecord(int stack_param_delta);
void AssembleDeconstructFrame();
// Generates code to manipulate the stack in preparation for a tail call.
void AssemblePrepareTailCall(int stack_param_delta);
......
......@@ -734,7 +734,8 @@ Node* CodeStubAssembler::ChangeFloat64ToTagged(Node* value) {
} else {
Node* pair = Int32AddWithOverflow(value32, value32);
Node* overflow = Projection(1, pair);
Label if_overflow(this, Label::kDeferred), if_notoverflow(this);
Label if_overflow(this, Label::kDeferred), if_notoverflow(this),
if_join(this);
Branch(overflow, &if_overflow, &if_notoverflow);
Bind(&if_overflow);
Goto(&if_valueisheapnumber);
......
......@@ -22,8 +22,9 @@ void FrameElider::MarkBlocks() {
for (InstructionBlock* block : instruction_blocks()) {
if (block->needs_frame()) continue;
for (int i = block->code_start(); i < block->code_end(); ++i) {
if (InstructionAt(i)->IsCall() ||
InstructionAt(i)->opcode() == ArchOpcode::kArchDeoptimize) {
const Instruction* instr = InstructionAt(i);
if (instr->IsCall() || instr->IsDeoptimizeCall() ||
instr->arch_opcode() == ArchOpcode::kArchStackPointer) {
block->mark_needs_frame();
break;
}
......@@ -50,6 +51,16 @@ void FrameElider::MarkDeConstruction() {
for (RpoNumber& succ : block->successors()) {
if (!InstructionBlockAt(succ)->needs_frame()) {
DCHECK_EQ(1U, block->SuccessorCount());
const Instruction* last =
InstructionAt(block->last_instruction_index());
if (last->IsThrow() || last->IsTailCall() ||
last->IsDeoptimizeCall()) {
// We need to keep the frame if we exit the block through any
// of these.
continue;
}
// The only cases when we need to deconstruct are ret and jump.
DCHECK(last->IsRet() || last->IsJump());
block->mark_must_deconstruct_frame();
}
}
......
......@@ -13,9 +13,7 @@ namespace internal {
namespace compiler {
Frame::Frame(int fixed_frame_size_in_slots, const CallDescriptor* descriptor)
: needs_frame_((descriptor != nullptr) &&
descriptor->RequiresFrameAsIncoming()),
frame_slot_count_(fixed_frame_size_in_slots),
: frame_slot_count_(fixed_frame_size_in_slots),
callee_saved_slot_count_(0),
spill_slot_count_(0),
allocated_registers_(nullptr),
......@@ -34,8 +32,13 @@ int Frame::AlignFrame(int alignment) {
return delta;
}
void FrameAccessState::MarkHasFrame(bool state) {
has_frame_ = state;
SetFrameAccessToDefault();
}
void FrameAccessState::SetFrameAccessToDefault() {
if (frame()->needs_frame() && !FLAG_turbo_sp_frame_access) {
if (has_frame() && !FLAG_turbo_sp_frame_access) {
SetFrameAccessToFP();
} else {
SetFrameAccessToSP();
......@@ -46,7 +49,6 @@ void FrameAccessState::SetFrameAccessToDefault() {
FrameOffset FrameAccessState::GetFrameOffset(int spill_slot) const {
const int frame_offset = FrameSlotToFPOffset(spill_slot);
if (access_frame_with_fp()) {
DCHECK(frame()->needs_frame());
return FrameOffset::FromFramePointer(frame_offset);
} else {
// No frame. Retrieve all parameters relative to stack pointer.
......
......@@ -81,26 +81,13 @@ class Frame : public ZoneObject {
explicit Frame(int fixed_frame_size_in_slots,
const CallDescriptor* descriptor);
inline bool needs_frame() const { return needs_frame_; }
inline void MarkNeedsFrame() { needs_frame_ = true; }
inline int GetTotalFrameSlotCount() const { return frame_slot_count_; }
inline int GetSPToFPSlotCount() const {
return GetTotalFrameSlotCount() -
StandardFrameConstants::kFixedSlotCountAboveFp;
}
inline int GetSavedCalleeRegisterSlotCount() const {
return callee_saved_slot_count_;
}
inline int GetSpillSlotCount() const { return spill_slot_count_; }
inline void SetElidedFrameSizeInSlots(int slots) {
DCHECK_EQ(0, callee_saved_slot_count_);
DCHECK_EQ(0, spill_slot_count_);
frame_slot_count_ = slots;
}
void SetAllocatedRegisters(BitVector* regs) {
DCHECK(allocated_registers_ == nullptr);
allocated_registers_ = regs;
......@@ -120,21 +107,18 @@ class Frame : public ZoneObject {
int alignment_slots = alignment / kPointerSize;
int delta = alignment_slots - (frame_slot_count_ & (alignment_slots - 1));
if (delta != alignment_slots) {
DCHECK(needs_frame_);
frame_slot_count_ += delta;
}
return delta;
}
void AllocateSavedCalleeRegisterSlots(int count) {
needs_frame_ = true;
frame_slot_count_ += count;
callee_saved_slot_count_ += count;
}
int AllocateSpillSlot(int width) {
DCHECK_EQ(0, callee_saved_slot_count_);
needs_frame_ = true;
int frame_slot_count_before = frame_slot_count_;
int slot = AllocateAlignedFrameSlot(width);
spill_slot_count_ += (frame_slot_count_ - frame_slot_count_before);
......@@ -146,7 +130,6 @@ class Frame : public ZoneObject {
int ReserveSpillSlots(size_t slot_count) {
DCHECK_EQ(0, callee_saved_slot_count_);
DCHECK_EQ(0, spill_slot_count_);
needs_frame_ = true;
spill_slot_count_ += static_cast<int>(slot_count);
frame_slot_count_ += static_cast<int>(slot_count);
return frame_slot_count_ - 1;
......@@ -168,7 +151,6 @@ class Frame : public ZoneObject {
}
private:
bool needs_frame_;
int frame_slot_count_;
int callee_saved_slot_count_;
int spill_slot_count_;
......@@ -210,23 +192,33 @@ class FrameOffset {
class FrameAccessState : public ZoneObject {
public:
explicit FrameAccessState(Frame* const frame)
: frame_(frame), access_frame_with_fp_(false), sp_delta_(0) {
SetFrameAccessToDefault();
}
: frame_(frame),
access_frame_with_fp_(false),
sp_delta_(0),
has_frame_(false) {}
Frame* frame() const { return frame_; }
void MarkHasFrame(bool state);
int sp_delta() const { return sp_delta_; }
void ClearSPDelta() { sp_delta_ = 0; }
void IncreaseSPDelta(int amount) { sp_delta_ += amount; }
bool access_frame_with_fp() const { return access_frame_with_fp_; }
// Regardless of how we access slots on the stack - using sp or fp - do we
// have a frame, at the current stage in code generation.
bool has_frame() const { return has_frame_; }
void SetFrameAccessToDefault();
void SetFrameAccessToFP() { access_frame_with_fp_ = true; }
void SetFrameAccessToSP() { access_frame_with_fp_ = false; }
int GetSPToFPSlotCount() const {
return frame_->GetSPToFPSlotCount() + sp_delta();
int frame_slot_count =
(has_frame() ? frame()->GetTotalFrameSlotCount() : kElidedFrameSlots) -
StandardFrameConstants::kFixedSlotCountAboveFp;
return frame_slot_count + sp_delta();
}
int GetSPToFPOffset() const { return GetSPToFPSlotCount() * kPointerSize; }
......@@ -240,6 +232,7 @@ class FrameAccessState : public ZoneObject {
Frame* const frame_;
bool access_frame_with_fp_;
int sp_delta_;
bool has_frame_;
};
} // namespace compiler
} // namespace internal
......
......@@ -330,6 +330,12 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
__ bind(&done); \
} while (false)
void CodeGenerator::AssembleDeconstructFrame() {
__ mov(esp, ebp);
__ pop(ebp);
}
void CodeGenerator::AssembleSetupStackPointer() {}
void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) {
int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
......@@ -346,7 +352,7 @@ void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) {
__ sub(esp, Immediate(-sp_slot_delta * kPointerSize));
frame_access_state()->IncreaseSPDelta(-sp_slot_delta);
}
if (frame()->needs_frame()) {
if (frame_access_state()->has_frame()) {
__ mov(ebp, MemOperand(ebp, 0));
}
frame_access_state()->SetFrameAccessToSP();
......@@ -514,7 +520,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
__ mov(i.OutputRegister(), ebp);
break;
case kArchParentFramePointer:
if (frame_access_state()->frame()->needs_frame()) {
if (frame_access_state()->has_frame()) {
__ mov(i.OutputRegister(), Operand(ebp, 0));
} else {
__ mov(i.OutputRegister(), ebp);
......@@ -1607,7 +1613,7 @@ void CodeGenerator::AssembleDeoptimizerCall(
void CodeGenerator::AssemblePrologue() {
CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
if (frame()->needs_frame()) {
if (frame_access_state()->has_frame()) {
if (descriptor->IsCFunctionCall()) {
__ push(ebp);
__ mov(ebp, esp);
......@@ -1616,11 +1622,7 @@ void CodeGenerator::AssemblePrologue() {
} else {
__ StubPrologue(info()->GetOutputStackFrameType());
}
} else {
frame()->SetElidedFrameSizeInSlots(kPCOnStackSize / kPointerSize);
}
frame_access_state()->SetFrameAccessToDefault();
int stack_shrink_slots = frame()->GetSpillSlotCount();
if (info()->is_osr()) {
// TurboFan OSR-compiled functions cannot be entered directly.
......@@ -1666,17 +1668,15 @@ void CodeGenerator::AssembleReturn() {
}
if (descriptor->IsCFunctionCall()) {
__ mov(esp, ebp); // Move stack pointer back to frame pointer.
__ pop(ebp); // Pop caller's frame pointer.
} else if (frame()->needs_frame()) {
AssembleDeconstructFrame();
} else if (frame_access_state()->has_frame()) {
// Canonicalize JSFunction return sites for now.
if (return_label_.is_bound()) {
__ jmp(&return_label_);
return;
} else {
__ bind(&return_label_);
__ mov(esp, ebp); // Move stack pointer back to frame pointer.
__ pop(ebp); // Pop caller's frame pointer.
AssembleDeconstructFrame();
}
}
size_t pop_size = descriptor->StackParameterCount() * kPointerSize;
......
......@@ -1190,7 +1190,6 @@ void InstructionSelector::VisitLoadStackPointer(Node* node) {
void InstructionSelector::VisitLoadFramePointer(Node* node) {
OperandGenerator g(this);
frame_->MarkNeedsFrame();
Emit(kArchFramePointer, g.DefineAsRegister(node));
}
......
......@@ -812,6 +812,23 @@ class Instruction final {
OutputCount() == 0 && TempCount() == 0;
}
bool IsDeoptimizeCall() const {
return arch_opcode() == ArchOpcode::kArchDeoptimize ||
FlagsModeField::decode(opcode()) == kFlags_deoptimize;
}
bool IsJump() const { return arch_opcode() == ArchOpcode::kArchJmp; }
bool IsRet() const { return arch_opcode() == ArchOpcode::kArchRet; }
bool IsTailCall() const {
return arch_opcode() == ArchOpcode::kArchTailCallCodeObject ||
arch_opcode() == ArchOpcode::kArchTailCallCodeObjectFromJSFunction ||
arch_opcode() == ArchOpcode::kArchTailCallJSFunction ||
arch_opcode() == ArchOpcode::kArchTailCallJSFunctionFromJSFunction;
}
bool IsThrow() const {
return arch_opcode() == ArchOpcode::kArchThrowTerminator;
}
enum GapPosition {
START,
END,
......
......@@ -96,7 +96,9 @@ bool JumpThreading::ComputeForwarding(Zone* local_zone,
// the frame at start. So we should move the decision of whether
// to build a frame or not in the register allocator, and trickle it
// here and to the code generator.
if (frame_at_start || !block->must_deconstruct_frame()) {
if (frame_at_start ||
!(block->must_deconstruct_frame() ||
block->must_construct_frame())) {
fw = code->InputRpo(instr, 0);
}
fallthru = false;
......
......@@ -224,7 +224,8 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
value_(value),
scratch0_(scratch0),
scratch1_(scratch1),
mode_(mode) {}
mode_(mode),
must_save_lr_(!gen->frame_access_state()->has_frame()) {}
void Generate() final {
if (mode_ > RecordWriteMode::kValueIsPointer) {
......@@ -238,7 +239,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
: OMIT_REMEMBERED_SET;
SaveFPRegsMode const save_fp_mode =
frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
if (!frame()->needs_frame()) {
if (must_save_lr_) {
// We need to save and restore ra if the frame was elided.
__ Push(ra);
}
......@@ -246,7 +247,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
remembered_set_action, save_fp_mode);
__ Addu(scratch1_, object_, index_);
__ CallStub(&stub);
if (!frame()->needs_frame()) {
if (must_save_lr_) {
__ Pop(ra);
}
}
......@@ -258,6 +259,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
Register const scratch0_;
Register const scratch1_;
RecordWriteMode const mode_;
bool must_save_lr_;
};
......@@ -470,6 +472,13 @@ FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate,
__ bind(&done); \
}
void CodeGenerator::AssembleDeconstructFrame() {
__ mov(sp, fp);
__ Pop(ra, fp);
}
void CodeGenerator::AssembleSetupStackPointer() {}
void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) {
int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
if (sp_slot_delta > 0) {
......@@ -485,7 +494,7 @@ void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) {
__ Subu(sp, sp, Operand(-sp_slot_delta * kPointerSize));
frame_access_state()->IncreaseSPDelta(-sp_slot_delta);
}
if (frame()->needs_frame()) {
if (frame_access_state()->has_frame()) {
__ lw(ra, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
__ lw(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
}
......@@ -645,7 +654,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
__ mov(i.OutputRegister(), fp);
break;
case kArchParentFramePointer:
if (frame_access_state()->frame()->needs_frame()) {
if (frame_access_state()->has_frame()) {
__ lw(i.OutputRegister(), MemOperand(fp, 0));
} else {
__ mov(i.OutputRegister(), fp);
......@@ -1564,7 +1573,7 @@ void CodeGenerator::AssembleDeoptimizerCall(
void CodeGenerator::AssemblePrologue() {
CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
int stack_shrink_slots = frame()->GetSpillSlotCount();
if (frame()->needs_frame()) {
if (frame_access_state()->has_frame()) {
if (descriptor->IsCFunctionCall()) {
__ Push(ra, fp);
__ mov(fp, sp);
......@@ -1573,10 +1582,7 @@ void CodeGenerator::AssemblePrologue() {
} else {
__ StubPrologue(info()->GetOutputStackFrameType());
}
} else {
frame()->SetElidedFrameSizeInSlots(0);
}
frame_access_state()->SetFrameAccessToDefault();
if (info()->is_osr()) {
// TurboFan OSR-compiled functions cannot be entered directly.
......@@ -1638,17 +1644,15 @@ void CodeGenerator::AssembleReturn() {
}
if (descriptor->IsCFunctionCall()) {
__ mov(sp, fp);
__ Pop(ra, fp);
} else if (frame()->needs_frame()) {
AssembleDeconstructFrame();
} else if (frame_access_state()->has_frame()) {
// Canonicalize JSFunction return sites for now.
if (return_label_.is_bound()) {
__ Branch(&return_label_);
return;
} else {
__ bind(&return_label_);
__ mov(sp, fp);
__ Pop(ra, fp);
AssembleDeconstructFrame();
}
}
if (pop_count != 0) {
......
......@@ -224,7 +224,8 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
value_(value),
scratch0_(scratch0),
scratch1_(scratch1),
mode_(mode) {}
mode_(mode),
must_save_lr_(gen->frame_access_state()->has_frame()) {}
void Generate() final {
if (mode_ > RecordWriteMode::kValueIsPointer) {
......@@ -238,7 +239,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
: OMIT_REMEMBERED_SET;
SaveFPRegsMode const save_fp_mode =
frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
if (!frame()->needs_frame()) {
if (must_save_lr_) {
// We need to save and restore ra if the frame was elided.
__ Push(ra);
}
......@@ -246,7 +247,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
remembered_set_action, save_fp_mode);
__ Daddu(scratch1_, object_, index_);
__ CallStub(&stub);
if (!frame()->needs_frame()) {
if (must_save_lr_) {
__ Pop(ra);
}
}
......@@ -258,6 +259,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
Register const scratch0_;
Register const scratch1_;
RecordWriteMode const mode_;
bool must_save_lr_;
};
......@@ -482,6 +484,13 @@ FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate,
__ bind(&done); \
}
void CodeGenerator::AssembleDeconstructFrame() {
__ mov(sp, fp);
__ Pop(ra, fp);
}
void CodeGenerator::AssembleSetupStackPointer() {}
void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) {
int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
if (sp_slot_delta > 0) {
......@@ -497,7 +506,7 @@ void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) {
__ Dsubu(sp, sp, Operand(-sp_slot_delta * kPointerSize));
frame_access_state()->IncreaseSPDelta(-sp_slot_delta);
}
if (frame()->needs_frame()) {
if (frame_access_state()->has_frame()) {
__ ld(ra, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
__ ld(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
}
......@@ -655,7 +664,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
__ mov(i.OutputRegister(), fp);
break;
case kArchParentFramePointer:
if (frame_access_state()->frame()->needs_frame()) {
if (frame_access_state()->has_frame()) {
__ ld(i.OutputRegister(), MemOperand(fp, 0));
} else {
__ mov(i.OutputRegister(), fp);
......@@ -1870,7 +1879,7 @@ void CodeGenerator::AssembleDeoptimizerCall(
void CodeGenerator::AssemblePrologue() {
CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
if (frame()->needs_frame()) {
if (frame_access_state()->has_frame()) {
if (descriptor->IsCFunctionCall()) {
__ Push(ra, fp);
__ mov(fp, sp);
......@@ -1879,10 +1888,7 @@ void CodeGenerator::AssemblePrologue() {
} else {
__ StubPrologue(info()->GetOutputStackFrameType());
}
} else {
frame()->SetElidedFrameSizeInSlots(0);
}
frame_access_state()->SetFrameAccessToDefault();
int stack_shrink_slots = frame()->GetSpillSlotCount();
if (info()->is_osr()) {
......@@ -1941,17 +1947,15 @@ void CodeGenerator::AssembleReturn() {
}
if (descriptor->IsCFunctionCall()) {
__ mov(sp, fp);
__ Pop(ra, fp);
} else if (frame()->needs_frame()) {
AssembleDeconstructFrame();
} else if (frame_access_state()->has_frame()) {
// Canonicalize JSFunction return sites for now.
if (return_label_.is_bound()) {
__ Branch(&return_label_);
return;
} else {
__ bind(&return_label_);
__ mov(sp, fp);
__ Pop(ra, fp);
AssembleDeconstructFrame();
}
}
int pop_count = static_cast<int>(descriptor->StackParameterCount());
......
......@@ -276,6 +276,9 @@ class PipelineData {
info()->isolate(), instruction_zone(), instruction_blocks);
if (descriptor && descriptor->RequiresFrameAsIncoming()) {
sequence_->instruction_blocks()[0]->mark_needs_frame();
} else {
DCHECK_EQ(0, descriptor->CalleeSavedFPRegisters());
DCHECK_EQ(0, descriptor->CalleeSavedRegisters());
}
}
......@@ -1370,6 +1373,7 @@ Handle<Code> Pipeline::ScheduleAndGenerateCode(
AllocateRegisters(
RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN),
call_descriptor, run_verifier);
Run<FrameElisionPhase>();
if (data->compilation_failed()) {
info()->AbortOptimization(kNotEnoughVirtualRegistersRegalloc);
return Handle<Code>();
......@@ -1378,11 +1382,7 @@ Handle<Code> Pipeline::ScheduleAndGenerateCode(
BeginPhaseKind("code generation");
// TODO(mtrofin): move this off to the register allocator.
bool generate_frame_at_start =
!FLAG_turbo_frame_elision || !data_->info()->IsStub() ||
!data_->frame()->needs_frame() ||
data_->sequence()->instruction_blocks().front()->needs_frame() ||
linkage.GetIncomingDescriptor()->CalleeSavedFPRegisters() != 0 ||
linkage.GetIncomingDescriptor()->CalleeSavedRegisters() != 0;
data_->sequence()->instruction_blocks().front()->must_construct_frame();
// Optimimize jumps.
if (FLAG_turbo_jt) {
Run<JumpThreadingPhase>(generate_frame_at_start);
......@@ -1502,7 +1502,6 @@ void Pipeline::AllocateRegisters(const RegisterConfiguration* config,
}
Run<LocateSpillSlotsPhase>();
Run<FrameElisionPhase>();
if (FLAG_trace_turbo_graph) {
OFStream os(stdout);
......
......@@ -602,6 +602,12 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
} \
} while (false)
void CodeGenerator::AssembleDeconstructFrame() {
__ movq(rsp, rbp);
__ popq(rbp);
}
void CodeGenerator::AssembleSetupStackPointer() {}
void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) {
int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
......@@ -618,7 +624,7 @@ void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) {
__ subq(rsp, Immediate(-sp_slot_delta * kPointerSize));
frame_access_state()->IncreaseSPDelta(-sp_slot_delta);
}
if (frame()->needs_frame()) {
if (frame_access_state()->has_frame()) {
__ movq(rbp, MemOperand(rbp, 0));
}
frame_access_state()->SetFrameAccessToSP();
......@@ -775,7 +781,7 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
__ movq(i.OutputRegister(), rbp);
break;
case kArchParentFramePointer:
if (frame_access_state()->frame()->needs_frame()) {
if (frame_access_state()->has_frame()) {
__ movq(i.OutputRegister(), Operand(rbp, 0));
} else {
__ movq(i.OutputRegister(), rbp);
......@@ -1929,7 +1935,7 @@ static const int kQuadWordSize = 16;
void CodeGenerator::AssemblePrologue() {
CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
if (frame()->needs_frame()) {
if (frame_access_state()->has_frame()) {
if (descriptor->IsCFunctionCall()) {
__ pushq(rbp);
__ movq(rbp, rsp);
......@@ -1938,11 +1944,7 @@ void CodeGenerator::AssemblePrologue() {
} else {
__ StubPrologue(info()->GetOutputStackFrameType());
}
} else {
frame()->SetElidedFrameSizeInSlots(kPCOnStackSize / kPointerSize);
}
frame_access_state()->SetFrameAccessToDefault();
int stack_shrink_slots = frame()->GetSpillSlotCount();
if (info()->is_osr()) {
// TurboFan OSR-compiled functions cannot be entered directly.
......@@ -2022,17 +2024,15 @@ void CodeGenerator::AssembleReturn() {
}
if (descriptor->IsCFunctionCall()) {
__ movq(rsp, rbp); // Move stack pointer back to frame pointer.
__ popq(rbp); // Pop caller's frame pointer.
} else if (frame()->needs_frame()) {
AssembleDeconstructFrame();
} else if (frame_access_state()->has_frame()) {
// Canonicalize JSFunction return sites for now.
if (return_label_.is_bound()) {
__ jmp(&return_label_);
return;
} else {
__ bind(&return_label_);
__ movq(rsp, rbp); // Move stack pointer back to frame pointer.
__ popq(rbp); // Pop caller's frame pointer.
AssembleDeconstructFrame();
}
}
size_t pop_size = descriptor->StackParameterCount() * kPointerSize;
......
......@@ -124,6 +124,11 @@ const int kFloatSize = sizeof(float); // NOLINT
const int kDoubleSize = sizeof(double); // NOLINT
const int kIntptrSize = sizeof(intptr_t); // NOLINT
const int kPointerSize = sizeof(void*); // NOLINT
#if V8_TARGET_ARCH_ARM64
const int kFrameAlignmentInBytes = 2 * kPointerSize;
#else
const int kFrameAlignmentInBytes = kPointerSize;
#endif
#if V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_32_BIT
const int kRegisterSize = kPointerSize + kPointerSize;
#else
......@@ -132,6 +137,12 @@ const int kRegisterSize = kPointerSize;
const int kPCOnStackSize = kRegisterSize;
const int kFPOnStackSize = kRegisterSize;
#if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_IA32
const int kElidedFrameSlots = kPCOnStackSize / kPointerSize;
#else
const int kElidedFrameSlots = 0;
#endif
const int kDoubleSizeLog2 = 3;
#if V8_HOST_ARCH_64_BIT
......
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