Reviewers: Benedikt Meurer,

Description:
[turbofan] Make IfException projections consume effects.

This is needed in order to allow expansion a throwing node into a set
of nodes that produce different effects for the successful and the
exceptional continuation.

[email protected]

Please review this at https://codereview.chromium.org/1179543002/

Base URL: https://chromium.googlesource.com/v8/v8.git@master

Affected files (+58, -41 lines):
  M src/compiler/ast-graph-builder.cc
  M src/compiler/common-operator.cc
  M src/compiler/graph-reducer.cc
  M src/compiler/instruction-selector.cc
  M src/compiler/node-properties.cc
  M test/unittests/compiler/common-operator-unittest.cc
  M test/unittests/compiler/graph-reducer-unittest.cc
  M test/unittests/compiler/node-properties-unittest.cc
  M test/unittests/compiler/scheduler-unittest.cc
  M test/unittests/compiler/tail-call-optimization-unittest.cc


Index: src/compiler/ast-graph-builder.cc
diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc index c5a9d232776748d7158919088a14bb76e579d3bf..43d402094539cfae9c31dd3f2f3395888a17db86 100644
--- a/src/compiler/ast-graph-builder.cc
+++ b/src/compiler/ast-graph-builder.cc
@@ -3845,8 +3845,10 @@ Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count,
         // Copy the environment for the success continuation.
         Environment* success_env = environment()->CopyForConditional();
         const Operator* op = common()->IfException(hint);
-        Node* on_exception = graph()->NewNode(op, result);
+        Node* effect = environment()->GetEffectDependency();
+        Node* on_exception = graph()->NewNode(op, effect, result);
         environment_->UpdateControlDependency(on_exception);
+        environment_->UpdateEffectDependency(on_exception);
         execution_control()->ThrowValue(on_exception);
         set_environment(success_env);
       }
Index: src/compiler/common-operator.cc
diff --git a/src/compiler/common-operator.cc b/src/compiler/common-operator.cc index 6e0ecfd6c1610f92545c6c1f7de4ccb01f553efe..a8cfbb3049f3035e5ac6a15bba3abc9bef890481 100644
--- a/src/compiler/common-operator.cc
+++ b/src/compiler/common-operator.cc
@@ -230,7 +230,7 @@ struct CommonOperatorGlobalCache final {
         : Operator1<IfExceptionHint>(                      // --
               IrOpcode::kIfException, Operator::kKontrol,  // opcode
               "IfException",                               // name
-              0, 0, 1, 1, 0, 1,                            // counts
+              0, 1, 1, 1, 1, 1,                            // counts
               kCaughtLocally) {}                           // parameter
   };
IfExceptionOperator<IfExceptionHint::kLocallyCaught> kIfExceptionCOperator;
Index: src/compiler/graph-reducer.cc
diff --git a/src/compiler/graph-reducer.cc b/src/compiler/graph-reducer.cc
index 0f347adbe1e0ec56d61d4b31b59e4d44e5b1dae8..2164d1e7c505e291e261fb2f21e8e88b84e38238 100644
--- a/src/compiler/graph-reducer.cc
+++ b/src/compiler/graph-reducer.cc
@@ -231,9 +231,10 @@ void GraphReducer::ReplaceWithValue(Node* node, Node* value, Node* effect,
       } else if (user->opcode() == IrOpcode::kIfException) {
         for (Edge e : user->use_edges()) {
           if (NodeProperties::IsValueEdge(e)) e.UpdateTo(dead_value_);
+ if (NodeProperties::IsEffectEdge(e)) e.UpdateTo(graph()->start());
           if (NodeProperties::IsControlEdge(e)) e.UpdateTo(dead_control_);
         }
-        user->Kill();
+        edge.UpdateTo(user);
       } else {
         UNREACHABLE();
       }
@@ -242,6 +243,7 @@ void GraphReducer::ReplaceWithValue(Node* node, Node* value, Node* effect,
       edge.UpdateTo(effect);
       Revisit(user);
     } else {
+      DCHECK_NOT_NULL(value);
       edge.UpdateTo(value);
       Revisit(user);
     }
