Add op_add tests to compare behavior of JIT generated code to the LLINT's.
[WebKit-https.git] / Source / JavaScriptCore / tests / stress / op_add.js
1 //@ runFTLNoCJIT
2
3 // This test module aims to test the addition operator by comparing its runtime
4 // behavior (using the different tiers) with expected values computed at initialization
5 // time using the LLINT / bytecode generator.
6 //
7 // It works by generating test scenarios from permutations of value pairs to exercise
8 // the addition operator. It computes the expected results by evaluating an expression
9 // to add the values in an initialization pass. The scenarios are later applied to
10 // a set of test functions of the forms:
11 //
12 //     variable + variable
13 //     constant + variable
14 //     variable + constant
15 //
16 // See generateScenarios() and initializeTestCases() for details on how the test
17 // cases are generated.
18 //
19 // If all goes well, this test module will terminate silently. If not, it will print
20 // errors.
21
22 var verbose = false;
23 var abortOnFirstFail = false;
24
25 var o1 = {
26     valueOf: function() { return 10; }
27 };
28
29 var set1 = [
30     'o1',
31     'null',
32     'undefined',
33     'NaN',
34     '"abc"',
35 ];
36
37 var set2 = [
38     '10',
39     '-10',
40     '2147483647',
41     '-2147483647',
42     '4294967296',
43     '-4294967296',
44     '100.2',
45     '-100.2',
46     'true',
47     'false',
48 ];
49
50 // Assemble the values that we'll be testing with:
51 var values = [];
52 for (var i = 0; i < set1.length; i++)
53     values.push(set1[i]);
54 for (var i = 0; i < set2.length; i++)
55     values.push(set2[i]);
56 for (var i = 0; i < set2.length; i++)
57     values.push('"' + set2[i] + '"');
58
59 function generateScenarios(xvalues, yvalues) {
60     var scenarios = [];
61     for (var i = 0; i < xvalues.length; i++) {
62         for (var j = 0; j < yvalues.length; j++) {
63             var xStr = xvalues[i];
64             var yStr = yvalues[j];
65             var x = eval(xStr);
66             var y = eval(yStr);
67             var name = "(" + xStr + " + " + yStr + ")";
68             var expected = eval("" + xStr + " + " + yStr);
69             var scenario = { name: name, x: x, y: y, expected: expected };
70
71             scenarios.push(scenario);
72         }
73     }
74     return scenarios;
75 }
76
77 function printScenarios(scenarios) {
78     for (var i = 0; i < scenarios.length; i++) {
79         var scenario = scenarios[i];
80         print("scenario[" + i + "]: { name: " + scenario.name + ", x: " + scenario.x, ", y: " + scenario.y + ", expected: " + scenario.expected + " }");
81     }
82 }
83
84 var testCases = [
85     {
86         name: "add",
87         func: function(x, y) { return x + y; },
88         xvalues: values,
89         yvalues: values
90     },
91     {
92         name: "addI32V",
93         func: function(x, y) { return 10 + y; },
94         xvalues: [ '10' ],
95         yvalues: values
96     },
97     {
98         name: "addVI32",
99         func: function(x, y) { return x + 10; },
100         xvalues: values,
101         yvalues: [ '10' ]
102     },
103     {
104         name: "addI32oV",
105         func: function(x, y) { return 2147483647 + y; },
106         xvalues: [ '2147483647' ],
107         yvalues: values
108     },
109     {
110         name: "addVI32o",
111         func: function(x, y) { return x + 2147483647; },
112         xvalues: values,
113         yvalues: [ '2147483647' ]
114     },
115     {
116         name: "addI32onV",
117         func: function(x, y) { return -2147483647 + y; },
118         xvalues: [ '-2147483647' ],
119         yvalues: values
120     },
121     {
122         name: "addVI32on",
123         func: function(x, y) { return x + (-2147483647); },
124         xvalues: values,
125         yvalues: [ '-2147483647' ]
126     },
127     {
128         name: "addI52V",
129         func: function(x, y) { return 4294967296 + y; },
130         xvalues: [ '4294967296' ],
131         yvalues: values
132     },
133     {
134         name: "addVI52",
135         func: function(x, y) { return x + 4294967296; },
136         xvalues: values,
137         yvalues: [ '4294967296' ]
138     },
139     {
140         name: "addI52nV",
141         func: function(x, y) { return -4294967296 + y; },
142         xvalues: [ '-4294967296' ],
143         yvalues: values
144     },
145     {
146         name: "addVI52n",
147         func: function(x, y) { return x + (-4294967296); },
148         xvalues: values,
149         yvalues: [ '-4294967296' ]
150     },
151     {
152         name: "addDV",
153         func: function(x, y) { return 100.2 + y; },
154         xvalues: [ '100.2' ],
155         yvalues: values
156     },
157     {
158         name: "addVD",
159         func: function(x, y) { return x + 100.2; },
160         xvalues: values,
161         yvalues: [ '100.2' ]
162     },
163     {
164         name: "addBV",
165         func: function(x, y) { return true + y; },
166         xvalues: [ 'true' ],
167         yvalues: values
168     },
169     {
170         name: "addVB",
171         func: function(x, y) { return x + true; },
172         xvalues: values,
173         yvalues: [ 'true' ]
174     },
175     {
176         name: "addSi32V",
177         func: function(x, y) { return "10" + y; },
178         xvalues: [ '"10"' ],
179         yvalues: values
180     },
181     {
182         name: "addVSi32",
183         func: function(x, y) { return x + "10"; },
184         xvalues: values,
185         yvalues: [ '"10"' ]
186     },
187
188     {
189         name: "addSi32oV",
190         func: function(x, y) { return "2147483647" + y; },
191         xvalues: [ '"2147483647"' ],
192         yvalues: values
193     },
194     {
195         name: "addVSi32o",
196         func: function(x, y) { return x + "2147483647"; },
197         xvalues: values,
198         yvalues: [ '"2147483647"' ]
199     },
200     {
201         name: "addSi32onV",
202         func: function(x, y) { return "-2147483647" + y; },
203         xvalues: [ '"-2147483647"' ],
204         yvalues: values
205     },
206     {
207         name: "addVSi32on",
208         func: function(x, y) { return x + "-2147483647"; },
209         xvalues: values,
210         yvalues: [ '"-2147483647"' ]
211     },
212     {
213         name: "addSi52V",
214         func: function(x, y) { return "4294967296" + y; },
215         xvalues: [ '"4294967296"' ],
216         yvalues: values
217     },
218     {
219         name: "addVSi52",
220         func: function(x, y) { return x + "4294967296"; },
221         xvalues: values,
222         yvalues: [ '"4294967296"' ]
223     },
224     {
225         name: "addSi52nV",
226         func: function(x, y) { return "-4294967296" + y; },
227         xvalues: [ '"-4294967296"' ],
228         yvalues: values
229     },
230     {
231         name: "addVSi52n",
232         func: function(x, y) { return x + "-4294967296"; },
233         xvalues: values,
234         yvalues: [ '"-4294967296"' ]
235     },
236     {
237         name: "addSdV",
238         func: function(x, y) { return "100.2" + y; },
239         xvalues: [ '"100.2"' ],
240         yvalues: values
241     },
242     {
243         name: "addVSd",
244         func: function(x, y) { return x + "100.2"; },
245         xvalues: values,
246         yvalues: [ '"100.2"' ]
247     },
248     {
249         name: "addSbV",
250         func: function(x, y) { return "true" + y; },
251         xvalues: [ '"true"' ],
252         yvalues: values
253     },
254     {
255         name: "addVSb",
256         func: function(x, y) { return x + "true"; },
257         xvalues: values,
258         yvalues: [ '"true"' ]
259     },
260
261     {
262         name: "addSV",
263         func: function(x, y) { return "abc" + y; },
264         xvalues: [ '"abc"' ],
265         yvalues: values
266     },
267     {
268         name: "addVS",
269         func: function(x, y) { return x + "abc"; },
270         xvalues: values,
271         yvalues: [ '"abc"' ]
272     },
273     {
274         name: "addNV",
275         func: function(x, y) { return null + y; },
276         xvalues: [ 'null' ],
277         yvalues: values
278     },
279     {
280         name: "addVN",
281         func: function(x, y) { return x + null; },
282         xvalues: values,
283         yvalues: [ 'null' ]
284     },
285     {
286         name: "addOV",
287         func: function(x, y) { return o1 + y; },
288         xvalues: [ 'o1' ],
289         yvalues: values
290     },
291     {
292         name: "addVO",
293         func: function(x, y) { return x + o1; },
294         xvalues: values,
295         yvalues: [ 'o1' ]
296     },
297     {
298         name: "addNaNV",
299         func: function(x, y) { return NaN + y; },
300         xvalues: [ 'NaN' ],
301         yvalues: values
302     },
303     {
304         name: "addVNaN",
305         func: function(x, y) { return x + NaN; },
306         xvalues: values,
307         yvalues: [ 'NaN' ]
308     },
309 ];
310
311 function initializeTestCases() {
312     for (var test of testCases) {
313         noInline(test.func);
314         test.scenarios = generateScenarios(test.xvalues, test.yvalues);
315     }
316 }
317 initializeTestCases();
318
319 var errorReport = "";
320
321 function runTest(test) {
322     var failedScenario = [];
323     var scenarios = test.scenarios;
324     var testFunc = test.func;
325     try {
326         for (var i = 0; i < 10000; i++) {
327             for (var scenarioID = 0; scenarioID < scenarios.length; scenarioID++) {
328                 var scenario = scenarios[scenarioID];
329                 if (verbose)
330                     print("Testing " + test.name + ":" + scenario.name + " on iteration " + i + ": expecting " + scenario.expected); 
331
332                 var result = testFunc(scenario.x, scenario.y);
333                 if (result == scenario.expected)
334                     continue;
335                 if (Number.isNaN(result) && Number.isNaN(scenario.expected))
336                     continue;
337                 if (!failedScenario[scenarioID]) {
338                     errorReport += "FAIL: " + test.name + ":" + scenario.name + " started failing on iteration " + i + ": expected " + scenario.expected + ", actual " + result + "\n";
339                     if (abortOnFirstFail)
340                         throw errorReport;
341                     failedScenario[scenarioID] = scenario;
342                 }
343             }
344         }
345     } catch(e) {
346         if (abortOnFirstFail)
347             throw e; // Negate the catch by re-throwing.
348         errorReport += "Unexpected exception: " + e + "\n";
349     }
350 }
351
352 for (var test of testCases)
353     runTest(test);
354
355 if (errorReport !== "")
356     throw "Error: bad result:\n" + errorReport;