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