Add deoptimization translations.
BUG= R=bmeurer@chromium.org, mstarzinger@chromium.org Review URL: https://codereview.chromium.org/442253002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22924 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
71857295b4
commit
117945ec6e
@ -172,9 +172,9 @@ AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder,
|
||||
parameters_node_(NULL),
|
||||
locals_node_(NULL),
|
||||
stack_node_(NULL),
|
||||
parameters_dirty_(false),
|
||||
locals_dirty_(false),
|
||||
stack_dirty_(false) {
|
||||
parameters_dirty_(true),
|
||||
locals_dirty_(true),
|
||||
stack_dirty_(true) {
|
||||
DCHECK_EQ(scope->num_parameters() + 1, parameters_count());
|
||||
|
||||
// Bind the receiver variable.
|
||||
@ -210,22 +210,40 @@ AstGraphBuilder::Environment::Environment(const Environment& copy)
|
||||
|
||||
|
||||
Node* AstGraphBuilder::Environment::Checkpoint(BailoutId ast_id) {
|
||||
UNIMPLEMENTED(); // TODO(mstarzinger): Implementation below is incomplete.
|
||||
if (parameters_dirty_) {
|
||||
Operator* op = common()->StateValues(parameters_count());
|
||||
if (parameters_count() != 0) {
|
||||
Node** parameters = &values()->front();
|
||||
parameters_node_ = graph()->NewNode(NULL, parameters_count(), parameters);
|
||||
parameters_node_ = graph()->NewNode(op, parameters_count(), parameters);
|
||||
} else {
|
||||
parameters_node_ = graph()->NewNode(op);
|
||||
}
|
||||
parameters_dirty_ = false;
|
||||
}
|
||||
if (locals_dirty_) {
|
||||
Operator* op = common()->StateValues(locals_count());
|
||||
if (locals_count() != 0) {
|
||||
Node** locals = &values()->at(parameters_count_);
|
||||
locals_node_ = graph()->NewNode(NULL, locals_count(), locals);
|
||||
locals_node_ = graph()->NewNode(op, locals_count(), locals);
|
||||
} else {
|
||||
locals_node_ = graph()->NewNode(op);
|
||||
}
|
||||
locals_dirty_ = false;
|
||||
}
|
||||
FrameStateDescriptor descriptor(ast_id);
|
||||
// TODO(jarin): add environment to the node.
|
||||
Operator* op = common()->FrameState(descriptor);
|
||||
if (stack_dirty_) {
|
||||
Operator* op = common()->StateValues(stack_height());
|
||||
if (stack_height() != 0) {
|
||||
Node** stack = &values()->at(parameters_count_ + locals_count_);
|
||||
stack_node_ = graph()->NewNode(op, stack_height(), stack);
|
||||
} else {
|
||||
stack_node_ = graph()->NewNode(op);
|
||||
}
|
||||
stack_dirty_ = false;
|
||||
}
|
||||
|
||||
return graph()->NewNode(op);
|
||||
Operator* op = common()->FrameState(ast_id);
|
||||
|
||||
return graph()->NewNode(op, parameters_node_, locals_node_, stack_node_);
|
||||
}
|
||||
|
||||
|
||||
@ -1951,8 +1969,7 @@ void AstGraphBuilder::BuildLazyBailout(Node* node, BailoutId ast_id) {
|
||||
|
||||
NewNode(common()->LazyDeoptimization());
|
||||
|
||||
FrameStateDescriptor stateDescriptor(ast_id);
|
||||
Node* state_node = NewNode(common()->FrameState(stateDescriptor));
|
||||
Node* state_node = environment()->Checkpoint(ast_id);
|
||||
|
||||
Node* deoptimize_node = NewNode(common()->Deoptimize(), state_node);
|
||||
|
||||
|
@ -236,6 +236,7 @@ class AstGraphBuilder::Environment
|
||||
DCHECK(stack_height() > 0);
|
||||
Node* back = values()->back();
|
||||
values()->pop_back();
|
||||
stack_dirty_ = true;
|
||||
return back;
|
||||
}
|
||||
|
||||
@ -244,6 +245,7 @@ class AstGraphBuilder::Environment
|
||||
DCHECK(depth >= 0 && depth < stack_height());
|
||||
int index = static_cast<int>(values()->size()) - depth - 1;
|
||||
values()->at(index) = node;
|
||||
stack_dirty_ = true;
|
||||
}
|
||||
Node* Peek(int depth) {
|
||||
DCHECK(depth >= 0 && depth < stack_height());
|
||||
@ -253,6 +255,7 @@ class AstGraphBuilder::Environment
|
||||
void Drop(int depth) {
|
||||
DCHECK(depth >= 0 && depth <= stack_height());
|
||||
values()->erase(values()->end() - depth, values()->end());
|
||||
stack_dirty_ = true;
|
||||
}
|
||||
|
||||
// Preserve a checkpoint of the environment for the IR graph. Any
|
||||
|
@ -213,8 +213,8 @@ void CodeGenerator::PopulateDeoptimizationData(Handle<Code> code_object) {
|
||||
|
||||
// Populate deoptimization entries.
|
||||
for (int i = 0; i < deopt_count; i++) {
|
||||
FrameStateDescriptor descriptor = code()->GetDeoptimizationEntry(i);
|
||||
data->SetAstId(i, descriptor.bailout_id());
|
||||
FrameStateDescriptor* descriptor = code()->GetDeoptimizationEntry(i);
|
||||
data->SetAstId(i, descriptor->bailout_id());
|
||||
data->SetTranslationIndex(i, Smi::FromInt(0));
|
||||
data->SetArgumentsStackHeight(i, Smi::FromInt(0));
|
||||
data->SetPc(i, Smi::FromInt(-1));
|
||||
@ -269,24 +269,61 @@ void CodeGenerator::BuildTranslation(Instruction* instr,
|
||||
// We should build translation only once.
|
||||
DCHECK_EQ(NULL, deoptimization_states_[deoptimization_id]);
|
||||
|
||||
// TODO(jarin) This should build translation codes from the instruction inputs
|
||||
// and from the framestate descriptor. At the moment, we only create a dummy
|
||||
// translation.
|
||||
|
||||
FrameStateDescriptor descriptor =
|
||||
FrameStateDescriptor* descriptor =
|
||||
code()->GetDeoptimizationEntry(deoptimization_id);
|
||||
Translation translation(&translations_, 1, 1, zone());
|
||||
translation.BeginJSFrame(descriptor.bailout_id(), Translation::kSelfLiteralId,
|
||||
0);
|
||||
int undefined_literal_id =
|
||||
DefineDeoptimizationLiteral(isolate()->factory()->undefined_value());
|
||||
translation.StoreLiteral(undefined_literal_id);
|
||||
translation.BeginJSFrame(descriptor->bailout_id(),
|
||||
Translation::kSelfLiteralId,
|
||||
descriptor->size() - descriptor->parameters_count());
|
||||
|
||||
for (int i = 0; i < descriptor->size(); i++) {
|
||||
AddTranslationForOperand(&translation, instr, instr->InputAt(i));
|
||||
}
|
||||
|
||||
deoptimization_states_[deoptimization_id] =
|
||||
new (zone()) DeoptimizationState(translation.index());
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::AddTranslationForOperand(Translation* translation,
|
||||
Instruction* instr,
|
||||
InstructionOperand* op) {
|
||||
if (op->IsStackSlot()) {
|
||||
translation->StoreStackSlot(op->index());
|
||||
} else if (op->IsDoubleStackSlot()) {
|
||||
translation->StoreDoubleStackSlot(op->index());
|
||||
} else if (op->IsRegister()) {
|
||||
InstructionOperandConverter converter(this, instr);
|
||||
translation->StoreRegister(converter.ToRegister(op));
|
||||
} else if (op->IsDoubleRegister()) {
|
||||
InstructionOperandConverter converter(this, instr);
|
||||
translation->StoreDoubleRegister(converter.ToDoubleRegister(op));
|
||||
} else if (op->IsImmediate()) {
|
||||
InstructionOperandConverter converter(this, instr);
|
||||
Constant constant = converter.ToConstant(op);
|
||||
Handle<Object> constant_object;
|
||||
switch (constant.type()) {
|
||||
case Constant::kInt32:
|
||||
constant_object =
|
||||
isolate()->factory()->NewNumberFromInt(constant.ToInt32());
|
||||
break;
|
||||
case Constant::kFloat64:
|
||||
constant_object =
|
||||
isolate()->factory()->NewHeapNumber(constant.ToFloat64());
|
||||
break;
|
||||
case Constant::kHeapObject:
|
||||
constant_object = constant.ToHeapObject();
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
int literal_id = DefineDeoptimizationLiteral(constant_object);
|
||||
translation->StoreLiteral(literal_id);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
#if !V8_TURBOFAN_BACKEND
|
||||
|
||||
void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
||||
@ -337,7 +374,6 @@ bool CodeGenerator::IsNopForSmiCodeInlining(Handle<Code> code, int start_pc,
|
||||
|
||||
#endif // !V8_TURBOFAN_BACKEND
|
||||
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -85,6 +85,8 @@ class CodeGenerator V8_FINAL : public GapResolver::Assembler {
|
||||
void PopulateDeoptimizationData(Handle<Code> code);
|
||||
int DefineDeoptimizationLiteral(Handle<Object> literal);
|
||||
void BuildTranslation(Instruction* instr, int deoptimization_id);
|
||||
void AddTranslationForOperand(Translation* translation, Instruction* instr,
|
||||
InstructionOperand* op);
|
||||
void AddNopForSmiCodeInlining();
|
||||
#if DEBUG
|
||||
static bool IsNopForSmiCodeInlining(Handle<Code> code, int start_pc,
|
||||
|
@ -43,17 +43,6 @@ class CallOperator : public Operator1<CallDescriptor*> {
|
||||
}
|
||||
};
|
||||
|
||||
class FrameStateDescriptor {
|
||||
public:
|
||||
explicit FrameStateDescriptor(BailoutId bailout_id)
|
||||
: bailout_id_(bailout_id) {}
|
||||
|
||||
BailoutId bailout_id() const { return bailout_id_; }
|
||||
|
||||
private:
|
||||
BailoutId bailout_id_;
|
||||
};
|
||||
|
||||
// Interface for building common operators that can be used at any level of IR,
|
||||
// including JavaScript, mid-level, and low-level.
|
||||
// TODO(titzer): Move the mnemonics into SimpleOperator and Operator1 classes.
|
||||
@ -141,9 +130,13 @@ class CommonOperatorBuilder {
|
||||
return new (zone_) Operator1<int>(IrOpcode::kEffectPhi, Operator::kPure, 0,
|
||||
0, "EffectPhi", arguments);
|
||||
}
|
||||
Operator* FrameState(const FrameStateDescriptor& descriptor) {
|
||||
return new (zone_) Operator1<FrameStateDescriptor>(
|
||||
IrOpcode::kFrameState, Operator::kPure, 0, 1, "FrameState", descriptor);
|
||||
Operator* StateValues(int arguments) {
|
||||
return new (zone_) Operator1<int>(IrOpcode::kStateValues, Operator::kPure,
|
||||
arguments, 1, "StateValues", arguments);
|
||||
}
|
||||
Operator* FrameState(BailoutId ast_id) {
|
||||
return new (zone_) Operator1<BailoutId>(
|
||||
IrOpcode::kFrameState, Operator::kPure, 3, 1, "FrameState", ast_id);
|
||||
}
|
||||
Operator* Call(CallDescriptor* descriptor) {
|
||||
return new (zone_) CallOperator(descriptor, "Call");
|
||||
|
@ -423,7 +423,7 @@ void InstructionSelector::VisitControl(BasicBlock* block) {
|
||||
case BasicBlockData::kThrow:
|
||||
return VisitThrow(input);
|
||||
case BasicBlockData::kDeoptimize:
|
||||
return VisitDeoptimization(input);
|
||||
return VisitDeoptimize(input);
|
||||
case BasicBlockData::kCall: {
|
||||
BasicBlock* deoptimization = block->SuccessorAt(0);
|
||||
BasicBlock* continuation = block->SuccessorAt(1);
|
||||
@ -490,7 +490,7 @@ void InstructionSelector::VisitNode(Node* node) {
|
||||
case IrOpcode::kCall:
|
||||
return VisitCall(node, NULL, NULL);
|
||||
case IrOpcode::kFrameState:
|
||||
// TODO(titzer): state nodes should be combined into their users.
|
||||
case IrOpcode::kStateValues:
|
||||
return;
|
||||
case IrOpcode::kLoad: {
|
||||
MachineRepresentation load_rep = OpParameter<MachineRepresentation>(node);
|
||||
@ -953,15 +953,56 @@ void InstructionSelector::VisitThrow(Node* value) {
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitDeoptimization(Node* deopt) {
|
||||
static InstructionOperand* UseOrImmediate(OperandGenerator* g, Node* input) {
|
||||
switch (input->opcode()) {
|
||||
case IrOpcode::kInt32Constant:
|
||||
case IrOpcode::kNumberConstant:
|
||||
case IrOpcode::kFloat64Constant:
|
||||
case IrOpcode::kHeapConstant:
|
||||
return g->UseImmediate(input);
|
||||
default:
|
||||
return g->Use(input);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitDeoptimize(Node* deopt) {
|
||||
DCHECK(deopt->op()->opcode() == IrOpcode::kDeoptimize);
|
||||
Node* state = deopt->InputAt(0);
|
||||
DCHECK(state->op()->opcode() == IrOpcode::kFrameState);
|
||||
FrameStateDescriptor descriptor = OpParameter<FrameStateDescriptor>(state);
|
||||
// TODO(jarin) We should also add an instruction input for every input to
|
||||
// the framestate node (and recurse for the inlined framestates).
|
||||
BailoutId ast_id = OpParameter<BailoutId>(state);
|
||||
|
||||
// Add the inputs.
|
||||
Node* parameters = state->InputAt(0);
|
||||
int parameters_count = OpParameter<int>(parameters);
|
||||
|
||||
Node* locals = state->InputAt(1);
|
||||
int locals_count = OpParameter<int>(locals);
|
||||
|
||||
Node* stack = state->InputAt(2);
|
||||
int stack_count = OpParameter<int>(stack);
|
||||
|
||||
OperandGenerator g(this);
|
||||
std::vector<InstructionOperand*> inputs;
|
||||
inputs.reserve(parameters_count + locals_count + stack_count);
|
||||
for (int i = 0; i < parameters_count; i++) {
|
||||
inputs.push_back(UseOrImmediate(&g, parameters->InputAt(i)));
|
||||
}
|
||||
for (int i = 0; i < locals_count; i++) {
|
||||
inputs.push_back(UseOrImmediate(&g, locals->InputAt(i)));
|
||||
}
|
||||
for (int i = 0; i < stack_count; i++) {
|
||||
inputs.push_back(UseOrImmediate(&g, stack->InputAt(i)));
|
||||
}
|
||||
|
||||
FrameStateDescriptor* descriptor = new (instruction_zone())
|
||||
FrameStateDescriptor(ast_id, parameters_count, locals_count, stack_count);
|
||||
|
||||
DCHECK_EQ(descriptor->size(), inputs.size());
|
||||
|
||||
int deoptimization_id = sequence()->AddDeoptimizationEntry(descriptor);
|
||||
Emit(kArchDeoptimize | MiscField::encode(deoptimization_id), NULL);
|
||||
Emit(kArchDeoptimize | MiscField::encode(deoptimization_id), 0, NULL,
|
||||
inputs.size(), &inputs.front(), 0, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -179,7 +179,7 @@ class InstructionSelector V8_FINAL {
|
||||
void VisitBranch(Node* input, BasicBlock* tbranch, BasicBlock* fbranch);
|
||||
void VisitReturn(Node* value);
|
||||
void VisitThrow(Node* value);
|
||||
void VisitDeoptimization(Node* deopt);
|
||||
void VisitDeoptimize(Node* deopt);
|
||||
|
||||
// ===========================================================================
|
||||
|
||||
|
@ -394,13 +394,13 @@ void InstructionSequence::AddGapMove(int index, InstructionOperand* from,
|
||||
|
||||
|
||||
int InstructionSequence::AddDeoptimizationEntry(
|
||||
const FrameStateDescriptor& descriptor) {
|
||||
FrameStateDescriptor* descriptor) {
|
||||
int deoptimization_id = static_cast<int>(deoptimization_entries_.size());
|
||||
deoptimization_entries_.push_back(descriptor);
|
||||
return deoptimization_id;
|
||||
}
|
||||
|
||||
FrameStateDescriptor InstructionSequence::GetDeoptimizationEntry(
|
||||
FrameStateDescriptor* InstructionSequence::GetDeoptimizationEntry(
|
||||
int deoptimization_id) {
|
||||
return deoptimization_entries_[deoptimization_id];
|
||||
}
|
||||
|
@ -694,6 +694,30 @@ class Constant V8_FINAL {
|
||||
int64_t value_;
|
||||
};
|
||||
|
||||
|
||||
class FrameStateDescriptor : public ZoneObject {
|
||||
public:
|
||||
FrameStateDescriptor(BailoutId bailout_id, int parameters_count,
|
||||
int locals_count, int stack_count)
|
||||
: bailout_id_(bailout_id),
|
||||
parameters_count_(parameters_count),
|
||||
locals_count_(locals_count),
|
||||
stack_count_(stack_count) {}
|
||||
|
||||
BailoutId bailout_id() const { return bailout_id_; }
|
||||
int parameters_count() { return parameters_count_; }
|
||||
int locals_count() { return locals_count_; }
|
||||
int stack_count() { return stack_count_; }
|
||||
|
||||
int size() { return parameters_count_ + locals_count_ + stack_count_; }
|
||||
|
||||
private:
|
||||
BailoutId bailout_id_;
|
||||
int parameters_count_;
|
||||
int locals_count_;
|
||||
int stack_count_;
|
||||
};
|
||||
|
||||
OStream& operator<<(OStream& os, const Constant& constant);
|
||||
|
||||
typedef std::deque<Constant, zone_allocator<Constant> > ConstantDeque;
|
||||
@ -704,7 +728,8 @@ typedef std::map<int, Constant, std::less<int>,
|
||||
typedef std::deque<Instruction*, zone_allocator<Instruction*> >
|
||||
InstructionDeque;
|
||||
typedef std::deque<PointerMap*, zone_allocator<PointerMap*> > PointerMapDeque;
|
||||
typedef std::vector<FrameStateDescriptor, zone_allocator<FrameStateDescriptor> >
|
||||
typedef std::vector<FrameStateDescriptor*,
|
||||
zone_allocator<FrameStateDescriptor*> >
|
||||
DeoptimizationVector;
|
||||
|
||||
|
||||
@ -814,8 +839,8 @@ class InstructionSequence V8_FINAL {
|
||||
return immediates_[index];
|
||||
}
|
||||
|
||||
int AddDeoptimizationEntry(const FrameStateDescriptor& descriptor);
|
||||
FrameStateDescriptor GetDeoptimizationEntry(int deoptimization_id);
|
||||
int AddDeoptimizationEntry(FrameStateDescriptor* descriptor);
|
||||
FrameStateDescriptor* GetDeoptimizationEntry(int deoptimization_id);
|
||||
int GetDeoptimizationEntryCount();
|
||||
|
||||
private:
|
||||
|
@ -34,6 +34,7 @@
|
||||
V(Phi) \
|
||||
V(EffectPhi) \
|
||||
V(FrameState) \
|
||||
V(StateValues) \
|
||||
V(Call) \
|
||||
V(Parameter) \
|
||||
V(Projection)
|
||||
|
@ -272,6 +272,11 @@ Bounds Typer::Visitor::TypeFrameState(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
Bounds Typer::Visitor::TypeStateValues(Node* node) {
|
||||
return Bounds(Type::None(zone()));
|
||||
}
|
||||
|
||||
|
||||
Bounds Typer::Visitor::TypeCall(Node* node) {
|
||||
return Bounds::Unbounded(zone());
|
||||
}
|
||||
|
@ -79,9 +79,6 @@
|
||||
##############################################################################
|
||||
# TurboFan compiler failures.
|
||||
|
||||
# TODO(jarin): Lazy deoptimization test.
|
||||
'test-run-deopt/TurboSimpleDeopt': [SKIP],
|
||||
|
||||
# TODO(mstarzinger): These need investigation and are not categorized yet.
|
||||
'test-cpu-profiler/*': [SKIP],
|
||||
'test-heap/NextCodeLinkIsWeak': [PASS, NO_VARIANTS],
|
||||
|
@ -149,8 +149,12 @@ class TrivialDeoptCodegenTester : public DeoptCodegenTester {
|
||||
m.NewNode(common.LazyDeoptimization(), call);
|
||||
|
||||
bailout_id = GetCallBailoutId();
|
||||
FrameStateDescriptor stateDescriptor(bailout_id);
|
||||
Node* state_node = m.NewNode(common.FrameState(stateDescriptor));
|
||||
Node* parameters = m.NewNode(common.StateValues(1), undef_node);
|
||||
Node* locals = m.NewNode(common.StateValues(0));
|
||||
Node* stack = m.NewNode(common.StateValues(0));
|
||||
|
||||
Node* state_node =
|
||||
m.NewNode(common.FrameState(bailout_id), parameters, locals, stack);
|
||||
m.Deoptimize(state_node);
|
||||
|
||||
// Schedule the graph:
|
||||
@ -280,8 +284,12 @@ class TrivialRuntimeDeoptCodegenTester : public DeoptCodegenTester {
|
||||
m.NewNode(common.LazyDeoptimization(), call);
|
||||
|
||||
bailout_id = GetCallBailoutId();
|
||||
FrameStateDescriptor stateDescriptor(bailout_id);
|
||||
Node* state_node = m.NewNode(common.FrameState(stateDescriptor));
|
||||
Node* parameters = m.NewNode(common.StateValues(1), undef_node);
|
||||
Node* locals = m.NewNode(common.StateValues(0));
|
||||
Node* stack = m.NewNode(common.StateValues(0));
|
||||
|
||||
Node* state_node =
|
||||
m.NewNode(common.FrameState(bailout_id), parameters, locals, stack);
|
||||
m.Deoptimize(state_node);
|
||||
|
||||
// Schedule the graph:
|
||||
|
@ -9,6 +9,7 @@
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
#if V8_TURBOFAN_TARGET
|
||||
|
||||
TEST(TurboSimpleDeopt) {
|
||||
FLAG_allow_natives_syntax = true;
|
||||
@ -26,6 +27,24 @@ TEST(TurboSimpleDeopt) {
|
||||
}
|
||||
|
||||
|
||||
TEST(TurboSimpleDeoptInExpr) {
|
||||
FLAG_allow_natives_syntax = true;
|
||||
FLAG_turbo_deoptimization = true;
|
||||
|
||||
FunctionTester T(
|
||||
"(function f(a) {"
|
||||
"var b = 1;"
|
||||
"var c = 2;"
|
||||
"if (!%IsOptimized()) return 0;"
|
||||
"var d = b + (%DeoptimizeFunction(f), c);"
|
||||
"if (%IsOptimized()) return 0;"
|
||||
"return d + a; })");
|
||||
|
||||
T.CheckCall(T.Val(6), T.Val(3));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
TEST(TurboTrivialDeopt) {
|
||||
FLAG_allow_natives_syntax = true;
|
||||
FLAG_turbo_deoptimization = true;
|
||||
|
@ -1716,7 +1716,7 @@ TEST(BuildScheduleTrivialLazyDeoptCall) {
|
||||
HandleAndZoneScope scope;
|
||||
Isolate* isolate = scope.main_isolate();
|
||||
Graph graph(scope.main_zone());
|
||||
CommonOperatorBuilder common_builder(scope.main_zone());
|
||||
CommonOperatorBuilder common(scope.main_zone());
|
||||
JSOperatorBuilder js_builder(scope.main_zone());
|
||||
|
||||
InitializedHandleScope handles;
|
||||
@ -1761,37 +1761,40 @@ TEST(BuildScheduleTrivialLazyDeoptCall) {
|
||||
PrintableUnique<Object>::CreateUninitialized(scope.main_zone(),
|
||||
undef_object);
|
||||
|
||||
Node* undef_node = graph.NewNode(common_builder.HeapConstant(undef_constant));
|
||||
Node* undef_node = graph.NewNode(common.HeapConstant(undef_constant));
|
||||
|
||||
Node* start_node = graph.NewNode(common_builder.Start(0));
|
||||
Node* start_node = graph.NewNode(common.Start(0));
|
||||
|
||||
CallDescriptor* descriptor = linkage.GetJSCallDescriptor(0);
|
||||
Node* call_node = graph.NewNode(common_builder.Call(descriptor),
|
||||
Node* call_node = graph.NewNode(common.Call(descriptor),
|
||||
undef_node, // function
|
||||
undef_node, // context
|
||||
start_node, // effect
|
||||
start_node); // control
|
||||
|
||||
Node* cont_node = graph.NewNode(common_builder.Continuation(), call_node);
|
||||
Node* lazy_deopt_node =
|
||||
graph.NewNode(common_builder.LazyDeoptimization(), call_node);
|
||||
Node* cont_node = graph.NewNode(common.Continuation(), call_node);
|
||||
Node* lazy_deopt_node = graph.NewNode(common.LazyDeoptimization(), call_node);
|
||||
|
||||
FrameStateDescriptor stateDescriptor(BailoutId(1234));
|
||||
Node* state_node = graph.NewNode(common_builder.FrameState(stateDescriptor));
|
||||
Node* parameters = graph.NewNode(common.StateValues(1), undef_node);
|
||||
Node* locals = graph.NewNode(common.StateValues(0));
|
||||
Node* stack = graph.NewNode(common.StateValues(0));
|
||||
|
||||
Node* return_node = graph.NewNode(common_builder.Return(),
|
||||
Node* state_node = graph.NewNode(common.FrameState(BailoutId(1234)),
|
||||
parameters, locals, stack);
|
||||
|
||||
Node* return_node = graph.NewNode(common.Return(),
|
||||
undef_node, // return value
|
||||
call_node, // effect
|
||||
cont_node); // control
|
||||
Node* deoptimization_node = graph.NewNode(common_builder.Deoptimize(),
|
||||
Node* deoptimization_node = graph.NewNode(common.Deoptimize(),
|
||||
state_node, // deopt environment
|
||||
call_node, // effect
|
||||
lazy_deopt_node); // control
|
||||
|
||||
Node* merge_node =
|
||||
graph.NewNode(common_builder.Merge(2), return_node, deoptimization_node);
|
||||
graph.NewNode(common.Merge(2), return_node, deoptimization_node);
|
||||
|
||||
Node* end_node = graph.NewNode(common_builder.End(), merge_node);
|
||||
Node* end_node = graph.NewNode(common.End(), merge_node);
|
||||
|
||||
graph.SetStart(start_node);
|
||||
graph.SetEnd(end_node);
|
||||
@ -1824,9 +1827,12 @@ TEST(BuildScheduleTrivialLazyDeoptCall) {
|
||||
CHECK(!cont_block->deferred_);
|
||||
// The lazy deopt block contains framestate + bailout (and nothing else).
|
||||
CHECK_EQ(deoptimization_node, deopt_block->control_input_);
|
||||
CHECK_EQ(2, static_cast<int>(deopt_block->nodes_.size()));
|
||||
CHECK_EQ(5, static_cast<int>(deopt_block->nodes_.size()));
|
||||
CHECK_EQ(lazy_deopt_node, deopt_block->nodes_[0]);
|
||||
CHECK_EQ(state_node, deopt_block->nodes_[1]);
|
||||
CHECK_EQ(IrOpcode::kStateValues, deopt_block->nodes_[1]->op()->opcode());
|
||||
CHECK_EQ(IrOpcode::kStateValues, deopt_block->nodes_[2]->op()->opcode());
|
||||
CHECK_EQ(IrOpcode::kStateValues, deopt_block->nodes_[3]->op()->opcode());
|
||||
CHECK_EQ(state_node, deopt_block->nodes_[4]);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user