[crankshaft] Handle @@toStringTag accessor correctly for BuildCompareInstruction.
authorbmeurer <bmeurer@chromium.org>
Tue, 22 Sep 2015 04:07:53 +0000 (21:07 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 22 Sep 2015 04:08:08 +0000 (04:08 +0000)
If @@toStringTag is an accessor property, we cannot assume that the result
of calling Object.prototype.toString() for objects with the same map.

R=adamk@chromium.org
BUG=chromium:534200
LOG=n

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

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

src/hydrogen.cc
test/mjsunit/compare-known-objects-tostringtag.js [new file with mode: 0644]

index 2796754..949562f 100644 (file)
@@ -11600,7 +11600,12 @@ HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction(
             this, LOAD, map, isolate()->factory()->to_primitive_symbol());
         PropertyAccessInfo to_string(this, LOAD, map,
                                      isolate()->factory()->toString_string());
+        PropertyAccessInfo to_string_tag(
+            this, LOAD, map, isolate()->factory()->to_string_tag_symbol());
         if (to_primitive.CanAccessMonomorphic() && !to_primitive.IsFound() &&
+            to_string_tag.CanAccessMonomorphic() &&
+            (!to_string_tag.IsFound() || to_string_tag.IsData() ||
+             to_string_tag.IsDataConstant()) &&
             value_of.CanAccessMonomorphic() && value_of.IsDataConstant() &&
             value_of.constant().is_identical_to(isolate()->object_value_of()) &&
             to_string.CanAccessMonomorphic() && to_string.IsDataConstant() &&
@@ -11608,7 +11613,7 @@ HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction(
                 isolate()->object_to_string())) {
           // We depend on the prototype chain to stay the same, because we
           // also need to deoptimize when someone installs @@toPrimitive
-          // somewhere in the prototype chain.
+          // or @@toStringTag somewhere in the prototype chain.
           BuildCheckPrototypeMaps(handle(JSObject::cast(map->prototype())),
                                   Handle<JSObject>::null());
           AddCheckMap(left, map);
diff --git a/test/mjsunit/compare-known-objects-tostringtag.js b/test/mjsunit/compare-known-objects-tostringtag.js
new file mode 100644 (file)
index 0000000..81544ca
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright 2015 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 --harmony-tostring
+
+function le(a, b) {
+  return a <= b;
+}
+
+function lt(a, b) {
+  return a < b;
+}
+
+function ge(a, b) {
+  return a >= b;
+}
+
+function gt(a, b) {
+  return a > b;
+}
+
+function test(a, b) {
+  // Check CompareIC for less than or equal of known objects.
+  assertThrows(function() {le(a, a)});
+  assertThrows(function() {le(a, b)});
+  assertThrows(function() {le(b, a)});
+  // Check CompareIC for less than of known objects.
+  assertThrows(function() {lt(a, a)});
+  assertThrows(function() {lt(a, b)});
+  assertThrows(function() {lt(b, a)});
+  // Check CompareIC for greater than or equal of known objects.
+  assertThrows(function() {ge(a, a)});
+  assertThrows(function() {ge(a, b)});
+  assertThrows(function() {ge(b, a)});
+  // Check CompareIC for greater than of known objects.
+  assertThrows(function() {gt(a, a)});
+  assertThrows(function() {gt(a, b)});
+  assertThrows(function() {gt(b, a)});
+}
+
+function O() { }
+Object.defineProperty(O.prototype, Symbol.toStringTag, {
+  get: function() { throw "@@toStringTag called!" }
+});
+
+var obj1 = new O;
+var obj2 = new O;
+
+assertTrue(%HaveSameMap(obj1, obj2));
+test(obj1, obj2);
+test(obj1, obj2);
+%OptimizeFunctionOnNextCall(le);
+%OptimizeFunctionOnNextCall(lt);
+%OptimizeFunctionOnNextCall(ge);
+%OptimizeFunctionOnNextCall(gt);
+test(obj1, obj2);