[turbofan] Introduce prediction for exception handlers.
authormstarzinger <mstarzinger@chromium.org>
Thu, 28 May 2015 13:22:48 +0000 (06:22 -0700)
committerCommit bot <commit-bot@chromium.org>
Thu, 28 May 2015 13:23:03 +0000 (13:23 +0000)
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}

22 files changed:
src/compiler/arm/instruction-selector-arm.cc
src/compiler/arm64/instruction-selector-arm64.cc
src/compiler/ast-graph-builder.cc
src/compiler/ast-graph-builder.h
src/compiler/code-generator.cc
src/compiler/code-generator.h
src/compiler/common-operator.cc
src/compiler/common-operator.h
src/compiler/ia32/instruction-selector-ia32.cc
src/compiler/linkage.h
src/compiler/mips/instruction-selector-mips.cc
src/compiler/mips64/instruction-selector-mips64.cc
src/compiler/ppc/instruction-selector-ppc.cc
src/compiler/x64/instruction-selector-x64.cc
src/frames.cc
src/objects.cc
src/objects.h
test/unittests/compiler/common-operator-unittest.cc
test/unittests/compiler/loop-peeling-unittest.cc
test/unittests/compiler/node-properties-unittest.cc
test/unittests/compiler/scheduler-unittest.cc
test/unittests/compiler/tail-call-optimization-unittest.cc

index 56b155da45bbc7b1ac0daece5c29c6074fb7e638..6fb0c5b5d5f61d8ef88418f8c86b191030f0613f 100644 (file)
@@ -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<IfExceptionHint>(handler->front());
+    if (hint == IfExceptionHint::kLocallyCaught) {
+      flags |= CallDescriptor::kHasLocalCatchHandler;
+    }
     flags |= CallDescriptor::kHasExceptionHandler;
     buffer.instruction_args.push_back(g.Label(handler));
   }
index 88871f5c572d1f379c206c1ace0f52df431ebc1d..3077ade7295e0d2269f639fd914c24dabc046c7a 100644 (file)
@@ -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<IfExceptionHint>(handler->front());
+    if (hint == IfExceptionHint::kLocallyCaught) {
+      flags |= CallDescriptor::kHasLocalCatchHandler;
+    }
     flags |= CallDescriptor::kHasExceptionHandler;
     buffer.instruction_args.push_back(g.Label(handler));
   }
index aaef0569e7b7e172d1a16e0fbcc45c3e322cd5bc..2a4bdd900eee2e95c8595b50c1b1175d74b05b75 100644 (file)
@@ -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);
       }
     }
