[JSC] Make ArithClz32 work with Cell arguments
[WebKit-https.git] / JSTests / stress / arith-clz32-on-various-types.js
1 "use strict";
2
3 let validInputTestCases = [
4     // input as string, expected result as string.
5     ["undefined", "32"],
6     ["null", "32"],
7     ["0", "32"],
8     ["-0.", "32"],
9     ["4", "29"],
10     ["Math.PI", "30"],
11     ["Infinity", "32"],
12     ["-Infinity", "32"],
13     ["NaN", "32"],
14     ["\"WebKit\"", "32"],
15     ["\"4\"", "29"],
16     ["{ valueOf: () => { return 4; } }", "29"],
17 ];
18
19 let validInputTypedTestCases = validInputTestCases.map((element) => { return [eval("(" + element[0] + ")"), eval(element[1])] });
20
21 function isIdentical(result, expected)
22 {
23     if (expected === expected) {
24         if (result !== expected)
25             return false;
26         if (!expected && 1 / expected === -Infinity && 1 / result !== -Infinity)
27             return false;
28
29         return true;
30     }
31     return result !== result;
32 }
33
34
35 // Test Math.clz32() without arguments.
36 function opaqueClz32NoArgument() {
37     return Math.clz32();
38 }
39 noInline(opaqueClz32NoArgument);
40 noOSRExitFuzzing(opaqueClz32NoArgument);
41
42 function testNoArgument() {
43     for (let i = 0; i < 1e4; ++i) {
44         let output = opaqueClz32NoArgument();
45         if (output !== 32) {
46             throw "Failed opaqueClz32NoArgument";
47         }
48     }
49     if (numberOfDFGCompiles(opaqueClz32NoArgument) > 1)
50         throw "The call without arguments should never exit.";
51 }
52 testNoArgument();
53
54
55 // Test Math.clz32() with a very polymorphic input. All test cases are seen at each iteration.
56 function opaqueAllTypesClz32(argument) {
57     return Math.clz32(argument);
58 }
59 noInline(opaqueAllTypesClz32);
60 noOSRExitFuzzing(opaqueAllTypesClz32);
61
62 function testAllTypesCall() {
63     for (let i = 0; i < 1e3; ++i) {
64         for (let testCaseInput of validInputTypedTestCases) {
65             let output = opaqueAllTypesClz32(testCaseInput[0]);
66             if (!isIdentical(output, testCaseInput[1]))
67                 throw "Failed testAllTypesCall for input " + testCaseInput[0] + " expected " + testCaseInput[1] + " got " + output;
68         }
69     }
70     if (numberOfDFGCompiles(opaqueAllTypesClz32) > 2)
71         throw "We should have detected clz32() was polymorphic and generated a generic version.";
72 }
73 testAllTypesCall();
74
75
76 // Test Math.clz32() on a completely typed input. Every call see only one type.
77 function testSingleTypeCall() {
78     for (let testCaseInput of validInputTestCases) {
79         eval(`
80             function opaqueClz32(argument) {
81                 return Math.clz32(argument);
82             }
83             noInline(opaqueClz32);
84             noOSRExitFuzzing(opaqueClz32);
85
86             for (let i = 0; i < 1e4; ++i) {
87                 if (!isIdentical(opaqueClz32(${testCaseInput[0]}), ${testCaseInput[1]})) {
88                     throw "Failed testSingleTypeCall()";
89                 }
90             }
91             if (numberOfDFGCompiles(opaqueClz32) > 1)
92                 throw "We should have compiled a single clz32 for the expected type.";
93         `);
94     }
95 }
96 testSingleTypeCall();
97
98
99 // Test Math.clz32() on constants
100 function testConstant() {
101     for (let testCaseInput of validInputTestCases) {
102         eval(`
103             function opaqueClz32OnConstant() {
104                 return Math.clz32(${testCaseInput[0]});
105             }
106             noInline(opaqueClz32OnConstant);
107             noOSRExitFuzzing(opaqueClz32OnConstant);
108
109             for (let i = 0; i < 1e4; ++i) {
110                 if (!isIdentical(opaqueClz32OnConstant(), ${testCaseInput[1]})) {
111                     throw "Failed testConstant()";
112                 }
113             }
114             if (numberOfDFGCompiles(opaqueClz32OnConstant) > 1)
115                 throw "We should have compiled a single clz32 for the expected type.";
116         `);
117     }
118 }
119 testConstant();
120
121
122 // Verify we call valueOf() exactly once per call.
123 function opaqueClz32ForSideEffects(argument) {
124     return Math.clz32(argument);
125 }
126 noInline(opaqueClz32ForSideEffects);
127 noOSRExitFuzzing(opaqueClz32ForSideEffects);
128
129 function testSideEffect() {
130     let testObject = {
131         counter: 0,
132         valueOf: function() { ++this.counter; return 16; }
133     };
134     let clz3216 = Math.clz32(16);
135     for (let i = 0; i < 1e4; ++i) {
136         if (opaqueClz32ForSideEffects(testObject) !== clz3216)
137             throw "Incorrect result in testSideEffect()";
138     }
139     if (testObject.counter !== 1e4)
140         throw "Failed testSideEffect()";
141     if (numberOfDFGCompiles(opaqueClz32ForSideEffects) > 1)
142         throw "opaqueClz32ForSideEffects() is predictable, it should only be compiled once.";
143 }
144 testSideEffect();
145
146
147 // Verify clz32() is not subject to CSE if the argument has side effects.
148 function opaqueClz32ForCSE(argument) {
149     return Math.clz32(argument) + Math.clz32(argument) + Math.clz32(argument);
150 }
151 noInline(opaqueClz32ForCSE);
152 noOSRExitFuzzing(opaqueClz32ForCSE);
153
154 function testCSE() {
155     let testObject = {
156         counter: 0,
157         valueOf: function() { ++this.counter; return 16; }
158     };
159     let clz3216 = Math.clz32(16);
160     let threeClz3216 = clz3216 + clz3216 + clz3216;
161     for (let i = 0; i < 1e4; ++i) {
162         if (opaqueClz32ForCSE(testObject) !== threeClz3216)
163             throw "Incorrect result in testCSE()";
164     }
165     if (testObject.counter !== 3e4)
166         throw "Failed testCSE()";
167     if (numberOfDFGCompiles(opaqueClz32ForCSE) > 1)
168         throw "opaqueClz32ForCSE() is predictable, it should only be compiled once.";
169 }
170 testCSE();
171
172
173 // Verify clz32() is not subject to DCE if the argument has side effects.
174 function opaqueClz32ForDCE(argument) {
175     Math.clz32(argument);
176 }
177 noInline(opaqueClz32ForDCE);
178 noOSRExitFuzzing(opaqueClz32ForDCE);
179
180 function testDCE() {
181     let testObject = {
182         counter: 0,
183         valueOf: function() { ++this.counter; return 16; }
184     };
185     for (let i = 0; i < 1e4; ++i) {
186         opaqueClz32ForDCE(testObject);
187     }
188     if (testObject.counter !== 1e4)
189         throw "Failed testDCE()";
190     if (numberOfDFGCompiles(opaqueClz32ForDCE) > 1)
191         throw "opaqueClz32ForDCE() is predictable, it should only be compiled once.";
192 }
193 testDCE();
194
195
196 // Test exceptions in the argument.
197 function testException() {
198     let counter = 0;
199     function opaqueClz32WithException(argument) {
200         let result = Math.clz32(argument);
201         ++counter;
202         return result;
203     }
204     noInline(opaqueClz32WithException);
205
206     let testObject = { valueOf: () => {  return 64; } };
207     let clz3264 = Math.clz32(64);
208
209     // Warm up without exception.
210     for (let i = 0; i < 1e3; ++i) {
211         if (opaqueClz32WithException(testObject) !== clz3264)
212             throw "Incorrect result in opaqueClz32WithException()";
213     }
214
215     let testThrowObject = { valueOf: () => { throw testObject; return 64; } };
216
217     for (let i = 0; i < 1e2; ++i) {
218         try {
219             if (opaqueClz32WithException(testThrowObject) !== 8)
220                 throw "This code should not be reached!!";
221         } catch (e) {
222             if (e !== testObject) {
223                 throw "Wrong object thrown from opaqueClz32WithException."
224             }
225         }
226     }
227
228     if (counter !== 1e3) {
229         throw "Invalid count in testException()";
230     }
231 }
232 testException();