From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- js/src/jit-test/tests/ion/inlining/array-pop.js | 17 +++ js/src/jit-test/tests/ion/inlining/array-push.js | 37 ++++++ js/src/jit-test/tests/ion/inlining/bug705251.js | 10 ++ .../ion/inlining/call-apply-non-singletons.js | 22 ++++ .../inlining/exception-during-inlining-decision.js | 115 +++++++++++++++++ .../tests/ion/inlining/getelem-getter-bailout.js | 48 +++++++ .../tests/ion/inlining/getelem-getter-frameiter.js | 48 +++++++ .../ion/inlining/getelem-getter-id-mismatch.js | 113 ++++++++++++++++ .../ion/inlining/getelem-getter-megamorphic.js | 79 ++++++++++++ .../ion/inlining/getelem-getter-noninlined-call.js | 52 ++++++++ .../tests/ion/inlining/getelem-getter-own.js | 51 ++++++++ .../tests/ion/inlining/getelem-getter-proto.js | 55 ++++++++ .../ion/inlining/inline-callarg-bailout-phi.js | 29 +++++ .../tests/ion/inlining/inline-callarg-bailout.js | 26 ++++ .../inlining/inline-callarg-ubench-no-double2.js | 27 ++++ .../tests/ion/inlining/inline-getelem-args.js | 59 +++++++++ .../inline-istypedarray-on-nontypedarray.js | 6 + .../jit-test/tests/ion/inlining/isFiniteInline.js | 15 +++ js/src/jit-test/tests/ion/inlining/isNaNInline.js | 15 +++ .../tests/ion/inlining/object-is-stricteq.js | 143 +++++++++++++++++++++ .../typedarray-data-inlining-neuter-samedata.js | 28 ++++ .../tests/ion/inlining/typedarray-large-length.js | 10 ++ .../inlining/typedarray-length-inlining-neuter.js | 22 ++++ 23 files changed, 1027 insertions(+) create mode 100644 js/src/jit-test/tests/ion/inlining/array-pop.js create mode 100644 js/src/jit-test/tests/ion/inlining/array-push.js create mode 100644 js/src/jit-test/tests/ion/inlining/bug705251.js create mode 100644 js/src/jit-test/tests/ion/inlining/call-apply-non-singletons.js create mode 100644 js/src/jit-test/tests/ion/inlining/exception-during-inlining-decision.js create mode 100644 js/src/jit-test/tests/ion/inlining/getelem-getter-bailout.js create mode 100644 js/src/jit-test/tests/ion/inlining/getelem-getter-frameiter.js create mode 100644 js/src/jit-test/tests/ion/inlining/getelem-getter-id-mismatch.js create mode 100644 js/src/jit-test/tests/ion/inlining/getelem-getter-megamorphic.js create mode 100644 js/src/jit-test/tests/ion/inlining/getelem-getter-noninlined-call.js create mode 100644 js/src/jit-test/tests/ion/inlining/getelem-getter-own.js create mode 100644 js/src/jit-test/tests/ion/inlining/getelem-getter-proto.js create mode 100644 js/src/jit-test/tests/ion/inlining/inline-callarg-bailout-phi.js create mode 100644 js/src/jit-test/tests/ion/inlining/inline-callarg-bailout.js create mode 100644 js/src/jit-test/tests/ion/inlining/inline-callarg-ubench-no-double2.js create mode 100644 js/src/jit-test/tests/ion/inlining/inline-getelem-args.js create mode 100644 js/src/jit-test/tests/ion/inlining/inline-istypedarray-on-nontypedarray.js create mode 100644 js/src/jit-test/tests/ion/inlining/isFiniteInline.js create mode 100644 js/src/jit-test/tests/ion/inlining/isNaNInline.js create mode 100644 js/src/jit-test/tests/ion/inlining/object-is-stricteq.js create mode 100644 js/src/jit-test/tests/ion/inlining/typedarray-data-inlining-neuter-samedata.js create mode 100644 js/src/jit-test/tests/ion/inlining/typedarray-large-length.js create mode 100644 js/src/jit-test/tests/ion/inlining/typedarray-length-inlining-neuter.js (limited to 'js/src/jit-test/tests/ion/inlining') diff --git a/js/src/jit-test/tests/ion/inlining/array-pop.js b/js/src/jit-test/tests/ion/inlining/array-pop.js new file mode 100644 index 0000000000..007b1dc8ec --- /dev/null +++ b/js/src/jit-test/tests/ion/inlining/array-pop.js @@ -0,0 +1,17 @@ +function f(arr) { + var x; + for (var i=0; i<100; i++) { + x = arr.pop(); + } + return x; +} + +var arr = []; +for (var i=0; i<130; i++) { + arr.push({i: i}); +} + +assertEq(f(arr).i, 30); +assertEq(arr.length, 30); +assertEq(f(arr), undefined); +assertEq(arr.length, 0); diff --git a/js/src/jit-test/tests/ion/inlining/array-push.js b/js/src/jit-test/tests/ion/inlining/array-push.js new file mode 100644 index 0000000000..3e7ac159e3 --- /dev/null +++ b/js/src/jit-test/tests/ion/inlining/array-push.js @@ -0,0 +1,37 @@ +function test1() { + function push(arr, x) { + return arr.push(x); + } + var arr = []; + for (var i=0; i<100; i++) { + assertEq(push(arr, i), i + 1); + } +} +test1(); + +function test2() { + var arr; + for (var i=0; i<60; i++) { + arr = []; + assertEq(arr.push(3.3), 1); + assertEq(arr.push(undefined), 2); + assertEq(arr.push(true), 3); + assertEq(arr.push(Math), 4); + assertEq(arr.toString(), "3.3,,true,[object Math]"); + } +} +test2(); + +function test3() { + function push(arr, v) { + arr.push(v); + } + for (var i=0; i<60; i++) { + var arr = []; + push(arr, null); + push(arr, 3.14); + push(arr, {}); + assertEq(arr.toString(), ",3.14,[object Object]"); + } +} +test3(); diff --git a/js/src/jit-test/tests/ion/inlining/bug705251.js b/js/src/jit-test/tests/ion/inlining/bug705251.js new file mode 100644 index 0000000000..19f639d7aa --- /dev/null +++ b/js/src/jit-test/tests/ion/inlining/bug705251.js @@ -0,0 +1,10 @@ +function bitsinbyte() { + var c = 0; + while (false) c = c * 2; +} +function TimeFunc(func) { + for(var y=0; y<11000; y++) + func(); +} +for (var i=0; i<50; i++) + TimeFunc(bitsinbyte); diff --git a/js/src/jit-test/tests/ion/inlining/call-apply-non-singletons.js b/js/src/jit-test/tests/ion/inlining/call-apply-non-singletons.js new file mode 100644 index 0000000000..9b26ddf0ab --- /dev/null +++ b/js/src/jit-test/tests/ion/inlining/call-apply-non-singletons.js @@ -0,0 +1,22 @@ +var arr1 = []; +var arr2 = []; +for (let i = 0; i < 10; i++) { + arr1.push(function f(x) { + if (x === 350) + bailout(); + assertEq(f, arr1[i]); + return x + i; + }); + arr2.push(function() { + return arr1[i].apply(null, arguments); + }); +} + +function test() { + for (var i = 0; i < 400; i++) { + for (var j = 0; j < arr2.length; j++) { + assertEq(arr2[j].call(null, i), i + j); + } + } +} +test(); diff --git a/js/src/jit-test/tests/ion/inlining/exception-during-inlining-decision.js b/js/src/jit-test/tests/ion/inlining/exception-during-inlining-decision.js new file mode 100644 index 0000000000..17c11f8599 --- /dev/null +++ b/js/src/jit-test/tests/ion/inlining/exception-during-inlining-decision.js @@ -0,0 +1,115 @@ +function runNearStackLimit(f) { + function t() { + try { + return t(); + } catch (e) { + return f(); + } + } + return t() +} +var helpers = function helpers() { + return { + get isCompatVersion9() { + } }; +}(); +var testRunner = function testRunner() { + var testRunner = { + asyncTestHasNoErr: function asyncTestHasNoErr() { + }, + runTests: function runTests(testsToRun) { + for (var i in testsToRun) { + this.runTest(i, testsToRun[i].name, testsToRun[i].body); + } + }, + runTest: function runTest(testIndex, testName, testBody) { + try { + testBody(); + } catch (ex) { + } + }, + asyncTestBegin: function asyncTestBegin() { + return explicitAsyncTestExit ? ` + ` : ` + `; + } }; + return testRunner; +}(); +var assert = function assert() { + var validate = function validate() { + }; + return { + areEqual: function areEqual() { + validate( message); + }, + areNotEqual: function areNotEqual() { + } }; +}(); +class __c_19 { + constructor() { + this.foo = 'SimpleParent'; + } +} +var __v_2735 = [{ + body: function () { + class __c_23 extends __c_19 { + constructor() { + super() + } + } + let __v_2738 = new __c_23(); + } +}, { + body: function () { + class __c_26 extends __c_19 { + constructor() { + super(); + } + } + let __v_2739 = new __c_26(); + } +}, { + body: function () { + class __c_29 extends __c_19 { + constructor() { + super() + } + } + let __v_2743 = new __c_29(); + class __c_30 extends __c_19 { + constructor() { + super() + super(); + } + } + let __v_2746 = new __c_30(); + } +}, { + body: function () { + class __c_34 extends __c_19 {} + let __v_2749 = new __c_34(); + } +}, { + body: function () { + class __c_87 extends __c_19 { + constructor() { + try { + assert.areEqual(); + } catch (e) {} + eval('super();') + } + } + function __f_683(__v_2812) { + __v_2812.foo + } + __f_683(new __c_87()) + runNearStackLimit(() => { + return __f_683(); + }) + } +}, { + body: function () { + } +}]; + testRunner.runTests(__v_2735, { + }); \ No newline at end of file diff --git a/js/src/jit-test/tests/ion/inlining/getelem-getter-bailout.js b/js/src/jit-test/tests/ion/inlining/getelem-getter-bailout.js new file mode 100644 index 0000000000..71fc680a8a --- /dev/null +++ b/js/src/jit-test/tests/ion/inlining/getelem-getter-bailout.js @@ -0,0 +1,48 @@ +// Test bailouts in inlined jsop_getelem accesses. + +// Defined outside of the test functions to ensure they're recognised as +// constants in Ion. +var atom = "prop"; +var symbol = Symbol(); + +function testAtom() { + var holder = { + get [atom]() { + bailout(); + return 1; + } + }; + + function f() { + for (var i = 0; i < 2000; ++i) { + var x = holder[atom]; + assertEq(x, 1); + } + } + + for (var i = 0; i < 2; i++) { + f(); + } +} +testAtom(); + +function testSymbol() { + var holder = { + get [symbol]() { + bailout(); + return 1; + } + }; + + function f() { + for (var i = 0; i < 2000; ++i) { + var x = holder[symbol]; + assertEq(x, 1); + } + } + + for (var i = 0; i < 2; i++) { + f(); + } +} +testSymbol(); diff --git a/js/src/jit-test/tests/ion/inlining/getelem-getter-frameiter.js b/js/src/jit-test/tests/ion/inlining/getelem-getter-frameiter.js new file mode 100644 index 0000000000..7a2e2f1405 --- /dev/null +++ b/js/src/jit-test/tests/ion/inlining/getelem-getter-frameiter.js @@ -0,0 +1,48 @@ +// Test bailouts in inlined jsop_getelem accesses. + +// Defined outside of the test functions to ensure they're recognised as +// constants in Ion. +var atom = "prop"; +var symbol = Symbol(); + +function testAtom() { + var holder = { + get [atom]() { + new Error().stack; + return 1; + } + }; + + function f() { + for (var i = 0; i < 2000; ++i) { + var x = holder[atom]; + assertEq(x, 1); + } + } + + for (var i = 0; i < 2; i++) { + f(); + } +} +testAtom(); + +function testSymbol() { + var holder = { + get [symbol]() { + new Error().stack; + return 1; + } + }; + + function f() { + for (var i = 0; i < 2000; ++i) { + var x = holder[symbol]; + assertEq(x, 1); + } + } + + for (var i = 0; i < 2; i++) { + f(); + } +} +testSymbol(); diff --git a/js/src/jit-test/tests/ion/inlining/getelem-getter-id-mismatch.js b/js/src/jit-test/tests/ion/inlining/getelem-getter-id-mismatch.js new file mode 100644 index 0000000000..57a2c0ff68 --- /dev/null +++ b/js/src/jit-test/tests/ion/inlining/getelem-getter-id-mismatch.js @@ -0,0 +1,113 @@ +// Ensure BaselineInspector properly handles mixed atom/symbols when determining +// whether or not a jsop_getelem access to a getter can be inlined. + +// Defined outside of the test functions to ensure they're recognised as +// constants in Ion. +var atom1 = "prop1"; +var atom2 = "prop2"; +var sym1 = Symbol(); +var sym2 = Symbol(); + +function testAtomAtom() { + var holder = { + get [atom1]() { return 1; }, + get [atom2]() { return 2; }, + }; + + function get(name) { + // Single access point called with different atoms. + return holder[name]; + } + + function f() { + for (var i = 0; i < 1000; ++i) { + var x = get(atom1); + var y = get(atom2); + assertEq(x, 1); + assertEq(y, 2); + } + } + + for (var i = 0; i < 2; i++) { + f(); + } +} +testAtomAtom(); + +function testAtomSymbol() { + var holder = { + get [atom1]() { return 1; }, + get [sym2]() { return 2; }, + }; + + function get(name) { + // Single access point called with atom and symbol. + return holder[name]; + } + + function f() { + for (var i = 0; i < 1000; ++i) { + var x = get(atom1); + var y = get(sym2); + assertEq(x, 1); + assertEq(y, 2); + } + } + + for (var i = 0; i < 2; i++) { + f(); + } +} +testAtomSymbol(); + +function testSymbolAtom() { + var holder = { + get [sym1]() { return 1; }, + get [atom2]() { return 2; }, + }; + + function get(name) { + // Single access point called with symbol and atom. + return holder[name]; + } + + function f() { + for (var i = 0; i < 1000; ++i) { + var x = get(sym1); + var y = get(atom2); + assertEq(x, 1); + assertEq(y, 2); + } + } + + for (var i = 0; i < 2; i++) { + f(); + } +} +testSymbolAtom(); + +function testSymbolSymbol() { + var holder = { + get [sym1]() { return 1; }, + get [sym2]() { return 2; }, + }; + + function get(name) { + // Single access point called with different symbols. + return holder[name]; + } + + function f() { + for (var i = 0; i < 1000; ++i) { + var x = get(sym1); + var y = get(sym2); + assertEq(x, 1); + assertEq(y, 2); + } + } + + for (var i = 0; i < 2; i++) { + f(); + } +} +testSymbolSymbol(); diff --git a/js/src/jit-test/tests/ion/inlining/getelem-getter-megamorphic.js b/js/src/jit-test/tests/ion/inlining/getelem-getter-megamorphic.js new file mode 100644 index 0000000000..2b8fdddcd0 --- /dev/null +++ b/js/src/jit-test/tests/ion/inlining/getelem-getter-megamorphic.js @@ -0,0 +1,79 @@ +// Test for inlined getters for jsop_getelem accesses, where the getter is a +// property on the prototype and a megamorphic IC is attached. + +function makeObjects(name) { + class Base { + constructor(v) { + this._prop = v; + } + get [name]() { + return this._prop; + } + } + + // When we hit |TYPE_FLAG_OBJECT_COUNT_LIMIT|, the objects are marked as + // |TYPE_FLAG_ANYOBJECT|. That means less than |TYPE_FLAG_OBJECT_COUNT_LIMIT| + // objects need to be created to have no unknown objects in the type set. + const TYPE_FLAG_OBJECT_COUNT_LIMIT = 7; + + // |ICState::ICState::MaxOptimizedStubs| defines the maximum number of + // optimized stubs, so as soon as we hit the maximum number, the megamorphic + // state is entered. + const ICState_MaxOptimizedStubs = 6; + + // Create enough classes to enter megamorphic state, but not too much to + // have |TYPE_FLAG_ANYOBJECT| in the TypeSet. + const OBJECT_COUNT = Math.min(ICState_MaxOptimizedStubs, TYPE_FLAG_OBJECT_COUNT_LIMIT); + + var objects = []; + for (var i = 0; i < OBJECT_COUNT; ++i) { + objects.push(new class extends Base {}(1)); + } + + return objects; +} + +// Defined outside of the test functions to ensure they're recognised as +// constants in Ion. +var atom = "prop"; +var symbol = Symbol(); + +function testAtom() { + var objects = makeObjects(atom); + + function f() { + var actual = 0; + var expected = 0; + for (var i = 0; i < 1000; i++) { + var obj = objects[i % objects.length]; + actual += obj[atom]; + expected += obj._prop; + } + assertEq(actual, expected); + } + + for (var i = 0; i < 2; ++i) { + f(); + } +} +testAtom(); + +function testSymbol() { + var objects = makeObjects(symbol); + + function f() { + var actual = 0; + var expected = 0; + for (var i = 0; i < 1000; i++) { + var obj = objects[i % objects.length]; + actual += obj[symbol]; + expected += obj._prop; + } + assertEq(actual, expected); + } + + for (var i = 0; i < 2; ++i) { + f(); + } +} +testSymbol(); diff --git a/js/src/jit-test/tests/ion/inlining/getelem-getter-noninlined-call.js b/js/src/jit-test/tests/ion/inlining/getelem-getter-noninlined-call.js new file mode 100644 index 0000000000..e3b741e0ef --- /dev/null +++ b/js/src/jit-test/tests/ion/inlining/getelem-getter-noninlined-call.js @@ -0,0 +1,52 @@ +// With-Statements are not supported in Ion, therefore functions containing +// them can't be inlined in Ion. However it's still possible to inline the +// property access to the getter into a simple guard-shape instruction. + +// Defined outside of the test functions to ensure they're recognised as +// constants in Ion. +var atom = "prop"; +var symbol = Symbol(); + +function testAtom() { + var holder = { + get [atom]() { + with ({}) { + return 1; + } + } + }; + + function f() { + for (var i = 0; i < 1000; ++i) { + var x = holder[atom]; + assertEq(x, 1); + } + } + + for (var i = 0; i < 2; i++) { + f(); + } +} +testAtom(); + +function testSymbol() { + var holder = { + get [symbol]() { + with ({}) { + return 1; + } + } + }; + + function f() { + for (var i = 0; i < 1000; ++i) { + var x = holder[symbol]; + assertEq(x, 1); + } + } + + for (var i = 0; i < 2; i++) { + f(); + } +} +testSymbol(); diff --git a/js/src/jit-test/tests/ion/inlining/getelem-getter-own.js b/js/src/jit-test/tests/ion/inlining/getelem-getter-own.js new file mode 100644 index 0000000000..f2e5ce617b --- /dev/null +++ b/js/src/jit-test/tests/ion/inlining/getelem-getter-own.js @@ -0,0 +1,51 @@ +// Test for inlined getters for jsop_getelem accesses, where the getter is an +// own property. + +// Defined outside of the test functions to ensure they're recognised as +// constants in Ion. +var atom1 = "prop1"; +var atom2 = "prop2"; +var sym1 = Symbol(); +var sym2 = Symbol(); + +function testAtom() { + var holder = { + get [atom1]() { return 1; }, + get [atom2]() { return 2; }, + }; + + function f() { + for (var i = 0; i < 1000; ++i) { + var x = holder[atom1]; + var y = holder[atom2]; + assertEq(x, 1); + assertEq(y, 2); + } + } + + for (var i = 0; i < 2; i++) { + f(); + } +} +testAtom(); + +function testSymbol() { + var holder = { + get [sym1]() { return 1; }, + get [sym2]() { return 2; }, + }; + + function f() { + for (var i = 0; i < 1000; ++i) { + var x = holder[sym1]; + var y = holder[sym2]; + assertEq(x, 1); + assertEq(y, 2); + } + } + + for (var i = 0; i < 2; i++) { + f(); + } +} +testSymbol(); diff --git a/js/src/jit-test/tests/ion/inlining/getelem-getter-proto.js b/js/src/jit-test/tests/ion/inlining/getelem-getter-proto.js new file mode 100644 index 0000000000..8aab839f1e --- /dev/null +++ b/js/src/jit-test/tests/ion/inlining/getelem-getter-proto.js @@ -0,0 +1,55 @@ +// Test for inlined getters for jsop_getelem accesses, where the getter is a +// property on the prototype. + +// Defined outside of the test functions to ensure they're recognised as +// constants in Ion. +var atom1 = "prop1"; +var atom2 = "prop2"; +var sym1 = Symbol(); +var sym2 = Symbol(); + +function testAtom() { + var proto = { + get [atom1]() { return 1; }, + get [atom2]() { return 2; }, + }; + + var holder = Object.create(proto); + + function f() { + for (var i = 0; i < 1000; ++i) { + var x = holder[atom1]; + var y = holder[atom2]; + assertEq(x, 1); + assertEq(y, 2); + } + } + + for (var i = 0; i < 2; i++) { + f(); + } +} +testAtom(); + +function testSymbol() { + var proto = { + get [sym1]() { return 1; }, + get [sym2]() { return 2; }, + }; + + var holder = Object.create(proto); + + function f() { + for (var i = 0; i < 1000; ++i) { + var x = holder[sym1]; + var y = holder[sym2]; + assertEq(x, 1); + assertEq(y, 2); + } + } + + for (var i = 0; i < 2; i++) { + f(); + } +} +testSymbol(); diff --git a/js/src/jit-test/tests/ion/inlining/inline-callarg-bailout-phi.js b/js/src/jit-test/tests/ion/inlining/inline-callarg-bailout-phi.js new file mode 100644 index 0000000000..06bc1f6efe --- /dev/null +++ b/js/src/jit-test/tests/ion/inlining/inline-callarg-bailout-phi.js @@ -0,0 +1,29 @@ +function add(x, y) { + if (x & 0x1) + return x + y; + else + return y + x; +} + +function runBinop(binop, lhs, rhs) { + return binop(lhs, rhs); +} + +//dis(run_binop); + +// Get the add function to compile. +var accum = 0; +for (var i = 0; i < 1000; ++i) + accum += add(1, 1); +assertEq(accum, 2000); + +// Get the runBinop function to compile and inline the add function. +var accum = 0; +for (var i = 0; i < 11000; ++i) + accum = runBinop(add, i, i); +assertEq(accum, 21998); + +var t30 = 1 << 30; +var t31 = t30 + t30; +var result = runBinop(add, t31, t31); +assertEq(result, Math.pow(2, 32)); diff --git a/js/src/jit-test/tests/ion/inlining/inline-callarg-bailout.js b/js/src/jit-test/tests/ion/inlining/inline-callarg-bailout.js new file mode 100644 index 0000000000..fad2c1a3bb --- /dev/null +++ b/js/src/jit-test/tests/ion/inlining/inline-callarg-bailout.js @@ -0,0 +1,26 @@ +function add(x, y) { + return x + y; +} + +function runBinop(binop, lhs, rhs) { + return binop(lhs, rhs); +} + +//dis(run_binop); + +// Get the add function to compile. +var accum = 0; +for (var i = 0; i < 1000; ++i) + accum += add(1, 1); +assertEq(accum, 2000); + +// Get the runBinop function to compile and inline the add function. +var accum = 0; +for (var i = 0; i < 10100; ++i) + accum = runBinop(add, i, i); +assertEq(accum, 20198); + +var t30 = 1 << 30; +var t31 = t30 + t30; +var result = runBinop(add, t31, t31); +assertEq(result, Math.pow(2, 32)); diff --git a/js/src/jit-test/tests/ion/inlining/inline-callarg-ubench-no-double2.js b/js/src/jit-test/tests/ion/inlining/inline-callarg-ubench-no-double2.js new file mode 100644 index 0000000000..385ea1a026 --- /dev/null +++ b/js/src/jit-test/tests/ion/inlining/inline-callarg-ubench-no-double2.js @@ -0,0 +1,27 @@ +function lameFunc(x, y) { + var lsw = (x & 0xFFFF) + (y & 0xFFFF); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); +} + +function runSomeTimes(func, iters) { + var result; + for (var i = 0; i < iters; ++i) { + result = func(42, 42); + result = func(42, 42); + } + return result; +} + +// First, run the inner function to get TI information. +for (var i = 0; i < 100; ++i) + lameFunc(42, 42); + +// Then, run the outer function with the inner function as a CALLARG to get it +// to Ion compile with inlining. +for (var i = 0; i < 11000; ++i) + runSomeTimes(lameFunc, 1); + +// Lastly, now that we're all inlined and compiled, perform the test! +var iterations = 100; +assertEq(84, runSomeTimes(lameFunc, iterations)); diff --git a/js/src/jit-test/tests/ion/inlining/inline-getelem-args.js b/js/src/jit-test/tests/ion/inlining/inline-getelem-args.js new file mode 100644 index 0000000000..41acaf6a04 --- /dev/null +++ b/js/src/jit-test/tests/ion/inlining/inline-getelem-args.js @@ -0,0 +1,59 @@ +function cat() { + var res = ""; + for (var i = 0; i < arguments.length; i++) + res += arguments[i]; + return res; +} + +function cat_m1(ion) { + var res = ""; + for (var i = (ion ? -1 : 0); i < arguments.length; i++) + res += arguments[i]; + return res; +} + +function cat_p1(ion) { + var res = ""; + for (var i = 0; i < arguments.length + (ion ? 1 : 0); i++) + res += arguments[i]; + return res; +} + +function sum() { + var res = 0; + for (var i = 0; i < arguments.length; i++) + res += arguments[i]; + return res; +} + +function wrapper() { + var res; + var i6 = { valueOf: () => 6 }, + i8 = 8.5, + s2 = { toString: () => "2" }, + s4 = {}, + s6 = "6", + s7 = undefined, + s8 = null; + for (var b = true; b; b = !inIon()) { + res = sum(1,2,3,4,5,i6,7,i8,9,10); + assertEq(res, 55.5); + + res = cat(true,s2,3,s4,5,s6,s7,s8); + assertEq(res, "true23[object Object]56undefinednull"); + + ion = inIon(); + if (typeof ion !== "boolean") break; + res = cat_m1(ion,1,s2,3,s4,5,s6,s7,s8); + if (ion) assertEq(res, "undefinedtrue123[object Object]56undefinednull"); + else assertEq(res, "false123[object Object]56undefinednull"); + + ion = inIon(); + if (typeof ion !== "boolean") break; + res = cat_p1(ion,1,s2,3,s4,5,s6,s7,s8); + if (ion) assertEq(res, "true123[object Object]56undefinednullundefined"); + else assertEq(res, "false123[object Object]56undefinednull"); + } +} + +wrapper(); diff --git a/js/src/jit-test/tests/ion/inlining/inline-istypedarray-on-nontypedarray.js b/js/src/jit-test/tests/ion/inlining/inline-istypedarray-on-nontypedarray.js new file mode 100644 index 0000000000..e1c540d19d --- /dev/null +++ b/js/src/jit-test/tests/ion/inlining/inline-istypedarray-on-nontypedarray.js @@ -0,0 +1,6 @@ +(new Int8Array(3)).join(); +[Math.abs, Math.abs].forEach(x => { + try { + Int8Array.prototype.join.call(x); + } catch(e) {} +}); diff --git a/js/src/jit-test/tests/ion/inlining/isFiniteInline.js b/js/src/jit-test/tests/ion/inlining/isFiniteInline.js new file mode 100644 index 0000000000..6f0897009b --- /dev/null +++ b/js/src/jit-test/tests/ion/inlining/isFiniteInline.js @@ -0,0 +1,15 @@ +/* Test inlining of Number.isFinite() */ + +for (var i = 0; i < 10_000; i++) { + assertEq(Number.isFinite(NaN), false); + assertEq(Number.isFinite(-NaN), false); + assertEq(Number.isFinite(+Infinity), false); + assertEq(Number.isFinite(-Infinity), false); + assertEq(Number.isFinite(3), true); + assertEq(Number.isFinite(3.141592654), true); + assertEq(Number.isFinite(+0), true); + assertEq(Number.isFinite(-0), true); + assertEq(Number.isFinite(-3), true); + assertEq(Number.isFinite(-3.141592654), true); + assertEq(Number.isFinite({}), false); +} diff --git a/js/src/jit-test/tests/ion/inlining/isNaNInline.js b/js/src/jit-test/tests/ion/inlining/isNaNInline.js new file mode 100644 index 0000000000..23766f7b5d --- /dev/null +++ b/js/src/jit-test/tests/ion/inlining/isNaNInline.js @@ -0,0 +1,15 @@ +/* Test inlining of Number.isNaN() */ + +for (var i = 0; i < 10_000; i++) { + assertEq(Number.isNaN(NaN), true); + assertEq(Number.isNaN(-NaN), true); + assertEq(Number.isNaN(+Infinity), false); + assertEq(Number.isNaN(-Infinity), false); + assertEq(Number.isNaN(3.14159), false); + assertEq(Number.isNaN(-3.14159), false); + assertEq(Number.isNaN(3), false); + assertEq(Number.isNaN(-3), false); + assertEq(Number.isNaN(+0), false); + assertEq(Number.isNaN(-0), false); + assertEq(Number.isNaN({}), false); +} diff --git a/js/src/jit-test/tests/ion/inlining/object-is-stricteq.js b/js/src/jit-test/tests/ion/inlining/object-is-stricteq.js new file mode 100644 index 0000000000..059c3f210c --- /dev/null +++ b/js/src/jit-test/tests/ion/inlining/object-is-stricteq.js @@ -0,0 +1,143 @@ +// Test when Object.is() is inlined as JSOP_STRICTEQ + +function SameValue(x, y) { + if (x === y) { + return (x !== 0) || (1 / x === 1 / y); + } + return (x !== x && y !== y); +} + +var compareTemplate = function compare(name, xs, ys) { + // Compare each entry in xs with each entry in ys and ensure Object.is + // computes the same result as SameValue. + for (var i = 0; i < 1000; ++i) { + var xi = (i % xs.length) | 0; + var yi = ((i + ((i / ys.length) | 0)) % ys.length) | 0; + + assertEq(Object.is(xs[xi], ys[yi]), SameValue(xs[xi], ys[yi]), name); + } +} + +const objects = { + plain: {}, + function: function(){}, + proxy: new Proxy({}, {}), +}; + +const sym = Symbol(); + +const testCases = [ + { + name: "Homogenous-Int32", + xs: [-1, 0, 1, 2, 0x7fffffff], + ys: [2, 1, 0, -5, -0x80000000], + }, + { + name: "Homogenous-Boolean", + xs: [true, false], + ys: [true, false], + }, + { + name: "Homogenous-Object", + xs: [{}, [], objects.plain, objects.proxy], + ys: [{}, objects.function, objects.plain, objects.proxy], + }, + { + name: "Homogenous-String", + xs: ["", "abc", "αβγαβγ", "𝐀𝐁𝐂𝐀𝐁𝐂", "ABCabc"], + ys: ["abc", "ABC", "ABCABC", "αβγαβγ", "𝐀𝐁𝐂𝐀𝐁𝐂"], + }, + { + name: "Homogenous-Symbol", + xs: [Symbol.iterator, Symbol(), Symbol.for("object-is"), sym], + ys: [sym, Symbol.match, Symbol(), Symbol.for("object-is-two")], + }, + { + name: "Homogenous-Null", + xs: [null, null], + ys: [null, null], + }, + { + name: "Homogenous-Undefined", + xs: [undefined, undefined], + ys: [undefined, undefined], + }, + + // Note: Values must not include floating-point types! + { + name: "String-Value", + xs: ["", "abc", "αβγαβγ", "𝐀𝐁𝐂𝐀𝐁𝐂"], + ys: [null, undefined, sym, true, 0, "", {}], + }, + { + name: "Null-Value", + xs: [null, null], + ys: [null, undefined, sym, true, 0, "", {}], + }, + { + name: "Undefined-Value", + xs: [undefined, undefined], + ys: [null, undefined, sym, true, 0, "", {}], + }, + { + name: "Boolean-Value", + xs: [true, false], + ys: [null, undefined, sym, true, 0, "", {}], + }, + + // Note: Values must not include floating-point types! + { + name: "Value-String", + xs: [null, undefined, sym, true, 0, "", {}], + ys: ["", "abc", "αβγαβγ", "𝐀𝐁𝐂𝐀𝐁𝐂"], + }, + { + name: "Value-Null", + xs: [null, undefined, sym, true, 0, "", {}], + ys: [null, null], + }, + { + name: "Value-Undefined", + xs: [null, undefined, sym, true, 0, "", {}], + ys: [undefined, undefined], + }, + { + name: "Value-Boolean", + xs: [null, undefined, sym, true, 0, "", {}], + ys: [undefined, undefined], + }, + + // Strict-equal comparison can be optimized to bitwise comparison when + // string types are not possible. + // Note: Values must not include floating-point types! + { + name: "Value-Value", + xs: [null, undefined, sym, true, 0, {}], + ys: [null, undefined, sym, true, 0, {}], + }, + { + name: "ValueMaybeString-ValueMaybeString", + xs: [null, undefined, sym, true, 0, "", {}], + ys: [null, undefined, sym, true, 0, "", {}], + }, + { + name: "Value-ValueMaybeString", + xs: [null, undefined, sym, true, 0, {}], + ys: [null, undefined, sym, true, 0, "", {}], + }, + { + name: "ValueMaybeString-Value", + xs: [null, undefined, sym, true, 0, "", {}], + ys: [null, undefined, sym, true, 0, {}], + }, +]; + +for (let {name, xs, ys} of testCases) { + // Create a separate function for each test case. + // Use indirect eval to avoid possible direct eval deopts. + const compare = (0, eval)(`(${compareTemplate})`); + + for (let i = 0; i < 5; ++i) { + compare(name, xs, ys); + } +} diff --git a/js/src/jit-test/tests/ion/inlining/typedarray-data-inlining-neuter-samedata.js b/js/src/jit-test/tests/ion/inlining/typedarray-data-inlining-neuter-samedata.js new file mode 100644 index 0000000000..16478e0a06 --- /dev/null +++ b/js/src/jit-test/tests/ion/inlining/typedarray-data-inlining-neuter-samedata.js @@ -0,0 +1,28 @@ +var NONINLINABLE_AMOUNT = 40; +var SIZEOF_INT32 = 4; + +var INLINABLE_INT8_AMOUNT = 4; + +// Large arrays with non-inline data + +var ab1 = new ArrayBuffer(NONINLINABLE_AMOUNT * SIZEOF_INT32); +var ta1 = new Int32Array(ab1); +for (var i = 0; i < ta1.length; i++) + ta1[i] = i + 43; +function q1() { return ta1[NONINLINABLE_AMOUNT - 1]; } +assertEq(q1(), NONINLINABLE_AMOUNT - 1 + 43); +assertEq(q1(), NONINLINABLE_AMOUNT - 1 + 43); +detachArrayBuffer(ab1); +assertEq(q1(), undefined); + +// Small arrays with inline data + +var ab2 = new ArrayBuffer(INLINABLE_INT8_AMOUNT); +var ta2 = new Int8Array(ab2); +for (var i = 0; i < ta2.length; i++) + ta2[i] = i + 13; +function q2() { return ta2[INLINABLE_INT8_AMOUNT - 1]; } +assertEq(q2(), INLINABLE_INT8_AMOUNT - 1 + 13); +assertEq(q2(), INLINABLE_INT8_AMOUNT - 1 + 13); +detachArrayBuffer(ab2); +assertEq(q2(), undefined); diff --git a/js/src/jit-test/tests/ion/inlining/typedarray-large-length.js b/js/src/jit-test/tests/ion/inlining/typedarray-large-length.js new file mode 100644 index 0000000000..9e6d67d3b3 --- /dev/null +++ b/js/src/jit-test/tests/ion/inlining/typedarray-large-length.js @@ -0,0 +1,10 @@ +var SINGLETON_BYTE_LENGTH = 1024 * 1024 * 10; + +for (var i = 0; i < 2000; i++) { + if (i == 1500) + len = SINGLETON_BYTE_LENGTH >> 3; + else + len = i % 64; + var arr = new Float64Array(len); + assertEq(arr[0], len ? 0 : undefined); +} diff --git a/js/src/jit-test/tests/ion/inlining/typedarray-length-inlining-neuter.js b/js/src/jit-test/tests/ion/inlining/typedarray-length-inlining-neuter.js new file mode 100644 index 0000000000..520dd1a38b --- /dev/null +++ b/js/src/jit-test/tests/ion/inlining/typedarray-length-inlining-neuter.js @@ -0,0 +1,22 @@ +var INLINE_INT8_AMOUNT = 4; +var OUT_OF_LINE_INT8_AMOUNT = 237; + +// Small and inline + +var ab1 = new ArrayBuffer(INLINE_INT8_AMOUNT); +var ta1 = new Int8Array(ab1); +function q1() { return ta1.length; } +q1(); +q1(); +detachArrayBuffer(ab1); +assertEq(q1(), 0); + +// Large and out-of-line + +var ab2 = new ArrayBuffer(OUT_OF_LINE_INT8_AMOUNT); +var ta2 = new Int8Array(ab2); +function q2() { return ta2.length; } +q2(); +q2(); +detachArrayBuffer(ab2); +assertEq(q2(), 0); -- cgit v1.2.3