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
31if ((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
38function nop() {}
39
40function 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
53function 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
66function 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
79function 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
92function 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
105function notEqualToAnyNumber(value) {
106    cmpToAnyNumber(NE, value);
107    cmpToAnyNumber(STRICT_NE, value);
108}
109
110notEqualToAnyNumber(null);
111notEqualToAnyNumber(void 0);
112notEqualToAnyNumber("abc");
113notEqualToAnyNumber({});
114notEqualToAnyNumber(["xyz"]);
115
116function 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}
126objectWithPrimitiveFunctionNotEqualToAnyNumber("valueOf");
127objectWithPrimitiveFunctionNotEqualToAnyNumber("toString");
128
129function objectEqualButNotStrictlyEqual(val, obj) {
130    EQ(val, obj);
131    STRICT_NE(val, obj);
132}
133
134function numberEqualButNotStrictlyEqualToObject(num, obj) {
135    objectEqualButNotStrictlyEqual(num, obj);
136    objectEqualButNotStrictlyEqual(num, [obj]);
137    objectEqualButNotStrictlyEqual(num, [[obj]]);
138}
139
140function numberEqualButNotStrictlyEqualToZeroObjects(num) {
141    numberEqualButNotStrictlyEqualToObject(num, [0]);
142    numberEqualButNotStrictlyEqualToObject(num, "");
143    numberEqualButNotStrictlyEqualToObject(num, []);
144    numberEqualButNotStrictlyEqualToObject(num, "0");
145}
146
147numberEqualButNotStrictlyEqualToZeroObjects(0);
148numberEqualButNotStrictlyEqualToZeroObjects(1/Infinity);
149numberEqualButNotStrictlyEqualToZeroObjects(false);
150
151function 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
160numberEqualButNotStrictlyEqualToObjectEquivalent(1);
161numberEqualButNotStrictlyEqualToObjectEquivalent(4294967296);
162numberEqualButNotStrictlyEqualToObjectEquivalent(1.2);
163numberEqualButNotStrictlyEqualToObjectEquivalent(Infinity);
164numberEqualButNotStrictlyEqualToObjectEquivalent(-Infinity);
165numberEqualButNotStrictlyEqualToObjectEquivalent(1/Infinity);
166numberEqualButNotStrictlyEqualToObjectEquivalent(0);
167numberEqualButNotStrictlyEqualToObjectEquivalent(-0);
168
169STRICT_EQ(1, new java.lang.Integer(1));
170STRICT_EQ(1, new java.lang.Double(1));
171STRICT_EQ(1.2, new java.lang.Double(1.2));
172
173function 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
186function mutuallyLessThanOrEqual(x, y) {
187    LE(x, y);
188    LE(y, x);
189}
190
191mutuallyLessThanOrEqual(0, null);
192mutuallyLessThanOrEqual(false, null);
193mutuallyLessThanOrEqual(1/Infinity, null);
194
195function mutuallyLessThanEqualToObjectWithValue(num, val) {
196    mutuallyLessThanOrEqual(num, { valueOf: function() { return val } });
197    mutuallyLessThanOrEqual(num, { toString: function() { return val } });
198}
199
200mutuallyLessThanEqualToObjectWithValue(false, 0);
201mutuallyLessThanEqualToObjectWithValue(false, "");
202
203mutuallyLessThanEqualToObjectWithValue(true, 1);
204mutuallyLessThanEqualToObjectWithValue(true, "1");
205
206function lessThanEqualToObjectEquivalent(num) {
207    var str = String(num);
208    mutuallyLessThanOrEqual(num, str);
209    mutuallyLessThanEqualToObjectWithValue(num, num);
210    mutuallyLessThanEqualToObjectWithValue(num, str);
211}
212
213lessThanEqualToObjectEquivalent(1);
214lessThanEqualToObjectEquivalent(4294967296);
215lessThanEqualToObjectEquivalent(1.2);
216lessThanEqualToObjectEquivalent(Infinity);
217lessThanEqualToObjectEquivalent(-Infinity);
218lessThanEqualToObjectEquivalent(1/Infinity);
219lessThanEqualToObjectEquivalent(0);
220lessThanEqualToObjectEquivalent(-0);
221
222function 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
243function isIncomparable(value) {
244    cmpToAnyNumber(INCOMPARABLE, value);
245}
246
247isIncomparable(void 0);
248isIncomparable({ valueOf: function() { return NaN }});
249isIncomparable({ toString: function() { return NaN }});
250
251// Force ScriptRuntime.LT(Object, Object) etc. comparisons
252function cmpObj(fn, x, y) {
253    fn({valueOf: function() { return x }}, {valueOf: function() { return y }});
254}
255
256function 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
263cmpObj(LT, 1, 2);
264cmpObj(LT, 1, "2");
265cmpObj(LT, "1", 2);
266cmpObj(LT, "a", "b");
267cmpObj(LT, -Infinity, 0);
268cmpObj(LT, 0, Infinity);
269cmpObj(LT, -Infinity, Infinity);
270cmpObj(INCOMPARABLE, 1, NaN);
271cmpObj(INCOMPARABLE, NaN, NaN);
272cmpObj(INCOMPARABLE, "boo", NaN);
273cmpObj(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})();
283