From 74e328efee7995aeee6d568f9d14f9bbc1087100 Mon Sep 17 00:00:00 2001 From: mstarzinger Date: Wed, 29 Jun 2016 01:42:16 -0700 Subject: [PATCH] [turbofan] Implicitly emit eager checkpoint at graph building. This makes preparation of eager checkpoints within the graph builder implicit. Every sub-expression visitation is now guaranteed to emit valid checkpoints in AstContext. R=jarin@chromium.org BUG=v8:5021 Review-Url: https://codereview.chromium.org/2074703002 Cr-Commit-Position: refs/heads/master@{#37368} --- src/compiler/ast-graph-builder.cc | 216 ++++++++++++------------- src/compiler/ast-graph-builder.h | 3 +- src/compiler/checkpoint-elimination.cc | 29 +++- src/compiler/checkpoint-elimination.h | 4 + src/full-codegen/full-codegen.cc | 2 +- 5 files changed, 133 insertions(+), 121 deletions(-) diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc index 2aec915833..9a8c48a3c0 100644 --- a/src/compiler/ast-graph-builder.cc +++ b/src/compiler/ast-graph-builder.cc @@ -40,14 +40,14 @@ class AstGraphBuilder::AstContext BASE_EMBEDDED { // Plug a node into this expression context. Call this function in tail // position in the Visit functions for expressions. - virtual void ProduceValue(Node* value) = 0; + virtual void ProduceValue(Expression* expr, Node* value) = 0; // Unplugs a node from this expression context. Call this to retrieve the // result of another Visit function that already plugged the context. virtual Node* ConsumeValue() = 0; // Shortcut for "context->ProduceValue(context->ConsumeValue())". - void ReplaceValue() { ProduceValue(ConsumeValue()); } + void ReplaceValue(Expression* expr) { ProduceValue(expr, ConsumeValue()); } protected: AstContext(AstGraphBuilder* owner, Expression::Context kind); @@ -75,7 +75,7 @@ class AstGraphBuilder::AstEffectContext final : public AstContext { explicit AstEffectContext(AstGraphBuilder* owner) : AstContext(owner, Expression::kEffect) {} ~AstEffectContext() final; - void ProduceValue(Node* value) final; + void ProduceValue(Expression* expr, Node* value) final; Node* ConsumeValue() final; }; @@ -86,7 +86,7 @@ class AstGraphBuilder::AstValueContext final : public AstContext { explicit AstValueContext(AstGraphBuilder* owner) : AstContext(owner, Expression::kValue) {} ~AstValueContext() final; - void ProduceValue(Node* value) final; + void ProduceValue(Expression* expr, Node* value) final; Node* ConsumeValue() final; }; @@ -97,7 +97,7 @@ class AstGraphBuilder::AstTestContext final : public AstContext { AstTestContext(AstGraphBuilder* owner, TypeFeedbackId feedback_id) : AstContext(owner, Expression::kTest), feedback_id_(feedback_id) {} ~AstTestContext() final; - void ProduceValue(Node* value) final; + void ProduceValue(Expression* expr, Node* value) final; Node* ConsumeValue() final; private: @@ -968,19 +968,22 @@ AstGraphBuilder::AstTestContext::~AstTestContext() { DCHECK(environment()->stack_height() == original_height_ + 1); } - -void AstGraphBuilder::AstEffectContext::ProduceValue(Node* value) { +void AstGraphBuilder::AstEffectContext::ProduceValue(Expression* expr, + Node* value) { // The value is ignored. + owner()->PrepareEagerCheckpoint(expr->id()); } - -void AstGraphBuilder::AstValueContext::ProduceValue(Node* value) { +void AstGraphBuilder::AstValueContext::ProduceValue(Expression* expr, + Node* value) { environment()->Push(value); + owner()->PrepareEagerCheckpoint(expr->id()); } - -void AstGraphBuilder::AstTestContext::ProduceValue(Node* value) { +void AstGraphBuilder::AstTestContext::ProduceValue(Expression* expr, + Node* value) { environment()->Push(owner()->BuildToBoolean(value, feedback_id_)); + owner()->PrepareEagerCheckpoint(expr->id()); } @@ -1071,7 +1074,7 @@ void AstGraphBuilder::VisitForValue(Expression* expr) { if (!CheckStackOverflow()) { expr->Accept(this); } else { - ast_context()->ProduceValue(jsgraph()->UndefinedConstant()); + ast_context()->ProduceValue(expr, jsgraph()->UndefinedConstant()); } } @@ -1081,7 +1084,7 @@ void AstGraphBuilder::VisitForEffect(Expression* expr) { if (!CheckStackOverflow()) { expr->Accept(this); } else { - ast_context()->ProduceValue(jsgraph()->UndefinedConstant()); + ast_context()->ProduceValue(expr, jsgraph()->UndefinedConstant()); } } @@ -1091,7 +1094,7 @@ void AstGraphBuilder::VisitForTest(Expression* expr) { if (!CheckStackOverflow()) { expr->Accept(this); } else { - ast_context()->ProduceValue(jsgraph()->UndefinedConstant()); + ast_context()->ProduceValue(expr, jsgraph()->UndefinedConstant()); } } @@ -1101,7 +1104,7 @@ void AstGraphBuilder::Visit(Expression* expr) { if (!CheckStackOverflow()) { expr->Accept(this); } else { - ast_context()->ProduceValue(jsgraph()->UndefinedConstant()); + ast_context()->ProduceValue(expr, jsgraph()->UndefinedConstant()); } } @@ -1433,10 +1436,13 @@ void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) { test_value.Then(); test_value.Else(); { + environment()->Push(value); + PrepareEagerCheckpoint(stmt->FilterId()); + value = environment()->Pop(); // Bind value and do loop body. VectorSlotPair feedback = CreateVectorSlotPair(stmt->EachFeedbackSlot()); - VisitForInAssignment(stmt->each(), value, feedback, stmt->FilterId(), + VisitForInAssignment(stmt->each(), value, feedback, stmt->AssignmentId()); VisitIterationBody(stmt, &for_loop); } @@ -1584,7 +1590,7 @@ void AstGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { PretenureFlag pretenure = expr->pretenure() ? TENURED : NOT_TENURED; const Operator* op = javascript()->CreateClosure(shared_info, pretenure); Node* value = NewNode(op); - ast_context()->ProduceValue(value); + ast_context()->ProduceValue(expr, value); } @@ -1699,7 +1705,7 @@ void AstGraphBuilder::VisitClassLiteralContents(ClassLiteral* expr) { BuildVariableAssignment(var, literal, Token::INIT, feedback, BailoutId::None()); } - ast_context()->ProduceValue(literal); + ast_context()->ProduceValue(expr, literal); } @@ -1711,7 +1717,7 @@ void AstGraphBuilder::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) { void AstGraphBuilder::VisitDoExpression(DoExpression* expr) { VisitBlock(expr->block()); VisitVariableProxy(expr->result()); - ast_context()->ReplaceValue(); + ast_context()->ReplaceValue(expr); } @@ -1725,7 +1731,11 @@ void AstGraphBuilder::VisitConditional(Conditional* expr) { compare_if.Else(); Visit(expr->else_expression()); compare_if.End(); - ast_context()->ReplaceValue(); + // Skip plugging AST evaluation contexts of the test kind. This is to stay in + // sync with full codegen which doesn't prepare the proper bailout point (see + // the implementation of FullCodeGenerator::VisitForControl). + if (ast_context()->IsTest()) return; + ast_context()->ReplaceValue(expr); } @@ -1734,13 +1744,13 @@ void AstGraphBuilder::VisitVariableProxy(VariableProxy* expr) { PrepareEagerCheckpoint(BeforeId(expr)); Node* value = BuildVariableLoad(expr->var(), expr->id(), pair, ast_context()->GetStateCombine()); - ast_context()->ProduceValue(value); + ast_context()->ProduceValue(expr, value); } void AstGraphBuilder::VisitLiteral(Literal* expr) { Node* value = jsgraph()->Constant(expr->value()); - ast_context()->ProduceValue(value); + ast_context()->ProduceValue(expr, value); } @@ -1752,7 +1762,7 @@ void AstGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { expr->pattern(), expr->flags(), expr->literal_index()); Node* literal = NewNode(op, closure); PrepareFrameState(literal, expr->id(), ast_context()->GetStateCombine()); - ast_context()->ProduceValue(literal); + ast_context()->ProduceValue(expr, literal); } @@ -1792,7 +1802,6 @@ void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { if (key->value()->IsInternalizedString()) { if (property->emit_store()) { VisitForValue(property->value()); - PrepareEagerCheckpoint(property->value()->id()); Node* value = environment()->Pop(); Node* literal = environment()->Top(); Handle name = key->AsPropertyName(); @@ -1938,7 +1947,7 @@ void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { } } - ast_context()->ProduceValue(environment()->Pop()); + ast_context()->ProduceValue(expr, environment()->Pop()); } @@ -1977,16 +1986,13 @@ void AstGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; VisitForValue(subexpr); - { - PrepareEagerCheckpoint(subexpr->id()); - VectorSlotPair pair = CreateVectorSlotPair(expr->LiteralFeedbackSlot()); - Node* value = environment()->Pop(); - Node* index = jsgraph()->Constant(array_index); - Node* literal = environment()->Top(); - Node* store = BuildKeyedStore(literal, index, value, pair); - PrepareFrameState(store, expr->GetIdForElement(array_index), - OutputFrameStateCombine::Ignore()); - } + VectorSlotPair pair = CreateVectorSlotPair(expr->LiteralFeedbackSlot()); + Node* value = environment()->Pop(); + Node* index = jsgraph()->Constant(array_index); + Node* literal = environment()->Top(); + Node* store = BuildKeyedStore(literal, index, value, pair); + PrepareFrameState(store, expr->GetIdForElement(array_index), + OutputFrameStateCombine::Ignore()); } // In case the array literal contains spread expressions it has two parts. The @@ -2009,14 +2015,12 @@ void AstGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { } } - ast_context()->ProduceValue(environment()->Pop()); + ast_context()->ProduceValue(expr, environment()->Pop()); } - void AstGraphBuilder::VisitForInAssignment(Expression* expr, Node* value, const VectorSlotPair& feedback, - BailoutId bailout_id_before, - BailoutId bailout_id_after) { + BailoutId bailout_id) { DCHECK(expr->IsValidReferenceExpressionOrThis()); // Left-hand side can only be a property, a global or a variable slot. @@ -2027,50 +2031,40 @@ void AstGraphBuilder::VisitForInAssignment(Expression* expr, Node* value, switch (assign_type) { case VARIABLE: { Variable* var = expr->AsVariableProxy()->var(); - environment()->Push(value); - PrepareEagerCheckpoint(bailout_id_before); - value = environment()->Pop(); - BuildVariableAssignment(var, value, Token::ASSIGN, feedback, - bailout_id_after); + BuildVariableAssignment(var, value, Token::ASSIGN, feedback, bailout_id); break; } case NAMED_PROPERTY: { environment()->Push(value); VisitForValue(property->obj()); - PrepareEagerCheckpoint(property->obj()->id()); Node* object = environment()->Pop(); value = environment()->Pop(); Handle name = property->key()->AsLiteral()->AsPropertyName(); Node* store = BuildNamedStore(object, name, value, feedback); - PrepareFrameState(store, bailout_id_after, - OutputFrameStateCombine::Ignore()); + PrepareFrameState(store, bailout_id, OutputFrameStateCombine::Ignore()); break; } case KEYED_PROPERTY: { environment()->Push(value); VisitForValue(property->obj()); VisitForValue(property->key()); - PrepareEagerCheckpoint(property->key()->id()); Node* key = environment()->Pop(); Node* object = environment()->Pop(); value = environment()->Pop(); Node* store = BuildKeyedStore(object, key, value, feedback); - PrepareFrameState(store, bailout_id_after, - OutputFrameStateCombine::Ignore()); + PrepareFrameState(store, bailout_id, OutputFrameStateCombine::Ignore()); break; } case NAMED_SUPER_PROPERTY: { environment()->Push(value); VisitForValue(property->obj()->AsSuperPropertyReference()->this_var()); VisitForValue(property->obj()->AsSuperPropertyReference()->home_object()); - PrepareEagerCheckpoint(property->obj()->id()); Node* home_object = environment()->Pop(); Node* receiver = environment()->Pop(); value = environment()->Pop(); Handle name = property->key()->AsLiteral()->AsPropertyName(); Node* store = BuildNamedSuperStore(receiver, home_object, name, value); - PrepareFrameState(store, bailout_id_after, - OutputFrameStateCombine::Ignore()); + PrepareFrameState(store, bailout_id, OutputFrameStateCombine::Ignore()); break; } case KEYED_SUPER_PROPERTY: { @@ -2078,14 +2072,12 @@ void AstGraphBuilder::VisitForInAssignment(Expression* expr, Node* value, VisitForValue(property->obj()->AsSuperPropertyReference()->this_var()); VisitForValue(property->obj()->AsSuperPropertyReference()->home_object()); VisitForValue(property->key()); - PrepareEagerCheckpoint(property->key()->id()); Node* key = environment()->Pop(); Node* home_object = environment()->Pop(); Node* receiver = environment()->Pop(); value = environment()->Pop(); Node* store = BuildKeyedSuperStore(receiver, home_object, key, value); - PrepareFrameState(store, bailout_id_after, - OutputFrameStateCombine::Ignore()); + PrepareFrameState(store, bailout_id, OutputFrameStateCombine::Ignore()); break; } } @@ -2129,7 +2121,6 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) { break; } - 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. if (expr->is_compound()) { @@ -2149,7 +2140,6 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) { Handle name = property->key()->AsLiteral()->AsPropertyName(); VectorSlotPair pair = CreateVectorSlotPair(property->PropertyFeedbackSlot()); - PrepareEagerCheckpoint(property->obj()->id()); old_value = BuildNamedLoad(object, name, pair); PrepareFrameState(old_value, property->LoadId(), OutputFrameStateCombine::Push()); @@ -2160,7 +2150,6 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) { Node* object = environment()->Peek(1); VectorSlotPair pair = CreateVectorSlotPair(property->PropertyFeedbackSlot()); - PrepareEagerCheckpoint(property->key()->id()); old_value = BuildKeyedLoad(object, key, pair); PrepareFrameState(old_value, property->LoadId(), OutputFrameStateCombine::Push()); @@ -2172,7 +2161,6 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) { Handle name = property->key()->AsLiteral()->AsPropertyName(); VectorSlotPair pair = CreateVectorSlotPair(property->PropertyFeedbackSlot()); - PrepareEagerCheckpoint(property->obj()->id()); old_value = BuildNamedSuperLoad(receiver, home_object, name, pair); PrepareFrameState(old_value, property->LoadId(), OutputFrameStateCombine::Push()); @@ -2184,7 +2172,6 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) { Node* receiver = environment()->Peek(2); VectorSlotPair pair = CreateVectorSlotPair(property->PropertyFeedbackSlot()); - PrepareEagerCheckpoint(property->key()->id()); old_value = BuildKeyedSuperLoad(receiver, home_object, key, pair); PrepareFrameState(old_value, property->LoadId(), OutputFrameStateCombine::Push()); @@ -2206,17 +2193,13 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) { } environment()->Push(value); if (needs_frame_state_before) { - before_store_id = expr->binary_operation()->id(); + PrepareEagerCheckpoint(expr->binary_operation()->id()); } } else { VisitForValue(expr->value()); - if (needs_frame_state_before) { - before_store_id = expr->value()->id(); - } } // Store the value. - PrepareEagerCheckpoint(before_store_id); Node* value = environment()->Pop(); VectorSlotPair feedback = CreateVectorSlotPair(expr->AssignmentSlot()); switch (assign_type) { @@ -2258,14 +2241,14 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) { } } - ast_context()->ProduceValue(value); + ast_context()->ProduceValue(expr, value); } void AstGraphBuilder::VisitYield(Yield* expr) { // Generator functions are supported only by going through Ignition first. SetStackOverflow(); - ast_context()->ProduceValue(jsgraph()->UndefinedConstant()); + ast_context()->ProduceValue(expr, jsgraph()->UndefinedConstant()); } @@ -2273,7 +2256,7 @@ void AstGraphBuilder::VisitThrow(Throw* expr) { VisitForValue(expr->exception()); Node* exception = environment()->Pop(); Node* value = BuildThrowError(exception, expr->id()); - ast_context()->ProduceValue(value); + ast_context()->ProduceValue(expr, value); } @@ -2287,7 +2270,6 @@ void AstGraphBuilder::VisitProperty(Property* expr) { break; case NAMED_PROPERTY: { VisitForValue(expr->obj()); - PrepareEagerCheckpoint(expr->obj()->id()); Node* object = environment()->Pop(); Handle name = expr->key()->AsLiteral()->AsPropertyName(); value = BuildNamedLoad(object, name, pair); @@ -2297,7 +2279,6 @@ void AstGraphBuilder::VisitProperty(Property* expr) { case KEYED_PROPERTY: { VisitForValue(expr->obj()); VisitForValue(expr->key()); - PrepareEagerCheckpoint(expr->key()->id()); Node* key = environment()->Pop(); Node* object = environment()->Pop(); value = BuildKeyedLoad(object, key, pair); @@ -2307,7 +2288,6 @@ void AstGraphBuilder::VisitProperty(Property* expr) { case NAMED_SUPER_PROPERTY: { VisitForValue(expr->obj()->AsSuperPropertyReference()->this_var()); VisitForValue(expr->obj()->AsSuperPropertyReference()->home_object()); - PrepareEagerCheckpoint(expr->obj()->id()); Node* home_object = environment()->Pop(); Node* receiver = environment()->Pop(); Handle name = expr->key()->AsLiteral()->AsPropertyName(); @@ -2319,7 +2299,6 @@ void AstGraphBuilder::VisitProperty(Property* expr) { VisitForValue(expr->obj()->AsSuperPropertyReference()->this_var()); VisitForValue(expr->obj()->AsSuperPropertyReference()->home_object()); VisitForValue(expr->key()); - PrepareEagerCheckpoint(expr->key()->id()); Node* key = environment()->Pop(); Node* home_object = environment()->Pop(); Node* receiver = environment()->Pop(); @@ -2328,7 +2307,7 @@ void AstGraphBuilder::VisitProperty(Property* expr) { break; } } - ast_context()->ProduceValue(value); + ast_context()->ProduceValue(expr, value); } @@ -2371,7 +2350,6 @@ void AstGraphBuilder::VisitCall(Call* expr) { VectorSlotPair feedback = CreateVectorSlotPair(property->PropertyFeedbackSlot()); VisitForValue(property->obj()); - PrepareEagerCheckpoint(property->obj()->id()); Handle name = property->key()->AsLiteral()->AsPropertyName(); Node* object = environment()->Top(); callee_value = BuildNamedLoad(object, name, feedback); @@ -2390,7 +2368,6 @@ void AstGraphBuilder::VisitCall(Call* expr) { CreateVectorSlotPair(property->PropertyFeedbackSlot()); VisitForValue(property->obj()); VisitForValue(property->key()); - PrepareEagerCheckpoint(property->key()->id()); Node* key = environment()->Pop(); Node* object = environment()->Top(); callee_value = BuildKeyedLoad(object, key, feedback); @@ -2412,7 +2389,6 @@ void AstGraphBuilder::VisitCall(Call* expr) { Node* home = environment()->Peek(1); Node* object = environment()->Top(); Handle name = property->key()->AsLiteral()->AsPropertyName(); - PrepareEagerCheckpoint(property->obj()->id()); callee_value = BuildNamedSuperLoad(object, home, name, VectorSlotPair()); PrepareFrameState(callee_value, property->LoadId(), OutputFrameStateCombine::Push()); @@ -2435,7 +2411,6 @@ void AstGraphBuilder::VisitCall(Call* expr) { Node* key = environment()->Pop(); Node* home = environment()->Pop(); Node* object = environment()->Pop(); - PrepareEagerCheckpoint(property->key()->id()); callee_value = BuildKeyedSuperLoad(object, home, key, VectorSlotPair()); PrepareFrameState(callee_value, property->LoadId(), OutputFrameStateCombine::Push()); @@ -2511,12 +2486,12 @@ void AstGraphBuilder::VisitCall(Call* expr) { VectorSlotPair feedback = CreateVectorSlotPair(expr->CallFeedbackICSlot()); const Operator* call = javascript()->CallFunction( args->length() + 2, feedback, receiver_hint, expr->tail_call_mode()); - PrepareEagerCheckpoint(expr->CallId()); + PrepareEagerCheckpoint(possibly_eval ? expr->EvalId() : expr->CallId()); Node* value = ProcessArguments(call, args->length() + 2); environment()->Push(value->InputAt(0)); // The callee passed to the call. PrepareFrameState(value, expr->ReturnId(), OutputFrameStateCombine::Push()); environment()->Drop(1); - ast_context()->ProduceValue(value); + ast_context()->ProduceValue(expr, value); } @@ -2542,10 +2517,9 @@ void AstGraphBuilder::VisitCallSuper(Call* expr) { // Create node to perform the super call. const Operator* call = javascript()->CallConstruct(args->length() + 2, VectorSlotPair()); - PrepareEagerCheckpoint(super->new_target_var()->id()); Node* value = ProcessArguments(call, args->length() + 2); PrepareFrameState(value, expr->ReturnId(), OutputFrameStateCombine::Push()); - ast_context()->ProduceValue(value); + ast_context()->ProduceValue(expr, value); } @@ -2556,11 +2530,6 @@ void AstGraphBuilder::VisitCallNew(CallNew* expr) { ZoneList* args = expr->arguments(); VisitForValues(args); - // The baseline compiler doesn't push the new.target, so we need to record - // the frame state before the push. - PrepareEagerCheckpoint(args->is_empty() ? expr->expression()->id() - : args->last()->id()); - // The new target is the same as the callee. environment()->Push(environment()->Peek(args->length())); @@ -2570,7 +2539,7 @@ void AstGraphBuilder::VisitCallNew(CallNew* expr) { javascript()->CallConstruct(args->length() + 2, feedback); Node* value = ProcessArguments(call, args->length() + 2); PrepareFrameState(value, expr->ReturnId(), OutputFrameStateCombine::Push()); - ast_context()->ProduceValue(value); + ast_context()->ProduceValue(expr, value); } @@ -2592,7 +2561,7 @@ void AstGraphBuilder::VisitCallJSRuntime(CallRuntime* expr) { PrepareEagerCheckpoint(expr->CallId()); Node* value = ProcessArguments(call, args->length() + 2); PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); - ast_context()->ProduceValue(value); + ast_context()->ProduceValue(expr, value); } @@ -2610,10 +2579,13 @@ void AstGraphBuilder::VisitCallRuntime(CallRuntime* expr) { // Create node to perform the runtime call. Runtime::FunctionId functionId = expr->function()->function_id; const Operator* call = javascript()->CallRuntime(functionId, args->length()); - PrepareEagerCheckpoint(expr->CallId()); + if (expr->function()->intrinsic_type == Runtime::IntrinsicType::RUNTIME || + expr->function()->function_id == Runtime::kInlineCall) { + PrepareEagerCheckpoint(expr->CallId()); + } Node* value = ProcessArguments(call, args->length()); PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); - ast_context()->ProduceValue(value); + ast_context()->ProduceValue(expr, value); } @@ -2661,7 +2633,6 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) { } case NAMED_PROPERTY: { VisitForValue(property->obj()); - PrepareEagerCheckpoint(property->obj()->id()); Node* object = environment()->Top(); Handle name = property->key()->AsLiteral()->AsPropertyName(); VectorSlotPair pair = @@ -2675,7 +2646,6 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) { case KEYED_PROPERTY: { VisitForValue(property->obj()); VisitForValue(property->key()); - PrepareEagerCheckpoint(property->key()->id()); Node* key = environment()->Top(); Node* object = environment()->Peek(1); VectorSlotPair pair = @@ -2689,7 +2659,6 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) { case NAMED_SUPER_PROPERTY: { VisitForValue(property->obj()->AsSuperPropertyReference()->this_var()); VisitForValue(property->obj()->AsSuperPropertyReference()->home_object()); - PrepareEagerCheckpoint(property->obj()->id()); Node* home_object = environment()->Top(); Node* receiver = environment()->Peek(1); Handle name = property->key()->AsLiteral()->AsPropertyName(); @@ -2705,7 +2674,6 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) { VisitForValue(property->obj()->AsSuperPropertyReference()->this_var()); VisitForValue(property->obj()->AsSuperPropertyReference()->home_object()); VisitForValue(property->key()); - PrepareEagerCheckpoint(property->obj()->id()); Node* key = environment()->Top(); Node* home_object = environment()->Peek(1); Node* receiver = environment()->Peek(2); @@ -2804,7 +2772,7 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) { // Restore old value for postfix expressions. if (is_postfix) value = environment()->Pop(); - ast_context()->ProduceValue(value); + ast_context()->ProduceValue(expr, value); } @@ -2824,7 +2792,7 @@ void AstGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { Node* value = BuildBinaryOp(left, right, expr->op(), expr->BinaryOperationFeedbackId()); states.AddToNode(value, expr->id(), ast_context()->GetStateCombine()); - ast_context()->ProduceValue(value); + ast_context()->ProduceValue(expr, value); } } } @@ -2844,23 +2812,21 @@ void AstGraphBuilder::VisitLiteralCompareNil(CompareOperation* expr, UNREACHABLE(); } VisitForValue(sub_expr); - PrepareEagerCheckpoint(sub_expr->id()); Node* value_to_compare = environment()->Pop(); Node* value = NewNode(op, value_to_compare, nil_value); PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); - return ast_context()->ProduceValue(value); + return ast_context()->ProduceValue(expr, value); } void AstGraphBuilder::VisitLiteralCompareTypeof(CompareOperation* expr, Expression* sub_expr, Handle check) { VisitTypeofExpression(sub_expr); - PrepareEagerCheckpoint(sub_expr->id()); Node* typeof_arg = NewNode(javascript()->TypeOf(), environment()->Pop()); Node* value = NewNode(javascript()->StrictEqual(CompareOperationHints::Any()), typeof_arg, jsgraph()->Constant(check)); PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); - return ast_context()->ProduceValue(value); + return ast_context()->ProduceValue(expr, value); } void AstGraphBuilder::VisitCompareOperation(CompareOperation* expr) { @@ -2930,7 +2896,7 @@ void AstGraphBuilder::VisitCompareOperation(CompareOperation* expr) { Node* left = environment()->Pop(); Node* value = NewNode(op, left, right); states.AddToNode(value, expr->id(), ast_context()->GetStateCombine()); - ast_context()->ProduceValue(value); + ast_context()->ProduceValue(expr, value); } @@ -2948,14 +2914,14 @@ void AstGraphBuilder::VisitEmptyParentheses(EmptyParentheses* expr) { void AstGraphBuilder::VisitThisFunction(ThisFunction* expr) { Node* value = GetFunctionClosure(); - ast_context()->ProduceValue(value); + ast_context()->ProduceValue(expr, value); } void AstGraphBuilder::VisitSuperPropertyReference( SuperPropertyReference* expr) { Node* value = BuildThrowUnsupportedSuperError(expr->id()); - ast_context()->ProduceValue(value); + ast_context()->ProduceValue(expr, value); } @@ -3036,14 +3002,14 @@ void AstGraphBuilder::VisitDelete(UnaryOperation* expr) { VisitForEffect(expr->expression()); value = jsgraph()->TrueConstant(); } - ast_context()->ProduceValue(value); + ast_context()->ProduceValue(expr, value); } void AstGraphBuilder::VisitVoid(UnaryOperation* expr) { VisitForEffect(expr->expression()); Node* value = jsgraph()->UndefinedConstant(); - ast_context()->ProduceValue(value); + ast_context()->ProduceValue(expr, value); } void AstGraphBuilder::VisitTypeofExpression(Expression* expr) { @@ -3065,33 +3031,46 @@ void AstGraphBuilder::VisitTypeofExpression(Expression* expr) { void AstGraphBuilder::VisitTypeof(UnaryOperation* expr) { VisitTypeofExpression(expr->expression()); Node* value = NewNode(javascript()->TypeOf(), environment()->Pop()); - ast_context()->ProduceValue(value); + ast_context()->ProduceValue(expr, value); } void AstGraphBuilder::VisitNot(UnaryOperation* expr) { - VisitForValue(expr->expression()); - Node* operand = environment()->Pop(); - Node* input = BuildToBoolean(operand, expr->expression()->test_id()); + VisitForTest(expr->expression()); + Node* input = environment()->Pop(); Node* value = NewNode(common()->Select(MachineRepresentation::kTagged), input, jsgraph()->FalseConstant(), jsgraph()->TrueConstant()); - ast_context()->ProduceValue(value); + // Skip plugging AST evaluation contexts of the test kind. This is to stay in + // sync with full codegen which doesn't prepare the proper bailout point (see + // the implementation of FullCodeGenerator::VisitForControl). + if (ast_context()->IsTest()) return environment()->Push(value); + ast_context()->ProduceValue(expr, value); } void AstGraphBuilder::VisitComma(BinaryOperation* expr) { VisitForEffect(expr->left()); Visit(expr->right()); - ast_context()->ReplaceValue(); + ast_context()->ReplaceValue(expr); } void AstGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) { bool is_logical_and = expr->op() == Token::AND; IfBuilder compare_if(this); - VisitForValue(expr->left()); - Node* condition = environment()->Top(); - compare_if.If(BuildToBoolean(condition, expr->left()->test_id())); + // Only use an AST evaluation context of the value kind when this expression + // is evaluated as value as well. Otherwise stick to a test context which is + // in sync with full codegen (see FullCodeGenerator::VisitLogicalExpression). + Node* condition = nullptr; + if (ast_context()->IsValue()) { + VisitForValue(expr->left()); + Node* left = environment()->Top(); + condition = BuildToBoolean(left, expr->left()->test_id()); + } else { + VisitForTest(expr->left()); + condition = environment()->Top(); + } + compare_if.If(condition); compare_if.Then(); if (is_logical_and) { environment()->Pop(); @@ -3111,7 +3090,11 @@ void AstGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) { environment()->Poke(0, jsgraph()->FalseConstant()); } compare_if.End(); - ast_context()->ReplaceValue(); + // Skip plugging AST evaluation contexts of the test kind. This is to stay in + // sync with full codegen which doesn't prepare the proper bailout point (see + // the implementation of FullCodeGenerator::VisitForControl). + if (ast_context()->IsTest()) return; + ast_context()->ReplaceValue(expr); } @@ -4072,6 +4055,7 @@ void AstGraphBuilder::PrepareEagerCheckpoint(BailoutId ast_id) { return; } if (ast_id != BailoutId::None()) { + DCHECK(info()->shared_info()->VerifyBailoutId(ast_id)); Node* node = NewNode(common()->Checkpoint()); DCHECK_EQ(IrOpcode::kDead, NodeProperties::GetFrameStateInput(node, 0)->opcode()); diff --git a/src/compiler/ast-graph-builder.h b/src/compiler/ast-graph-builder.h index 8346a51d01..c3603d8b96 100644 --- a/src/compiler/ast-graph-builder.h +++ b/src/compiler/ast-graph-builder.h @@ -445,8 +445,7 @@ class AstGraphBuilder : public AstVisitor { // Dispatched from VisitForInStatement. void VisitForInAssignment(Expression* expr, Node* value, const VectorSlotPair& feedback, - BailoutId bailout_id_before, - BailoutId bailout_id_after); + BailoutId bailout_id); // Dispatched from VisitObjectLiteral. void VisitObjectLiteralAccessor(Node* home_object, diff --git a/src/compiler/checkpoint-elimination.cc b/src/compiler/checkpoint-elimination.cc index d81e109682..ce1a861056 100644 --- a/src/compiler/checkpoint-elimination.cc +++ b/src/compiler/checkpoint-elimination.cc @@ -30,14 +30,39 @@ bool IsRedundantCheckpoint(Node* node) { } // namespace -Reduction CheckpointElimination::Reduce(Node* node) { - if (node->opcode() != IrOpcode::kCheckpoint) return NoChange(); +Reduction CheckpointElimination::ReduceCheckpoint(Node* node) { + DCHECK_EQ(IrOpcode::kCheckpoint, node->opcode()); if (IsRedundantCheckpoint(node)) { return Replace(NodeProperties::GetEffectInput(node)); } return NoChange(); } +Reduction CheckpointElimination::ReduceReturn(Node* node) { + DCHECK_EQ(IrOpcode::kReturn, node->opcode()); + Node* effect = NodeProperties::GetEffectInput(node); + if (effect->opcode() == IrOpcode::kCheckpoint && effect->OwnedBy(node)) { + // Any checkpoint that is wholly owned by a {Return} node can never be used + // for an actual bailout and can hence be cut out of the effect chain. + Node* replacement = NodeProperties::GetEffectInput(effect); + NodeProperties::ReplaceEffectInput(node, replacement); + return Changed(node); + } + return NoChange(); +} + +Reduction CheckpointElimination::Reduce(Node* node) { + switch (node->opcode()) { + case IrOpcode::kCheckpoint: + return ReduceCheckpoint(node); + case IrOpcode::kReturn: + return ReduceReturn(node); + default: + break; + } + return NoChange(); +} + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/src/compiler/checkpoint-elimination.h b/src/compiler/checkpoint-elimination.h index 4d6aadac2f..deb4c38b01 100644 --- a/src/compiler/checkpoint-elimination.h +++ b/src/compiler/checkpoint-elimination.h @@ -18,6 +18,10 @@ class CheckpointElimination final : public AdvancedReducer { ~CheckpointElimination() final {} Reduction Reduce(Node* node) final; + + private: + Reduction ReduceCheckpoint(Node* node); + Reduction ReduceReturn(Node* node); }; } // namespace compiler diff --git a/src/full-codegen/full-codegen.cc b/src/full-codegen/full-codegen.cc index 9a82492f9b..1632935c07 100644 --- a/src/full-codegen/full-codegen.cc +++ b/src/full-codegen/full-codegen.cc @@ -875,7 +875,7 @@ void FullCodeGenerator::VisitDoExpression(DoExpression* expr) { Comment cmnt(masm_, "[ Do Expression"); SetExpressionPosition(expr); VisitBlock(expr->block()); - EmitVariableLoad(expr->result()); + VisitInDuplicateContext(expr->result()); }