[turbofan] Add an operator to access the parent frame pointer
This functionality is useful for stubs that need to walk the stack. The new machine operator, LoadParentFramePointer dosn't force the currently compiling method to have a frame in contrast to LoadFramePointer. Instead, it adapts accordingly when frame elision is possible, making efficient stack walks possible without incurring a performance penalty for small stubs that can benefit from frame elision. R=bmeurer@chromium.org LOG=N Review URL: https://codereview.chromium.org/1695313002 Cr-Commit-Position: refs/heads/master@{#34014}
This commit is contained in:
parent
d99cbb7a74
commit
fd8fd05cc5
@ -533,6 +533,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
|||||||
__ mov(i.OutputRegister(), fp);
|
__ mov(i.OutputRegister(), fp);
|
||||||
DCHECK_EQ(LeaveCC, i.OutputSBit());
|
DCHECK_EQ(LeaveCC, i.OutputSBit());
|
||||||
break;
|
break;
|
||||||
|
case kArchParentFramePointer:
|
||||||
|
if (frame_access_state()->frame()->needs_frame()) {
|
||||||
|
__ ldr(i.OutputRegister(), MemOperand(fp, 0));
|
||||||
|
} else {
|
||||||
|
__ mov(i.OutputRegister(), fp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case kArchTruncateDoubleToI:
|
case kArchTruncateDoubleToI:
|
||||||
__ TruncateDoubleToI(i.OutputRegister(), i.InputFloat64Register(0));
|
__ TruncateDoubleToI(i.OutputRegister(), i.InputFloat64Register(0));
|
||||||
DCHECK_EQ(LeaveCC, i.OutputSBit());
|
DCHECK_EQ(LeaveCC, i.OutputSBit());
|
||||||
|
@ -626,6 +626,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
|||||||
case kArchFramePointer:
|
case kArchFramePointer:
|
||||||
__ mov(i.OutputRegister(), fp);
|
__ mov(i.OutputRegister(), fp);
|
||||||
break;
|
break;
|
||||||
|
case kArchParentFramePointer:
|
||||||
|
if (frame_access_state()->frame()->needs_frame()) {
|
||||||
|
__ ldr(i.OutputRegister(), MemOperand(fp, 0));
|
||||||
|
} else {
|
||||||
|
__ mov(i.OutputRegister(), fp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case kArchTruncateDoubleToI:
|
case kArchTruncateDoubleToI:
|
||||||
__ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
|
__ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
|
||||||
break;
|
break;
|
||||||
|
@ -103,6 +103,10 @@ Node* CodeStubAssembler::LoadFramePointer() {
|
|||||||
return raw_assembler_->LoadFramePointer();
|
return raw_assembler_->LoadFramePointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Node* CodeStubAssembler::LoadParentFramePointer() {
|
||||||
|
return raw_assembler_->LoadParentFramePointer();
|
||||||
|
}
|
||||||
|
|
||||||
Node* CodeStubAssembler::LoadStackPointer() {
|
Node* CodeStubAssembler::LoadStackPointer() {
|
||||||
return raw_assembler_->LoadStackPointer();
|
return raw_assembler_->LoadStackPointer();
|
||||||
}
|
}
|
||||||
|
@ -471,6 +471,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
|||||||
case kArchFramePointer:
|
case kArchFramePointer:
|
||||||
__ mov(i.OutputRegister(), ebp);
|
__ mov(i.OutputRegister(), ebp);
|
||||||
break;
|
break;
|
||||||
|
case kArchParentFramePointer:
|
||||||
|
if (frame_access_state()->frame()->needs_frame()) {
|
||||||
|
__ mov(i.OutputRegister(), Operand(ebp, 0));
|
||||||
|
} else {
|
||||||
|
__ mov(i.OutputRegister(), ebp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case kArchTruncateDoubleToI: {
|
case kArchTruncateDoubleToI: {
|
||||||
auto result = i.OutputRegister();
|
auto result = i.OutputRegister();
|
||||||
auto input = i.InputDoubleRegister(0);
|
auto input = i.InputDoubleRegister(0);
|
||||||
|
@ -57,6 +57,7 @@ enum class RecordWriteMode { kValueIsMap, kValueIsPointer, kValueIsAny };
|
|||||||
V(ArchRet) \
|
V(ArchRet) \
|
||||||
V(ArchStackPointer) \
|
V(ArchStackPointer) \
|
||||||
V(ArchFramePointer) \
|
V(ArchFramePointer) \
|
||||||
|
V(ArchParentFramePointer) \
|
||||||
V(ArchTruncateDoubleToI) \
|
V(ArchTruncateDoubleToI) \
|
||||||
V(ArchStoreWithWriteBarrier) \
|
V(ArchStoreWithWriteBarrier) \
|
||||||
V(CheckedLoadInt8) \
|
V(CheckedLoadInt8) \
|
||||||
|
@ -174,6 +174,7 @@ int InstructionScheduler::GetInstructionFlags(const Instruction* instr) const {
|
|||||||
case kArchNop:
|
case kArchNop:
|
||||||
case kArchStackPointer:
|
case kArchStackPointer:
|
||||||
case kArchFramePointer:
|
case kArchFramePointer:
|
||||||
|
case kArchParentFramePointer:
|
||||||
case kArchTruncateDoubleToI:
|
case kArchTruncateDoubleToI:
|
||||||
case kArchStackSlot:
|
case kArchStackSlot:
|
||||||
return kNoOpcodeFlags;
|
return kNoOpcodeFlags;
|
||||||
|
@ -1077,6 +1077,8 @@ void InstructionSelector::VisitNode(Node* node) {
|
|||||||
return VisitLoadStackPointer(node);
|
return VisitLoadStackPointer(node);
|
||||||
case IrOpcode::kLoadFramePointer:
|
case IrOpcode::kLoadFramePointer:
|
||||||
return VisitLoadFramePointer(node);
|
return VisitLoadFramePointer(node);
|
||||||
|
case IrOpcode::kLoadParentFramePointer:
|
||||||
|
return VisitLoadParentFramePointer(node);
|
||||||
case IrOpcode::kCheckedLoad: {
|
case IrOpcode::kCheckedLoad: {
|
||||||
MachineRepresentation rep =
|
MachineRepresentation rep =
|
||||||
CheckedLoadRepresentationOf(node->op()).representation();
|
CheckedLoadRepresentationOf(node->op()).representation();
|
||||||
@ -1101,9 +1103,14 @@ void InstructionSelector::VisitLoadStackPointer(Node* node) {
|
|||||||
|
|
||||||
void InstructionSelector::VisitLoadFramePointer(Node* node) {
|
void InstructionSelector::VisitLoadFramePointer(Node* node) {
|
||||||
OperandGenerator g(this);
|
OperandGenerator g(this);
|
||||||
|
frame_->MarkNeedsFrame();
|
||||||
Emit(kArchFramePointer, g.DefineAsRegister(node));
|
Emit(kArchFramePointer, g.DefineAsRegister(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InstructionSelector::VisitLoadParentFramePointer(Node* node) {
|
||||||
|
OperandGenerator g(this);
|
||||||
|
Emit(kArchParentFramePointer, g.DefineAsRegister(node));
|
||||||
|
}
|
||||||
|
|
||||||
void InstructionSelector::EmitTableSwitch(const SwitchInfo& sw,
|
void InstructionSelector::EmitTableSwitch(const SwitchInfo& sw,
|
||||||
InstructionOperand& index_operand) {
|
InstructionOperand& index_operand) {
|
||||||
|
@ -194,7 +194,8 @@ MachineRepresentation StackSlotRepresentationOf(Operator const* op) {
|
|||||||
V(Float64InsertLowWord32, Operator::kNoProperties, 2, 0, 1) \
|
V(Float64InsertLowWord32, Operator::kNoProperties, 2, 0, 1) \
|
||||||
V(Float64InsertHighWord32, Operator::kNoProperties, 2, 0, 1) \
|
V(Float64InsertHighWord32, Operator::kNoProperties, 2, 0, 1) \
|
||||||
V(LoadStackPointer, Operator::kNoProperties, 0, 0, 1) \
|
V(LoadStackPointer, Operator::kNoProperties, 0, 0, 1) \
|
||||||
V(LoadFramePointer, Operator::kNoProperties, 0, 0, 1)
|
V(LoadFramePointer, Operator::kNoProperties, 0, 0, 1) \
|
||||||
|
V(LoadParentFramePointer, Operator::kNoProperties, 0, 0, 1)
|
||||||
|
|
||||||
#define PURE_OPTIONAL_OP_LIST(V) \
|
#define PURE_OPTIONAL_OP_LIST(V) \
|
||||||
V(Word32Ctz, Operator::kNoProperties, 1, 0, 1) \
|
V(Word32Ctz, Operator::kNoProperties, 1, 0, 1) \
|
||||||
|
@ -313,6 +313,7 @@ class MachineOperatorBuilder final : public ZoneObject {
|
|||||||
// Access to the machine stack.
|
// Access to the machine stack.
|
||||||
const Operator* LoadStackPointer();
|
const Operator* LoadStackPointer();
|
||||||
const Operator* LoadFramePointer();
|
const Operator* LoadFramePointer();
|
||||||
|
const Operator* LoadParentFramePointer();
|
||||||
|
|
||||||
// checked-load heap, index, length
|
// checked-load heap, index, length
|
||||||
const Operator* CheckedLoad(CheckedLoadRepresentation);
|
const Operator* CheckedLoad(CheckedLoadRepresentation);
|
||||||
|
@ -604,6 +604,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
|||||||
case kArchFramePointer:
|
case kArchFramePointer:
|
||||||
__ mov(i.OutputRegister(), fp);
|
__ mov(i.OutputRegister(), fp);
|
||||||
break;
|
break;
|
||||||
|
case kArchParentFramePointer:
|
||||||
|
if (frame_access_state()->frame()->needs_frame()) {
|
||||||
|
__ lw(i.OutputRegister(), MemOperand(fp, 0));
|
||||||
|
} else {
|
||||||
|
__ mov(i.OutputRegister(), fp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case kArchTruncateDoubleToI:
|
case kArchTruncateDoubleToI:
|
||||||
__ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
|
__ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
|
||||||
break;
|
break;
|
||||||
|
@ -614,6 +614,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
|||||||
case kArchFramePointer:
|
case kArchFramePointer:
|
||||||
__ mov(i.OutputRegister(), fp);
|
__ mov(i.OutputRegister(), fp);
|
||||||
break;
|
break;
|
||||||
|
case kArchParentFramePointer:
|
||||||
|
if (frame_access_state()->frame()->needs_frame()) {
|
||||||
|
__ lw(i.OutputRegister(), MemOperand(fp, 0));
|
||||||
|
} else {
|
||||||
|
__ mov(i.OutputRegister(), fp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case kArchTruncateDoubleToI:
|
case kArchTruncateDoubleToI:
|
||||||
__ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
|
__ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
|
||||||
break;
|
break;
|
||||||
|
@ -326,6 +326,7 @@
|
|||||||
V(Float64InsertHighWord32) \
|
V(Float64InsertHighWord32) \
|
||||||
V(LoadStackPointer) \
|
V(LoadStackPointer) \
|
||||||
V(LoadFramePointer) \
|
V(LoadFramePointer) \
|
||||||
|
V(LoadParentFramePointer) \
|
||||||
V(CheckedLoad) \
|
V(CheckedLoad) \
|
||||||
V(CheckedStore)
|
V(CheckedStore)
|
||||||
|
|
||||||
|
@ -566,6 +566,9 @@ class RawMachineAssembler {
|
|||||||
// Stack operations.
|
// Stack operations.
|
||||||
Node* LoadStackPointer() { return AddNode(machine()->LoadStackPointer()); }
|
Node* LoadStackPointer() { return AddNode(machine()->LoadStackPointer()); }
|
||||||
Node* LoadFramePointer() { return AddNode(machine()->LoadFramePointer()); }
|
Node* LoadFramePointer() { return AddNode(machine()->LoadFramePointer()); }
|
||||||
|
Node* LoadParentFramePointer() {
|
||||||
|
return AddNode(machine()->LoadParentFramePointer());
|
||||||
|
}
|
||||||
|
|
||||||
// Parameters.
|
// Parameters.
|
||||||
Node* Parameter(size_t index);
|
Node* Parameter(size_t index);
|
||||||
|
@ -1409,6 +1409,7 @@ class RepresentationSelector {
|
|||||||
NodeOutputInfo::Float64());
|
NodeOutputInfo::Float64());
|
||||||
case IrOpcode::kLoadStackPointer:
|
case IrOpcode::kLoadStackPointer:
|
||||||
case IrOpcode::kLoadFramePointer:
|
case IrOpcode::kLoadFramePointer:
|
||||||
|
case IrOpcode::kLoadParentFramePointer:
|
||||||
return VisitLeaf(node, NodeOutputInfo::Pointer());
|
return VisitLeaf(node, NodeOutputInfo::Pointer());
|
||||||
case IrOpcode::kStateValues:
|
case IrOpcode::kStateValues:
|
||||||
VisitStateValues(node);
|
VisitStateValues(node);
|
||||||
|
@ -2405,6 +2405,9 @@ Type* Typer::Visitor::TypeLoadFramePointer(Node* node) {
|
|||||||
return Type::Internal();
|
return Type::Internal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type* Typer::Visitor::TypeLoadParentFramePointer(Node* node) {
|
||||||
|
return Type::Internal();
|
||||||
|
}
|
||||||
|
|
||||||
Type* Typer::Visitor::TypeCheckedLoad(Node* node) { return Type::Any(); }
|
Type* Typer::Visitor::TypeCheckedLoad(Node* node) { return Type::Any(); }
|
||||||
|
|
||||||
|
@ -945,6 +945,7 @@ void Verifier::Visitor::Check(Node* node) {
|
|||||||
case IrOpcode::kFloat64InsertHighWord32:
|
case IrOpcode::kFloat64InsertHighWord32:
|
||||||
case IrOpcode::kLoadStackPointer:
|
case IrOpcode::kLoadStackPointer:
|
||||||
case IrOpcode::kLoadFramePointer:
|
case IrOpcode::kLoadFramePointer:
|
||||||
|
case IrOpcode::kLoadParentFramePointer:
|
||||||
case IrOpcode::kCheckedLoad:
|
case IrOpcode::kCheckedLoad:
|
||||||
case IrOpcode::kCheckedStore:
|
case IrOpcode::kCheckedStore:
|
||||||
// TODO(rossberg): Check.
|
// TODO(rossberg): Check.
|
||||||
|
@ -712,6 +712,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
|||||||
case kArchFramePointer:
|
case kArchFramePointer:
|
||||||
__ movq(i.OutputRegister(), rbp);
|
__ movq(i.OutputRegister(), rbp);
|
||||||
break;
|
break;
|
||||||
|
case kArchParentFramePointer:
|
||||||
|
if (frame_access_state()->frame()->needs_frame()) {
|
||||||
|
__ movq(i.OutputRegister(), Operand(rbp, 0));
|
||||||
|
} else {
|
||||||
|
__ movq(i.OutputRegister(), rbp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case kArchTruncateDoubleToI: {
|
case kArchTruncateDoubleToI: {
|
||||||
auto result = i.OutputRegister();
|
auto result = i.OutputRegister();
|
||||||
auto input = i.InputDoubleRegister(0);
|
auto input = i.InputDoubleRegister(0);
|
||||||
|
@ -6196,6 +6196,27 @@ TEST(RunComputedCodeObject) {
|
|||||||
CHECK_EQ(44, r.Call(0));
|
CHECK_EQ(44, r.Call(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ParentFramePointer) {
|
||||||
|
RawMachineAssemblerTester<int32_t> r(MachineType::Int32());
|
||||||
|
RawMachineLabel tlabel;
|
||||||
|
RawMachineLabel flabel;
|
||||||
|
RawMachineLabel merge;
|
||||||
|
Node* frame = r.LoadFramePointer();
|
||||||
|
Node* parent_frame = r.LoadParentFramePointer();
|
||||||
|
frame = r.Load(MachineType::IntPtr(), frame);
|
||||||
|
r.Branch(r.WordEqual(frame, parent_frame), &tlabel, &flabel);
|
||||||
|
r.Bind(&tlabel);
|
||||||
|
Node* fa = r.Int32Constant(1);
|
||||||
|
r.Goto(&merge);
|
||||||
|
r.Bind(&flabel);
|
||||||
|
Node* fb = r.Int32Constant(0);
|
||||||
|
r.Goto(&merge);
|
||||||
|
r.Bind(&merge);
|
||||||
|
Node* phi = r.Phi(MachineRepresentation::kWord32, fa, fb);
|
||||||
|
r.Return(phi);
|
||||||
|
CHECK_EQ(1, r.Call(1));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace compiler
|
} // namespace compiler
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
Loading…
Reference in New Issue
Block a user