Commit 02e31851 authored by Jaroslav Sevcik's avatar Jaroslav Sevcik

[turbofan] Add an extra frame state for deoptimization before binary op.

BUG=
R=bmeurer@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#27060}
parent 25895aee
...@@ -1177,7 +1177,9 @@ void AstGraphBuilder::VisitForInBody(ForInStatement* stmt) { ...@@ -1177,7 +1177,9 @@ void AstGraphBuilder::VisitForInBody(ForInStatement* stmt) {
Node* index_inc = Node* index_inc =
NewNode(javascript()->Add(), index, jsgraph()->OneConstant()); NewNode(javascript()->Add(), index, jsgraph()->OneConstant());
// TODO(jarin): provide real bailout id. // TODO(jarin): provide real bailout id.
PrepareFrameState(index_inc, BailoutId::None()); PrepareFrameStateAfterAndBefore(index_inc, BailoutId::None(),
OutputFrameStateCombine::Ignore(),
jsgraph()->EmptyFrameState());
environment()->Poke(0, index_inc); environment()->Poke(0, index_inc);
for_loop.Continue(); for_loop.Continue();
is_property_missing.Else(); is_property_missing.Else();
...@@ -1197,7 +1199,9 @@ void AstGraphBuilder::VisitForInBody(ForInStatement* stmt) { ...@@ -1197,7 +1199,9 @@ void AstGraphBuilder::VisitForInBody(ForInStatement* stmt) {
Node* index_inc = Node* index_inc =
NewNode(javascript()->Add(), index, jsgraph()->OneConstant()); NewNode(javascript()->Add(), index, jsgraph()->OneConstant());
// TODO(jarin): provide real bailout id. // TODO(jarin): provide real bailout id.
PrepareFrameState(index_inc, BailoutId::None()); PrepareFrameStateAfterAndBefore(index_inc, BailoutId::None(),
OutputFrameStateCombine::Ignore(),
jsgraph()->EmptyFrameState());
environment()->Poke(0, index_inc); environment()->Poke(0, index_inc);
for_loop.EndLoop(); for_loop.EndLoop();
environment()->Drop(5); environment()->Drop(5);
...@@ -1831,11 +1835,13 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) { ...@@ -1831,11 +1835,13 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) {
} }
environment()->Push(old_value); environment()->Push(old_value);
VisitForValue(expr->value()); VisitForValue(expr->value());
Node* frame_state_before = environment()->Checkpoint(expr->value()->id());
Node* right = environment()->Pop(); Node* right = environment()->Pop();
Node* left = environment()->Pop(); Node* left = environment()->Pop();
Node* value = BuildBinaryOp(left, right, expr->binary_op()); Node* value = BuildBinaryOp(left, right, expr->binary_op());
PrepareFrameState(value, expr->binary_operation()->id(), PrepareFrameStateAfterAndBefore(value, expr->binary_operation()->id(),
OutputFrameStateCombine::Push()); OutputFrameStateCombine::Push(),
frame_state_before);
environment()->Push(value); environment()->Push(value);
} else { } else {
VisitForValue(expr->value()); VisitForValue(expr->value());
...@@ -2173,9 +2179,11 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) { ...@@ -2173,9 +2179,11 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
// Create node to perform +1/-1 operation. // Create node to perform +1/-1 operation.
Node* value = Node* value =
BuildBinaryOp(old_value, jsgraph()->OneConstant(), expr->binary_op()); BuildBinaryOp(old_value, jsgraph()->OneConstant(), expr->binary_op());
// TODO(jarin) Insert proper bailout id here (will need to change // This should never deoptimize because we have converted to number
// full code generator). // before.
PrepareFrameState(value, BailoutId::None()); PrepareFrameStateAfterAndBefore(value, BailoutId::None(),
OutputFrameStateCombine::Ignore(),
jsgraph()->EmptyFrameState());
// Store the value. // Store the value.
switch (assign_type) { switch (assign_type) {
...@@ -2227,10 +2235,13 @@ void AstGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { ...@@ -2227,10 +2235,13 @@ void AstGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
default: { default: {
VisitForValue(expr->left()); VisitForValue(expr->left());
VisitForValue(expr->right()); VisitForValue(expr->right());
Node* frame_state_before = environment()->Checkpoint(expr->right()->id());
Node* right = environment()->Pop(); Node* right = environment()->Pop();
Node* left = environment()->Pop(); Node* left = environment()->Pop();
Node* value = BuildBinaryOp(left, right, expr->op()); Node* value = BuildBinaryOp(left, right, expr->op());
PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); PrepareFrameStateAfterAndBefore(value, expr->id(),
ast_context()->GetStateCombine(),
frame_state_before);
ast_context()->ProduceValue(value); ast_context()->ProduceValue(value);
} }
} }
...@@ -2979,11 +2990,31 @@ bool AstGraphBuilder::CheckOsrEntry(IterationStatement* stmt) { ...@@ -2979,11 +2990,31 @@ bool AstGraphBuilder::CheckOsrEntry(IterationStatement* stmt) {
void AstGraphBuilder::PrepareFrameState(Node* node, BailoutId ast_id, void AstGraphBuilder::PrepareFrameState(Node* node, BailoutId ast_id,
OutputFrameStateCombine combine) { OutputFrameStateCombine combine) {
if (OperatorProperties::HasFrameStateInput(node->op())) { if (OperatorProperties::GetFrameStateInputCount(node->op()) > 0) {
DCHECK(NodeProperties::GetFrameStateInput(node)->opcode() == DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
IrOpcode::kDead);
DCHECK_EQ(IrOpcode::kDead,
NodeProperties::GetFrameStateInput(node, 0)->opcode());
NodeProperties::ReplaceFrameStateInput(
node, 0, environment()->Checkpoint(ast_id, combine));
}
}
void AstGraphBuilder::PrepareFrameStateAfterAndBefore(
Node* node, BailoutId ast_id, OutputFrameStateCombine combine,
Node* frame_state_before) {
if (OperatorProperties::GetFrameStateInputCount(node->op()) > 0) {
DCHECK_EQ(2, OperatorProperties::GetFrameStateInputCount(node->op()));
DCHECK_EQ(IrOpcode::kDead,
NodeProperties::GetFrameStateInput(node, 0)->opcode());
NodeProperties::ReplaceFrameStateInput( NodeProperties::ReplaceFrameStateInput(
node, environment()->Checkpoint(ast_id, combine)); node, 0, environment()->Checkpoint(ast_id, combine));
DCHECK_EQ(IrOpcode::kDead,
NodeProperties::GetFrameStateInput(node, 1)->opcode());
NodeProperties::ReplaceFrameStateInput(node, 1, frame_state_before);
} }
} }
...@@ -3010,7 +3041,7 @@ Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count, ...@@ -3010,7 +3041,7 @@ Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count,
DCHECK(op->ValueInputCount() == value_input_count); DCHECK(op->ValueInputCount() == value_input_count);
bool has_context = OperatorProperties::HasContextInput(op); bool has_context = OperatorProperties::HasContextInput(op);
bool has_framestate = OperatorProperties::HasFrameStateInput(op); int frame_state_count = OperatorProperties::GetFrameStateInputCount(op);
bool has_control = op->ControlInputCount() == 1; bool has_control = op->ControlInputCount() == 1;
bool has_effect = op->EffectInputCount() == 1; bool has_effect = op->EffectInputCount() == 1;
...@@ -3018,13 +3049,13 @@ Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count, ...@@ -3018,13 +3049,13 @@ Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count,
DCHECK(op->EffectInputCount() < 2); DCHECK(op->EffectInputCount() < 2);
Node* result = NULL; Node* result = NULL;
if (!has_context && !has_framestate && !has_control && !has_effect) { if (!has_context && frame_state_count == 0 && !has_control && !has_effect) {
result = graph()->NewNode(op, value_input_count, value_inputs, incomplete); result = graph()->NewNode(op, value_input_count, value_inputs, incomplete);
} else { } else {
bool inside_try_scope = try_nesting_level_ > 0; bool inside_try_scope = try_nesting_level_ > 0;
int input_count_with_deps = value_input_count; int input_count_with_deps = value_input_count;
if (has_context) ++input_count_with_deps; if (has_context) ++input_count_with_deps;
if (has_framestate) ++input_count_with_deps; input_count_with_deps += frame_state_count;
if (has_control) ++input_count_with_deps; if (has_control) ++input_count_with_deps;
if (has_effect) ++input_count_with_deps; if (has_effect) ++input_count_with_deps;
Node** buffer = EnsureInputBufferSize(input_count_with_deps); Node** buffer = EnsureInputBufferSize(input_count_with_deps);
...@@ -3033,7 +3064,7 @@ Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count, ...@@ -3033,7 +3064,7 @@ Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count,
if (has_context) { if (has_context) {
*current_input++ = current_context(); *current_input++ = current_context();
} }
if (has_framestate) { for (int i = 0; i < frame_state_count; i++) {
// The frame state will be inserted later. Here we misuse // The frame state will be inserted later. Here we misuse
// the {DeadControl} node as a sentinel to be later overwritten // the {DeadControl} node as a sentinel to be later overwritten
// with the real frame state. // with the real frame state.
......
...@@ -320,6 +320,9 @@ class AstGraphBuilder : public AstVisitor { ...@@ -320,6 +320,9 @@ class AstGraphBuilder : public AstVisitor {
void PrepareFrameState( void PrepareFrameState(
Node* node, BailoutId ast_id, Node* node, BailoutId ast_id,
OutputFrameStateCombine combine = OutputFrameStateCombine::Ignore()); OutputFrameStateCombine combine = OutputFrameStateCombine::Ignore());
void PrepareFrameStateAfterAndBefore(Node* node, BailoutId ast_id,
OutputFrameStateCombine combine,
Node* frame_state_before);
BitVector* GetVariablesAssignedInLoop(IterationStatement* stmt); BitVector* GetVariablesAssignedInLoop(IterationStatement* stmt);
...@@ -410,7 +413,8 @@ class AstGraphBuilder::Environment : public ZoneObject { ...@@ -410,7 +413,8 @@ class AstGraphBuilder::Environment : public ZoneObject {
// Preserve a checkpoint of the environment for the IR graph. Any // Preserve a checkpoint of the environment for the IR graph. Any
// 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 =
OutputFrameStateCombine::Ignore());
// Control dependency tracked by this environment. // Control dependency tracked by this environment.
Node* GetControlDependency() { return control_dependency_; } Node* GetControlDependency() { return control_dependency_; }
......
...@@ -229,10 +229,12 @@ Reduction ChangeLowering::ChangeTaggedToFloat64(Node* value, Node* control) { ...@@ -229,10 +229,12 @@ Reduction ChangeLowering::ChangeTaggedToFloat64(Node* value, Node* control) {
Diamond d1(graph(), common(), TestNotSmi(object), BranchHint::kFalse); Diamond d1(graph(), common(), TestNotSmi(object), BranchHint::kFalse);
d1.Chain(control); d1.Chain(control);
DCHECK_EQ(FLAG_turbo_deoptimization,
OperatorProperties::GetFrameStateInputCount(value->op()) == 1);
Node* number = Node* number =
OperatorProperties::HasFrameStateInput(value->op()) FLAG_turbo_deoptimization
? graph()->NewNode(value->op(), object, context, ? graph()->NewNode(value->op(), object, context,
NodeProperties::GetFrameStateInput(value), NodeProperties::GetFrameStateInput(value, 0),
effect, d1.if_true) effect, d1.if_true)
: graph()->NewNode(value->op(), object, context, effect, : graph()->NewNode(value->op(), object, context, effect,
d1.if_true); d1.if_true);
......
...@@ -107,7 +107,7 @@ REPLACE_UNIMPLEMENTED(JSDebugger) ...@@ -107,7 +107,7 @@ REPLACE_UNIMPLEMENTED(JSDebugger)
static CallDescriptor::Flags FlagsForNode(Node* node) { static CallDescriptor::Flags FlagsForNode(Node* node) {
CallDescriptor::Flags result = CallDescriptor::kNoFlags; CallDescriptor::Flags result = CallDescriptor::kNoFlags;
if (OperatorProperties::HasFrameStateInput(node->op())) { if (OperatorProperties::GetFrameStateInputCount(node->op()) > 0) {
result |= CallDescriptor::kNeedsFrameState; result |= CallDescriptor::kNeedsFrameState;
} }
return result; return result;
...@@ -130,14 +130,14 @@ void JSGenericLowering::ReplaceWithCompareIC(Node* node, Token::Value token) { ...@@ -130,14 +130,14 @@ void JSGenericLowering::ReplaceWithCompareIC(Node* node, Token::Value token) {
if (node->op()->HasProperty(Operator::kPure)) { if (node->op()->HasProperty(Operator::kPure)) {
// A pure (strict) comparison doesn't have an effect, control or frame // A pure (strict) comparison doesn't have an effect, control or frame
// state. But for the graph, we need to add control and effect inputs. // state. But for the graph, we need to add control and effect inputs.
DCHECK(!OperatorProperties::HasFrameStateInput(node->op())); DCHECK(OperatorProperties::GetFrameStateInputCount(node->op()) == 0);
inputs.push_back(graph()->start()); inputs.push_back(graph()->start());
inputs.push_back(graph()->start()); inputs.push_back(graph()->start());
} else { } else {
DCHECK(OperatorProperties::HasFrameStateInput(node->op()) == DCHECK((OperatorProperties::GetFrameStateInputCount(node->op()) == 1) ==
FLAG_turbo_deoptimization); FLAG_turbo_deoptimization);
if (FLAG_turbo_deoptimization) { if (FLAG_turbo_deoptimization) {
inputs.push_back(NodeProperties::GetFrameStateInput(node)); inputs.push_back(NodeProperties::GetFrameStateInput(node, 0));
} }
inputs.push_back(NodeProperties::GetEffectInput(node)); inputs.push_back(NodeProperties::GetEffectInput(node));
inputs.push_back(NodeProperties::GetControlInput(node)); inputs.push_back(NodeProperties::GetControlInput(node));
...@@ -198,12 +198,26 @@ void JSGenericLowering::ReplaceWithCompareIC(Node* node, Token::Value token) { ...@@ -198,12 +198,26 @@ void JSGenericLowering::ReplaceWithCompareIC(Node* node, Token::Value token) {
void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable, void JSGenericLowering::ReplaceWithStubCall(Node* node, Callable callable,
CallDescriptor::Flags flags) { CallDescriptor::Flags flags) {
Operator::Properties properties = node->op()->properties(); Operator::Properties properties = node->op()->properties();
CallDescriptor* desc = flags |= FlagsForNode(node);
Linkage::GetStubCallDescriptor(isolate(), zone(), callable.descriptor(), CallDescriptor* desc = Linkage::GetStubCallDescriptor(
0, flags | FlagsForNode(node), properties); isolate(), zone(), callable.descriptor(), 0, flags, properties);
const Operator* new_op = common()->Call(desc);
// Take care of frame states.
int old_frame_state_count =
OperatorProperties::GetFrameStateInputCount(node->op());
int new_frame_state_count =
(flags & CallDescriptor::kNeedsFrameState) ? 1 : 0;
DCHECK_GE(old_frame_state_count, new_frame_state_count);
// If there are extra frame states, get rid of them.
for (int i = new_frame_state_count; i < old_frame_state_count; i++) {
node->RemoveInput(NodeProperties::FirstFrameStateIndex(node) +
new_frame_state_count);
}
Node* stub_code = jsgraph()->HeapConstant(callable.code()); Node* stub_code = jsgraph()->HeapConstant(callable.code());
node->InsertInput(zone(), 0, stub_code); node->InsertInput(zone(), 0, stub_code);
node->set_op(common()->Call(desc)); node->set_op(new_op);
} }
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "src/compiler/js-operator.h" #include "src/compiler/js-operator.h"
#include "src/compiler/node-matchers.h" #include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties.h" #include "src/compiler/node-properties.h"
#include "src/compiler/operator-properties.h"
#include "src/compiler/simplified-operator.h" #include "src/compiler/simplified-operator.h"
#include "src/compiler/typer.h" #include "src/compiler/typer.h"
#include "src/full-codegen.h" #include "src/full-codegen.h"
...@@ -49,7 +50,7 @@ class JSCallFunctionAccessor { ...@@ -49,7 +50,7 @@ class JSCallFunctionAccessor {
return value_inputs - 2; return value_inputs - 2;
} }
Node* frame_state() { return NodeProperties::GetFrameStateInput(call_); } Node* frame_state() { return NodeProperties::GetFrameStateInput(call_, 0); }
private: private:
Node* call_; Node* call_;
...@@ -379,8 +380,9 @@ Reduction JSInliner::Reduce(Node* node) { ...@@ -379,8 +380,9 @@ Reduction JSInliner::Reduce(Node* node) {
for (Node* node : visitor.copies()) { for (Node* node : visitor.copies()) {
if (node && node->opcode() == IrOpcode::kFrameState) { if (node && node->opcode() == IrOpcode::kFrameState) {
DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
AddClosureToFrameState(node, function); AddClosureToFrameState(node, function);
NodeProperties::ReplaceFrameStateInput(node, outer_frame_state); NodeProperties::ReplaceFrameStateInput(node, 0, outer_frame_state);
} }
} }
} }
......
...@@ -51,7 +51,7 @@ Reduction JSIntrinsicLowering::Reduce(Node* node) { ...@@ -51,7 +51,7 @@ Reduction JSIntrinsicLowering::Reduce(Node* node) {
Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) { Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) {
if (!FLAG_turbo_deoptimization) return NoChange(); if (!FLAG_turbo_deoptimization) return NoChange();
Node* frame_state = NodeProperties::GetFrameStateInput(node); Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
DCHECK_EQ(frame_state->opcode(), IrOpcode::kFrameState); DCHECK_EQ(frame_state->opcode(), IrOpcode::kFrameState);
Node* effect = NodeProperties::GetEffectInput(node); Node* effect = NodeProperties::GetEffectInput(node);
......
...@@ -646,8 +646,9 @@ Reduction JSTypedLowering::ReduceJSToNumber(Node* node) { ...@@ -646,8 +646,9 @@ Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant()); NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
NodeProperties::ReplaceControlInput(node, graph()->start()); NodeProperties::ReplaceControlInput(node, graph()->start());
NodeProperties::ReplaceEffectInput(node, graph()->start()); NodeProperties::ReplaceEffectInput(node, graph()->start());
if (OperatorProperties::HasFrameStateInput(node->op())) { if (FLAG_turbo_deoptimization) {
NodeProperties::ReplaceFrameStateInput(node, DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
NodeProperties::ReplaceFrameStateInput(node, 0,
jsgraph()->EmptyFrameState()); jsgraph()->EmptyFrameState());
} }
return Changed(node); return Changed(node);
...@@ -769,8 +770,10 @@ Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) { ...@@ -769,8 +770,10 @@ Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
if (number_reduction.Changed()) { if (number_reduction.Changed()) {
value = number_reduction.replacement(); value = number_reduction.replacement();
} else { } else {
if (OperatorProperties::HasFrameStateInput( DCHECK(FLAG_turbo_deoptimization ==
javascript()->ToNumber())) { (OperatorProperties::GetFrameStateInputCount(
javascript()->ToNumber()) == 1));
if (FLAG_turbo_deoptimization) {
value = effect = value = effect =
graph()->NewNode(javascript()->ToNumber(), value, context, graph()->NewNode(javascript()->ToNumber(), value, context,
jsgraph()->EmptyFrameState(), effect, control); jsgraph()->EmptyFrameState(), effect, control);
......
...@@ -58,9 +58,9 @@ Node* NodeProperties::GetContextInput(Node* node) { ...@@ -58,9 +58,9 @@ Node* NodeProperties::GetContextInput(Node* node) {
// static // static
Node* NodeProperties::GetFrameStateInput(Node* node) { Node* NodeProperties::GetFrameStateInput(Node* node, int index) {
DCHECK(OperatorProperties::HasFrameStateInput(node->op())); DCHECK_LT(index, OperatorProperties::GetFrameStateInputCount(node->op()));
return node->InputAt(FirstFrameStateIndex(node)); return node->InputAt(FirstFrameStateIndex(node) + index);
} }
...@@ -138,9 +138,10 @@ void NodeProperties::ReplaceEffectInput(Node* node, Node* effect, int index) { ...@@ -138,9 +138,10 @@ void NodeProperties::ReplaceEffectInput(Node* node, Node* effect, int index) {
// static // static
void NodeProperties::ReplaceFrameStateInput(Node* node, Node* frame_state) { void NodeProperties::ReplaceFrameStateInput(Node* node, int index,
DCHECK(OperatorProperties::HasFrameStateInput(node->op())); Node* frame_state) {
node->ReplaceInput(FirstFrameStateIndex(node), frame_state); DCHECK_LT(index, OperatorProperties::GetFrameStateInputCount(node->op()));
node->ReplaceInput(FirstFrameStateIndex(node) + index, frame_state);
} }
......
...@@ -39,7 +39,7 @@ class NodeProperties FINAL { ...@@ -39,7 +39,7 @@ class NodeProperties FINAL {
static Node* GetValueInput(Node* node, int index); static Node* GetValueInput(Node* node, int index);
static Node* GetContextInput(Node* node); static Node* GetContextInput(Node* node);
static Node* GetFrameStateInput(Node* node); static Node* GetFrameStateInput(Node* node, int index);
static Node* GetEffectInput(Node* node, int index = 0); static Node* GetEffectInput(Node* node, int index = 0);
static Node* GetControlInput(Node* node, int index = 0); static Node* GetControlInput(Node* node, int index = 0);
...@@ -77,7 +77,7 @@ class NodeProperties FINAL { ...@@ -77,7 +77,7 @@ class NodeProperties FINAL {
static void ReplaceContextInput(Node* node, Node* context); static void ReplaceContextInput(Node* node, Node* context);
static void ReplaceControlInput(Node* node, Node* control); static void ReplaceControlInput(Node* node, Node* control);
static void ReplaceEffectInput(Node* node, Node* effect, int index = 0); static void ReplaceEffectInput(Node* node, Node* effect, int index = 0);
static void ReplaceFrameStateInput(Node* node, Node* frame_state); static void ReplaceFrameStateInput(Node* node, int index, Node* frame_state);
static void RemoveNonValueInputs(Node* node); static void RemoveNonValueInputs(Node* node);
// Replace value uses of {node} with {value} and effect uses of {node} with // Replace value uses of {node} with {value} and effect uses of {node} with
......
...@@ -20,13 +20,13 @@ bool OperatorProperties::HasContextInput(const Operator* op) { ...@@ -20,13 +20,13 @@ bool OperatorProperties::HasContextInput(const Operator* op) {
// static // static
bool OperatorProperties::HasFrameStateInput(const Operator* op) { int OperatorProperties::GetFrameStateInputCount(const Operator* op) {
if (!FLAG_turbo_deoptimization) { if (!FLAG_turbo_deoptimization) {
return false; return 0;
} }
switch (op->opcode()) { switch (op->opcode()) {
case IrOpcode::kFrameState: case IrOpcode::kFrameState:
return true; return 1;
case IrOpcode::kJSCallRuntime: { case IrOpcode::kJSCallRuntime: {
const CallRuntimeParameters& p = CallRuntimeParametersOf(op); const CallRuntimeParameters& p = CallRuntimeParametersOf(op);
return Linkage::NeedsFrameState(p.id()); return Linkage::NeedsFrameState(p.id());
...@@ -35,7 +35,7 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) { ...@@ -35,7 +35,7 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) {
// Strict equality cannot lazily deoptimize. // Strict equality cannot lazily deoptimize.
case IrOpcode::kJSStrictEqual: case IrOpcode::kJSStrictEqual:
case IrOpcode::kJSStrictNotEqual: case IrOpcode::kJSStrictNotEqual:
return false; return 0;
// Calls // Calls
case IrOpcode::kJSCallFunction: case IrOpcode::kJSCallFunction:
...@@ -51,19 +51,6 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) { ...@@ -51,19 +51,6 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) {
case IrOpcode::kJSLessThanOrEqual: case IrOpcode::kJSLessThanOrEqual:
case IrOpcode::kJSNotEqual: case IrOpcode::kJSNotEqual:
// Binary operations
case IrOpcode::kJSAdd:
case IrOpcode::kJSBitwiseAnd:
case IrOpcode::kJSBitwiseOr:
case IrOpcode::kJSBitwiseXor:
case IrOpcode::kJSDivide:
case IrOpcode::kJSModulus:
case IrOpcode::kJSMultiply:
case IrOpcode::kJSShiftLeft:
case IrOpcode::kJSShiftRight:
case IrOpcode::kJSShiftRightLogical:
case IrOpcode::kJSSubtract:
// Context operations // Context operations
case IrOpcode::kJSCreateWithContext: case IrOpcode::kJSCreateWithContext:
...@@ -81,10 +68,26 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) { ...@@ -81,10 +68,26 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) {
case IrOpcode::kJSStoreNamed: case IrOpcode::kJSStoreNamed:
case IrOpcode::kJSStoreProperty: case IrOpcode::kJSStoreProperty:
case IrOpcode::kJSDeleteProperty: case IrOpcode::kJSDeleteProperty:
return true; return 1;
// Binary operators that can deopt in the middle the operation (e.g.,
// as a result of lazy deopt in ToNumber conversion) need a second frame
// state so that we can resume before the operation.
case IrOpcode::kJSMultiply:
case IrOpcode::kJSAdd:
case IrOpcode::kJSBitwiseAnd:
case IrOpcode::kJSBitwiseOr:
case IrOpcode::kJSBitwiseXor:
case IrOpcode::kJSDivide:
case IrOpcode::kJSModulus:
case IrOpcode::kJSShiftLeft:
case IrOpcode::kJSShiftRight:
case IrOpcode::kJSShiftRightLogical:
case IrOpcode::kJSSubtract:
return 2;
default: default:
return false; return 0;
} }
} }
......
...@@ -18,14 +18,11 @@ class Operator; ...@@ -18,14 +18,11 @@ class Operator;
class OperatorProperties FINAL { class OperatorProperties FINAL {
public: public:
static bool HasContextInput(const Operator* op); static bool HasContextInput(const Operator* op);
static bool HasFrameStateInput(const Operator* op);
static int GetContextInputCount(const Operator* op) { static int GetContextInputCount(const Operator* op) {
return HasContextInput(op) ? 1 : 0; return HasContextInput(op) ? 1 : 0;
} }
static int GetFrameStateInputCount(const Operator* op) { static int GetFrameStateInputCount(const Operator* op);
return HasFrameStateInput(op) ? 1 : 0;
}
static int GetTotalInputCount(const Operator* op); static int GetTotalInputCount(const Operator* op);
static bool IsBasicBlockBegin(const Operator* op); static bool IsBasicBlockBegin(const Operator* op);
......
...@@ -125,8 +125,8 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -125,8 +125,8 @@ void Verifier::Visitor::Check(Node* node) {
CHECK_EQ(input_count, node->InputCount()); CHECK_EQ(input_count, node->InputCount());
// Verify that frame state has been inserted for the nodes that need it. // Verify that frame state has been inserted for the nodes that need it.
if (OperatorProperties::HasFrameStateInput(node->op())) { for (int i = 0; i < frame_state_count; i++) {
Node* frame_state = NodeProperties::GetFrameStateInput(node); Node* frame_state = NodeProperties::GetFrameStateInput(node, i);
CHECK(frame_state->opcode() == IrOpcode::kFrameState || CHECK(frame_state->opcode() == IrOpcode::kFrameState ||
// kFrameState uses undefined as a sentinel. // kFrameState uses undefined as a sentinel.
(node->opcode() == IrOpcode::kFrameState && (node->opcode() == IrOpcode::kFrameState &&
......
...@@ -48,7 +48,7 @@ Node* SimplifiedGraphBuilder::MakeNode(const Operator* op, ...@@ -48,7 +48,7 @@ Node* SimplifiedGraphBuilder::MakeNode(const Operator* op,
DCHECK(op->ValueInputCount() == value_input_count); DCHECK(op->ValueInputCount() == value_input_count);
DCHECK(!OperatorProperties::HasContextInput(op)); DCHECK(!OperatorProperties::HasContextInput(op));
DCHECK(!OperatorProperties::HasFrameStateInput(op)); DCHECK_EQ(0, OperatorProperties::GetFrameStateInputCount(op));
bool has_control = op->ControlInputCount() == 1; bool has_control = op->ControlInputCount() == 1;
bool has_effect = op->EffectInputCount() == 1; bool has_effect = op->EffectInputCount() == 1;
......
...@@ -113,9 +113,13 @@ class JSTypedLoweringTester : public HandleAndZoneScope { ...@@ -113,9 +113,13 @@ class JSTypedLoweringTester : public HandleAndZoneScope {
Node* Binop(const Operator* op, Node* left, Node* right) { Node* Binop(const Operator* op, Node* left, Node* right) {
// JS binops also require context, effect, and control // JS binops also require context, effect, and control
if (OperatorProperties::HasFrameStateInput(op)) { if (OperatorProperties::GetFrameStateInputCount(op) == 1) {
return graph.NewNode(op, left, right, context(), return graph.NewNode(op, left, right, context(),
EmptyFrameState(context()), start(), control()); EmptyFrameState(context()), start(), control());
} else if (OperatorProperties::GetFrameStateInputCount(op) == 2) {
return graph.NewNode(op, left, right, context(),
EmptyFrameState(context()),
EmptyFrameState(context()), start(), control());
} else { } else {
return graph.NewNode(op, left, right, context(), start(), control()); return graph.NewNode(op, left, right, context(), start(), control());
} }
...@@ -123,7 +127,8 @@ class JSTypedLoweringTester : public HandleAndZoneScope { ...@@ -123,7 +127,8 @@ class JSTypedLoweringTester : public HandleAndZoneScope {
Node* Unop(const Operator* op, Node* input) { Node* Unop(const Operator* op, Node* input) {
// JS unops also require context, effect, and control // JS unops also require context, effect, and control
if (OperatorProperties::HasFrameStateInput(op)) { if (OperatorProperties::GetFrameStateInputCount(op) > 0) {
DCHECK(OperatorProperties::GetFrameStateInputCount(op) == 1);
return graph.NewNode(op, input, context(), EmptyFrameState(context()), return graph.NewNode(op, input, context(), EmptyFrameState(context()),
start(), control()); start(), control());
} else { } else {
...@@ -133,7 +138,10 @@ class JSTypedLoweringTester : public HandleAndZoneScope { ...@@ -133,7 +138,10 @@ class JSTypedLoweringTester : public HandleAndZoneScope {
Node* UseForEffect(Node* node) { Node* UseForEffect(Node* node) {
// TODO(titzer): use EffectPhi after fixing EffectCount // TODO(titzer): use EffectPhi after fixing EffectCount
if (OperatorProperties::HasFrameStateInput(javascript.ToNumber())) { if (OperatorProperties::GetFrameStateInputCount(javascript.ToNumber()) >
0) {
DCHECK(OperatorProperties::GetFrameStateInputCount(
javascript.ToNumber()) == 1);
return graph.NewNode(javascript.ToNumber(), node, context(), return graph.NewNode(javascript.ToNumber(), node, context(),
EmptyFrameState(context()), node, control()); EmptyFrameState(context()), node, control());
} else { } else {
...@@ -748,8 +756,9 @@ TEST(RemoveToNumberEffects) { ...@@ -748,8 +756,9 @@ TEST(RemoveToNumberEffects) {
switch (i) { switch (i) {
case 0: case 0:
// TODO(jarin) Replace with a query of FLAG_turbo_deoptimization. if (FLAG_turbo_deoptimization) {
if (OperatorProperties::HasFrameStateInput(R.javascript.ToNumber())) { DCHECK(OperatorProperties::GetFrameStateInputCount(
R.javascript.ToNumber()) == 1);
effect_use = R.graph.NewNode(R.javascript.ToNumber(), p0, R.context(), effect_use = R.graph.NewNode(R.javascript.ToNumber(), p0, R.context(),
frame_state, ton, R.start()); frame_state, ton, R.start());
} else { } else {
...@@ -758,8 +767,9 @@ TEST(RemoveToNumberEffects) { ...@@ -758,8 +767,9 @@ TEST(RemoveToNumberEffects) {
} }
break; break;
case 1: case 1:
// TODO(jarin) Replace with a query of FLAG_turbo_deoptimization. if (FLAG_turbo_deoptimization) {
if (OperatorProperties::HasFrameStateInput(R.javascript.ToNumber())) { DCHECK(OperatorProperties::GetFrameStateInputCount(
R.javascript.ToNumber()) == 1);
effect_use = effect_use =
R.graph.NewNode(R.javascript.ToNumber(), ton, R.context(), R.graph.NewNode(R.javascript.ToNumber(), ton, R.context(),
frame_state, ton, R.start()); frame_state, ton, R.start());
...@@ -772,11 +782,11 @@ TEST(RemoveToNumberEffects) { ...@@ -772,11 +782,11 @@ TEST(RemoveToNumberEffects) {
effect_use = R.graph.NewNode(R.common.EffectPhi(1), ton, R.start()); effect_use = R.graph.NewNode(R.common.EffectPhi(1), ton, R.start());
case 3: case 3:
effect_use = R.graph.NewNode(R.javascript.Add(), ton, ton, R.context(), effect_use = R.graph.NewNode(R.javascript.Add(), ton, ton, R.context(),
frame_state, ton, R.start()); frame_state, frame_state, ton, R.start());
break; break;
case 4: case 4:
effect_use = R.graph.NewNode(R.javascript.Add(), p0, p0, R.context(), effect_use = R.graph.NewNode(R.javascript.Add(), p0, p0, R.context(),
frame_state, ton, R.start()); frame_state, frame_state, ton, R.start());
break; break;
case 5: case 5:
effect_use = R.graph.NewNode(R.common.Return(), p0, ton, R.start()); effect_use = R.graph.NewNode(R.common.Return(), p0, ton, R.start());
......
...@@ -55,17 +55,17 @@ const SharedOperator kSharedOperators[] = { ...@@ -55,17 +55,17 @@ const SharedOperator kSharedOperators[] = {
SHARED(GreaterThan, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), SHARED(GreaterThan, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2),
SHARED(LessThanOrEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), SHARED(LessThanOrEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2),
SHARED(GreaterThanOrEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), SHARED(GreaterThanOrEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2),
SHARED(BitwiseOr, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), SHARED(BitwiseOr, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(BitwiseXor, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), SHARED(BitwiseXor, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(BitwiseAnd, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), SHARED(BitwiseAnd, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(ShiftLeft, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), SHARED(ShiftLeft, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(ShiftRight, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), SHARED(ShiftRight, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(ShiftRightLogical, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), SHARED(ShiftRightLogical, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(Add, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), SHARED(Add, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(Subtract, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), SHARED(Subtract, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(Multiply, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), SHARED(Multiply, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(Divide, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), SHARED(Divide, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(Modulus, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), SHARED(Modulus, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(UnaryNot, Operator::kPure, 1, 0, 0, 0, 1, 0, 0), SHARED(UnaryNot, Operator::kPure, 1, 0, 0, 0, 1, 0, 0),
SHARED(ToBoolean, Operator::kPure, 1, 0, 0, 0, 1, 0, 0), SHARED(ToBoolean, Operator::kPure, 1, 0, 0, 0, 1, 0, 0),
SHARED(ToNumber, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2), SHARED(ToNumber, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2),
......
...@@ -673,6 +673,8 @@ TEST_F(SchedulerTest, BuildScheduleIfSplit) { ...@@ -673,6 +673,8 @@ TEST_F(SchedulerTest, BuildScheduleIfSplit) {
TEST_F(SchedulerTest, BuildScheduleIfSplitWithEffects) { TEST_F(SchedulerTest, BuildScheduleIfSplitWithEffects) {
FLAG_turbo_deoptimization = false;
const Operator* op; const Operator* op;
// Manually transcripted code for: // Manually transcripted code for:
...@@ -809,6 +811,8 @@ TEST_F(SchedulerTest, BuildScheduleIfSplitWithEffects) { ...@@ -809,6 +811,8 @@ TEST_F(SchedulerTest, BuildScheduleIfSplitWithEffects) {
TEST_F(SchedulerTest, BuildScheduleSimpleLoop) { TEST_F(SchedulerTest, BuildScheduleSimpleLoop) {
FLAG_turbo_deoptimization = false;
const Operator* op; const Operator* op;
// Manually transcripted code for: // Manually transcripted code for:
...@@ -912,6 +916,8 @@ TEST_F(SchedulerTest, BuildScheduleSimpleLoop) { ...@@ -912,6 +916,8 @@ TEST_F(SchedulerTest, BuildScheduleSimpleLoop) {
TEST_F(SchedulerTest, BuildScheduleComplexLoops) { TEST_F(SchedulerTest, BuildScheduleComplexLoops) {
FLAG_turbo_deoptimization = false;
const Operator* op; const Operator* op;
// Manually transcripted code for: // Manually transcripted code for:
...@@ -1150,6 +1156,8 @@ TEST_F(SchedulerTest, BuildScheduleComplexLoops) { ...@@ -1150,6 +1156,8 @@ TEST_F(SchedulerTest, BuildScheduleComplexLoops) {
TEST_F(SchedulerTest, BuildScheduleBreakAndContinue) { TEST_F(SchedulerTest, BuildScheduleBreakAndContinue) {
FLAG_turbo_deoptimization = false;
const Operator* op; const Operator* op;
// Manually transcripted code for: // Manually transcripted code for:
...@@ -1470,6 +1478,8 @@ TEST_F(SchedulerTest, BuildScheduleBreakAndContinue) { ...@@ -1470,6 +1478,8 @@ TEST_F(SchedulerTest, BuildScheduleBreakAndContinue) {
TEST_F(SchedulerTest, BuildScheduleSimpleLoopWithCodeMotion) { TEST_F(SchedulerTest, BuildScheduleSimpleLoopWithCodeMotion) {
FLAG_turbo_deoptimization = false;
const Operator* op; const Operator* op;
// Manually transcripted code for: // Manually transcripted code for:
......
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