Lazy deoptimization for comparisons in Turbofan.
authorjarin@chromium.org <jarin@chromium.org>
Tue, 2 Sep 2014 10:38:31 +0000 (10:38 +0000)
committerjarin@chromium.org <jarin@chromium.org>
Tue, 2 Sep 2014 10:38:31 +0000 (10:38 +0000)
BUG=
R=mstarzinger@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23594 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

12 files changed:
src/compiler/arm/linkage-arm.cc
src/compiler/arm64/linkage-arm64.cc
src/compiler/ia32/linkage-ia32.cc
src/compiler/js-generic-lowering.cc
src/compiler/linkage-impl.h
src/compiler/linkage.cc
src/compiler/linkage.h
src/compiler/operator-properties-inl.h
src/compiler/raw-machine-assembler.cc
src/compiler/verifier.cc
src/compiler/x64/linkage-x64.cc
test/cctest/cctest.status

index 15f49ad..fc4680f 100644 (file)
@@ -42,10 +42,9 @@ CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone) {
 CallDescriptor* Linkage::GetRuntimeCallDescriptor(Runtime::FunctionId function,
                                                   int parameter_count,
                                                   Operator::Property properties,
-                                                  CallDescriptor::Flags flags,
                                                   Zone* zone) {
   return LinkageHelper::GetRuntimeCallDescriptor<LinkageHelperTraits>(
-      zone, function, parameter_count, properties, flags);
+      zone, function, parameter_count, properties);
 }
 
 
index 495aa93..c785777 100644 (file)
@@ -42,10 +42,9 @@ CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone) {
 CallDescriptor* Linkage::GetRuntimeCallDescriptor(Runtime::FunctionId function,
                                                   int parameter_count,
                                                   Operator::Property properties,
-                                                  CallDescriptor::Flags flags,
                                                   Zone* zone) {
   return LinkageHelper::GetRuntimeCallDescriptor<LinkageHelperTraits>(
-      zone, function, parameter_count, properties, flags);
+      zone, function, parameter_count, properties);
 }
 
 
index 6386e12..c687ca4 100644 (file)
@@ -38,10 +38,9 @@ CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone) {
 CallDescriptor* Linkage::GetRuntimeCallDescriptor(Runtime::FunctionId function,
                                                   int parameter_count,
                                                   Operator::Property properties,
-                                                  CallDescriptor::Flags flags,
                                                   Zone* zone) {
   return LinkageHelper::GetRuntimeCallDescriptor<LinkageHelperTraits>(
-      zone, function, parameter_count, properties, flags);
+      zone, function, parameter_count, properties);
 }
 
 
index f576557..f3f337f 100644 (file)
@@ -299,28 +299,48 @@ void JSGenericLowering::ReplaceWithCompareIC(Node* node, Token::Value token,
                                              bool pure) {
   BinaryOpICStub stub(isolate(), Token::ADD);  // TODO(mstarzinger): Hack.
   CodeStubInterfaceDescriptor* d = stub.GetInterfaceDescriptor();
+  bool has_frame_state = OperatorProperties::HasFrameStateInput(node->op());
   CallDescriptor* desc_compare = linkage()->GetStubCallDescriptor(
-      d, 0, CallDescriptor::kPatchableCallSiteWithNop);
+      d, 0, CallDescriptor::kPatchableCallSiteWithNop | FlagsForNode(node));
   Handle<Code> ic = CompareIC::GetUninitialized(isolate(), token);
