| Index: src/compiler/ast-graph-builder.cc
|
| diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc
|
| index 9a751a0952ec115d9147ebc63a3c429601ce08f6..8bf9312aa75c25d6b34b00f6a90e3f0a5a88bfa6 100644
|
| --- a/src/compiler/ast-graph-builder.cc
|
| +++ b/src/compiler/ast-graph-builder.cc
|
| @@ -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;
|
|
|