[turbofan] Use Start as sentinel for frame states.
authorbmeurer <bmeurer@chromium.org>
Wed, 27 May 2015 11:01:51 +0000 (04:01 -0700)
committerCommit bot <commit-bot@chromium.org>
Wed, 27 May 2015 11:02:01 +0000 (11:02 +0000)
This simplifies inlining, in that we only need to update uses of Start
and inputs of End instead of walking the whole inlinee to update all
outer frame states.

R=mstarzinger@chromium.org

Review URL: https://codereview.chromium.org/1146403008

Cr-Commit-Position: refs/heads/master@{#28649}

src/compiler/ast-graph-builder.cc
src/compiler/js-graph.cc
src/compiler/js-inlining.cc
src/compiler/js-inlining.h
src/compiler/verifier.cc
test/cctest/compiler/test-run-inlining.cc

index 9778c79..bc96c4c 100644 (file)
@@ -856,7 +856,7 @@ Node* AstGraphBuilder::Environment::Checkpoint(
   Node* result = graph()->NewNode(op, parameters_node_, locals_node_,
                                   stack_node_, builder()->current_context(),
                                   builder()->GetFunctionClosure(),
-                                  builder()->jsgraph()->UndefinedConstant());
+                                  builder()->graph()->start());
 
   DCHECK(IsLivenessBlockConsistent());
   if (liveness_block() != nullptr) {
index 44d5c52..4d83c86 100644 (file)
@@ -191,7 +191,7 @@ Node* JSGraph::EmptyFrameState() {
         common()->FrameState(JS_FRAME, BailoutId::None(),
                              OutputFrameStateCombine::Ignore()),
         state_values, state_values, state_values, NoContextConstant(),
-        UndefinedConstant(), UndefinedConstant());
+        UndefinedConstant(), graph()->start());
     cached_nodes_[kEmptyFrameState] = empty_frame_state;
   }
   return empty_frame_state;
index 72f12fc..6964e5e 100644 (file)
@@ -116,7 +116,8 @@ class CopyVisitor {
 };
 
 
-Reduction JSInliner::InlineCall(Node* call, Node* start, Node* end) {
+Reduction JSInliner::InlineCall(Node* call, Node* frame_state, Node* start,
+                                Node* end) {
   // The scheduler is smart enough to place our code; we just ensure {control}
   // becomes the control input of the start of the inlinee, and {effect} becomes
   // the effect input of the start of the inlinee.
@@ -158,6 +159,8 @@ Reduction JSInliner::InlineCall(Node* call, Node* start, Node* end) {
           edge.UpdateTo(effect);
         } else if (NodeProperties::IsControlEdge(edge)) {
           edge.UpdateTo(control);
+        } else if (NodeProperties::IsFrameStateEdge(edge)) {
+          edge.UpdateTo(frame_state);
         } else {
           UNREACHABLE();
         }
@@ -284,7 +287,7 @@ Reduction JSInliner::Reduce(Node* node) {
   Node* start = visitor.GetCopy(graph.start());
   Node* end = visitor.GetCopy(graph.end());
 
-  Node* outer_frame_state = call.frame_state();
+  Node* frame_state = call.frame_state();
   size_t const inlinee_formal_parameters = start->op()->ValueOutputCount() - 3;
   // Insert argument adaptor frame if required.
   if (call.formal_arguments() != inlinee_formal_parameters) {
@@ -294,22 +297,10 @@ Reduction JSInliner::Reduce(Node* node) {
         call.formal_arguments() < inlinee_formal_parameters) {
       return NoChange();
     }
-    outer_frame_state = CreateArgumentsAdaptorFrameState(&call, info.zone());
+    frame_state = CreateArgumentsAdaptorFrameState(&call, info.zone());
   }
 
-  // Fix up all outer frame states from the inlinee.
-  for (Node* const node : visitor.copies()) {
-    if (node->opcode() == IrOpcode::kFrameState) {
-      DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
-      // Don't touch this frame state, if it already has an "outer frame state".
-      if (NodeProperties::GetFrameStateInput(node, 0)->opcode() !=
-          IrOpcode::kFrameState) {
-        NodeProperties::ReplaceFrameStateInput(node, 0, outer_frame_state);
-      }
-    }
-  }
-
-  return InlineCall(node, start, end);
+  return InlineCall(node, frame_state, start, end);
 }
 
 }  // namespace compiler
index f7a0ba3..af82ed6 100644 (file)
@@ -37,7 +37,7 @@ class JSInliner final : public AdvancedReducer {
   Node* CreateArgumentsAdaptorFrameState(JSCallFunctionAccessor* call,
                                          Zone* temp_zone);
 
-  Reduction InlineCall(Node* call, Node* start, Node* end);
+  Reduction InlineCall(Node* call, Node* frame_state, Node* start, Node* end);
 };
 
 }  // namespace compiler
index da94390..d258203 100644 (file)
@@ -118,9 +118,9 @@ void Verifier::Visitor::Check(Node* node) {
   for (int i = 0; i < frame_state_count; i++) {
     Node* frame_state = NodeProperties::GetFrameStateInput(node, i);
     CHECK(frame_state->opcode() == IrOpcode::kFrameState ||
-          // kFrameState uses undefined as a sentinel.
+          // kFrameState uses Start as a sentinel.
           (node->opcode() == IrOpcode::kFrameState &&
-           frame_state->opcode() == IrOpcode::kHeapConstant));
+           frame_state->opcode() == IrOpcode::kStart));
     CHECK(IsDefUseChainLinkPresent(frame_state, node));
     CHECK(IsUseDefChainLinkPresent(frame_state, node));
   }
index 2ab7217..3de929c 100644 (file)
@@ -78,6 +78,20 @@ TEST(SimpleInliningDeopt) {
 }
 
 
+TEST(SimpleInliningDeoptSelf) {
+  FunctionTester T(
+      "(function(){"
+      "  function foo(s) { %_DeoptimizeNow(); return s; };"
+      "  function bar(s, t) { return foo(s); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.Val(1), T.Val(1), T.Val(2));
+}
+
+
 TEST(SimpleInliningContext) {
   FunctionTester T(
       "(function () {"