summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/ion/inlining
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /js/src/jit-test/tests/ion/inlining
parentInitial commit. (diff)
downloadfirefox-esr-upstream.tar.xz
firefox-esr-upstream.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/jit-test/tests/ion/inlining')
-rw-r--r--js/src/jit-test/tests/ion/inlining/array-pop.js17
-rw-r--r--js/src/jit-test/tests/ion/inlining/array-push.js37
-rw-r--r--js/src/jit-test/tests/ion/inlining/bug705251.js10
-rw-r--r--js/src/jit-test/tests/ion/inlining/call-apply-non-singletons.js22
-rw-r--r--js/src/jit-test/tests/ion/inlining/exception-during-inlining-decision.js115
-rw-r--r--js/src/jit-test/tests/ion/inlining/getelem-getter-bailout.js48
-rw-r--r--js/src/jit-test/tests/ion/inlining/getelem-getter-frameiter.js48
-rw-r--r--js/src/jit-test/tests/ion/inlining/getelem-getter-id-mismatch.js113
-rw-r--r--js/src/jit-test/tests/ion/inlining/getelem-getter-megamorphic.js79
-rw-r--r--js/src/jit-test/tests/ion/inlining/getelem-getter-noninlined-call.js52
-rw-r--r--js/src/jit-test/tests/ion/inlining/getelem-getter-own.js51
-rw-r--r--js/src/jit-test/tests/ion/inlining/getelem-getter-proto.js55
-rw-r--r--js/src/jit-test/tests/ion/inlining/inline-callarg-bailout-phi.js29
-rw-r--r--js/src/jit-test/tests/ion/inlining/inline-callarg-bailout.js26
-rw-r--r--js/src/jit-test/tests/ion/inlining/inline-callarg-ubench-no-double2.js27
-rw-r--r--js/src/jit-test/tests/ion/inlining/inline-getelem-args.js59
-rw-r--r--js/src/jit-test/tests/ion/inlining/inline-istypedarray-on-nontypedarray.js6
-rw-r--r--js/src/jit-test/tests/ion/inlining/isFiniteInline.js15
-rw-r--r--js/src/jit-test/tests/ion/inlining/isNaNInline.js15
-rw-r--r--js/src/jit-test/tests/ion/inlining/object-is-stricteq.js143
-rw-r--r--js/src/jit-test/tests/ion/inlining/typedarray-data-inlining-neuter-samedata.js28
-rw-r--r--js/src/jit-test/tests/ion/inlining/typedarray-large-length.js10
-rw-r--r--js/src/jit-test/tests/ion/inlining/typedarray-length-inlining-neuter.js22
23 files changed, 1027 insertions, 0 deletions
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);