1 /*
   2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /**
  25  * JDK-8035712: Restore some of the RuntimeCallSite specializations
  26  *
  27  * @test
  28  * @run
  29  */
  30 
  31 if ((typeof Assert) == "undefined") {
  32     Assert = { 
  33         assertTrue: function(x) { if(!x) { throw "expected true" } },
  34         assertFalse: function(x) { if(x) { throw "expected false" } },
  35     };
  36 }
  37 
  38 function nop() {}
  39 
  40 function EQ(x, y) {
  41     // Exercise normal evaluation
  42     Assert.assertTrue (x == y);
  43     Assert.assertTrue (y == x);
  44     Assert.assertFalse(x != y);
  45     Assert.assertFalse(y != x);
  46     // Exercise the branch optimizer
  47     if (x == y) { nop(); } else { Assert.fail(); }
  48     if (y == x) { nop(); } else { Assert.fail(); }
  49     if (x != y) { Assert.fail(); } else { nop(); }
  50     if (y != x) { Assert.fail(); } else { nop(); }
  51 }
  52 
  53 function NE(x, y) {
  54     // Exercise normal evaluation
  55     Assert.assertTrue (x != y);
  56     Assert.assertTrue (y != x);
  57     Assert.assertFalse(x == y);
  58     Assert.assertFalse(y == x);
  59     // Exercise the branch optimizer
  60     if (x != y) { nop(); } else { Assert.fail(); }
  61     if (y != x) { nop(); } else { Assert.fail(); }
  62     if (x == y) { Assert.fail(); } else { nop(); }
  63     if (y == x) { Assert.fail(); } else { nop(); }
  64 }
  65 
  66 function STRICT_EQ(x, y) {
  67     // Exercise normal evaluation
  68     Assert.assertTrue (x === y);
  69     Assert.assertTrue (y === x);
  70     Assert.assertFalse(x !== y);
  71     Assert.assertFalse(y !== x);
  72     // Exercise the branch optimizer
  73     if (x === y) { nop(); } else { Assert.fail(); }
  74     if (y === x) { nop(); } else { Assert.fail(); }
  75     if (x !== y) { Assert.fail(); } else { nop(); }
  76     if (y !== x) { Assert.fail(); } else { nop(); }
  77 }
  78 
  79 function STRICT_NE(x, y) {
  80     // Exercise normal evaluation
  81     Assert.assertTrue (x !== y);
  82     Assert.assertTrue (y !== x);
  83     Assert.assertFalse(x === y);
  84     Assert.assertFalse(y === x);
  85     // Exercise the branch optimizer
  86     if (x !== y) { nop(); } else { Assert.fail(); }
  87     if (y !== x) { nop(); } else { Assert.fail(); }
  88     if (x === y) { Assert.fail(); } else { nop(); }
  89     if (y === x) { Assert.fail(); } else { nop(); }
  90 }
  91 
  92 function cmpToAnyNumber(cmp, value) {
  93     cmp(1, value);
  94     cmp(4294967296, value);
  95     cmp(1.2, value);
  96     cmp(Infinity, value);
  97     cmp(-Infinity, value);
  98     cmp(1/Infinity, value);
  99     cmp(0, value);
 100     cmp(-0, value);
 101     cmp(true, value);
 102     cmp(false, value);
 103 }
 104 
 105 function notEqualToAnyNumber(value) {
 106     cmpToAnyNumber(NE, value);
 107     cmpToAnyNumber(STRICT_NE, value);
 108 }
 109 
 110 notEqualToAnyNumber(null);
 111 notEqualToAnyNumber(void 0);
 112 notEqualToAnyNumber("abc");
 113 notEqualToAnyNumber({});
 114 notEqualToAnyNumber(["xyz"]);
 115 
 116 function objectWithPrimitiveFunctionNotEqualToAnyNumber(fnName) {
 117     var obj = {
 118         count: 0
 119     };
 120     obj[fnName] = function() { this.count++; return "foo"; };
 121     notEqualToAnyNumber(obj);
 122     // Every NE will invoke it 8 times; cmpToAnyNumber has 10 comparisons
 123     // STRICT_NE doesn't invoke toString.
 124     Assert.assertTrue(80 === obj.count);
 125 }
 126 objectWithPrimitiveFunctionNotEqualToAnyNumber("valueOf");
 127 objectWithPrimitiveFunctionNotEqualToAnyNumber("toString");
 128 
 129 function objectEqualButNotStrictlyEqual(val, obj) {
 130     EQ(val, obj);
 131     STRICT_NE(val, obj);
 132 }
 133 
 134 function numberEqualButNotStrictlyEqualToObject(num, obj) {
 135     objectEqualButNotStrictlyEqual(num, obj);
 136     objectEqualButNotStrictlyEqual(num, [obj]);
 137     objectEqualButNotStrictlyEqual(num, [[obj]]);
 138 }
 139 
 140 function numberEqualButNotStrictlyEqualToZeroObjects(num) {
 141     numberEqualButNotStrictlyEqualToObject(num, [0]);
 142     numberEqualButNotStrictlyEqualToObject(num, "");
 143     numberEqualButNotStrictlyEqualToObject(num, []);
 144     numberEqualButNotStrictlyEqualToObject(num, "0");
 145 }
 146 
 147 numberEqualButNotStrictlyEqualToZeroObjects(0);
 148 numberEqualButNotStrictlyEqualToZeroObjects(1/Infinity);
 149 numberEqualButNotStrictlyEqualToZeroObjects(false);
 150 
 151 function numberEqualButNotStrictlyEqualToObjectEquivalent(num) {
 152     var str = String(num);
 153     objectEqualButNotStrictlyEqual(num, str);
 154     objectEqualButNotStrictlyEqual(num, { valueOf:  function() { return str }});
 155     objectEqualButNotStrictlyEqual(num, { toString: function() { return str }});
 156     objectEqualButNotStrictlyEqual(num, { valueOf:  function() { return num }});
 157     objectEqualButNotStrictlyEqual(num, { toString: function() { return num }});
 158 }
 159 
 160 numberEqualButNotStrictlyEqualToObjectEquivalent(1);
 161 numberEqualButNotStrictlyEqualToObjectEquivalent(4294967296);
 162 numberEqualButNotStrictlyEqualToObjectEquivalent(1.2);
 163 numberEqualButNotStrictlyEqualToObjectEquivalent(Infinity);
 164 numberEqualButNotStrictlyEqualToObjectEquivalent(-Infinity);
 165 numberEqualButNotStrictlyEqualToObjectEquivalent(1/Infinity);
 166 numberEqualButNotStrictlyEqualToObjectEquivalent(0);
 167 numberEqualButNotStrictlyEqualToObjectEquivalent(-0);
 168 
 169 STRICT_EQ(1, new java.lang.Integer(1));
 170 STRICT_EQ(1, new java.lang.Double(1));
 171 STRICT_EQ(1.2, new java.lang.Double(1.2));
 172 
 173 function LE(x, y) {
 174     // Exercise normal evaluation
 175     Assert.assertTrue(x <= y);
 176     Assert.assertTrue(y >= x);
 177     Assert.assertFalse(x > y);
 178     Assert.assertFalse(x < y);
 179     // Exercise the branch optimizer
 180     if (x <= y) { nop(); } else { Assert.fail(); }
 181     if (y >= x) { nop(); } else { Assert.fail(); }
 182     if (x > y) { Assert.fail(); } else { nop(); }
 183     if (y < x) { Assert.fail(); } else { nop(); }
 184 }
 185 
 186 function mutuallyLessThanOrEqual(x, y) {
 187     LE(x, y);
 188     LE(y, x);
 189 }
 190 
 191 mutuallyLessThanOrEqual(0, null);
 192 mutuallyLessThanOrEqual(false, null);
 193 mutuallyLessThanOrEqual(1/Infinity, null);
 194 
 195 function mutuallyLessThanEqualToObjectWithValue(num, val) {
 196     mutuallyLessThanOrEqual(num, { valueOf: function() { return val } });
 197     mutuallyLessThanOrEqual(num, { toString: function() { return val } });
 198 }
 199 
 200 mutuallyLessThanEqualToObjectWithValue(false, 0);
 201 mutuallyLessThanEqualToObjectWithValue(false, "");
 202 
 203 mutuallyLessThanEqualToObjectWithValue(true, 1);
 204 mutuallyLessThanEqualToObjectWithValue(true, "1");
 205 
 206 function lessThanEqualToObjectEquivalent(num) {
 207     var str = String(num);
 208     mutuallyLessThanOrEqual(num, str);
 209     mutuallyLessThanEqualToObjectWithValue(num, num);
 210     mutuallyLessThanEqualToObjectWithValue(num, str);
 211 }
 212 
 213 lessThanEqualToObjectEquivalent(1);
 214 lessThanEqualToObjectEquivalent(4294967296);
 215 lessThanEqualToObjectEquivalent(1.2);
 216 lessThanEqualToObjectEquivalent(Infinity);
 217 lessThanEqualToObjectEquivalent(-Infinity);
 218 lessThanEqualToObjectEquivalent(1/Infinity);
 219 lessThanEqualToObjectEquivalent(0);
 220 lessThanEqualToObjectEquivalent(-0);
 221 
 222 function INCOMPARABLE(x, y) {
 223     // Exercise normal evaluation
 224     Assert.assertFalse(x < y);
 225     Assert.assertFalse(x > y);
 226     Assert.assertFalse(x <= y);
 227     Assert.assertFalse(x >= y);
 228     Assert.assertFalse(y < x);
 229     Assert.assertFalse(y > x);
 230     Assert.assertFalse(y <= x);
 231     Assert.assertFalse(y >= x);
 232     // Exercise the branch optimizer
 233     if (x < y) { Assert.fail(); } else { nop(); }
 234     if (x > y) { Assert.fail(); } else { nop(); }
 235     if (x <= y) { Assert.fail(); } else { nop(); }
 236     if (x >= y) { Assert.fail(); } else { nop(); }
 237     if (y < x) { Assert.fail(); } else { nop(); }
 238     if (y > x) { Assert.fail(); } else { nop(); }
 239     if (y <= x) { Assert.fail(); } else { nop(); }
 240     if (y >= x) { Assert.fail(); } else { nop(); }
 241 }
 242 
 243 function isIncomparable(value) {
 244     cmpToAnyNumber(INCOMPARABLE, value);
 245 }
 246 
 247 isIncomparable(void 0);
 248 isIncomparable({ valueOf: function() { return NaN }});
 249 isIncomparable({ toString: function() { return NaN }});
 250 
 251 // Force ScriptRuntime.LT(Object, Object) etc. comparisons
 252 function cmpObj(fn, x, y) {
 253     fn({valueOf: function() { return x }}, {valueOf: function() { return y }});
 254 }
 255 
 256 function LT(x, y) {
 257     Assert.assertTrue(x < y);
 258     Assert.assertTrue(y > x);
 259     Assert.assertFalse(x >= y);
 260     Assert.assertFalse(y <= x);
 261 }
 262 
 263 cmpObj(LT, 1, 2);
 264 cmpObj(LT, 1, "2");
 265 cmpObj(LT, "1", 2);
 266 cmpObj(LT, "a", "b");
 267 cmpObj(LT, -Infinity, 0);
 268 cmpObj(LT, 0, Infinity);
 269 cmpObj(LT, -Infinity, Infinity);
 270 cmpObj(INCOMPARABLE, 1, NaN);
 271 cmpObj(INCOMPARABLE, NaN, NaN);
 272 cmpObj(INCOMPARABLE, "boo", NaN);
 273 cmpObj(INCOMPARABLE, 1, "boo"); // boo number value will be NaN
 274 
 275 // Test that a comparison call site can deoptimize from (int, int) to (object, object)
 276 (function(){
 277     var x = [1,  2,  "a"];
 278     var y = [2, "3", "b"];
 279     for(var i = 0; i < 3; ++i) {
 280         Assert.assertTrue(x[i] < y[i]);
 281     }
 282 })();