Index: src/compiler/instruction-selector.cc
diff --git a/src/compiler/instruction-selector.cc b/src/compiler/instruction-selector.cc index 1c1f3fafd7f11bbe659c093226e3231ed100e19c..13a76da12ae0c6f090b288395dec147cf707b45e 100644
--- a/src/compiler/instruction-selector.cc
+++ b/src/compiler/instruction-selector.cc
@@ -931,7 +931,7 @@ void InstructionSelector::VisitParameter(Node* node) {

 void InstructionSelector::VisitIfException(Node* node) {
   OperandGenerator g(this);
-  Node* call = node->InputAt(0);
+  Node* call = node->InputAt(1);
   DCHECK_EQ(IrOpcode::kCall, call->opcode());
const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(call);
   Emit(kArchNop, g.DefineAsLocation(node, descriptor->GetReturnLocation(0),
Index: src/compiler/node-properties.cc
diff --git a/src/compiler/node-properties.cc b/src/compiler/node-properties.cc index eb216781d18fae37fd765194873cb4677e11c456..ac768a7d37f1781f8404c8ad0414ba93997bda8b 100644
--- a/src/compiler/node-properties.cc
+++ b/src/compiler/node-properties.cc
@@ -214,7 +214,9 @@ void NodeProperties::CollectControlProjections(Node* node, Node** projections,
   std::memset(projections, 0, sizeof(*projections) * projection_count);
 #endif
   size_t if_value_index = 0;
-  for (Node* const use : node->uses()) {
+  for (Edge const edge : node->use_edges()) {
+    if (!IsControlEdge(edge)) continue;
+    Node* use = edge.from();
     size_t index;
     switch (use->opcode()) {
       case IrOpcode::kIfTrue:
Index: test/unittests/compiler/common-operator-unittest.cc
diff --git a/test/unittests/compiler/common-operator-unittest.cc b/test/unittests/compiler/common-operator-unittest.cc index 2d1e0dcc30694b5e0bf84b4533ae0fc38a6d5d3b..26e861c1b67684cb7b8fa040318dd1c20c6dd642 100644
--- a/test/unittests/compiler/common-operator-unittest.cc
+++ b/test/unittests/compiler/common-operator-unittest.cc
@@ -225,11 +225,11 @@ TEST_F(CommonOperatorTest, IfException) {
     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->EffectInputCount());
     EXPECT_EQ(1, op->ControlInputCount());
-    EXPECT_EQ(1, OperatorProperties::GetTotalInputCount(op));
+    EXPECT_EQ(2, OperatorProperties::GetTotalInputCount(op));
     EXPECT_EQ(1, op->ValueOutputCount());
-    EXPECT_EQ(0, op->EffectOutputCount());
+    EXPECT_EQ(1, op->EffectOutputCount());
     EXPECT_EQ(1, op->ControlOutputCount());
   }
 }
Index: test/unittests/compiler/graph-reducer-unittest.cc
diff --git a/test/unittests/compiler/graph-reducer-unittest.cc b/test/unittests/compiler/graph-reducer-unittest.cc index d3e97975786d8c30cb9af5dd11dbb1f32dfd7b04..06befae59efbde0c541897567399dae7daf27902 100644
--- a/test/unittests/compiler/graph-reducer-unittest.cc
+++ b/test/unittests/compiler/graph-reducer-unittest.cc
@@ -340,10 +340,11 @@ TEST_F(AdvancedReducerTest, ReplaceWithValue_ControlUse1) {
 TEST_F(AdvancedReducerTest, ReplaceWithValue_ControlUse2) {
   CommonOperatorBuilder common(zone());
   Node* start = graph()->NewNode(common.Start(1));
+  Node* effect = graph()->NewNode(&kMockOperator);
   Node* dead = graph()->NewNode(&kMockOperator);
   Node* node = graph()->NewNode(&kMockOpControl, start);
   Node* success = graph()->NewNode(common.IfSuccess(), node);
-  Node* exception = graph()->NewNode(common.IfException(kNoHint), node);
+ Node* exception = graph()->NewNode(common.IfException(kNoHint), effect, node);
   Node* use_control = graph()->NewNode(common.Merge(1), success);
Node* use_exception_control = graph()->NewNode(common.Merge(1), exception);
   Node* replacement = graph()->NewNode(&kMockOperator);
@@ -364,10 +365,11 @@ TEST_F(AdvancedReducerTest, ReplaceWithValue_ControlUse2) {
 TEST_F(AdvancedReducerTest, ReplaceWithValue_ControlUse3) {
   CommonOperatorBuilder common(zone());
   Node* start = graph()->NewNode(common.Start(1));
+  Node* effect = graph()->NewNode(&kMockOperator);
   Node* dead = graph()->NewNode(&kMockOperator);
   Node* node = graph()->NewNode(&kMockOpControl, start);
   Node* success = graph()->NewNode(common.IfSuccess(), node);
-  Node* exception = graph()->NewNode(common.IfException(kNoHint), node);
+ Node* exception = graph()->NewNode(common.IfException(kNoHint), effect, node);
   Node* use_control = graph()->NewNode(common.Merge(1), success);
   Node* use_exception_value = graph()->NewNode(common.Return(), exception);
   Node* replacement = graph()->NewNode(&kMockOperator);
Index: test/unittests/compiler/node-properties-unittest.cc
diff --git a/test/unittests/compiler/node-properties-unittest.cc b/test/unittests/compiler/node-properties-unittest.cc index bcc21384155ea8035e935b9898612aa136694b0b..463948d43f4e33de2d05901d1c943ded2b97ae15 100644
--- a/test/unittests/compiler/node-properties-unittest.cc
+++ b/test/unittests/compiler/node-properties-unittest.cc
@@ -17,8 +17,16 @@ namespace compiler {

 class NodePropertiesTest : public TestWithZone {
  public:
-  Node* NewMockNode(const Operator* op, int input_count, Node** inputs) {
-    return Node::New(zone(), 0, op, input_count, inputs, false);
+  Node* NewMockNode(const Operator* op) {
+    return Node::New(zone(), 0, op, 0, nullptr, false);
+  }
+  Node* NewMockNode(const Operator* op, Node* n1) {
+    Node* nodes[] = {n1};
+    return Node::New(zone(), 0, op, arraysize(nodes), nodes, false);
+  }
+  Node* NewMockNode(const Operator* op, Node* n1, Node* n2) {
+    Node* nodes[] = {n1, n2};
+    return Node::New(zone(), 0, op, arraysize(nodes), nodes, false);
   }
 };

@@ -29,26 +37,28 @@ const Operator kMockOperator(IrOpcode::kDead, Operator::kNoProperties,
 const Operator kMockCallOperator(IrOpcode::kCall, Operator::kNoProperties,
                                  "MockCallOperator", 0, 0, 0, 0, 0, 2);

+const IfExceptionHint kNoHint = IfExceptionHint::kLocallyCaught;
+
 }  // namespace


 TEST_F(NodePropertiesTest, ReplaceUses) {
   CommonOperatorBuilder common(zone());
-  IfExceptionHint kNoHint = IfExceptionHint::kLocallyCaught;
-  Node* node = NewMockNode(&kMockOperator, 0, nullptr);
-  Node* use_value = NewMockNode(common.Return(), 1, &node);
-  Node* use_effect = NewMockNode(common.EffectPhi(1), 1, &node);
-  Node* use_success = NewMockNode(common.IfSuccess(), 1, &node);
-  Node* use_exception = NewMockNode(common.IfException(kNoHint), 1, &node);
-  Node* r_value = NewMockNode(&kMockOperator, 0, nullptr);
-  Node* r_effect = NewMockNode(&kMockOperator, 0, nullptr);
-  Node* r_success = NewMockNode(&kMockOperator, 0, nullptr);
-  Node* r_exception = NewMockNode(&kMockOperator, 0, nullptr);
+  Node* node = NewMockNode(&kMockOperator);
+  Node* effect = NewMockNode(&kMockOperator);
+  Node* use_value = NewMockNode(common.Return(), node);
+  Node* use_effect = NewMockNode(common.EffectPhi(1), node);
+  Node* use_success = NewMockNode(common.IfSuccess(), node);
+ Node* use_exception = NewMockNode(common.IfException(kNoHint), effect, node);
+  Node* r_value = NewMockNode(&kMockOperator);
+  Node* r_effect = NewMockNode(&kMockOperator);
+  Node* r_success = NewMockNode(&kMockOperator);
+  Node* r_exception = NewMockNode(&kMockOperator);
NodeProperties::ReplaceUses(node, r_value, r_effect, r_success, r_exception);
   EXPECT_EQ(r_value, use_value->InputAt(0));
   EXPECT_EQ(r_effect, use_effect->InputAt(0));
   EXPECT_EQ(r_success, use_success->InputAt(0));
-  EXPECT_EQ(r_exception, use_exception->InputAt(0));
+  EXPECT_EQ(r_exception, use_exception->InputAt(1));
   EXPECT_EQ(0, node->UseCount());
   EXPECT_EQ(1, r_value->UseCount());
   EXPECT_EQ(1, r_effect->UseCount());
@@ -63,9 +73,9 @@ TEST_F(NodePropertiesTest, ReplaceUses) {

 TEST_F(NodePropertiesTest, FindProjection) {
   CommonOperatorBuilder common(zone());
-  Node* start = Node::New(zone(), 0, common.Start(1), 0, nullptr, false);
- Node* proj0 = Node::New(zone(), 1, common.Projection(0), 1, &start, false); - Node* proj1 = Node::New(zone(), 2, common.Projection(1), 1, &start, false);
+  Node* start = NewMockNode(common.Start(1));
+  Node* proj0 = NewMockNode(common.Projection(0), start);
+  Node* proj1 = NewMockNode(common.Projection(1), start);
   EXPECT_EQ(proj0, NodeProperties::FindProjection(start, 0));
   EXPECT_EQ(proj1, NodeProperties::FindProjection(start, 1));
   EXPECT_THAT(NodeProperties::FindProjection(start, 2), IsNull());
@@ -76,9 +86,9 @@ TEST_F(NodePropertiesTest, FindProjection) {
 TEST_F(NodePropertiesTest, CollectControlProjections_Branch) {
   Node* result[2];
   CommonOperatorBuilder common(zone());
-  Node* branch = Node::New(zone(), 1, common.Branch(), 0, nullptr, false);
- Node* if_false = Node::New(zone(), 2, common.IfFalse(), 1, &branch, false);
-  Node* if_true = Node::New(zone(), 3, common.IfTrue(), 1, &branch, false);
+  Node* branch = NewMockNode(common.Branch());
+  Node* if_false = NewMockNode(common.IfFalse(), branch);
+  Node* if_true = NewMockNode(common.IfTrue(), branch);
NodeProperties::CollectControlProjections(branch, result, arraysize(result));
   EXPECT_EQ(if_true, result[0]);
   EXPECT_EQ(if_false, result[1]);
@@ -88,10 +98,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(h), 1, &call, false);
-  Node* if_ok = Node::New(zone(), 3, common.IfSuccess(), 1, &call, false);
+  Node* call = NewMockNode(&kMockCallOperator);
+  Node* if_ex = NewMockNode(common.IfException(kNoHint), call, call);
+  Node* if_ok = NewMockNode(common.IfSuccess(), call);
NodeProperties::CollectControlProjections(call, result, arraysize(result));
   EXPECT_EQ(if_ok, result[0]);
   EXPECT_EQ(if_ex, result[1]);
@@ -101,10 +110,10 @@ TEST_F(NodePropertiesTest, CollectControlProjections_Call) {
 TEST_F(NodePropertiesTest, CollectControlProjections_Switch) {
   Node* result[3];
   CommonOperatorBuilder common(zone());
-  Node* sw = Node::New(zone(), 1, common.Switch(3), 0, nullptr, false);
- Node* if_default = Node::New(zone(), 2, common.IfDefault(), 1, &sw, false);
-  Node* if_value1 = Node::New(zone(), 3, common.IfValue(1), 1, &sw, false);
-  Node* if_value2 = Node::New(zone(), 4, common.IfValue(2), 1, &sw, false);
+  Node* sw = NewMockNode(common.Switch(3));
+  Node* if_default = NewMockNode(common.IfDefault(), sw);
+  Node* if_value1 = NewMockNode(common.IfValue(1), sw);
+  Node* if_value2 = NewMockNode(common.IfValue(2), sw);
   NodeProperties::CollectControlProjections(sw, result, arraysize(result));
   EXPECT_THAT(result[0], AnyOf(if_value1, if_value2));
   EXPECT_THAT(result[1], AnyOf(if_value1, if_value2));
Index: test/unittests/compiler/scheduler-unittest.cc
diff --git a/test/unittests/compiler/scheduler-unittest.cc b/test/unittests/compiler/scheduler-unittest.cc index b94cb03c00c44ba75e3e91f3bf5d6efd5d35ea27..45c636b27a7e9d2b1b09679110f6d181b1c0e115 100644
--- a/test/unittests/compiler/scheduler-unittest.cc
+++ b/test/unittests/compiler/scheduler-unittest.cc
@@ -1060,11 +1060,11 @@ TARGET_TEST_F(SchedulerTest, CallException) {
   Node* c1 = graph()->NewNode(&kMockCall, start);
   Node* ok1 = graph()->NewNode(common()->IfSuccess(), c1);
   Node* ex1 = graph()->NewNode(
-      common()->IfException(IfExceptionHint::kLocallyUncaught), c1);
+      common()->IfException(IfExceptionHint::kLocallyUncaught), c1, c1);
   Node* c2 = graph()->NewNode(&kMockCall, ok1);
   Node* ok2 = graph()->NewNode(common()->IfSuccess(), c2);
   Node* ex2 = graph()->NewNode(
-      common()->IfException(IfExceptionHint::kLocallyUncaught), c2);
+      common()->IfException(IfExceptionHint::kLocallyUncaught), c2, 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: test/unittests/compiler/tail-call-optimization-unittest.cc
diff --git a/test/unittests/compiler/tail-call-optimization-unittest.cc b/test/unittests/compiler/tail-call-optimization-unittest.cc index 37e37d5182d9f2465ed42be351ba62877c772fae..b8f38602e86c0615e360402573fa3cbe1435714c 100644
--- a/test/unittests/compiler/tail-call-optimization-unittest.cc
+++ b/test/unittests/compiler/tail-call-optimization-unittest.cc
@@ -60,7 +60,7 @@ TEST_F(TailCallOptimizationTest, CallCodeObject1) {
                                 graph()->start(), graph()->start());
   Node* if_success = graph()->NewNode(common()->IfSuccess(), call);
   Node* if_exception = graph()->NewNode(
-      common()->IfException(IfExceptionHint::kLocallyUncaught), call);
+ common()->IfException(IfExceptionHint::kLocallyUncaught), call, call);
   Node* ret = graph()->NewNode(common()->Return(), call, call, if_success);
   Node* end = graph()->NewNode(common()->End(1), if_exception);
   graph()->SetEnd(end);
@@ -126,7 +126,7 @@ TEST_F(TailCallOptimizationTest, CallJSFunction1) {
                                 graph()->start(), graph()->start());
   Node* if_success = graph()->NewNode(common()->IfSuccess(), call);
   Node* if_exception = graph()->NewNode(
-      common()->IfException(IfExceptionHint::kLocallyUncaught), call);
+ common()->IfException(IfExceptionHint::kLocallyUncaught), call, call);
   Node* ret = graph()->NewNode(common()->Return(), call, call, if_success);
   Node* end = graph()->NewNode(common()->End(1), if_exception);
   graph()->SetEnd(end);


--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to