[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:
danno 2016-02-15 23:28:57 -08:00 committed by Commit bot
parent d99cbb7a74
commit fd8fd05cc5
18 changed files with 88 additions and 1 deletions

View File

@ -533,6 +533,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
__ mov(i.OutputRegister(), fp);
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArchParentFramePointer:
if (frame_access_state()->frame()->needs_frame()) {
__ ldr(i.OutputRegister(), MemOperand(fp, 0));
} else {
__ mov(i.OutputRegister(), fp);
}
break;
case kArchTruncateDoubleToI:
__ TruncateDoubleToI(i.OutputRegister(), i.InputFloat64Register(0));
DCHECK_EQ(LeaveCC, i.OutputSBit());

View File

@ -626,6 +626,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
case kArchFramePointer:
__ mov(i.OutputRegister(), fp);
break;
case kArchParentFramePointer:
if (frame_access_state()->frame()->needs_frame()) {
__ ldr(i.OutputRegister(), MemOperand(fp, 0));
} else {
__ mov(i.OutputRegister(), fp);
}
break;
case kArchTruncateDoubleToI:
__ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
break;

View File

@ -103,6 +103,10 @@ Node* CodeStubAssembler::LoadFramePointer() {
return raw_assembler_->LoadFramePointer();
}
Node* CodeStubAssembler::LoadParentFramePointer() {
return raw_assembler_->LoadParentFramePointer();
}
Node* CodeStubAssembler::LoadStackPointer() {
return raw_assembler_->LoadStackPointer();
}

View File

@ -471,6 +471,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
case kArchFramePointer:
__ mov(i.OutputRegister(), ebp);
break;
case kArchParentFramePointer:
if (frame_access_state()->frame()->needs_frame()) {
__ mov(i.OutputRegister(), Operand(ebp, 0));
} else {
__ mov(i.OutputRegister(), ebp);
}
break;
case kArchTruncateDoubleToI: {
auto result = i.OutputRegister();
auto input = i.InputDoubleRegister(0);

View File

@ -57,6 +57,7 @@ enum class RecordWriteMode { kValueIsMap, kValueIsPointer, kValueIsAny };
V(ArchRet) \
V(ArchStackPointer) \
V(ArchFramePointer) \
V(ArchParentFramePointer) \
V(ArchTruncateDoubleToI) \
V(ArchStoreWithWriteBarrier) \
V(CheckedLoadInt8) \

View File

@ -174,6 +174,7 @@ int InstructionScheduler::GetInstructionFlags(const Instruction* instr) const {
case kArchNop:
case kArchStackPointer:
case kArchFramePointer:
case kArchParentFramePointer:
case kArchTruncateDoubleToI:
case kArchStackSlot:
return kNoOpcodeFlags;

View File

@ -1077,6 +1077,8 @@ void InstructionSelector::VisitNode(Node* node) {
return VisitLoadStackPointer(node);
case IrOpcode::kLoadFramePointer:
return VisitLoadFramePointer(node);
case IrOpcode::kLoadParentFramePointer:
return VisitLoadParentFramePointer(node);
case IrOpcode::kCheckedLoad: {
MachineRepresentation rep =
CheckedLoadRepresentationOf(node->op()).representation();
@ -1101,9 +1103,14 @@ void InstructionSelector::VisitLoadStackPointer(Node* node) {
void InstructionSelector::VisitLoadFramePointer(Node* node) {
OperandGenerator g(this);
frame_->MarkNeedsFrame();
Emit(kArchFramePointer, g.DefineAsRegister(node));
}
void InstructionSelector::VisitLoadParentFramePointer(Node* node) {
OperandGenerator g(this);
Emit(kArchParentFramePointer, g.DefineAsRegister(node));
}
void InstructionSelector::EmitTableSwitch(const SwitchInfo& sw,
InstructionOperand& index_operand) {

View File

@ -194,7 +194,8 @@ MachineRepresentation StackSlotRepresentationOf(Operator const* op) {
V(Float64InsertLowWord32, Operator::kNoProperties, 2, 0, 1) \
V(Float64InsertHighWord32, Operator::kNoProperties, 2, 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) \
V(Word32Ctz, Operator::kNoProperties, 1, 0, 1) \

View File

@ -313,6 +313,7 @@ class MachineOperatorBuilder final : public ZoneObject {
// Access to the machine stack.
const Operator* LoadStackPointer();
const Operator* LoadFramePointer();
const Operator* LoadParentFramePointer();
// checked-load heap, index, length
const Operator* CheckedLoad(CheckedLoadRepresentation);

View File

@ -604,6 +604,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
case kArchFramePointer:
__ mov(i.OutputRegister(), fp);
break;
case kArchParentFramePointer:
if (frame_access_state()->frame()->needs_frame()) {
__ lw(i.OutputRegister(), MemOperand(fp, 0));
} else {
__ mov(i.OutputRegister(), fp);
}
break;
case kArchTruncateDoubleToI:
__ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
break;

View File

@ -614,6 +614,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
case kArchFramePointer:
__ mov(i.OutputRegister(), fp);
break;
case kArchParentFramePointer:
if (frame_access_state()->frame()->needs_frame()) {
__ lw(i.OutputRegister(), MemOperand(fp, 0));
} else {
__ mov(i.OutputRegister(), fp);
}
break;
case kArchTruncateDoubleToI:
__ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
break;

View File

@ -326,6 +326,7 @@
V(Float64InsertHighWord32) \
V(LoadStackPointer) \
V(LoadFramePointer) \
V(LoadParentFramePointer) \
V(CheckedLoad) \
V(CheckedStore)

View File

@ -566,6 +566,9 @@ class RawMachineAssembler {
// Stack operations.
Node* LoadStackPointer() { return AddNode(machine()->LoadStackPointer()); }
Node* LoadFramePointer() { return AddNode(machine()->LoadFramePointer()); }
Node* LoadParentFramePointer() {
return AddNode(machine()->LoadParentFramePointer());
}
// Parameters.
Node* Parameter(size_t index);

View File

@ -1409,6 +1409,7 @@ class RepresentationSelector {
NodeOutputInfo::Float64());
case IrOpcode::kLoadStackPointer:
case IrOpcode::kLoadFramePointer:
case IrOpcode::kLoadParentFramePointer:
return VisitLeaf(node, NodeOutputInfo::Pointer());
case IrOpcode::kStateValues:
VisitStateValues(node);

View File

@ -2405,6 +2405,9 @@ Type* Typer::Visitor::TypeLoadFramePointer(Node* node) {
return Type::Internal();
}
Type* Typer::Visitor::TypeLoadParentFramePointer(Node* node) {
return Type::Internal();
}
Type* Typer::Visitor::TypeCheckedLoad(Node* node) { return Type::Any(); }

View File

@ -945,6 +945,7 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kFloat64InsertHighWord32:
case IrOpcode::kLoadStackPointer:
case IrOpcode::kLoadFramePointer:
case IrOpcode::kLoadParentFramePointer:
case IrOpcode::kCheckedLoad:
case IrOpcode::kCheckedStore:
// TODO(rossberg): Check.

View File

@ -712,6 +712,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
case kArchFramePointer:
__ movq(i.OutputRegister(), rbp);
break;
case kArchParentFramePointer:
if (frame_access_state()->frame()->needs_frame()) {
__ movq(i.OutputRegister(), Operand(rbp, 0));
} else {
__ movq(i.OutputRegister(), rbp);
}
break;
case kArchTruncateDoubleToI: {
auto result = i.OutputRegister();
auto input = i.InputDoubleRegister(0);

View File

@ -6196,6 +6196,27 @@ TEST(RunComputedCodeObject) {
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 internal
} // namespace v8