Make FrameStates recursive (to be used for inlining).
- Changes FrameState node to require a 5th input (use undefined as sentinel). - Adds outer_state pointer to FrameStateDescriptor. - Instruction selection dumps dependencies of FrameState chain into the instruction. - Code generator builds the translation for rec. FrameStates. (will require further integration tests) R=jarin@chromium.org Review URL: https://codereview.chromium.org/517323002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23595 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
bb6cfbc416
commit
7117cae25e
@ -227,7 +227,8 @@ Node* AstGraphBuilder::Environment::Checkpoint(
|
|||||||
Operator* op = common()->FrameState(ast_id, combine);
|
Operator* op = common()->FrameState(ast_id, combine);
|
||||||
|
|
||||||
return graph()->NewNode(op, parameters_node_, locals_node_, stack_node_,
|
return graph()->NewNode(op, parameters_node_, locals_node_, stack_node_,
|
||||||
GetContext());
|
GetContext(),
|
||||||
|
builder()->jsgraph()->UndefinedConstant());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -260,6 +260,12 @@ class AstGraphBuilder::Environment
|
|||||||
// further mutation of the environment will not affect checkpoints.
|
// further mutation of the environment will not affect checkpoints.
|
||||||
Node* Checkpoint(BailoutId ast_id, OutputFrameStateCombine combine);
|
Node* Checkpoint(BailoutId ast_id, OutputFrameStateCombine combine);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
AstGraphBuilder* builder() const {
|
||||||
|
return reinterpret_cast<AstGraphBuilder*>(
|
||||||
|
StructuredGraphBuilder::Environment::builder());
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void UpdateStateValues(Node** state_values, int offset, int count);
|
void UpdateStateValues(Node** state_values, int offset, int count);
|
||||||
|
|
||||||
|
@ -301,11 +301,16 @@ FrameStateDescriptor* CodeGenerator::GetFrameStateDescriptor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int CodeGenerator::BuildTranslation(Instruction* instr, int frame_state_offset,
|
void CodeGenerator::BuildTranslationForFrameStateDescriptor(
|
||||||
OutputFrameStateCombine state_combine) {
|
FrameStateDescriptor* descriptor, Instruction* instr,
|
||||||
FrameStateDescriptor* descriptor =
|
Translation* translation, int frame_state_offset,
|
||||||
GetFrameStateDescriptor(instr, frame_state_offset);
|
OutputFrameStateCombine state_combine) {
|
||||||
frame_state_offset++;
|
// Outer-most state must be added to translation first.
|
||||||
|
if (descriptor->outer_state() != NULL) {
|
||||||
|
BuildTranslationForFrameStateDescriptor(
|
||||||
|
descriptor->outer_state(), instr, translation,
|
||||||
|
frame_state_offset + descriptor->size(), kIgnoreOutput);
|
||||||
|
}
|
||||||
|
|
||||||
int height = descriptor->size() - descriptor->parameters_count();
|
int height = descriptor->size() - descriptor->parameters_count();
|
||||||
switch (state_combine) {
|
switch (state_combine) {
|
||||||
@ -316,24 +321,35 @@ int CodeGenerator::BuildTranslation(Instruction* instr, int frame_state_offset,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
translation->BeginJSFrame(descriptor->bailout_id(),
|
||||||
Translation translation(&translations_, 1, 1, zone());
|
Translation::kSelfLiteralId, height);
|
||||||
translation.BeginJSFrame(descriptor->bailout_id(),
|
|
||||||
Translation::kSelfLiteralId, height);
|
|
||||||
|
|
||||||
for (int i = 0; i < descriptor->size(); i++) {
|
for (int i = 0; i < descriptor->size(); i++) {
|
||||||
AddTranslationForOperand(&translation, instr,
|
AddTranslationForOperand(translation, instr,
|
||||||
instr->InputAt(i + frame_state_offset));
|
instr->InputAt(i + frame_state_offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (state_combine) {
|
switch (state_combine) {
|
||||||
case kPushOutput:
|
case kPushOutput:
|
||||||
DCHECK(instr->OutputCount() == 1);
|
DCHECK(instr->OutputCount() == 1);
|
||||||
AddTranslationForOperand(&translation, instr, instr->OutputAt(0));
|
AddTranslationForOperand(translation, instr, instr->OutputAt(0));
|
||||||
break;
|
break;
|
||||||
case kIgnoreOutput:
|
case kIgnoreOutput:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int CodeGenerator::BuildTranslation(Instruction* instr, int frame_state_offset,
|
||||||
|
OutputFrameStateCombine state_combine) {
|
||||||
|
FrameStateDescriptor* descriptor =
|
||||||
|
GetFrameStateDescriptor(instr, frame_state_offset);
|
||||||
|
frame_state_offset++;
|
||||||
|
|
||||||
|
int frame_count = descriptor->GetFrameCount();
|
||||||
|
Translation translation(&translations_, frame_count, frame_count, zone());
|
||||||
|
BuildTranslationForFrameStateDescriptor(descriptor, instr, &translation,
|
||||||
|
frame_state_offset, state_combine);
|
||||||
|
|
||||||
int deoptimization_id = static_cast<int>(deoptimization_states_.size());
|
int deoptimization_id = static_cast<int>(deoptimization_states_.size());
|
||||||
|
|
||||||
|
@ -91,6 +91,10 @@ class CodeGenerator FINAL : public GapResolver::Assembler {
|
|||||||
int frame_state_offset);
|
int frame_state_offset);
|
||||||
int BuildTranslation(Instruction* instr, int frame_state_offset,
|
int BuildTranslation(Instruction* instr, int frame_state_offset,
|
||||||
OutputFrameStateCombine state_combine);
|
OutputFrameStateCombine state_combine);
|
||||||
|
void BuildTranslationForFrameStateDescriptor(
|
||||||
|
FrameStateDescriptor* descriptor, Instruction* instr,
|
||||||
|
Translation* translation, int frame_state_offset,
|
||||||
|
OutputFrameStateCombine state_combine);
|
||||||
void AddTranslationForOperand(Translation* translation, Instruction* instr,
|
void AddTranslationForOperand(Translation* translation, Instruction* instr,
|
||||||
InstructionOperand* op);
|
InstructionOperand* op);
|
||||||
void AddNopForSmiCodeInlining();
|
void AddNopForSmiCodeInlining();
|
||||||
|
@ -41,7 +41,7 @@ Node* StructuredGraphBuilder::MakeNode(Operator* op, int value_input_count,
|
|||||||
DCHECK(OperatorProperties::GetEffectInputCount(op) < 2);
|
DCHECK(OperatorProperties::GetEffectInputCount(op) < 2);
|
||||||
|
|
||||||
Node* result = NULL;
|
Node* result = NULL;
|
||||||
if (!has_context && !has_control && !has_effect) {
|
if (!has_context && !has_framestate && !has_control && !has_effect) {
|
||||||
result = graph()->NewNode(op, value_input_count, value_inputs);
|
result = graph()->NewNode(op, value_input_count, value_inputs);
|
||||||
} else {
|
} else {
|
||||||
int input_count_with_deps = value_input_count;
|
int input_count_with_deps = value_input_count;
|
||||||
|
@ -345,7 +345,8 @@ struct CallBuffer {
|
|||||||
int frame_state_value_count() const {
|
int frame_state_value_count() const {
|
||||||
return (frame_state_descriptor == NULL)
|
return (frame_state_descriptor == NULL)
|
||||||
? 0
|
? 0
|
||||||
: (frame_state_descriptor->size() + 1);
|
: (frame_state_descriptor->total_size() +
|
||||||
|
1); // Include deopt id.
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -330,8 +330,9 @@ TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) {
|
|||||||
Node* stack = m.NewNode(m.common()->StateValues(0));
|
Node* stack = m.NewNode(m.common()->StateValues(0));
|
||||||
Node* context_dummy = m.Int32Constant(0);
|
Node* context_dummy = m.Int32Constant(0);
|
||||||
|
|
||||||
Node* state_node = m.NewNode(m.common()->FrameState(bailout_id, kPushOutput),
|
Node* state_node =
|
||||||
parameters, locals, stack, context_dummy);
|
m.NewNode(m.common()->FrameState(bailout_id, kPushOutput), parameters,
|
||||||
|
locals, stack, context_dummy, m.UndefinedConstant());
|
||||||
Node* call = m.CallJS0(function_node, receiver, state_node);
|
Node* call = m.CallJS0(function_node, receiver, state_node);
|
||||||
m.Return(call);
|
m.Return(call);
|
||||||
|
|
||||||
@ -367,10 +368,11 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) {
|
|||||||
Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(43));
|
Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(43));
|
||||||
Node* locals = m.NewNode(m.common()->StateValues(1), m.Int32Constant(44));
|
Node* locals = m.NewNode(m.common()->StateValues(1), m.Int32Constant(44));
|
||||||
Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(45));
|
Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(45));
|
||||||
|
|
||||||
Node* context_sentinel = m.Int32Constant(0);
|
Node* context_sentinel = m.Int32Constant(0);
|
||||||
Node* frame_state_before =
|
Node* frame_state_before = m.NewNode(
|
||||||
m.NewNode(m.common()->FrameState(bailout_id_before, kPushOutput),
|
m.common()->FrameState(bailout_id_before, kPushOutput), parameters,
|
||||||
parameters, locals, stack, context_sentinel);
|
locals, stack, context_sentinel, m.UndefinedConstant());
|
||||||
|
|
||||||
// Build the call.
|
// Build the call.
|
||||||
Node* call = m.CallFunctionStub0(function_node, receiver, context,
|
Node* call = m.CallFunctionStub0(function_node, receiver, context,
|
||||||
@ -426,6 +428,96 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) {
|
|||||||
EXPECT_EQ(index, s.size());
|
EXPECT_EQ(index, s.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TARGET_TEST_F(InstructionSelectorTest,
|
||||||
|
CallFunctionStubDeoptRecursiveFrameState) {
|
||||||
|
StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged, kMachAnyTagged,
|
||||||
|
kMachAnyTagged);
|
||||||
|
|
||||||
|
BailoutId bailout_id_before(42);
|
||||||
|
BailoutId bailout_id_parent(62);
|
||||||
|
|
||||||
|
// Some arguments for the call node.
|
||||||
|
Node* function_node = m.Parameter(0);
|
||||||
|
Node* receiver = m.Parameter(1);
|
||||||
|
Node* context = m.Int32Constant(66);
|
||||||
|
|
||||||
|
// Build frame state for the state before the call.
|
||||||
|
Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(63));
|
||||||
|
Node* locals = m.NewNode(m.common()->StateValues(1), m.Int32Constant(64));
|
||||||
|
Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(65));
|
||||||
|
Node* frame_state_parent =
|
||||||
|
m.NewNode(m.common()->FrameState(bailout_id_parent, kIgnoreOutput),
|
||||||
|
parameters, locals, stack, context, m.UndefinedConstant());
|
||||||
|
|
||||||
|
Node* context2 = m.Int32Constant(46);
|
||||||
|
Node* parameters2 =
|
||||||
|
m.NewNode(m.common()->StateValues(1), m.Int32Constant(43));
|
||||||
|
Node* locals2 = m.NewNode(m.common()->StateValues(1), m.Int32Constant(44));
|
||||||
|
Node* stack2 = m.NewNode(m.common()->StateValues(1), m.Int32Constant(45));
|
||||||
|
Node* frame_state_before =
|
||||||
|
m.NewNode(m.common()->FrameState(bailout_id_before, kPushOutput),
|
||||||
|
parameters2, locals2, stack2, context2, frame_state_parent);
|
||||||
|
|
||||||
|
// Build the call.
|
||||||
|
Node* call = m.CallFunctionStub0(function_node, receiver, context2,
|
||||||
|
frame_state_before, CALL_AS_METHOD);
|
||||||
|
|
||||||
|
m.Return(call);
|
||||||
|
|
||||||
|
Stream s = m.Build(kAllExceptNopInstructions);
|
||||||
|
|
||||||
|
// Skip until kArchCallJSFunction.
|
||||||
|
size_t index = 0;
|
||||||
|
for (; index < s.size() && s[index]->arch_opcode() != kArchCallCodeObject;
|
||||||
|
index++) {
|
||||||
|
}
|
||||||
|
// Now we should have three instructions: call, return.
|
||||||
|
EXPECT_EQ(index + 2, s.size());
|
||||||
|
|
||||||
|
// Check the call instruction
|
||||||
|
const Instruction* call_instr = s[index++];
|
||||||
|
EXPECT_EQ(kArchCallCodeObject, call_instr->arch_opcode());
|
||||||
|
size_t num_operands =
|
||||||
|
1 + // Code object.
|
||||||
|
1 + // Frame state deopt id
|
||||||
|
4 + // One input for each value in frame state + context.
|
||||||
|
4 + // One input for each value in the parent frame state + context.
|
||||||
|
1 + // Function.
|
||||||
|
1; // Context.
|
||||||
|
EXPECT_EQ(num_operands, call_instr->InputCount());
|
||||||
|
// Code object.
|
||||||
|
EXPECT_TRUE(call_instr->InputAt(0)->IsImmediate());
|
||||||
|
|
||||||
|
// Deoptimization id.
|
||||||
|
int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1));
|
||||||
|
FrameStateDescriptor* desc_before =
|
||||||
|
s.GetFrameStateDescriptor(deopt_id_before);
|
||||||
|
EXPECT_EQ(bailout_id_before, desc_before->bailout_id());
|
||||||
|
EXPECT_EQ(1, desc_before->parameters_count());
|
||||||
|
EXPECT_EQ(1, desc_before->locals_count());
|
||||||
|
EXPECT_EQ(1, desc_before->stack_count());
|
||||||
|
EXPECT_EQ(63, s.ToInt32(call_instr->InputAt(2)));
|
||||||
|
// Context:
|
||||||
|
EXPECT_EQ(66, s.ToInt32(call_instr->InputAt(3)));
|
||||||
|
EXPECT_EQ(64, s.ToInt32(call_instr->InputAt(4)));
|
||||||
|
EXPECT_EQ(65, s.ToInt32(call_instr->InputAt(5)));
|
||||||
|
// Values from parent environment should follow.
|
||||||
|
EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(6)));
|
||||||
|
EXPECT_EQ(46, s.ToInt32(call_instr->InputAt(7)));
|
||||||
|
EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(8)));
|
||||||
|
EXPECT_EQ(45, s.ToInt32(call_instr->InputAt(9)));
|
||||||
|
|
||||||
|
// Function.
|
||||||
|
EXPECT_EQ(function_node->id(), s.ToVreg(call_instr->InputAt(10)));
|
||||||
|
// Context.
|
||||||
|
EXPECT_EQ(context2->id(), s.ToVreg(call_instr->InputAt(11)));
|
||||||
|
// Continuation.
|
||||||
|
|
||||||
|
EXPECT_EQ(kArchRet, s[index++]->arch_opcode());
|
||||||
|
EXPECT_EQ(index, s.size());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace compiler
|
} // namespace compiler
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
@ -1001,15 +1001,21 @@ void InstructionSelector::VisitThrow(Node* value) {
|
|||||||
|
|
||||||
FrameStateDescriptor* InstructionSelector::GetFrameStateDescriptor(
|
FrameStateDescriptor* InstructionSelector::GetFrameStateDescriptor(
|
||||||
Node* state) {
|
Node* state) {
|
||||||
DCHECK(state->op()->opcode() == IrOpcode::kFrameState);
|
DCHECK(state->opcode() == IrOpcode::kFrameState);
|
||||||
|
DCHECK_EQ(5, state->InputCount());
|
||||||
FrameStateCallInfo state_info = OpParameter<FrameStateCallInfo>(state);
|
FrameStateCallInfo state_info = OpParameter<FrameStateCallInfo>(state);
|
||||||
Node* parameters = state->InputAt(0);
|
int parameters = OpParameter<int>(state->InputAt(0));
|
||||||
Node* locals = state->InputAt(1);
|
int locals = OpParameter<int>(state->InputAt(1));
|
||||||
Node* stack = state->InputAt(2);
|
int stack = OpParameter<int>(state->InputAt(2));
|
||||||
|
|
||||||
|
FrameStateDescriptor* outer_state = NULL;
|
||||||
|
Node* outer_node = state->InputAt(4);
|
||||||
|
if (outer_node->opcode() == IrOpcode::kFrameState) {
|
||||||
|
outer_state = GetFrameStateDescriptor(outer_node);
|
||||||
|
}
|
||||||
|
|
||||||
return new (instruction_zone())
|
return new (instruction_zone())
|
||||||
FrameStateDescriptor(state_info, OpParameter<int>(parameters),
|
FrameStateDescriptor(state_info, parameters, locals, stack, outer_state);
|
||||||
OpParameter<int>(locals), OpParameter<int>(stack));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1031,6 +1037,10 @@ void InstructionSelector::AddFrameStateInputs(
|
|||||||
FrameStateDescriptor* descriptor) {
|
FrameStateDescriptor* descriptor) {
|
||||||
DCHECK_EQ(IrOpcode::kFrameState, state->op()->opcode());
|
DCHECK_EQ(IrOpcode::kFrameState, state->op()->opcode());
|
||||||
|
|
||||||
|
if (descriptor->outer_state() != NULL) {
|
||||||
|
AddFrameStateInputs(state->InputAt(4), inputs, descriptor->outer_state());
|
||||||
|
}
|
||||||
|
|
||||||
Node* parameters = state->InputAt(0);
|
Node* parameters = state->InputAt(0);
|
||||||
Node* locals = state->InputAt(1);
|
Node* locals = state->InputAt(1);
|
||||||
Node* stack = state->InputAt(2);
|
Node* stack = state->InputAt(2);
|
||||||
|
@ -702,30 +702,55 @@ class Constant FINAL {
|
|||||||
class FrameStateDescriptor : public ZoneObject {
|
class FrameStateDescriptor : public ZoneObject {
|
||||||
public:
|
public:
|
||||||
FrameStateDescriptor(const FrameStateCallInfo& state_info,
|
FrameStateDescriptor(const FrameStateCallInfo& state_info,
|
||||||
int parameters_count, int locals_count, int stack_count)
|
int parameters_count, int locals_count, int stack_count,
|
||||||
|
FrameStateDescriptor* outer_state = NULL)
|
||||||
: bailout_id_(state_info.bailout_id()),
|
: bailout_id_(state_info.bailout_id()),
|
||||||
frame_state_combine_(state_info.state_combine()),
|
frame_state_combine_(state_info.state_combine()),
|
||||||
parameters_count_(parameters_count),
|
parameters_count_(parameters_count),
|
||||||
locals_count_(locals_count),
|
locals_count_(locals_count),
|
||||||
stack_count_(stack_count) {}
|
stack_count_(stack_count),
|
||||||
|
outer_state_(outer_state) {}
|
||||||
|
|
||||||
BailoutId bailout_id() const { return bailout_id_; }
|
BailoutId bailout_id() const { return bailout_id_; }
|
||||||
OutputFrameStateCombine state_combine() const { return frame_state_combine_; }
|
OutputFrameStateCombine state_combine() const { return frame_state_combine_; }
|
||||||
int parameters_count() { return parameters_count_; }
|
int parameters_count() { return parameters_count_; }
|
||||||
int locals_count() { return locals_count_; }
|
int locals_count() { return locals_count_; }
|
||||||
int stack_count() { return stack_count_; }
|
int stack_count() { return stack_count_; }
|
||||||
|
FrameStateDescriptor* outer_state() { return outer_state_; }
|
||||||
|
void set_outer_state(FrameStateDescriptor* outer_state) {
|
||||||
|
outer_state_ = outer_state;
|
||||||
|
}
|
||||||
|
|
||||||
int size() {
|
int size() {
|
||||||
return parameters_count_ + locals_count_ + stack_count_ +
|
return parameters_count_ + locals_count_ + stack_count_ +
|
||||||
1; // Includes context.
|
1; // Includes context.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int total_size() {
|
||||||
|
int total_size = 0;
|
||||||
|
for (FrameStateDescriptor* iter = this; iter != NULL;
|
||||||
|
iter = iter->outer_state_) {
|
||||||
|
total_size += iter->size();
|
||||||
|
}
|
||||||
|
return total_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetFrameCount() {
|
||||||
|
int count = 0;
|
||||||
|
for (FrameStateDescriptor* iter = this; iter != NULL;
|
||||||
|
iter = iter->outer_state_) {
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BailoutId bailout_id_;
|
BailoutId bailout_id_;
|
||||||
OutputFrameStateCombine frame_state_combine_;
|
OutputFrameStateCombine frame_state_combine_;
|
||||||
int parameters_count_;
|
int parameters_count_;
|
||||||
int locals_count_;
|
int locals_count_;
|
||||||
int stack_count_;
|
int stack_count_;
|
||||||
|
FrameStateDescriptor* outer_state_;
|
||||||
};
|
};
|
||||||
|
|
||||||
OStream& operator<<(OStream& os, const Constant& constant);
|
OStream& operator<<(OStream& os, const Constant& constant);
|
||||||
|
@ -77,10 +77,17 @@ typedef NodeVectorVector::reverse_iterator NodeVectorVectorRIter;
|
|||||||
typedef Node::Uses::iterator UseIter;
|
typedef Node::Uses::iterator UseIter;
|
||||||
typedef Node::Inputs::iterator InputIter;
|
typedef Node::Inputs::iterator InputIter;
|
||||||
|
|
||||||
|
// Helper to extract parameters from Operator1<*> operator.
|
||||||
|
template <typename T>
|
||||||
|
static inline T OpParameter(Operator* op) {
|
||||||
|
return reinterpret_cast<Operator1<T>*>(op)->parameter();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Helper to extract parameters from Operator1<*> nodes.
|
// Helper to extract parameters from Operator1<*> nodes.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static inline T OpParameter(Node* node) {
|
static inline T OpParameter(Node* node) {
|
||||||
return reinterpret_cast<Operator1<T>*>(node->op())->parameter();
|
return OpParameter<T>(node->op());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,8 @@ inline bool OperatorProperties::HasFrameStateInput(Operator* op) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (op->opcode()) {
|
switch (op->opcode()) {
|
||||||
|
case IrOpcode::kFrameState:
|
||||||
|
return true;
|
||||||
case IrOpcode::kJSCallRuntime: {
|
case IrOpcode::kJSCallRuntime: {
|
||||||
Runtime::FunctionId function =
|
Runtime::FunctionId function =
|
||||||
reinterpret_cast<Operator1<Runtime::FunctionId>*>(op)->parameter();
|
reinterpret_cast<Operator1<Runtime::FunctionId>*>(op)->parameter();
|
||||||
|
@ -64,6 +64,12 @@ class RawMachineAssembler : public GraphBuilder,
|
|||||||
return call_descriptor_builder_->parameter_types();
|
return call_descriptor_builder_->parameter_types();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Node* UndefinedConstant() {
|
||||||
|
PrintableUnique<Object> unique = PrintableUnique<Object>::CreateImmovable(
|
||||||
|
zone(), isolate()->factory()->undefined_value());
|
||||||
|
return NewNode(common()->HeapConstant(unique));
|
||||||
|
}
|
||||||
|
|
||||||
// Parameters.
|
// Parameters.
|
||||||
Node* Parameter(int index);
|
Node* Parameter(int index);
|
||||||
|
|
||||||
|
@ -114,7 +114,6 @@ class TrivialDeoptCodegenTester : public DeoptCodegenTester {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Schedule* BuildGraphAndSchedule(Graph* graph) {
|
Schedule* BuildGraphAndSchedule(Graph* graph) {
|
||||||
Isolate* isolate = info.isolate();
|
|
||||||
CommonOperatorBuilder common(zone());
|
CommonOperatorBuilder common(zone());
|
||||||
|
|
||||||
// Manually construct a schedule for the function below:
|
// Manually construct a schedule for the function below:
|
||||||
@ -128,12 +127,6 @@ class TrivialDeoptCodegenTester : public DeoptCodegenTester {
|
|||||||
|
|
||||||
RawMachineAssembler m(graph, &descriptor_builder);
|
RawMachineAssembler m(graph, &descriptor_builder);
|
||||||
|
|
||||||
Handle<Object> undef_object =
|
|
||||||
Handle<Object>(isolate->heap()->undefined_value(), isolate);
|
|
||||||
PrintableUnique<Object> undef_constant =
|
|
||||||
PrintableUnique<Object>::CreateUninitialized(zone(), undef_object);
|
|
||||||
Node* undef_node = m.NewNode(common.HeapConstant(undef_constant));
|
|
||||||
|
|
||||||
Handle<JSFunction> deopt_function =
|
Handle<JSFunction> deopt_function =
|
||||||
NewFunction("function deopt() { %DeoptimizeFunction(foo); }; deopt");
|
NewFunction("function deopt() { %DeoptimizeFunction(foo); }; deopt");
|
||||||
PrintableUnique<Object> deopt_fun_constant =
|
PrintableUnique<Object> deopt_fun_constant =
|
||||||
@ -142,16 +135,17 @@ class TrivialDeoptCodegenTester : public DeoptCodegenTester {
|
|||||||
|
|
||||||
|
|
||||||
bailout_id = GetCallBailoutId();
|
bailout_id = GetCallBailoutId();
|
||||||
Node* parameters = m.NewNode(common.StateValues(1), undef_node);
|
Node* parameters = m.NewNode(common.StateValues(1), m.UndefinedConstant());
|
||||||
Node* locals = m.NewNode(common.StateValues(0));
|
Node* locals = m.NewNode(common.StateValues(0));
|
||||||
Node* stack = m.NewNode(common.StateValues(0));
|
Node* stack = m.NewNode(common.StateValues(0));
|
||||||
|
|
||||||
Node* state_node = m.NewNode(common.FrameState(bailout_id, kIgnoreOutput),
|
Node* state_node =
|
||||||
parameters, locals, stack, undef_node);
|
m.NewNode(common.FrameState(bailout_id, kIgnoreOutput), parameters,
|
||||||
|
locals, stack, m.UndefinedConstant(), m.UndefinedConstant());
|
||||||
|
|
||||||
m.CallJS0(deopt_fun_node, undef_node, state_node);
|
m.CallJS0(deopt_fun_node, m.UndefinedConstant(), state_node);
|
||||||
|
|
||||||
m.Return(undef_node);
|
m.Return(m.UndefinedConstant());
|
||||||
|
|
||||||
// Schedule the graph:
|
// Schedule the graph:
|
||||||
Schedule* schedule = m.Export();
|
Schedule* schedule = m.Export();
|
||||||
@ -230,7 +224,6 @@ class TrivialRuntimeDeoptCodegenTester : public DeoptCodegenTester {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Schedule* BuildGraphAndSchedule(Graph* graph) {
|
Schedule* BuildGraphAndSchedule(Graph* graph) {
|
||||||
Isolate* isolate = info.isolate();
|
|
||||||
CommonOperatorBuilder common(zone());
|
CommonOperatorBuilder common(zone());
|
||||||
|
|
||||||
// Manually construct a schedule for the function below:
|
// Manually construct a schedule for the function below:
|
||||||
@ -244,27 +237,22 @@ class TrivialRuntimeDeoptCodegenTester : public DeoptCodegenTester {
|
|||||||
|
|
||||||
RawMachineAssembler m(graph, &descriptor_builder);
|
RawMachineAssembler m(graph, &descriptor_builder);
|
||||||
|
|
||||||
Handle<Object> undef_object =
|
|
||||||
Handle<Object>(isolate->heap()->undefined_value(), isolate);
|
|
||||||
PrintableUnique<Object> undef_constant =
|
|
||||||
PrintableUnique<Object>::CreateUninitialized(zone(), undef_object);
|
|
||||||
Node* undef_node = m.NewNode(common.HeapConstant(undef_constant));
|
|
||||||
|
|
||||||
PrintableUnique<Object> this_fun_constant =
|
PrintableUnique<Object> this_fun_constant =
|
||||||
PrintableUnique<Object>::CreateUninitialized(zone(), function);
|
PrintableUnique<Object>::CreateUninitialized(zone(), function);
|
||||||
Node* this_fun_node = m.NewNode(common.HeapConstant(this_fun_constant));
|
Node* this_fun_node = m.NewNode(common.HeapConstant(this_fun_constant));
|
||||||
|
|
||||||
bailout_id = GetCallBailoutId();
|
bailout_id = GetCallBailoutId();
|
||||||
Node* parameters = m.NewNode(common.StateValues(1), undef_node);
|
Node* parameters = m.NewNode(common.StateValues(1), m.UndefinedConstant());
|
||||||
Node* locals = m.NewNode(common.StateValues(0));
|
Node* locals = m.NewNode(common.StateValues(0));
|
||||||
Node* stack = m.NewNode(common.StateValues(0));
|
Node* stack = m.NewNode(common.StateValues(0));
|
||||||
|
|
||||||
Node* state_node = m.NewNode(common.FrameState(bailout_id, kIgnoreOutput),
|
Node* state_node =
|
||||||
parameters, locals, stack, undef_node);
|
m.NewNode(common.FrameState(bailout_id, kIgnoreOutput), parameters,
|
||||||
|
locals, stack, m.UndefinedConstant(), m.UndefinedConstant());
|
||||||
|
|
||||||
m.CallRuntime1(Runtime::kDeoptimizeFunction, this_fun_node, state_node);
|
m.CallRuntime1(Runtime::kDeoptimizeFunction, this_fun_node, state_node);
|
||||||
|
|
||||||
m.Return(undef_node);
|
m.Return(m.UndefinedConstant());
|
||||||
|
|
||||||
// Schedule the graph:
|
// Schedule the graph:
|
||||||
Schedule* schedule = m.Export();
|
Schedule* schedule = m.Export();
|
||||||
|
Loading…
Reference in New Issue
Block a user