-  Node* compare;
+  NodeVector inputs(zone());
+  inputs.reserve(node->InputCount() + 1);
+  inputs.push_back(CodeConstant(ic));
+  inputs.push_back(NodeProperties::GetValueInput(node, 0));
+  inputs.push_back(NodeProperties::GetValueInput(node, 1));
+  inputs.push_back(NodeProperties::GetContextInput(node));
   if (pure) {
-    // A pure (strict) comparison doesn't have an effect or control.
-    // But for the graph, we need to add these inputs.
-    compare = graph()->NewNode(common()->Call(desc_compare), CodeConstant(ic),
-                               NodeProperties::GetValueInput(node, 0),
-                               NodeProperties::GetValueInput(node, 1),
-                               NodeProperties::GetContextInput(node),
-                               graph()->start(), graph()->start());
+    // A pure (strict) comparison doesn't have an effect, control or frame
+    // state.  But for the graph, we need to add control and effect inputs.
+    DCHECK(!has_frame_state);
+    inputs.push_back(graph()->start());
+    inputs.push_back(graph()->start());
   } else {
-    compare = graph()->NewNode(common()->Call(desc_compare), CodeConstant(ic),
-                               NodeProperties::GetValueInput(node, 0),
-                               NodeProperties::GetValueInput(node, 1),
-                               NodeProperties::GetContextInput(node),
-                               NodeProperties::GetEffectInput(node),
-                               NodeProperties::GetControlInput(node));
+    DCHECK(has_frame_state == FLAG_turbo_deoptimization);
+    if (FLAG_turbo_deoptimization) {
+      inputs.push_back(NodeProperties::GetFrameStateInput(node));
+    }
+    inputs.push_back(NodeProperties::GetEffectInput(node));
+    inputs.push_back(NodeProperties::GetControlInput(node));
   }
+  Node* compare = graph()->NewNode(common()->Call(desc_compare), inputs.size(),
+                                   &inputs.front());
+
   node->ReplaceInput(0, compare);
   node->ReplaceInput(1, SmiConstant(token));
+
+  if (has_frame_state) {
+    // Remove the frame state from inputs.
+    // TODO(jarin) This should use Node::RemoveInput (which does not exist yet).
+    int dest = NodeProperties::FirstFrameStateIndex(node);
+    for (int i = NodeProperties::PastFrameStateIndex(node);
+         i < node->InputCount(); i++) {
+      node->ReplaceInput(dest, node->InputAt(i));
+      dest++;
+    }
+    node->TrimInputCount(dest);
+  }
+
   ReplaceWithRuntimeCall(node, Runtime::kBooleanize);
 }
 