index f9b8b84359f998d1d1321133bc11835ba6750a3a..eaaf2a8d69b65f3e5f252bb59993c1559a803153 100644 (file)
@@ -90,6 +90,7 @@ class AstGraphBuilder : public AstVisitor {
   SetOncePointer<Node> 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.
index fd7b061e2c87d4cec09495b22b5610dce14b8771..752b3eaa55fa9419726624b32b98647c526da740 100644 (file)
@@ -156,8 +156,12 @@ Handle<Code> CodeGenerator::GenerateCode() {
             HandlerTable::LengthForReturn(static_cast<int>(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<int>(i), handlers_[i].pc_offset);
-      table->SetReturnHandler(static_cast<int>(i), handlers_[i].handler->pos());
+      table->SetReturnHandler(static_cast<int>(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<int>(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) {
index a8df2c3d0b9f4ec53f7c579f80506548a5e4dc27..ea53ba62c4625915f8ecc5b3d61a21da8fd8265b 100644 (file)
@@ -160,6 +160,7 @@ class CodeGenerator final : public GapResolver::Assembler {
   };
 
   struct HandlerInfo {
+    bool caught_locally;
     Label* handler;
     int pc_offset;
   };
index 330eeec7d95f3ea386283066713b3b3f8dd8ef1c..6e0ecfd6c1610f92545c6c1f7de4ccb01f553efe 100644 (file)
@@ -36,6 +36,21 @@ BranchHint BranchHintOf(const Operator* const op) {
 }
 
 
+size_t hash_value(IfExceptionHint hint) { return static_cast<size_t>(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 <IfExceptionHint kCaughtLocally>
+  struct IfExceptionOperator final : public Operator1<IfExceptionHint> {
+    IfExceptionOperator()
+        : Operator1<IfExceptionHint>(                      // --
+              IrOpcode::kIfException, Operator::kKontrol,  // opcode
+              "IfException",                               // name
+              0, 0, 1, 1, 0, 1,                            // counts
+              kCaughtLocally) {}                           // parameter
+  };
+  IfExceptionOperator<IfExceptionHint::kLocallyCaught> kIfExceptionCOperator;
+  IfExceptionOperator<IfExceptionHint::kLocallyUncaught> kIfExceptionUOperator;
+
   template <size_t kInputCount>
   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(               // --
index 1c004448b8a9a19e40f3c46f1ab6c9615323042d..08553bceaa6ec7650d4ba96318c1c87f976f7a56 100644 (file)
@@ -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();
index 8343dc1a09326f6d297a01e52521ed816ea5a499..e7ddc1ad18287b909eb05a3fbb8ced724459e865 100644 (file)
@@ -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<IfExceptionHint>(handler->front());
+    if (hint == IfExceptionHint::kLocallyCaught) {
+      flags |= CallDescriptor::kHasLocalCatchHandler;
+    }
     flags |= CallDescriptor::kHasExceptionHandler;
     buffer.instruction_args.push_back(g.Label(handler));
   }
index aa680689d7ab7d9871740b2daab881f9e7710c12..abdef7a4efc47eafaf9f32105600c03a6a40d3f0 100644 (file)
@@ -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<Flag> Flags;
index 6694768702233d74c43459458282ee27e03a8943..c042ea11e67de559428dfb716773aa78259ae80d 100644 (file)
@@ -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<IfExceptionHint>(handler->front());
+    if (hint == IfExceptionHint::kLocallyCaught) {
+      flags |= CallDescriptor::kHasLocalCatchHandler;
+    }
     flags |= CallDescriptor::kHasExceptionHandler;
     buffer.instruction_args.push_back(g.Label(handler));
   }
index 9fd208d376fb6512a10b426b755e7b306f099ae0..05ad5aa1a34779b4bf39cea677083ea00ce237df 100644 (file)
@@ -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<IfExceptionHint>(handler->front());
+    if (hint == IfExceptionHint::kLocallyCaught) {
+      flags |= CallDescriptor::kHasLocalCatchHandler;
+    }
     flags |= CallDescriptor::kHasExceptionHandler;
     buffer.instruction_args.push_back(g.Label(handler));
   }
index afe30d4c8591b4673aad949e887ff06720490762..4f1cbe025b83e9d2f92b550a09c7dd97bc0de908 100644 (file)
@@ -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<IfExceptionHint>(handler->front());
+    if (hint == IfExceptionHint::kLocallyCaught) {
+      flags |= CallDescriptor::kHasLocalCatchHandler;
+    }
     flags |= CallDescriptor::kHasExceptionHandler;
     buffer.instruction_args.push_back(g.Label(handler));
   }
index 26d8960b913f897c458f9de1ba0cad07959786d4..df0f8809a7bb87c2c3c33246959cbea2eb8ec2f8 100644 (file)
@@ -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<IfExceptionHint>(handler->front());
+    if (hint == IfExceptionHint::kLocallyCaught) {
+      flags |= CallDescriptor::kHasLocalCatchHandler;
+    }
     flags |= CallDescriptor::kHasExceptionHandler;
     buffer.instruction_args.push_back(g.Label(handler));
   }
index 4dd64aad63af3154caa64e650a15e0138865109c..86f2a1166b641b551412926cf46fed5ce765db01 100644 (file)
@@ -983,7 +983,8 @@ int OptimizedFrame::LookupExceptionHandlerInTable(int* stack_slots) {
   HandlerTable* table = HandlerTable::cast(code->handler_table());
   int pc_offset = static_cast<int>(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);
 }
 
 
index 6048a02b2a3a9a96dab1783f0921ca56b0f9488b..91603ffe148340caf791fd2bc0e12807446feaf6 100644 (file)
@@ -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";
   }
 }
 
index 0e78af87f127f9f03ca4f5bd2d6a2a25db7f98a4..46b457c18917d61324c0ea83f54612a4a7c2f6ee 100644 (file)
@@ -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<CatchPrediction, 0, 1> {};
+  class HandlerOffsetField : public BitField<int, 1, 30> {};
 };
 
 
index d2f816beb7cecfe6bfab7f2e24e14f4cab181e3c..45bb9533d05652a2b58dd7608205bb63771460ce 100644 (file)
@@ -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<int32_t>::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());
index d3eff716a7f0aabc3c2b3197995b2593e23dfce5..c725a27cc0e9c7271633c9ac54bbc0e25fddcc64 100644 (file)
@@ -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);
index 2bec4faf4da6c67870a3ce99ffa12ad6222cc0aa..9c73c5e3c5016c24e9188a945c4e4746521c3d85 100644 (file)
@@ -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]);
index 543ea8a02416cb4dc5a81987c6c8afdeb0636d7b..b94cb03c00c44ba75e3e91f3bf5d6efd5d35ea27 100644 (file)
@@ -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);
index 72735f50fdd6389adfd9185dffc4155eeac5d97c..37e37d5182d9f2465ed42be351ba62877c772fae 100644 (file)
@@ -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);