//------------------------------------------------------------------------------------------------------- // Copyright (C) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. //------------------------------------------------------------------------------------------------------- // Notes on running this script: // - rldirs.xml is set up in the following way so that this script is called 2 times: // - First, it's called for interpreted variant. // - Then, when it's called for dynapogo variant, jshost is called with: -args dynapogo. // - This script is not called for the default variant. // - Idea: // - Collect dynamic profile cache when called for interpreted variant. // - Use dynamic profile cache when called with -args dynapogo. // - Some tests cause bailout by passing different parameter to test function // as when dynamic profile cache was created. // - How to manually run/repro: // - jshost -nonative -dynamicprofilecache:inlineBuiltIns.dpl inlineBuiltIns.js // - jshost -forcenative -dynamicprofileinput:inlineBuiltIns.dpl inlineBuiltIns.js -args dynapogo // - also trying using -testtrace:bailout to make sure you get the bailouts. // TODO: change passing -args native to jshost and instead // add support to WScript to expose getFlagByString() for Js::ConfigFlagsTable flags and check for -native. if (typeof (WScript) != "undefined") { WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js", "self"); } var Runtime = { // returns true when this jshost is called with arguments: -args native get isDynapogo() { return WScript.Arguments.length > 0 && WScript.Arguments[0] == "dynapogo"; } }; var tests = { test01: { name: "Bailout on function = null", body: function () { function TestSin(x) { var r1 = Math.sin(x); return r1; }; if (Runtime.isDynapogo) { var sinOrig = Math.sin; // back up Math.sin assert.throws(function() { Math.sin = null; var r = TestSin({}); assert.isTrue(isNaN(r)); }, TypeError); Math.sin = sinOrig; // restore Math.sin } else TestSin(); } }, test02: { name: "Bailout on function = object, not a function", body: function () { function TestSin(x) { var r1 = Math.sin(x); return r1; }; if (Runtime.isDynapogo) { var sinOrig = Math.sin; // back up Math.sin assert.throws(function() { Math.sin = {}; var r = TestSin({}); assert.isTrue(isNaN(r)); }, TypeError); Math.sin = sinOrig; // restore Math.sin } else TestSin(); } }, test03: { name: "Bailout on function = wrong function", body: function () { function TestSin(x) { var r1 = Math.sin(x); return r1; }; var sinOrig = Math.sin; // back up Math.sin Math.sin = Math.cos; var r = TestSin({}); assert.isTrue(isNaN(r)); Math.sin = sinOrig; // restore Math.sin } }, test04: { name: "Bailout on argument = string", body: function () { function TestSin(x) { var r1 = Math.sin(x); return r1; }; var r = TestSin("string"); assert.isTrue(isNaN(r)); } }, test05: { name: "Bailout on argument = object", body: function () { function TestSin(x) { var r1 = Math.sin(x); return r1; }; var r = TestSin({}); assert.isTrue(isNaN(r)); } }, test06: { name: "Bailout on 2nd argument = string", body: function () { function TestPow(x, y) { var r1 = Math.pow(x, y); return r1; }; var r = TestPow(2, "string"); assert.isTrue(isNaN(r)); } }, test07: { name: "Float/int type specialized argOuts which we restore at bailout", body: function () { // As long as there is no assert/crash, we are fine. (function() { var i = -8.1E+18; var r = Math.pow(1, Math.exp(Math.atan2(1, ((~i) - 737882964)))); })(); (function() { var e = 1; return Math.pow(e >> 1, 3.2) })(); (function() { var e = 1; Math.atan2(1, Math.pow((e >>= 1), Math.tan((-1031883772 * Math.abs(-951135089))))); })(); (function() { var ary = new Array(); ary[0] = 0; Math.pow(1808815940.1, -ary[0]); })(); (function() { return Math.pow(Math.sin(1), Math.pow(1, 1)); })(); (function() { var o = { x: 0 }; var func0 = function() { Math.pow(1.1, o.x * -1); } Math.atan2(func0(), 1); })(); } }, test08: { name: "Bailout on argument after function copy-prop into InlineBuiltInStart", body: function () { for(var i in [0, 1]) assert.isTrue(isNaN(Math.pow(Math.pow(/x/, 0.1), 0.1))); } }, test09: { name: "Bailout (pre-op) on 2nd arg which is updated in the place of the call - make sure 1st arg is not updated", body: function() { var accumulator = ""; var vOf = function vOf() { accumulator += "x"; return 3; } function testFunc() { var i = 1; do { // We need to make sure that we pass original value of i (== 1) as 1st arg. var x = Math.pow(i, Runtime.isDynapogo ? i = { valueOf: vOf } : 1); } while (vOf == undefined); } testFunc(); if (Runtime.isDynapogo) { assert.areEqual("x", accumulator, "valueOf was called wrong number of times"); } } }, }; // tests. testRunner.runTests(tests);