From d8b94f34cc2a4c1604ce8192765738f5ea56462f Mon Sep 17 00:00:00 2001 From: mstarzinger Date: Thu, 28 May 2015 06:22:48 -0700 Subject: [PATCH] [turbofan] Introduce prediction for exception handlers. This introduces a conservative prediction for each exception handler whether it will locally catch an exception or re-throw it to outside the code bondaries. It will allow for a more intuitive prediction of whether an exception is considered "caught" or "uncaught". R=bmeurer@chromium.org,yangguo@chromium.org BUG=chromium:492522 LOG=N Review URL: https://codereview.chromium.org/1158563008 Cr-Commit-Position: refs/heads/master@{#28681} --- src/compiler/arm/instruction-selector-arm.cc | 5 +++ .../arm64/instruction-selector-arm64.cc | 5 +++ src/compiler/ast-graph-builder.cc | 14 +++++-- src/compiler/ast-graph-builder.h | 1 + src/compiler/code-generator.cc | 12 ++++-- src/compiler/code-generator.h | 1 + src/compiler/common-operator.cc | 40 ++++++++++++++++++- src/compiler/common-operator.h | 10 ++++- .../ia32/instruction-selector-ia32.cc | 5 +++ src/compiler/linkage.h | 3 +- .../mips/instruction-selector-mips.cc | 5 +++ .../mips64/instruction-selector-mips64.cc | 5 +++ src/compiler/ppc/instruction-selector-ppc.cc | 5 +++ src/compiler/x64/instruction-selector-x64.cc | 5 +++ src/frames.cc | 3 +- src/objects.cc | 17 +++++--- src/objects.h | 15 ++++++- .../compiler/common-operator-unittest.cc | 27 ++++++++++--- .../compiler/loop-peeling-unittest.cc | 3 +- .../compiler/node-properties-unittest.cc | 3 +- test/unittests/compiler/scheduler-unittest.cc | 6 ++- .../tail-call-optimization-unittest.cc | 6 ++- 22 files changed, 166 insertions(+), 30 deletions(-) diff --git a/src/compiler/arm/instruction-selector-arm.cc b/src/compiler/arm/instruction-selector-arm.cc index 56b155da45..6fb0c5b5d5 100644 --- a/src/compiler/arm/instruction-selector-arm.cc +++ b/src/compiler/arm/instruction-selector-arm.cc @@ -1106,6 +1106,11 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) { // Pass label of exception handler block. CallDescriptor::Flags flags = descriptor->flags(); if (handler) { + DCHECK_EQ(IrOpcode::kIfException, handler->front()->opcode()); + IfExceptionHint hint = OpParameter(handler->front()); + if (hint == IfExceptionHint::kLocallyCaught) { + flags |= CallDescriptor::kHasLocalCatchHandler; + } flags |= CallDescriptor::kHasExceptionHandler; buffer.instruction_args.push_back(g.Label(handler)); } diff --git a/src/compiler/arm64/instruction-selector-arm64.cc b/src/compiler/arm64/instruction-selector-arm64.cc index 88871f5c57..3077ade729 100644 --- a/src/compiler/arm64/instruction-selector-arm64.cc +++ b/src/compiler/arm64/instruction-selector-arm64.cc @@ -1276,6 +1276,11 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) { // Pass label of exception handler block. CallDescriptor::Flags flags = descriptor->flags(); if (handler != nullptr) { + DCHECK_EQ(IrOpcode::kIfException, handler->front()->opcode()); + IfExceptionHint hint = OpParameter(handler->front()); + if (hint == IfExceptionHint::kLocallyCaught) { + flags |= CallDescriptor::kHasLocalCatchHandler; + } flags |= CallDescriptor::kHasExceptionHandler; buffer.instruction_args.push_back(g.Label(handler)); } diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc index aaef0569e7..2a4bdd900e 100644 --- a/src/compiler/ast-graph-builder.cc +++ b/src/compiler/ast-graph-builder.cc @@ -335,9 +335,11 @@ class AstGraphBuilder::ControlScopeForCatch : public ControlScope { ControlScopeForCatch(AstGraphBuilder* owner, TryCatchBuilder* control) : ControlScope(owner), control_(control) { builder()->try_nesting_level_++; // Increment nesting. + builder()->try_catch_nesting_level_++; } ~ControlScopeForCatch() { builder()->try_nesting_level_--; // Decrement nesting. + builder()->try_catch_nesting_level_--; } protected: @@ -437,6 +439,7 @@ AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info, globals_(0, local_zone), execution_control_(nullptr), execution_context_(nullptr), + try_catch_nesting_level_(0), try_nesting_level_(0), input_buffer_size_(0), input_buffer_(nullptr), @@ -3563,17 +3566,22 @@ Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count, } // Add implicit exception continuation for throwing nodes. if (!result->op()->HasProperty(Operator::kNoThrow) && inside_try_scope) { + // Conservative prediction whether caught locally. + IfExceptionHint hint = try_catch_nesting_level_ > 0 + ? IfExceptionHint::kLocallyCaught + : IfExceptionHint::kLocallyUncaught; // Copy the environment for the success continuation. Environment* success_env = environment()->CopyForConditional(); - - Node* on_exception = graph()->NewNode(common()->IfException(), result); + const Operator* op = common()->IfException(hint); + Node* on_exception = graph()->NewNode(op, result); environment_->UpdateControlDependency(on_exception); execution_control()->ThrowValue(on_exception); set_environment(success_env); } // Add implicit success continuation for throwing nodes. if (!result->op()->HasProperty(Operator::kNoThrow)) { - Node* on_success = graph()->NewNode(common()->IfSuccess(), result); + const Operator* op = common()->IfSuccess(); + Node* on_success = graph()->NewNode(op, result); environment_->UpdateControlDependency(on_success); } } diff --git a/src/compiler/ast-graph-builder.h b/src/compiler/ast-graph-builder.h index f9b8b84359..eaaf2a8d69 100644 --- a/src/compiler/ast-graph-builder.h +++ b/src/compiler/ast-graph-builder.h @@ -90,6 +90,7 @@ class AstGraphBuilder : public AstVisitor { SetOncePointer function_context_; // Tracks how many try-blocks are currently entered. + int try_catch_nesting_level_; int try_nesting_level_; // Temporary storage for building node input lists. diff --git a/src/compiler/code-generator.cc b/src/compiler/code-generator.cc index fd7b061e2c..752b3eaa55 100644 --- a/src/compiler/code-generator.cc +++ b/src/compiler/code-generator.cc @@ -156,8 +156,12 @@ Handle CodeGenerator::GenerateCode() { HandlerTable::LengthForReturn(static_cast(handlers_.size())), TENURED)); for (size_t i = 0; i < handlers_.size(); ++i) { + int position = handlers_[i].handler->pos(); + HandlerTable::CatchPrediction prediction = handlers_[i].caught_locally + ? HandlerTable::CAUGHT + : HandlerTable::UNCAUGHT; table->SetReturnOffset(static_cast(i), handlers_[i].pc_offset); - table->SetReturnHandler(static_cast(i), handlers_[i].handler->pos()); + table->SetReturnHandler(static_cast(i), position, prediction); } result->set_handler_table(*table); } @@ -379,9 +383,9 @@ void CodeGenerator::RecordCallPosition(Instruction* instr) { if (flags & CallDescriptor::kHasExceptionHandler) { InstructionOperandConverter i(this, instr); - RpoNumber handler_rpo = - i.InputRpo(static_cast(instr->InputCount()) - 1); - handlers_.push_back({GetLabel(handler_rpo), masm()->pc_offset()}); + bool caught = flags & CallDescriptor::kHasLocalCatchHandler; + RpoNumber handler_rpo = i.InputRpo(instr->InputCount() - 1); + handlers_.push_back({caught, GetLabel(handler_rpo), masm()->pc_offset()}); } if (flags & CallDescriptor::kNeedsNopAfterCall) { diff --git a/src/compiler/code-generator.h b/src/compiler/code-generator.h index a8df2c3d0b..ea53ba62c4 100644 --- a/src/compiler/code-generator.h +++ b/src/compiler/code-generator.h @@ -160,6 +160,7 @@ class CodeGenerator final : public GapResolver::Assembler { }; struct HandlerInfo { + bool caught_locally; Label* handler; int pc_offset; }; diff --git a/src/compiler/common-operator.cc b/src/compiler/common-operator.cc index 330eeec7d9..6e0ecfd6c1 100644 --- a/src/compiler/common-operator.cc +++ b/src/compiler/common-operator.cc @@ -36,6 +36,21 @@ BranchHint BranchHintOf(const Operator* const op) { } +size_t hash_value(IfExceptionHint hint) { return static_cast(hint); } + + +std::ostream& operator<<(std::ostream& os, IfExceptionHint hint) { + switch (hint) { + case IfExceptionHint::kLocallyCaught: + return os << "Caught"; + case IfExceptionHint::kLocallyUncaught: + return os << "Uncaught"; + } + UNREACHABLE(); + return os; +} + + bool operator==(SelectParameters const& lhs, SelectParameters const& rhs) { return lhs.type() == rhs.type() && lhs.hint() == rhs.hint(); } @@ -105,7 +120,6 @@ std::ostream& operator<<(std::ostream& os, ParameterInfo const& i) { V(IfTrue, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \ V(IfFalse, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \ V(IfSuccess, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \ - V(IfException, Operator::kKontrol, 0, 0, 1, 1, 0, 1) \ V(IfDefault, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \ V(Throw, Operator::kKontrol, 1, 1, 1, 0, 0, 1) \ V(Deoptimize, Operator::kNoThrow, 1, 1, 1, 0, 0, 1) \ @@ -210,6 +224,18 @@ struct CommonOperatorGlobalCache final { CACHED_OP_LIST(CACHED) #undef CACHED + template + struct IfExceptionOperator final : public Operator1 { + IfExceptionOperator() + : Operator1( // -- + IrOpcode::kIfException, Operator::kKontrol, // opcode + "IfException", // name + 0, 0, 1, 1, 0, 1, // counts + kCaughtLocally) {} // parameter + }; + IfExceptionOperator kIfExceptionCOperator; + IfExceptionOperator kIfExceptionUOperator; + template struct EndOperator final : public Operator { EndOperator() @@ -385,6 +411,18 @@ const Operator* CommonOperatorBuilder::Branch(BranchHint hint) { } +const Operator* CommonOperatorBuilder::IfException(IfExceptionHint hint) { + switch (hint) { + case IfExceptionHint::kLocallyCaught: + return &cache_.kIfExceptionCOperator; + case IfExceptionHint::kLocallyUncaught: + return &cache_.kIfExceptionUOperator; + } + UNREACHABLE(); + return nullptr; +} + + const Operator* CommonOperatorBuilder::Switch(size_t control_output_count) { DCHECK_GE(control_output_count, 3u); // Disallow trivial switches. return new (zone()) Operator( // -- diff --git a/src/compiler/common-operator.h b/src/compiler/common-operator.h index 1c004448b8..08553bceaa 100644 --- a/src/compiler/common-operator.h +++ b/src/compiler/common-operator.h @@ -34,6 +34,14 @@ std::ostream& operator<<(std::ostream&, BranchHint); BranchHint BranchHintOf(const Operator* const); +// Prediction whether throw-site is surrounded by any local catch-scope. +enum class IfExceptionHint { kLocallyUncaught, kLocallyCaught }; + +size_t hash_value(IfExceptionHint hint); + +std::ostream& operator<<(std::ostream&, IfExceptionHint); + + class SelectParameters final { public: explicit SelectParameters(MachineType type, @@ -94,7 +102,7 @@ class CommonOperatorBuilder final : public ZoneObject { const Operator* IfTrue(); const Operator* IfFalse(); const Operator* IfSuccess(); - const Operator* IfException(); + const Operator* IfException(IfExceptionHint hint); const Operator* Switch(size_t control_output_count); const Operator* IfValue(int32_t value); const Operator* IfDefault(); diff --git a/src/compiler/ia32/instruction-selector-ia32.cc b/src/compiler/ia32/instruction-selector-ia32.cc index 8343dc1a09..e7ddc1ad18 100644 --- a/src/compiler/ia32/instruction-selector-ia32.cc +++ b/src/compiler/ia32/instruction-selector-ia32.cc @@ -843,6 +843,11 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) { // Pass label of exception handler block. CallDescriptor::Flags flags = descriptor->flags(); if (handler) { + DCHECK_EQ(IrOpcode::kIfException, handler->front()->opcode()); + IfExceptionHint hint = OpParameter(handler->front()); + if (hint == IfExceptionHint::kLocallyCaught) { + flags |= CallDescriptor::kHasLocalCatchHandler; + } flags |= CallDescriptor::kHasExceptionHandler; buffer.instruction_args.push_back(g.Label(handler)); } diff --git a/src/compiler/linkage.h b/src/compiler/linkage.h index aa680689d7..abdef7a4ef 100644 --- a/src/compiler/linkage.h +++ b/src/compiler/linkage.h @@ -73,7 +73,8 @@ class CallDescriptor final : public ZoneObject { kPatchableCallSite = 1u << 1, kNeedsNopAfterCall = 1u << 2, kHasExceptionHandler = 1u << 3, - kSupportsTailCalls = 1u << 4, + kHasLocalCatchHandler = 1u << 4, + kSupportsTailCalls = 1u << 5, kPatchableCallSiteWithNop = kPatchableCallSite | kNeedsNopAfterCall }; typedef base::Flags Flags; diff --git a/src/compiler/mips/instruction-selector-mips.cc b/src/compiler/mips/instruction-selector-mips.cc index 6694768702..c042ea11e6 100644 --- a/src/compiler/mips/instruction-selector-mips.cc +++ b/src/compiler/mips/instruction-selector-mips.cc @@ -541,6 +541,11 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) { // Pass label of exception handler block. CallDescriptor::Flags flags = descriptor->flags(); if (handler) { + DCHECK_EQ(IrOpcode::kIfException, handler->front()->opcode()); + IfExceptionHint hint = OpParameter(handler->front()); + if (hint == IfExceptionHint::kLocallyCaught) { + flags |= CallDescriptor::kHasLocalCatchHandler; + } flags |= CallDescriptor::kHasExceptionHandler; buffer.instruction_args.push_back(g.Label(handler)); } diff --git a/src/compiler/mips64/instruction-selector-mips64.cc b/src/compiler/mips64/instruction-selector-mips64.cc index 9fd208d376..05ad5aa1a3 100644 --- a/src/compiler/mips64/instruction-selector-mips64.cc +++ b/src/compiler/mips64/instruction-selector-mips64.cc @@ -690,6 +690,11 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) { // Pass label of exception handler block. CallDescriptor::Flags flags = descriptor->flags(); if (handler) { + DCHECK_EQ(IrOpcode::kIfException, handler->front()->opcode()); + IfExceptionHint hint = OpParameter(handler->front()); + if (hint == IfExceptionHint::kLocallyCaught) { + flags |= CallDescriptor::kHasLocalCatchHandler; + } flags |= CallDescriptor::kHasExceptionHandler; buffer.instruction_args.push_back(g.Label(handler)); } diff --git a/src/compiler/ppc/instruction-selector-ppc.cc b/src/compiler/ppc/instruction-selector-ppc.cc index afe30d4c85..4f1cbe025b 100644 --- a/src/compiler/ppc/instruction-selector-ppc.cc +++ b/src/compiler/ppc/instruction-selector-ppc.cc @@ -1461,6 +1461,11 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) { // Pass label of exception handler block. CallDescriptor::Flags flags = descriptor->flags(); if (handler) { + DCHECK_EQ(IrOpcode::kIfException, handler->front()->opcode()); + IfExceptionHint hint = OpParameter(handler->front()); + if (hint == IfExceptionHint::kLocallyCaught) { + flags |= CallDescriptor::kHasLocalCatchHandler; + } flags |= CallDescriptor::kHasExceptionHandler; buffer.instruction_args.push_back(g.Label(handler)); } diff --git a/src/compiler/x64/instruction-selector-x64.cc b/src/compiler/x64/instruction-selector-x64.cc index 26d8960b91..df0f8809a7 100644 --- a/src/compiler/x64/instruction-selector-x64.cc +++ b/src/compiler/x64/instruction-selector-x64.cc @@ -1047,6 +1047,11 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) { // Pass label of exception handler block. CallDescriptor::Flags flags = descriptor->flags(); if (handler) { + DCHECK_EQ(IrOpcode::kIfException, handler->front()->opcode()); + IfExceptionHint hint = OpParameter(handler->front()); + if (hint == IfExceptionHint::kLocallyCaught) { + flags |= CallDescriptor::kHasLocalCatchHandler; + } flags |= CallDescriptor::kHasExceptionHandler; buffer.instruction_args.push_back(g.Label(handler)); } diff --git a/src/frames.cc b/src/frames.cc index 4dd64aad63..86f2a1166b 100644 --- a/src/frames.cc +++ b/src/frames.cc @@ -983,7 +983,8 @@ int OptimizedFrame::LookupExceptionHandlerInTable(int* stack_slots) { HandlerTable* table = HandlerTable::cast(code->handler_table()); int pc_offset = static_cast(pc() - code->entry()); *stack_slots = code->stack_slots(); - return table->LookupReturn(pc_offset); + HandlerTable::CatchPrediction prediction; // TODO(yangguo): For debugger. + return table->LookupReturn(pc_offset, &prediction); } diff --git a/src/objects.cc b/src/objects.cc index 6048a02b2a..91603ffe14 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -8638,11 +8638,14 @@ int HandlerTable::LookupRange(int pc_offset, int* stack_depth_out) { // TODO(turbofan): Make sure table is sorted and use binary search. -int HandlerTable::LookupReturn(int pc_offset) { +int HandlerTable::LookupReturn(int pc_offset, CatchPrediction* prediction) { for (int i = 0; i < length(); i += kReturnEntrySize) { int return_offset = Smi::cast(get(i + kReturnOffsetIndex))->value(); - int handler_offset = Smi::cast(get(i + kReturnHandlerIndex))->value(); - if (pc_offset == return_offset) return handler_offset; + int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value(); + if (pc_offset == return_offset) { + *prediction = HandlerPredictionField::decode(handler_field); + return HandlerOffsetField::decode(handler_field); + } } return -1; } @@ -11841,12 +11844,14 @@ void HandlerTable::HandlerTableRangePrint(std::ostream& os) { void HandlerTable::HandlerTableReturnPrint(std::ostream& os) { - os << " off hdlr\n"; + os << " off hdlr (c)\n"; for (int i = 0; i < length(); i += kReturnEntrySize) { int pc_offset = Smi::cast(get(i + kReturnOffsetIndex))->value(); - int handler = Smi::cast(get(i + kReturnHandlerIndex))->value(); + int handler_field = Smi::cast(get(i + kReturnHandlerIndex))->value(); + int handler_offset = HandlerOffsetField::decode(handler_field); + CatchPrediction prediction = HandlerPredictionField::decode(handler_field); os << " " << std::setw(4) << pc_offset << " -> " << std::setw(4) - << handler << "\n"; + << handler_offset << " (" << prediction << ")\n"; } } diff --git a/src/objects.h b/src/objects.h index 0e78af87f1..46b457c189 100644 --- a/src/objects.h +++ b/src/objects.h @@ -5159,6 +5159,11 @@ class DeoptimizationOutputData: public FixedArray { // [ return-address-offset , handler-offset ] class HandlerTable : public FixedArray { public: + // Conservative prediction whether a given handler will locally catch an + // exception or cause a re-throw to outside the code boundary. Since this is + // undecidable it is merely an approximation (e.g. useful for debugger). + enum CatchPrediction { UNCAUGHT, CAUGHT }; + // Accessors for handler table based on ranges. void SetRangeStart(int index, int value) { set(index * kRangeEntrySize + kRangeStartIndex, Smi::FromInt(value)); @@ -5177,7 +5182,9 @@ class HandlerTable : public FixedArray { void SetReturnOffset(int index, int value) { set(index * kReturnEntrySize + kReturnOffsetIndex, Smi::FromInt(value)); } - void SetReturnHandler(int index, int value) { + void SetReturnHandler(int index, int offset, CatchPrediction prediction) { + int value = HandlerOffsetField::encode(offset) | + HandlerPredictionField::encode(prediction); set(index * kReturnEntrySize + kReturnHandlerIndex, Smi::FromInt(value)); } @@ -5185,7 +5192,7 @@ class HandlerTable : public FixedArray { int LookupRange(int pc_offset, int* stack_depth); // Lookup handler in a table based on return addresses. - int LookupReturn(int pc_offset); + int LookupReturn(int pc_offset, CatchPrediction* prediction); // Returns the required length of the underlying fixed array. static int LengthForRange(int entries) { return entries * kRangeEntrySize; } @@ -5210,6 +5217,10 @@ class HandlerTable : public FixedArray { static const int kReturnOffsetIndex = 0; static const int kReturnHandlerIndex = 1; static const int kReturnEntrySize = 2; + + // Encoding of the {handler} field. + class HandlerPredictionField : public BitField {}; + class HandlerOffsetField : public BitField {}; }; diff --git a/test/unittests/compiler/common-operator-unittest.cc b/test/unittests/compiler/common-operator-unittest.cc index d2f816beb7..45bb9533d0 100644 --- a/test/unittests/compiler/common-operator-unittest.cc +++ b/test/unittests/compiler/common-operator-unittest.cc @@ -52,7 +52,6 @@ const SharedOperator kSharedOperators[] = { SHARED(IfTrue, Operator::kKontrol, 0, 0, 1, 0, 0, 1), SHARED(IfFalse, Operator::kKontrol, 0, 0, 1, 0, 0, 1), SHARED(IfSuccess, Operator::kKontrol, 0, 0, 1, 0, 0, 1), - SHARED(IfException, Operator::kKontrol, 0, 0, 1, 1, 0, 1), SHARED(Throw, Operator::kKontrol, 1, 1, 1, 0, 0, 1), SHARED(Return, Operator::kNoThrow, 1, 1, 1, 0, 0, 1), SHARED(Terminate, Operator::kKontrol, 0, 1, 1, 0, 0, 1) @@ -178,8 +177,8 @@ const int32_t kInt32Values[] = { 2008792749, 2045320228, std::numeric_limits::max()}; -const BranchHint kHints[] = {BranchHint::kNone, BranchHint::kTrue, - BranchHint::kFalse}; +const BranchHint kBranchHints[] = {BranchHint::kNone, BranchHint::kTrue, + BranchHint::kFalse}; } // namespace @@ -201,7 +200,7 @@ TEST_F(CommonOperatorTest, End) { TEST_F(CommonOperatorTest, Branch) { - TRACED_FOREACH(BranchHint, hint, kHints) { + TRACED_FOREACH(BranchHint, hint, kBranchHints) { const Operator* const op = common()->Branch(hint); EXPECT_EQ(IrOpcode::kBranch, op->opcode()); EXPECT_EQ(Operator::kKontrol, op->properties()); @@ -217,6 +216,24 @@ TEST_F(CommonOperatorTest, Branch) { } +TEST_F(CommonOperatorTest, IfException) { + static const IfExceptionHint kIfExceptionHints[] = { + IfExceptionHint::kLocallyCaught, IfExceptionHint::kLocallyUncaught}; + TRACED_FOREACH(IfExceptionHint, hint, kIfExceptionHints) { + const Operator* const op = common()->IfException(hint); + EXPECT_EQ(IrOpcode::kIfException, op->opcode()); + EXPECT_EQ(Operator::kKontrol, op->properties()); + EXPECT_EQ(0, op->ValueInputCount()); + EXPECT_EQ(0, op->EffectInputCount()); + EXPECT_EQ(1, op->ControlInputCount()); + EXPECT_EQ(1, OperatorProperties::GetTotalInputCount(op)); + EXPECT_EQ(1, op->ValueOutputCount()); + EXPECT_EQ(0, op->EffectOutputCount()); + EXPECT_EQ(1, op->ControlOutputCount()); + } +} + + TEST_F(CommonOperatorTest, Switch) { TRACED_FOREACH(size_t, cases, kCases) { const Operator* const op = common()->Switch(cases); @@ -256,7 +273,7 @@ TEST_F(CommonOperatorTest, Select) { kMachInt32, kMachUint32, kMachInt64, kMachUint64, kMachFloat32, kMachFloat64, kMachAnyTagged}; TRACED_FOREACH(MachineType, type, kTypes) { - TRACED_FOREACH(BranchHint, hint, kHints) { + TRACED_FOREACH(BranchHint, hint, kBranchHints) { const Operator* const op = common()->Select(type, hint); EXPECT_EQ(IrOpcode::kSelect, op->opcode()); EXPECT_EQ(Operator::kPure, op->properties()); diff --git a/test/unittests/compiler/loop-peeling-unittest.cc b/test/unittests/compiler/loop-peeling-unittest.cc index d3eff716a7..c725a27cc0 100644 --- a/test/unittests/compiler/loop-peeling-unittest.cc +++ b/test/unittests/compiler/loop-peeling-unittest.cc @@ -478,7 +478,8 @@ TEST_F(LoopPeelingTest, TwoExitLoopWithCall_nope) { Node* call = graph()->NewNode(&kMockCall, b1.if_true); Node* if_success = graph()->NewNode(common()->IfSuccess(), call); - Node* if_exception = graph()->NewNode(common()->IfException(), call); + Node* if_exception = graph()->NewNode( + common()->IfException(IfExceptionHint::kLocallyUncaught), call); loop->ReplaceInput(1, if_success); Node* merge = graph()->NewNode(common()->Merge(2), b1.if_false, if_exception); diff --git a/test/unittests/compiler/node-properties-unittest.cc b/test/unittests/compiler/node-properties-unittest.cc index 2bec4faf4d..9c73c5e3c5 100644 --- a/test/unittests/compiler/node-properties-unittest.cc +++ b/test/unittests/compiler/node-properties-unittest.cc @@ -104,8 +104,9 @@ TEST_F(NodePropertiesTest, CollectControlProjections_Branch) { TEST_F(NodePropertiesTest, CollectControlProjections_Call) { Node* result[2]; CommonOperatorBuilder common(zone()); + IfExceptionHint h = IfExceptionHint::kLocallyUncaught; Node* call = Node::New(zone(), 1, &kMockCallOperator, 0, nullptr, false); - Node* if_ex = Node::New(zone(), 2, common.IfException(), 1, &call, false); + Node* if_ex = Node::New(zone(), 2, common.IfException(h), 1, &call, false); Node* if_ok = Node::New(zone(), 3, common.IfSuccess(), 1, &call, false); NodeProperties::CollectControlProjections(call, result, arraysize(result)); EXPECT_EQ(if_ok, result[0]); diff --git a/test/unittests/compiler/scheduler-unittest.cc b/test/unittests/compiler/scheduler-unittest.cc index 543ea8a024..b94cb03c00 100644 --- a/test/unittests/compiler/scheduler-unittest.cc +++ b/test/unittests/compiler/scheduler-unittest.cc @@ -1059,10 +1059,12 @@ TARGET_TEST_F(SchedulerTest, CallException) { Node* p0 = graph()->NewNode(common()->Parameter(0), start); Node* c1 = graph()->NewNode(&kMockCall, start); Node* ok1 = graph()->NewNode(common()->IfSuccess(), c1); - Node* ex1 = graph()->NewNode(common()->IfException(), c1); + Node* ex1 = graph()->NewNode( + common()->IfException(IfExceptionHint::kLocallyUncaught), c1); Node* c2 = graph()->NewNode(&kMockCall, ok1); Node* ok2 = graph()->NewNode(common()->IfSuccess(), c2); - Node* ex2 = graph()->NewNode(common()->IfException(), c2); + Node* ex2 = graph()->NewNode( + common()->IfException(IfExceptionHint::kLocallyUncaught), c2); Node* hdl = graph()->NewNode(common()->Merge(2), ex1, ex2); Node* m = graph()->NewNode(common()->Merge(2), ok2, hdl); Node* phi = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), c2, p0, m); diff --git a/test/unittests/compiler/tail-call-optimization-unittest.cc b/test/unittests/compiler/tail-call-optimization-unittest.cc index 72735f50fd..37e37d5182 100644 --- a/test/unittests/compiler/tail-call-optimization-unittest.cc +++ b/test/unittests/compiler/tail-call-optimization-unittest.cc @@ -59,7 +59,8 @@ TEST_F(TailCallOptimizationTest, CallCodeObject1) { Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1, graph()->start(), graph()->start()); Node* if_success = graph()->NewNode(common()->IfSuccess(), call); - Node* if_exception = graph()->NewNode(common()->IfException(), call); + Node* if_exception = graph()->NewNode( + common()->IfException(IfExceptionHint::kLocallyUncaught), call); Node* ret = graph()->NewNode(common()->Return(), call, call, if_success); Node* end = graph()->NewNode(common()->End(1), if_exception); graph()->SetEnd(end); @@ -124,7 +125,8 @@ TEST_F(TailCallOptimizationTest, CallJSFunction1) { Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1, graph()->start(), graph()->start()); Node* if_success = graph()->NewNode(common()->IfSuccess(), call); - Node* if_exception = graph()->NewNode(common()->IfException(), call); + Node* if_exception = graph()->NewNode( + common()->IfException(IfExceptionHint::kLocallyUncaught), call); Node* ret = graph()->NewNode(common()->Return(), call, call, if_success); Node* end = graph()->NewNode(common()->End(1), if_exception); graph()->SetEnd(end);