Avoid hydrogen compare-objects-equal assertions in dead code
authorjarin@chromium.org <jarin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 9 Apr 2014 13:08:28 +0000 (13:08 +0000)
committerjarin@chromium.org <jarin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 9 Apr 2014 13:08:28 +0000 (13:08 +0000)
ClusterFuzz test is triggering assertions for dead code. This fix issues
HDeoptimize instruction when it finds out that the compare instruction
is dead (because of previous checks).

R=yangguo@chromium.org
BUG=359491
LOG=N

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

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

src/hydrogen.cc
test/mjsunit/regress/regress-359491.js [new file with mode: 0644]

index 8ce614fd660484efbc59f05e954b078d30acd6a9..309278703b59e4c34000df3c8c91169aef42893e 100644 (file)
@@ -9846,6 +9846,17 @@ HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction(
     }
   } else if (combined_type->Is(Type::InternalizedString()) &&
              Token::IsEqualityOp(op)) {
+    // If we have a constant argument, it should be consistent with the type
+    // feedback (otherwise we fail assertions in HCompareObjectEqAndBranch).
+    if ((left->IsConstant() &&
+         !HConstant::cast(left)->HasInternalizedStringValue()) ||
+        (right->IsConstant() &&
+         !HConstant::cast(right)->HasInternalizedStringValue())) {
+      Add<HDeoptimize>("Type mismatch between feedback and constant",
+                       Deoptimizer::SOFT);
+      // The caller expects a branch instruction, so make it happy.
+      return New<HBranch>(graph()->GetConstantTrue());
+    }
     BuildCheckHeapObject(left);
     Add<HCheckInstanceType>(left, HCheckInstanceType::IS_INTERNALIZED_STRING);
     BuildCheckHeapObject(right);
@@ -9854,6 +9865,17 @@ HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction(
         New<HCompareObjectEqAndBranch>(left, right);
     return result;
   } else if (combined_type->Is(Type::String())) {
+    // If we have a constant argument, it should be consistent with the type
+    // feedback (otherwise we fail assertions in HCompareObjectEqAndBranch).
+    if ((left->IsConstant() &&
+         !HConstant::cast(left)->HasStringValue()) ||
+        (right->IsConstant() &&
+         !HConstant::cast(right)->HasStringValue())) {
+      Add<HDeoptimize>("Type mismatch between feedback and constant",
+                       Deoptimizer::SOFT);
+      // The caller expects a branch instruction, so make it happy.
+      return New<HBranch>(graph()->GetConstantTrue());
+    }
     BuildCheckHeapObject(left);
     Add<HCheckInstanceType>(left, HCheckInstanceType::IS_STRING);
     BuildCheckHeapObject(right);
diff --git a/test/mjsunit/regress/regress-359491.js b/test/mjsunit/regress/regress-359491.js
new file mode 100644 (file)
index 0000000..194376b
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function f(a, b, mode) {
+  if (mode) {
+    return a === b;
+  } else {
+    return a === b;
+  }
+}
+
+// Gather type feedback for both branches.
+f("a", "b", 1);
+f("c", "d", 1);
+f("a", "b", 0);
+f("c", "d", 0);
+
+function g(mode) {
+  var x = 1e10 | 0;
+  f(x, x, mode);
+}
+
+// Gather type feedback for g, but only on one branch for f.
+g(1);
+g(1);
+%OptimizeFunctionOnNextCall(g);
+// Optimize g, which inlines f. Both branches in f will see the constant.
+g(0);