| // Copyright 2018 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Flags: --allow-natives-syntax --opt --no-always-opt |
| |
| function runTest(f, message, mkICTraining, deoptArg) { |
| function test(f, message, ictraining, deoptArg) { |
| // Train the call ic to the maps. |
| let t = ictraining; |
| |
| // We put the training data into local variables |
| // to ensure their maps are kepts alive. If the |
| // maps die, gc *may* deoptimize {f}, which makes |
| // the test flaky. |
| let t1 = t(); |
| let t2 = t(); |
| let t3 = t(); |
| |
| for (let a of t1) { |
| f(a.arr, () => a.el); |
| } |
| for (let a of t2) { |
| f(a.arr, () => a.el); |
| } |
| %OptimizeFunctionOnNextCall(f); |
| message += " trained with" + JSON.stringify(t()); |
| if (deoptArg == undefined) { |
| // Make sure the optimized function can handle |
| // all trained maps without deopt. |
| for (let a of t3) { |
| f(a.arr, () => a.el); |
| message += " for args " + JSON.stringify(a); |
| assertOptimized(f, undefined, message + " should have been optimized"); |
| } |
| } else { |
| // Trigger deopt, causing no-speculation bit to be set. |
| let a1 = deoptArg; |
| let a2 = deoptArg; |
| message += " for args " + JSON.stringify(a1); |
| f(a1.arr, () => a1.el); |
| assertUnoptimized(f, undefined, message + " should have been unoptimized"); |
| %OptimizeFunctionOnNextCall(f); |
| // No speculation should protect against further deopts. |
| f(a2.arr, () => a2.el); |
| assertOptimized(f, undefined, message + " should have been optimized"); |
| } |
| } |
| |
| // Get function as a string. |
| var testString = test.toString(); |
| // Remove the function header.. |
| testString = testString.replace(new RegExp("[^\n]*"), "let f = " + f.toString() + ";"); |
| // ..and trailing '}'. |
| testString = testString.replace(new RegExp("[^\n]*$"), ""); |
| // Substitute parameters. |
| testString = testString.replace(new RegExp("ictraining", 'g'), mkICTraining.toString()); |
| testString = testString.replace(new RegExp("deoptArg", 'g'), |
| deoptArg ? JSON.stringify(deoptArg) : "undefined"); |
| |
| var modTest = new Function("message", testString); |
| //print(modTest); |
| modTest(message); |
| } |
| |
| let checks = { |
| smiReceiver: |
| { mkTrainingArguments : () => [{arr:[1], el:3}], |
| deoptingArguments : [{arr:[0.1], el:1}, {arr:[{}], el:1}] |
| }, |
| objectReceiver: |
| { mkTrainingArguments : () => [{arr:[{}], el:0.1}], |
| deoptingArguments : [] |
| }, |
| multipleSmiReceivers: |
| { mkTrainingArguments : () => { let b = [1]; b.x=3; return [{arr:[1], el:3}, {arr:b, el:3}] }, |
| deoptingArguments : [{arr:[0.1], el:1}, {arr:[{}], el:1}] |
| }, |
| multipleSmiReceiversPackedUnpacked: |
| { mkTrainingArguments : () => { let b = [1]; b[100] = 3; return [{arr:[1], el:3}, {arr:b, el:3}] }, |
| deoptingArguments : [{arr:[0.1], el:1}, {arr:[{}], el:1}] |
| }, |
| multipleDoubleReceivers: |
| { mkTrainingArguments : () => { let b = [0.1]; b.x=0.3; return [{arr:[0.1], el:0.3}, {arr:b, el:0.3}] }, |
| deoptingArguments : [{arr:[{}], el:true}, {arr:[1], el:true}] |
| }, |
| multipleDoubleReceiversPackedUnpacked: |
| { mkTrainingArguments : () => { let b = [0.1]; b[100] = 0.3; return [{arr:[0.1], el:0.3}, {arr:b, el:0.3}] }, |
| deoptingArguments : [{arr:[{}], el:true}, {arr:[1], el:true}] |
| }, |
| multipleMixedReceivers: |
| { mkTrainingArguments : () => { let b = [0.1]; b.x=0.3; return [{arr:[1], el:0.3}, {arr:[{}], el:true}, {arr:b, el:0.3}] }, |
| deoptingArguments : [] |
| }, |
| multipleMixedReceiversPackedUnpacked: |
| { mkTrainingArguments : () => { let b = [0.1]; b[100] = 0.3; return [{arr:[1], el:0.3}, {arr:[{}], el:true}, {arr:b, el:0.3}] }, |
| deoptingArguments : [] |
| }, |
| }; |
| |
| const functions = { |
| push_reliable: (a,g) => { let b = g(); return a.push(2, b); }, |
| push_unreliable: (a,g) => { return a.push(2, g()); }, |
| pop_reliable: (a,g) => { let b = g(); return a.pop(2, b); }, |
| pop_unreliable: (a,g) => { return a.pop(2, g()); }, |
| shift_reliable: (a,g) => { let b = g(); return a.shift(2, b); }, |
| shift_unreliable: (a,g) => { return a.shift(2, g()); } |
| } |
| |
| Object.keys(checks).forEach( |
| key => { |
| let check = checks[key]; |
| |
| for (fnc in functions) { |
| runTest(functions[fnc], "test-reliable-" + key, check.mkTrainingArguments); |
| // Test each deopting arg separately. |
| for (let deoptArg of check.deoptingArguments) { |
| runTest(functions[fnc], "testDeopt-reliable-" + key, check.mkTrainingArguments, deoptArg); |
| } |
| } |
| } |
| ); |