@@ -360,8 +380,7 @@ void JSGenericLowering::ReplaceWithRuntimeCall(Node* node,
   Operator::Property props = node->op()->properties();
   const Runtime::Function* fun = Runtime::FunctionForId(f);
   int nargs = (nargs_override < 0) ? fun->nargs : nargs_override;
-  CallDescriptor* desc =
-      linkage()->GetRuntimeCallDescriptor(f, nargs, props, FlagsForNode(node));
+  CallDescriptor* desc = linkage()->GetRuntimeCallDescriptor(f, nargs, props);
   Node* ref = ExternalConstant(ExternalReference(f, isolate()));
   Node* arity = Int32Constant(nargs);
   if (!centrystub_constant_.is_set()) {
index 88cf125..c4a8007 100644 (file)
@@ -71,7 +71,7 @@ class LinkageHelper {
   template <typename LinkageTraits>
   static CallDescriptor* GetRuntimeCallDescriptor(
       Zone* zone, Runtime::FunctionId function_id, int parameter_count,
-      Operator::Property properties, CallDescriptor::Flags flags) {
+      Operator::Property properties) {
     const int code_count = 1;
     const int function_count = 1;
     const int num_args_count = 1;
@@ -109,6 +109,10 @@ class LinkageHelper {
         WordRegisterLocation(LinkageTraits::RuntimeCallArgCountReg());
     locations[index++] = TaggedRegisterLocation(LinkageTraits::ContextReg());
 
+    CallDescriptor::Flags flags = Linkage::NeedsFrameState(function_id)
+                                      ? CallDescriptor::kNeedsFrameState
+                                      : CallDescriptor::kNoFlags;
+
     // TODO(titzer): refactor TurboFan graph to consider context a value input.
     return new (zone) CallDescriptor(CallDescriptor::kCallCodeObject,  // kind
                                      return_count,     // return_count
@@ -196,6 +200,25 @@ class LinkageHelper {
   }
 };
 
+
+bool Linkage::NeedsFrameState(Runtime::FunctionId function) {
+  if (!FLAG_turbo_deoptimization) {
+    return false;
+  }
+  // TODO(jarin) At the moment, we only add frame state for
+  // few chosen runtime functions.
+  switch (function) {
+    case Runtime::kDebugBreak:
+    case Runtime::kDeoptimizeFunction:
+    case Runtime::kSetScriptBreakPoint:
+    case Runtime::kDebugGetLoadedScripts:
+    case Runtime::kStackGuard:
+      return true;
+    default:
+      return false;
+  }
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index 4bee176..670c4bb 100644 (file)
@@ -93,11 +93,10 @@ CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count) {
 }
 
 
-CallDescriptor* Linkage::GetRuntimeCallDescriptor(Runtime::FunctionId function,
-                                                  int parameter_count,
-                                                  Operator::Property properties,
-                                                  CallDescriptor::Flags flags) {
-  return GetRuntimeCallDescriptor(function, parameter_count, properties, flags,
+CallDescriptor* Linkage::GetRuntimeCallDescriptor(
+    Runtime::FunctionId function, int parameter_count,
+    Operator::Property properties) {
+  return GetRuntimeCallDescriptor(function, parameter_count, properties,
                                   this->info_->zone());
 }
 
@@ -123,7 +122,6 @@ CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone) {
 CallDescriptor* Linkage::GetRuntimeCallDescriptor(Runtime::FunctionId function,
                                                   int parameter_count,
                                                   Operator::Property properties,
-                                                  CallDescriptor::Flags flags,
                                                   Zone* zone) {
   UNIMPLEMENTED();
   return NULL;
index e7df4df..296015c 100644 (file)
@@ -147,14 +147,12 @@ class Linkage : public ZoneObject {
   CallDescriptor* GetIncomingDescriptor() { return incoming_; }
   CallDescriptor* GetJSCallDescriptor(int parameter_count);
   static CallDescriptor* GetJSCallDescriptor(int parameter_count, Zone* zone);
-  CallDescriptor* GetRuntimeCallDescriptor(
-      Runtime::FunctionId function, int parameter_count,
-      Operator::Property properties,
-      CallDescriptor::Flags flags = CallDescriptor::kNoFlags);
+  CallDescriptor* GetRuntimeCallDescriptor(Runtime::FunctionId function,
+                                           int parameter_count,
+                                           Operator::Property properties);
   static CallDescriptor* GetRuntimeCallDescriptor(Runtime::FunctionId function,
                                                   int parameter_count,
                                                   Operator::Property properties,
-                                                  CallDescriptor::Flags flags,
                                                   Zone* zone);
 
   CallDescriptor* GetStubCallDescriptor(
@@ -191,6 +189,8 @@ class Linkage : public ZoneObject {
 
   CompilationInfo* info() const { return info_; }
 
+  static bool NeedsFrameState(Runtime::FunctionId function);
+
  private:
   CompilationInfo* info_;
   CallDescriptor* incoming_;
index 374d9ba..db160a8 100644 (file)
@@ -37,27 +37,29 @@ inline bool OperatorProperties::HasFrameStateInput(Operator* op) {
   }
 
   switch (op->opcode()) {
-    case IrOpcode::kJSCallFunction:
-    case IrOpcode::kJSCallConstruct:
-      return true;
     case IrOpcode::kJSCallRuntime: {
       Runtime::FunctionId function =
           reinterpret_cast<Operator1<Runtime::FunctionId>*>(op)->parameter();
-      // TODO(jarin) At the moment, we only add frame state for
-      // few chosen runtime functions.
-      switch (function) {
-        case Runtime::kDebugBreak:
-        case Runtime::kDeoptimizeFunction:
-        case Runtime::kSetScriptBreakPoint:
-        case Runtime::kDebugGetLoadedScripts:
-        case Runtime::kStackGuard:
-          return true;
-        default:
-          return false;
-      }
-      UNREACHABLE();
+      return Linkage::NeedsFrameState(function);
     }
 
+    // Strict equality cannot lazily deoptimize.
+    case IrOpcode::kJSStrictEqual:
+    case IrOpcode::kJSStrictNotEqual:
+      return false;
+
+    // Calls
+    case IrOpcode::kJSCallFunction:
+    case IrOpcode::kJSCallConstruct:
+
+    // Compare operations
+    case IrOpcode::kJSEqual:
+    case IrOpcode::kJSNotEqual:
+    case IrOpcode::kJSLessThan:
+    case IrOpcode::kJSGreaterThan:
+    case IrOpcode::kJSLessThanOrEqual:
+    case IrOpcode::kJSGreaterThanOrEqual:
+
     // Binary operations
     case IrOpcode::kJSBitwiseOr:
     case IrOpcode::kJSBitwiseXor:
index 3b4a9ac..395c96e 100644 (file)
@@ -107,8 +107,7 @@ Node* RawMachineAssembler::CallJS0(Node* function, Node* receiver,
 Node* RawMachineAssembler::CallRuntime1(Runtime::FunctionId function,
                                         Node* arg0, Node* frame_state) {
   CallDescriptor* descriptor = Linkage::GetRuntimeCallDescriptor(
-      function, 1, Operator::kNoProperties, CallDescriptor::kNeedsFrameState,
-      zone());
+      function, 1, Operator::kNoProperties, zone());
 
   Node* centry = HeapConstant(CEntryStub(isolate(), 1).GetCode());
   Node* ref = NewNode(
index 97ebb8f..d750f8d 100644 (file)
@@ -73,6 +73,14 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
                     effect_count + control_count;
   CHECK_EQ(input_count, node->InputCount());
 
+  // Verify that frame state has been inserted for the nodes that need it.
+  if (OperatorProperties::HasFrameStateInput(node->op())) {
+    Node* frame_state = NodeProperties::GetFrameStateInput(node);
+    CHECK(frame_state->opcode() == IrOpcode::kFrameState);
+    CHECK(IsDefUseChainLinkPresent(frame_state, node));
+    CHECK(IsUseDefChainLinkPresent(frame_state, node));
+  }
+
   // Verify all value inputs actually produce a value.
   for (int i = 0; i < value_count; ++i) {
     Node* value = NodeProperties::GetValueInput(node, i);
index f58c6bc..42e131b 100644 (file)
@@ -57,10 +57,9 @@ CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone) {
 CallDescriptor* Linkage::GetRuntimeCallDescriptor(Runtime::FunctionId function,
                                                   int parameter_count,
                                                   Operator::Property properties,
-                                                  CallDescriptor::Flags flags,
                                                   Zone* zone) {
   return LinkageHelper::GetRuntimeCallDescriptor<LinkageHelperTraits>(
-      zone, function, parameter_count, properties, flags);
+      zone, function, parameter_count, properties);
 }
 
 
index 894ae1b..d4e3b15 100644 (file)
   'test-debug/ThreadedDebugging': [PASS, NO_VARIANTS],
   'test-debug/DebugBreakLoop': [PASS, NO_VARIANTS],
 
-  # Support for lazy deoptimization is missing.
-  'test-deoptimization/DeoptimizeCompare': [PASS, NO_VARIANTS],
-
   # Support for breakpoints requires using LoadICs and StoreICs.
   'test-debug/BreakPointICStore': [PASS, NO_VARIANTS],
   'test-debug/BreakPointICLoad': [PASS, NO_VARIANTS],