[turbofan] Use FrameStatesBeforeAndAfter to simplify handling of before/after frame states in AstGraphBuilder.
R=jarin@chromium.org BUG= Review URL: https://codereview.chromium.org/1128193005 Cr-Commit-Position: refs/heads/master@{#28361}
This commit is contained in:
parent
7fcbeb289d
commit
0c80fdc61e
@ -384,6 +384,48 @@ class AstGraphBuilder::ControlScopeForFinally : public ControlScope {
|
||||
};
|
||||
|
||||
|
||||
// Helper for generating before and after frame states.
|
||||
class AstGraphBuilder::FrameStateBeforeAndAfter {
|
||||
public:
|
||||
FrameStateBeforeAndAfter(AstGraphBuilder* builder, BailoutId id_before)
|
||||
: builder_(builder), frame_state_before_(nullptr) {
|
||||
frame_state_before_ = id_before == BailoutId::None()
|
||||
? builder_->jsgraph()->EmptyFrameState()
|
||||
: builder_->environment()->Checkpoint(id_before);
|
||||
}
|
||||
|
||||
void AddToNode(Node* node, BailoutId id_after,
|
||||
OutputFrameStateCombine combine) {
|
||||
int count = OperatorProperties::GetFrameStateInputCount(node->op());
|
||||
DCHECK_LE(count, 2);
|
||||
|
||||
if (count >= 1) {
|
||||
// Add the frame state for after the operation.
|
||||
DCHECK_EQ(IrOpcode::kDead,
|
||||
NodeProperties::GetFrameStateInput(node, 0)->opcode());
|
||||
|
||||
Node* frame_state_after =
|
||||
id_after == BailoutId::None()
|
||||
? builder_->jsgraph()->EmptyFrameState()
|
||||
: builder_->environment()->Checkpoint(id_after, combine);
|
||||
|
||||
NodeProperties::ReplaceFrameStateInput(node, 0, frame_state_after);
|
||||
}
|
||||
|
||||
if (count >= 2) {
|
||||
// Add the frame state for before the operation.
|
||||
DCHECK_EQ(IrOpcode::kDead,
|
||||
NodeProperties::GetFrameStateInput(node, 1)->opcode());
|
||||
NodeProperties::ReplaceFrameStateInput(node, 1, frame_state_before_);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
AstGraphBuilder* builder_;
|
||||
Node* frame_state_before_;
|
||||
};
|
||||
|
||||
|
||||
AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info,
|
||||
JSGraph* jsgraph, LoopAssignmentAnalysis* loop,
|
||||
JSTypeFeedbackTable* js_type_feedback)
|
||||
@ -1304,14 +1346,15 @@ void AstGraphBuilder::VisitForInBody(ForInStatement* stmt) {
|
||||
is_property_missing.If(property_missing);
|
||||
is_property_missing.Then();
|
||||
// Inc counter and continue.
|
||||
Node* index_inc =
|
||||
NewNode(javascript()->Add(LanguageMode::SLOPPY), index,
|
||||
jsgraph()->OneConstant());
|
||||
// TODO(jarin): provide real bailout id.
|
||||
PrepareFrameStateAfterAndBefore(index_inc, BailoutId::None(),
|
||||
OutputFrameStateCombine::Ignore(),
|
||||
jsgraph()->EmptyFrameState());
|
||||
environment()->Poke(0, index_inc);
|
||||
{
|
||||
// TODO(jarin): provide real bailout id.
|
||||
FrameStateBeforeAndAfter states(this, BailoutId::None());
|
||||
Node* index_inc = NewNode(javascript()->Add(LanguageMode::SLOPPY),
|
||||
index, jsgraph()->OneConstant());
|
||||
states.AddToNode(index_inc, BailoutId::None(),
|
||||
OutputFrameStateCombine::Ignore());
|
||||
environment()->Poke(0, index_inc);
|
||||
}
|
||||
for_loop.Continue();
|
||||
is_property_missing.Else();
|
||||
is_property_missing.End();
|
||||
@ -1332,10 +1375,12 @@ void AstGraphBuilder::VisitForInBody(ForInStatement* stmt) {
|
||||
Node* index_inc =
|
||||
NewNode(javascript()->Add(LanguageMode::SLOPPY), index,
|
||||
jsgraph()->OneConstant());
|
||||
// TODO(jarin): provide real bailout id.
|
||||
PrepareFrameStateAfterAndBefore(index_inc, BailoutId::None(),
|
||||
OutputFrameStateCombine::Ignore(),
|
||||
jsgraph()->EmptyFrameState());
|
||||
{
|
||||
// TODO(jarin): provide real bailout ids.
|
||||
FrameStateBeforeAndAfter states(this, BailoutId::None());
|
||||
states.AddToNode(index_inc, BailoutId::None(),
|
||||
OutputFrameStateCombine::Ignore());
|
||||
}
|
||||
environment()->Poke(0, index_inc);
|
||||
for_loop.EndLoop();
|
||||
environment()->Drop(5);
|
||||
@ -1870,15 +1915,15 @@ void AstGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
|
||||
|
||||
VisitForValue(subexpr);
|
||||
Node* frame_state_before = environment()->Checkpoint(
|
||||
subexpr->id(), OutputFrameStateCombine::PokeAt(0));
|
||||
Node* value = environment()->Pop();
|
||||
Node* index = jsgraph()->Constant(i);
|
||||
Node* store =
|
||||
BuildKeyedStore(literal, index, value, TypeFeedbackId::None());
|
||||
PrepareFrameStateAfterAndBefore(store, expr->GetIdForElement(i),
|
||||
OutputFrameStateCombine::Ignore(),
|
||||
frame_state_before);
|
||||
{
|
||||
FrameStateBeforeAndAfter states(this, subexpr->id());
|
||||
Node* value = environment()->Pop();
|
||||
Node* index = jsgraph()->Constant(i);
|
||||
Node* store =
|
||||
BuildKeyedStore(literal, index, value, TypeFeedbackId::None());
|
||||
states.AddToNode(store, expr->GetIdForElement(i),
|
||||
OutputFrameStateCombine::Ignore());
|
||||
}
|
||||
}
|
||||
|
||||
environment()->Pop(); // Array literal index.
|
||||
@ -1916,14 +1961,16 @@ void AstGraphBuilder::VisitForInAssignment(Expression* expr, Node* value,
|
||||
environment()->Push(value);
|
||||
VisitForValue(property->obj());
|
||||
VisitForValue(property->key());
|
||||
Node* key = environment()->Pop();
|
||||
Node* object = environment()->Pop();
|
||||
value = environment()->Pop();
|
||||
Node* store = BuildKeyedStore(object, key, value, TypeFeedbackId::None());
|
||||
// TODO(jarin) Provide a real frame state before.
|
||||
PrepareFrameStateAfterAndBefore(store, bailout_id,
|
||||
OutputFrameStateCombine::Ignore(),
|
||||
jsgraph()->EmptyFrameState());
|
||||
{
|
||||
// TODO(jarin) Provide a real frame state before.
|
||||
FrameStateBeforeAndAfter states(this, BailoutId::None());
|
||||
Node* key = environment()->Pop();
|
||||
Node* object = environment()->Pop();
|
||||
value = environment()->Pop();
|
||||
Node* store =
|
||||
BuildKeyedStore(object, key, value, TypeFeedbackId::None());
|
||||
states.AddToNode(store, bailout_id, OutputFrameStateCombine::Ignore());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1936,12 +1983,19 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) {
|
||||
// Left-hand side can only be a property, a global or a variable slot.
|
||||
Property* property = expr->target()->AsProperty();
|
||||
LhsKind assign_type = DetermineLhsKind(expr->target());
|
||||
bool needs_frame_state_before = true;
|
||||
|
||||
// Evaluate LHS expression.
|
||||
switch (assign_type) {
|
||||
case VARIABLE:
|
||||
// Nothing to do here.
|
||||
case VARIABLE: {
|
||||
Variable* variable = expr->target()->AsVariableProxy()->var();
|
||||
if (variable->location() == Variable::PARAMETER ||
|
||||
variable->location() == Variable::LOCAL ||
|
||||
variable->location() == Variable::CONTEXT) {
|
||||
needs_frame_state_before = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NAMED_PROPERTY:
|
||||
VisitForValue(property->obj());
|
||||
break;
|
||||
@ -1952,10 +2006,9 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) {
|
||||
}
|
||||
}
|
||||
|
||||
BailoutId before_store_id = BailoutId::None();
|
||||
// Evaluate the value and potentially handle compound assignments by loading
|
||||
// the left-hand side value and performing a binary operation.
|
||||
Node* frame_state_before_store = nullptr;
|
||||
bool needs_frame_state_before = (assign_type == KEYED_PROPERTY);
|
||||
if (expr->is_compound()) {
|
||||
Node* old_value = NULL;
|
||||
switch (assign_type) {
|
||||
@ -1991,31 +2044,27 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) {
|
||||
}
|
||||
environment()->Push(old_value);
|
||||
VisitForValue(expr->value());
|
||||
Node* frame_state_before = environment()->Checkpoint(expr->value()->id());
|
||||
Node* right = environment()->Pop();
|
||||
Node* left = environment()->Pop();
|
||||
Node* value = BuildBinaryOp(left, right, expr->binary_op());
|
||||
PrepareFrameStateAfterAndBefore(value, expr->binary_operation()->id(),
|
||||
OutputFrameStateCombine::Push(),
|
||||
frame_state_before);
|
||||
Node* value;
|
||||
{
|
||||
FrameStateBeforeAndAfter states(this, expr->value()->id());
|
||||
Node* right = environment()->Pop();
|
||||
Node* left = environment()->Pop();
|
||||
value = BuildBinaryOp(left, right, expr->binary_op());
|
||||
states.AddToNode(value, expr->binary_operation()->id(),
|
||||
OutputFrameStateCombine::Push());
|
||||
}
|
||||
environment()->Push(value);
|
||||
if (needs_frame_state_before) {
|
||||
frame_state_before_store = environment()->Checkpoint(
|
||||
expr->binary_operation()->id(), OutputFrameStateCombine::PokeAt(0));
|
||||
before_store_id = expr->binary_operation()->id();
|
||||
}
|
||||
} else {
|
||||
VisitForValue(expr->value());
|
||||
if (needs_frame_state_before) {
|
||||
// This frame state can be used for lazy-deopting from a to-number
|
||||
// conversion if we are storing into a typed array. It is important
|
||||
// that the frame state is usable for such lazy deopt (i.e., it has
|
||||
// to specify how to override the value before the conversion, in this
|
||||
// case, it overwrites the stack top).
|
||||
frame_state_before_store = environment()->Checkpoint(
|
||||
expr->value()->id(), OutputFrameStateCombine::PokeAt(0));
|
||||
before_store_id = expr->value()->id();
|
||||
}
|
||||
}
|
||||
|
||||
FrameStateBeforeAndAfter store_states(this, before_store_id);
|
||||
// Store the value.
|
||||
Node* value = environment()->Pop();
|
||||
switch (assign_type) {
|
||||
@ -2030,7 +2079,8 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) {
|
||||
Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
|
||||
Node* store =
|
||||
BuildNamedStore(object, name, value, expr->AssignmentFeedbackId());
|
||||
PrepareFrameState(store, expr->id(), ast_context()->GetStateCombine());
|
||||
store_states.AddToNode(store, expr->id(),
|
||||
ast_context()->GetStateCombine());
|
||||
break;
|
||||
}
|
||||
case KEYED_PROPERTY: {
|
||||
@ -2038,9 +2088,8 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) {
|
||||
Node* object = environment()->Pop();
|
||||
Node* store =
|
||||
BuildKeyedStore(object, key, value, expr->AssignmentFeedbackId());
|
||||
PrepareFrameStateAfterAndBefore(store, expr->id(),
|
||||
ast_context()->GetStateCombine(),
|
||||
frame_state_before_store);
|
||||
store_states.AddToNode(store, expr->id(),
|
||||
ast_context()->GetStateCombine());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2362,22 +2411,25 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
|
||||
PrepareFrameState(old_value, expr->ToNumberId(),
|
||||
OutputFrameStateCombine::Push());
|
||||
|
||||
Node* frame_state_before_store =
|
||||
assign_type == KEYED_PROPERTY
|
||||
? environment()->Checkpoint(expr->ToNumberId())
|
||||
: nullptr;
|
||||
// TODO(titzer): combine this framestate with the above?
|
||||
FrameStateBeforeAndAfter store_states(this, assign_type == KEYED_PROPERTY
|
||||
? expr->ToNumberId()
|
||||
: BailoutId::None());
|
||||
|
||||
// Save result for postfix expressions at correct stack depth.
|
||||
if (is_postfix) environment()->Poke(stack_depth, old_value);
|
||||
|
||||
// Create node to perform +1/-1 operation.
|
||||
Node* value =
|
||||
BuildBinaryOp(old_value, jsgraph()->OneConstant(), expr->binary_op());
|
||||
// This should never deoptimize because we have converted to number
|
||||
// before.
|
||||
PrepareFrameStateAfterAndBefore(value, BailoutId::None(),
|
||||
OutputFrameStateCombine::Ignore(),
|
||||
jsgraph()->EmptyFrameState());
|
||||
Node* value;
|
||||
{
|
||||
FrameStateBeforeAndAfter states(this, BailoutId::None());
|
||||
value =
|
||||
BuildBinaryOp(old_value, jsgraph()->OneConstant(), expr->binary_op());
|
||||
// This should never deoptimize because we have converted to number
|
||||
// before.
|
||||
states.AddToNode(value, BailoutId::None(),
|
||||
OutputFrameStateCombine::Ignore());
|
||||
}
|
||||
|
||||
// Store the value.
|
||||
switch (assign_type) {
|
||||
@ -2405,9 +2457,8 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
|
||||
Node* store =
|
||||
BuildKeyedStore(object, key, value, expr->CountStoreFeedbackId());
|
||||
environment()->Push(value);
|
||||
PrepareFrameStateAfterAndBefore(store, expr->AssignmentId(),
|
||||
OutputFrameStateCombine::Ignore(),
|
||||
frame_state_before_store);
|
||||
store_states.AddToNode(store, expr->AssignmentId(),
|
||||
OutputFrameStateCombine::Ignore());
|
||||
environment()->Pop();
|
||||
break;
|
||||
}
|
||||
@ -2430,13 +2481,11 @@ void AstGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
|
||||
default: {
|
||||
VisitForValue(expr->left());
|
||||
VisitForValue(expr->right());
|
||||
Node* frame_state_before = environment()->Checkpoint(expr->right()->id());
|
||||
FrameStateBeforeAndAfter states(this, expr->right()->id());
|
||||
Node* right = environment()->Pop();
|
||||
Node* left = environment()->Pop();
|
||||
Node* value = BuildBinaryOp(left, right, expr->op());
|
||||
PrepareFrameStateAfterAndBefore(value, expr->id(),
|
||||
ast_context()->GetStateCombine(),
|
||||
frame_state_before);
|
||||
states.AddToNode(value, expr->id(), ast_context()->GetStateCombine());
|
||||
ast_context()->ProduceValue(value);
|
||||
}
|
||||
}
|
||||
@ -3297,24 +3346,6 @@ void AstGraphBuilder::PrepareFrameState(Node* node, BailoutId ast_id,
|
||||
}
|
||||
|
||||
|
||||
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(
|
||||
node, 0, environment()->Checkpoint(ast_id, combine));
|
||||
|
||||
DCHECK_EQ(IrOpcode::kDead,
|
||||
NodeProperties::GetFrameStateInput(node, 1)->opcode());
|
||||
NodeProperties::ReplaceFrameStateInput(node, 1, frame_state_before);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BitVector* AstGraphBuilder::GetVariablesAssignedInLoop(
|
||||
IterationStatement* stmt) {
|
||||
if (loop_assignment_analysis_ == NULL) return NULL;
|
||||
|
@ -67,6 +67,7 @@ class AstGraphBuilder : public AstVisitor {
|
||||
class ControlScopeForCatch;
|
||||
class ControlScopeForFinally;
|
||||
class Environment;
|
||||
class FrameStateBeforeAndAfter;
|
||||
friend class ControlBuilder;
|
||||
|
||||
Zone* local_zone_;
|
||||
@ -212,9 +213,6 @@ class AstGraphBuilder : public AstVisitor {
|
||||
void PrepareFrameState(
|
||||
Node* node, BailoutId ast_id,
|
||||
OutputFrameStateCombine combine = OutputFrameStateCombine::Ignore());
|
||||
void PrepareFrameStateAfterAndBefore(Node* node, BailoutId ast_id,
|
||||
OutputFrameStateCombine combine,
|
||||
Node* frame_state_before);
|
||||
|
||||
BitVector* GetVariablesAssignedInLoop(IterationStatement* stmt);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user