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