summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/warp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /js/src/jit-test/tests/warp
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/jit-test/tests/warp')
-rw-r--r--js/src/jit-test/tests/warp/arguments-object-load-arg.js109
-rw-r--r--js/src/jit-test/tests/warp/arguments-object-load-length.js57
-rw-r--r--js/src/jit-test/tests/warp/booleantostring.js9
-rw-r--r--js/src/jit-test/tests/warp/bug1646041.js9
-rw-r--r--js/src/jit-test/tests/warp/bug1646302.js9
-rw-r--r--js/src/jit-test/tests/warp/bug1647054.js8
-rw-r--r--js/src/jit-test/tests/warp/bug1652049.js7
-rw-r--r--js/src/jit-test/tests/warp/bug1652732.js8
-rw-r--r--js/src/jit-test/tests/warp/bug1653913.js3
-rw-r--r--js/src/jit-test/tests/warp/bug1653972.js11
-rw-r--r--js/src/jit-test/tests/warp/bug1661530.js7
-rw-r--r--js/src/jit-test/tests/warp/bug1661728.js43
-rw-r--r--js/src/jit-test/tests/warp/bug1662146.js12
-rw-r--r--js/src/jit-test/tests/warp/bug1663993.js9
-rw-r--r--js/src/jit-test/tests/warp/bug1664007.js12
-rw-r--r--js/src/jit-test/tests/warp/bug1665303.js20
-rw-r--r--js/src/jit-test/tests/warp/bug1666070.js8
-rw-r--r--js/src/jit-test/tests/warp/bug1666142-1.js19
-rw-r--r--js/src/jit-test/tests/warp/bug1666142-2.js19
-rw-r--r--js/src/jit-test/tests/warp/bug1667680.js8
-rw-r--r--js/src/jit-test/tests/warp/bug1667685.js27
-rw-r--r--js/src/jit-test/tests/warp/bug1667699.js15
-rw-r--r--js/src/jit-test/tests/warp/bug1668197.js6
-rw-r--r--js/src/jit-test/tests/warp/bug1669415.js11
-rw-r--r--js/src/jit-test/tests/warp/bug1669597.js14
-rw-r--r--js/src/jit-test/tests/warp/bug1671812.js11
-rw-r--r--js/src/jit-test/tests/warp/bug1676631.js7
-rw-r--r--js/src/jit-test/tests/warp/bug1676639.js7
-rw-r--r--js/src/jit-test/tests/warp/bug1681056.js9
-rw-r--r--js/src/jit-test/tests/warp/bug1681597.js19
-rw-r--r--js/src/jit-test/tests/warp/bug1681677.js7
-rw-r--r--js/src/jit-test/tests/warp/bug1681806.js92
-rw-r--r--js/src/jit-test/tests/warp/bug1683306.js19
-rw-r--r--js/src/jit-test/tests/warp/bug1683309.js20
-rw-r--r--js/src/jit-test/tests/warp/bug1683535-1.js6
-rw-r--r--js/src/jit-test/tests/warp/bug1683535-2.js10
-rw-r--r--js/src/jit-test/tests/warp/bug1683614.js14
-rw-r--r--js/src/jit-test/tests/warp/bug1686207.js11
-rw-r--r--js/src/jit-test/tests/warp/bug1686702.js3
-rw-r--r--js/src/jit-test/tests/warp/bug1687661.js13
-rw-r--r--js/src/jit-test/tests/warp/bug1687672.js14
-rw-r--r--js/src/jit-test/tests/warp/cancel-offthread-compile.js21
-rw-r--r--js/src/jit-test/tests/warp/catch-overflow-regexp.js8
-rw-r--r--js/src/jit-test/tests/warp/force-warp.js11
-rw-r--r--js/src/jit-test/tests/warp/function-load-length.js86
-rw-r--r--js/src/jit-test/tests/warp/function-load-name.js100
-rw-r--r--js/src/jit-test/tests/warp/guard-function-is-non-builtin-ctor.js20
-rw-r--r--js/src/jit-test/tests/warp/guard-has-getter-setter.js263
-rw-r--r--js/src/jit-test/tests/warp/guard-string-to-number-or-int32.js36
-rw-r--r--js/src/jit-test/tests/warp/guardproto-nursery.js13
-rw-r--r--js/src/jit-test/tests/warp/inline-array-at.js17
-rw-r--r--js/src/jit-test/tests/warp/load-unboxed-typedarray-bigint.js7
-rw-r--r--js/src/jit-test/tests/warp/math-indirect-truncate.js55
-rw-r--r--js/src/jit-test/tests/warp/mega-morphic-load-and-has-prop.js99
-rw-r--r--js/src/jit-test/tests/warp/non-int32-array-length.js10
-rw-r--r--js/src/jit-test/tests/warp/null-not-zero-index.js17
-rw-r--r--js/src/jit-test/tests/warp/object-class-tostring.js65
-rw-r--r--js/src/jit-test/tests/warp/phi-specialization.js42
-rw-r--r--js/src/jit-test/tests/warp/property-add-shape.js98
-rw-r--r--js/src/jit-test/tests/warp/small-inlinable-builtins.js10
-rw-r--r--js/src/jit-test/tests/warp/string-char.js15
-rw-r--r--js/src/jit-test/tests/warp/super-native-newtarget.js20
-rw-r--r--js/src/jit-test/tests/warp/typedarray-element-exists.js46
-rw-r--r--js/src/jit-test/tests/warp/typedarrayindextoint32.js10
64 files changed, 1791 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/warp/arguments-object-load-arg.js b/js/src/jit-test/tests/warp/arguments-object-load-arg.js
new file mode 100644
index 0000000000..0598c3b1d6
--- /dev/null
+++ b/js/src/jit-test/tests/warp/arguments-object-load-arg.js
@@ -0,0 +1,109 @@
+// Test transpiling of LoadArgumentsObjectArgResult and cover all possible bailout conditions.
+
+function blackhole() {
+ // Direct eval prevents any compile-time optimisations.
+ eval("");
+}
+
+function testConstantArgAccess() {
+ blackhole(arguments); // Create an arguments object.
+
+ for (var i = 0; i < 50; ++i) {
+ assertEq(arguments[0], 1);
+ }
+}
+for (var i = 0; i < 20; ++i) testConstantArgAccess(1);
+
+function testDynamicArgAccess() {
+ blackhole(arguments); // Create an arguments object.
+
+ for (var i = 0; i < 50; ++i) {
+ assertEq(arguments[i & 1], 1 + (i & 1));
+ }
+}
+for (var i = 0; i < 20; ++i) testDynamicArgAccess(1, 2);
+
+function markElementOveriddenIf(args, cond, value) {
+ with ({}) ; // Don't Warp compile to avoid cold code bailouts.
+ if (cond) {
+ Object.defineProperty(args, 0, {value});
+ }
+}
+
+function testBailoutElementReified() {
+ blackhole(arguments); // Create an arguments object.
+
+ for (var i = 0; i < 50; ++i) {
+ markElementOveriddenIf(arguments, i === 25, 2);
+
+ var expected = 1 + (i >= 25);
+ assertEq(arguments[0], expected);
+ }
+}
+for (var i = 0; i < 20; ++i) testBailoutElementReified(1);
+
+function markLengthOveriddenIf(args, cond, value) {
+ with ({}) ; // Don't Warp compile to avoid cold code bailouts.
+ if (cond) {
+ args.length = value;
+ }
+}
+
+function testBailoutLengthReified() {
+ blackhole(arguments); // Create an arguments object.
+
+ for (var i = 0; i < 50; ++i) {
+ markLengthOveriddenIf(arguments, i === 25, 0);
+
+ assertEq(arguments[0], 1);
+ }
+}
+for (var i = 0; i < 20; ++i) testBailoutLengthReified(1);
+
+function deleteElementIf(args, cond) {
+ with ({}) ; // Don't Warp compile to avoid cold code bailouts.
+ if (cond) {
+ delete args[0];
+ }
+}
+
+function testBailoutElementDeleted() {
+ blackhole(arguments); // Create an arguments object.
+
+ // Load expected values from an array to avoid possible cold code bailouts.
+ var values = [1, undefined];
+
+ for (var i = 0; i < 50; ++i) {
+ deleteElementIf(arguments, i === 25);
+
+ var expected = values[0 + (i >= 25)];
+ assertEq(arguments[0], expected);
+ }
+}
+for (var i = 0; i < 20; ++i) testBailoutElementDeleted(1);
+
+function testBailoutOutOfBounds() {
+ blackhole(arguments); // Create an arguments object.
+
+ // Load expected values from an array to avoid possible cold code bailouts.
+ var values = [1, undefined];
+
+ for (var i = 0; i < 50; ++i) {
+ var index = 0 + (i >= 25);
+ var expected = values[index];
+ assertEq(arguments[index], expected);
+ }
+}
+for (var i = 0; i < 20; ++i) testBailoutOutOfBounds(1);
+
+function testBailoutArgForwarded(arg1, arg2) {
+ blackhole(arguments); // Create an arguments object.
+ blackhole(() => arg2); // Ensure |arg2| is marked as "forwarded".
+
+ for (var i = 0; i < 50; ++i) {
+ var index = 0 + (i >= 25);
+ var expected = 1 + (i >= 25);
+ assertEq(arguments[index], expected);
+ }
+}
+for (var i = 0; i < 20; ++i) testBailoutArgForwarded(1, 2);
diff --git a/js/src/jit-test/tests/warp/arguments-object-load-length.js b/js/src/jit-test/tests/warp/arguments-object-load-length.js
new file mode 100644
index 0000000000..935c406ac0
--- /dev/null
+++ b/js/src/jit-test/tests/warp/arguments-object-load-length.js
@@ -0,0 +1,57 @@
+// Test transpiling of LoadArgumentsObjectLengthResult and cover all possible bailout conditions.
+
+function blackhole() {
+ // Direct eval prevents any compile-time optimisations.
+ eval("");
+}
+
+function testLengthAccess() {
+ blackhole(arguments); // Create an arguments object.
+
+ for (var i = 0; i < 50; ++i) {
+ assertEq(arguments.length, 1);
+ }
+}
+for (var i = 0; i < 20; ++i) testLengthAccess(1);
+
+function markLengthOveriddenIf(args, cond, value) {
+ with ({}) ; // Don't Warp compile to avoid cold code bailouts.
+ if (cond) {
+ args.length = value;
+ }
+}
+
+function testBailoutLengthReified() {
+ blackhole(arguments); // Create an arguments object.
+
+ for (var i = 0; i < 50; ++i) {
+ markLengthOveriddenIf(arguments, i === 25, 0);
+
+ var expected = 0 + (i < 25);
+ assertEq(arguments.length, expected);
+ }
+}
+for (var i = 0; i < 20; ++i) testBailoutLengthReified(1);
+
+
+function deleteLengthIf(args, cond) {
+ with ({}) ; // Don't Warp compile to avoid cold code bailouts.
+ if (cond) {
+ delete args.length;
+ }
+}
+
+function testBailoutLengthDeleted() {
+ blackhole(arguments); // Create an arguments object.
+
+ // Load expected values from an array to avoid possible cold code bailouts.
+ var values = [1, undefined];
+
+ for (var i = 0; i < 50; ++i) {
+ deleteLengthIf(arguments, i === 25);
+
+ var expected = values[0 + (i >= 25)];
+ assertEq(arguments.length, expected);
+ }
+}
+for (var i = 0; i < 20; ++i) testBailoutLengthDeleted(1);
diff --git a/js/src/jit-test/tests/warp/booleantostring.js b/js/src/jit-test/tests/warp/booleantostring.js
new file mode 100644
index 0000000000..39ff0b1b6d
--- /dev/null
+++ b/js/src/jit-test/tests/warp/booleantostring.js
@@ -0,0 +1,9 @@
+var a = [true, false];
+for (var i = 0; i < 1e4; i++) {
+ var str = "x: " + a[i & 1];
+ if (i & 1) {
+ assertEq(str, "x: false");
+ } else {
+ assertEq(str, "x: true");
+ }
+}
diff --git a/js/src/jit-test/tests/warp/bug1646041.js b/js/src/jit-test/tests/warp/bug1646041.js
new file mode 100644
index 0000000000..892553ed9f
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1646041.js
@@ -0,0 +1,9 @@
+// |jit-test| --ion-warmup-threshold=2
+function f() {
+ while (true) {
+ return 1;
+ }
+}
+for (var i = 0; i < 100; i++) {
+ f();
+}
diff --git a/js/src/jit-test/tests/warp/bug1646302.js b/js/src/jit-test/tests/warp/bug1646302.js
new file mode 100644
index 0000000000..bf86fe702c
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1646302.js
@@ -0,0 +1,9 @@
+function f(x) {
+ function fnc() {}
+ fnc.prototype = 3;
+ new fnc;
+ if (x < 50) {
+ new new.target(x + 1);
+ }
+}
+new f(0);
diff --git a/js/src/jit-test/tests/warp/bug1647054.js b/js/src/jit-test/tests/warp/bug1647054.js
new file mode 100644
index 0000000000..fa868c60a8
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1647054.js
@@ -0,0 +1,8 @@
+function f() {
+ for (var i = 0; i < 200; ++i) {
+ for (var j = 0; 0 & ++i; ++j) {
+ i();
+ }
+ }
+}
+f();
diff --git a/js/src/jit-test/tests/warp/bug1652049.js b/js/src/jit-test/tests/warp/bug1652049.js
new file mode 100644
index 0000000000..a28e35d353
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1652049.js
@@ -0,0 +1,7 @@
+function f() {
+ var o = {__proto__: null};
+ for (var i = 0; i < 15; i++) {
+ assertEq("foo" in o, false);
+ }
+}
+f();
diff --git a/js/src/jit-test/tests/warp/bug1652732.js b/js/src/jit-test/tests/warp/bug1652732.js
new file mode 100644
index 0000000000..f5df3bc648
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1652732.js
@@ -0,0 +1,8 @@
+function test() {
+ var obj = {};
+ obj[{}] = 1;
+ f = () => { for (var x of obj) {} };
+}
+for (var i = 0; i < 5; i++) {
+ test();
+}
diff --git a/js/src/jit-test/tests/warp/bug1653913.js b/js/src/jit-test/tests/warp/bug1653913.js
new file mode 100644
index 0000000000..adaaf3c7c8
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1653913.js
@@ -0,0 +1,3 @@
+var s = "aaaaaaaaaaaa";
+var a = [, [...s]];
+assertEq(a.toString(), ",a,a,a,a,a,a,a,a,a,a,a,a");
diff --git a/js/src/jit-test/tests/warp/bug1653972.js b/js/src/jit-test/tests/warp/bug1653972.js
new file mode 100644
index 0000000000..953bb0077f
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1653972.js
@@ -0,0 +1,11 @@
+function maybeSetLength(arr, b) {
+ if (b) {
+ arr.length = 0x8000_1111;
+ }
+}
+var arr = [];
+for (var i = 0; i < 1600; i++) {
+ maybeSetLength(arr, i > 1500);
+ arr.push(2);
+}
+assertEq(arr.length, 0x8000_1112);
diff --git a/js/src/jit-test/tests/warp/bug1661530.js b/js/src/jit-test/tests/warp/bug1661530.js
new file mode 100644
index 0000000000..c4ea7fdb92
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1661530.js
@@ -0,0 +1,7 @@
+Function.prototype.call = function() {};
+var sum = 0;
+function foo() { sum++; }
+for (var i = 0; i < 1000; i++) {
+ foo.call({}, 0);
+}
+assertEq(sum, 0);
diff --git a/js/src/jit-test/tests/warp/bug1661728.js b/js/src/jit-test/tests/warp/bug1661728.js
new file mode 100644
index 0000000000..ac4ad86552
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1661728.js
@@ -0,0 +1,43 @@
+with ({}) {} // Don't inline anything into the top-level script.
+
+function foo() {}
+
+function inline_foo_into_bar() {
+ with ({}) {} // Don't inline anything into this function.
+ for (var i = 0; i < 10; i++) {
+ bar(2);
+ }
+
+}
+
+function bar(x) {
+ switch (x) {
+ case 1:
+ inline_foo_into_bar();
+
+ // Trigger a compacting gc to discard foo's jitscript.
+ // Do it while bar is on the stack to keep bar's jitscript alive.
+ gc(foo, 'shrinking');
+ break;
+ case 2:
+ foo();
+ break;
+ case 3:
+ break;
+ }
+}
+
+// Warm up foo and bar.
+for (var i = 0; i < 10; i++) {
+ foo();
+ bar(3);
+}
+
+// Inline and discard foo's jitscript.
+bar(1);
+
+// Warp-compile bar
+for (var i = 0; i < 50; i++) {
+ foo(); // ensure that foo has a new jitscript
+ bar(3);
+}
diff --git a/js/src/jit-test/tests/warp/bug1662146.js b/js/src/jit-test/tests/warp/bug1662146.js
new file mode 100644
index 0000000000..cfc62b98f2
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1662146.js
@@ -0,0 +1,12 @@
+var sum = 0;
+function f1(a) {
+ try {
+ not_a_function();
+ } catch (e) {
+ sum++;
+ }
+}
+for (var i = 0; i < 50; ++i) {
+ f1.call();
+}
+assertEq(sum, 50);
diff --git a/js/src/jit-test/tests/warp/bug1663993.js b/js/src/jit-test/tests/warp/bug1663993.js
new file mode 100644
index 0000000000..c7199e85cf
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1663993.js
@@ -0,0 +1,9 @@
+function r(relazify) {
+ "foo".substr(0);
+ if (relazify) relazifyFunctions();
+}
+
+for (var i = 0; i < 10; i++) {
+ r(i == 9);
+ r("");
+}
diff --git a/js/src/jit-test/tests/warp/bug1664007.js b/js/src/jit-test/tests/warp/bug1664007.js
new file mode 100644
index 0000000000..de5d8d1233
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1664007.js
@@ -0,0 +1,12 @@
+function f(depth) {
+ function Obj() {
+ this.prop = null;
+ this.prop = this;
+ }
+ var o = new Obj();
+ assertEq(o.prop, o);
+ if (depth < 1000) {
+ f(depth + 1);
+ }
+}
+f(0);
diff --git a/js/src/jit-test/tests/warp/bug1665303.js b/js/src/jit-test/tests/warp/bug1665303.js
new file mode 100644
index 0000000000..b2c26e01cf
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1665303.js
@@ -0,0 +1,20 @@
+// |jit-test| skip-if: !('oomTest' in this); --fast-warmup
+
+// Prevent slowness with --ion-eager.
+setJitCompilerOption("ion.warmup.trigger", 100);
+
+function f() { return 1; }
+function test() {
+ oomTest(function() {
+ function foo() {
+ for (var i = 0; i < 10; i++) {
+ f();
+ trialInline();
+ }
+ }
+ evaluate(foo.toString() + "foo()");
+ });
+}
+for (var i = 0; i < 3; i++) {
+ test();
+}
diff --git a/js/src/jit-test/tests/warp/bug1666070.js b/js/src/jit-test/tests/warp/bug1666070.js
new file mode 100644
index 0000000000..54f737689a
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1666070.js
@@ -0,0 +1,8 @@
+// |jit-test| --fast-warmup
+function f() {}
+for (var i = 0; i < 15; i++) {
+ f();
+ var g = newGlobal();
+ g.trialInline();
+}
+trialInline();
diff --git a/js/src/jit-test/tests/warp/bug1666142-1.js b/js/src/jit-test/tests/warp/bug1666142-1.js
new file mode 100644
index 0000000000..b5bb0aca77
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1666142-1.js
@@ -0,0 +1,19 @@
+// |jit-test| --fast-warmup
+
+// This test triggers a GC in CreateThisForIC,
+// without using the arguments rectifier.
+var records = [];
+function Record() {
+ return Object.create(null);
+}
+function init() {
+ records.push(new Record());
+}
+function f() {
+ for (var i = 0; i < 100; i++) {
+ init();
+ }
+}
+
+gczeal(14,25);
+f();
diff --git a/js/src/jit-test/tests/warp/bug1666142-2.js b/js/src/jit-test/tests/warp/bug1666142-2.js
new file mode 100644
index 0000000000..9fa94e8f20
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1666142-2.js
@@ -0,0 +1,19 @@
+// |jit-test| --fast-warmup
+
+// This test triggers a GC in CreateThisForIC,
+// while using the arguments rectifier.
+var records = [];
+function Record(val) {
+ return Object.create(null);
+}
+function init() {
+ records.push(new Record());
+}
+function f() {
+ for (var i = 0; i < 100; i++) {
+ init();
+ }
+}
+
+gczeal(14,25);
+f();
diff --git a/js/src/jit-test/tests/warp/bug1667680.js b/js/src/jit-test/tests/warp/bug1667680.js
new file mode 100644
index 0000000000..8e1b8c0097
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1667680.js
@@ -0,0 +1,8 @@
+// |jit-test| --ion-limit-script-size=off
+function f() {
+ var s = "for (var i = 0; i < 100; i++) {}; return 2;";
+ s += "var x = [" + "9,".repeat(100_000) + "];";
+ var g = Function(s);
+ assertEq(g(), 2);
+}
+f();
diff --git a/js/src/jit-test/tests/warp/bug1667685.js b/js/src/jit-test/tests/warp/bug1667685.js
new file mode 100644
index 0000000000..2b9e392d24
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1667685.js
@@ -0,0 +1,27 @@
+// |jit-test| skip-if: !('oomTest' in this); --fast-warmup
+
+// Prevent slowness with --ion-eager.
+setJitCompilerOption("ion.warmup.trigger", 100);
+
+function h() {
+ return 1;
+}
+function g() {
+ for (var j = 0; j < 10; j++) {
+ h();
+ }
+ trialInline();
+}
+function f() {
+ for (var i = 0; i < 2; i++) {
+ var fun = Function(g.toString() + "g()");
+ try {
+ fun();
+ } catch {}
+ try {
+ fun();
+ } catch {}
+ }
+
+}
+oomTest(f);
diff --git a/js/src/jit-test/tests/warp/bug1667699.js b/js/src/jit-test/tests/warp/bug1667699.js
new file mode 100644
index 0000000000..a88115c7c5
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1667699.js
@@ -0,0 +1,15 @@
+// |jit-test| --fast-warmup
+function f(s) {
+ // Trial-inline self-hosted |replace| and relazify.
+ for (var i = 0; i < 50; i++) {
+ s = s.replace("a", "b");
+ }
+ trialInline();
+ relazifyFunctions();
+
+ // Warp-compile.
+ for (var j = 0; j < 50; j++) {}
+
+ return s;
+}
+assertEq(f("a"), "b");
diff --git a/js/src/jit-test/tests/warp/bug1668197.js b/js/src/jit-test/tests/warp/bug1668197.js
new file mode 100644
index 0000000000..2dcd6cb376
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1668197.js
@@ -0,0 +1,6 @@
+// |jit-test| skip-if: !('oomTest' in this)
+function f(x, y) {
+ return ~Math.hypot(x >>> 0, 2 - x >>> 0);
+}
+f(2, Math);
+oomTest(f);
diff --git a/js/src/jit-test/tests/warp/bug1669415.js b/js/src/jit-test/tests/warp/bug1669415.js
new file mode 100644
index 0000000000..e22497f86d
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1669415.js
@@ -0,0 +1,11 @@
+function f(x, y) {
+ return +(-y ? -x : (y ? x : NaN));
+}
+let arr = [false, {}, {}];
+for (let i = 0; i < 9; ++i) {
+ f(1.1, 2);
+}
+for (let i = 0; i < arr.length; i++) {
+ output = f(true, arr[i]);
+}
+assertEq(output, 1);
diff --git a/js/src/jit-test/tests/warp/bug1669597.js b/js/src/jit-test/tests/warp/bug1669597.js
new file mode 100644
index 0000000000..c4110c581f
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1669597.js
@@ -0,0 +1,14 @@
+// |jit-test| --fast-warmup
+var str = '';
+function g(x) {
+ with(this) {} // Don't inline.
+ return x;
+}
+function f() {
+ var x = 0;
+ for (var i = 0; i < 100; i++) {
+ x += +g(+str);
+ }
+ return x;
+}
+assertEq(f(), 0);
diff --git a/js/src/jit-test/tests/warp/bug1671812.js b/js/src/jit-test/tests/warp/bug1671812.js
new file mode 100644
index 0000000000..560a01a871
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1671812.js
@@ -0,0 +1,11 @@
+// |jit-test| --fast-warmup; --baseline-eager
+function f() {
+ let val1 = Math.sqrt(9007199254740992);
+ let val2 = 0;
+ let arr = new Float32Array(100);
+ for (let i = 0; i < 100; i++) {
+ val2 = arr[i];
+ }
+ return val1 + val2;
+}
+assertEq(f(), Math.sqrt(9007199254740992));
diff --git a/js/src/jit-test/tests/warp/bug1676631.js b/js/src/jit-test/tests/warp/bug1676631.js
new file mode 100644
index 0000000000..d9f7947396
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1676631.js
@@ -0,0 +1,7 @@
+function f() {
+ var a = arguments;
+ for (var i = 0; i < 10; i++) {
+ a[""]
+ }
+}
+f();
diff --git a/js/src/jit-test/tests/warp/bug1676639.js b/js/src/jit-test/tests/warp/bug1676639.js
new file mode 100644
index 0000000000..f813c53a9a
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1676639.js
@@ -0,0 +1,7 @@
+function foo() {
+ return Math.atanh(true === Math.fround(0) | 0) != true;
+}
+var results = [];
+for (var j = 0; j < 50; j++) {
+ results.push(foo(0,0));
+}
diff --git a/js/src/jit-test/tests/warp/bug1681056.js b/js/src/jit-test/tests/warp/bug1681056.js
new file mode 100644
index 0000000000..6a3d094854
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1681056.js
@@ -0,0 +1,9 @@
+gczeal(14,10);
+let y = [];
+try {
+ evaluate(`(function() {
+ for (let x10 = 0;
+ new class Object extends Object { v = function () {} };
+ arguments << this) {}
+ })()`);
+} catch(exc) {}
diff --git a/js/src/jit-test/tests/warp/bug1681597.js b/js/src/jit-test/tests/warp/bug1681597.js
new file mode 100644
index 0000000000..cc0d83f4b9
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1681597.js
@@ -0,0 +1,19 @@
+// |jit-test| --fast-warmup; --no-threads
+
+function f(x) {
+ (function () {
+ (1 == (x & 0) * 1.1) + x;
+ })();
+}
+let y = [,,,2147483648,0,0];
+for (let i = 0; i < 6; i++) {
+ f(y[i]);
+ f(y[i]);
+ f(y[i]);
+ f(y[i]);
+ f(y[i]);
+ f(y[i]);
+ f(y[i]);
+ f(y[i]);
+ f(y[i]);
+}
diff --git a/js/src/jit-test/tests/warp/bug1681677.js b/js/src/jit-test/tests/warp/bug1681677.js
new file mode 100644
index 0000000000..157a28740b
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1681677.js
@@ -0,0 +1,7 @@
+var a = [1];
+var p = {__proto__: Array.prototype};
+Object.setPrototypeOf(a, p);
+for (var i = 0; i < 100; ++i) {
+ var x = a.slice(0);
+ assertEq(x.__proto__, Array.prototype);
+}
diff --git a/js/src/jit-test/tests/warp/bug1681806.js b/js/src/jit-test/tests/warp/bug1681806.js
new file mode 100644
index 0000000000..8dfdfd1b4c
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1681806.js
@@ -0,0 +1,92 @@
+// |jit-test| skip-if: !getJitCompilerOptions()['ion.enable']
+
+with ({}) {}
+
+let foo, bar, active;
+
+function test(depth) {
+ print(depth);
+
+ // Define two mutually recursive functions with as many locals as possible
+ // to maximize the size of the rematerialized frame when we bail out (~4K).
+ foo = new Function('n', `
+ var a0,b0,c0,d0,e0,f0,g0,h0,i0,j0,k0,l0,m0,n0,o0,p0,q0,r0,s0,t0,u0,v0,w0,x0,y0,z0;
+ var a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,o1,p1,q1,r1,s1,t1,u1,v1,w1,x1,y1,z1;
+ var a2,b2,c2,d2,e2,f2,g2,h2,i2,j2,k2,l2,m2,n2,o2,p2,q2,r2,s2,t2,u2,v2,w2,x2,y2,z2;
+ var a3,b3,c3,d3,e3,f3,g3,h3,i3,j3,k3,l3,m3,n3,o3,p3,q3,r3,s3,t3,u3,v3,w3,x3,y3,z3;
+ var a4,b4,c4,d4,e4,f4,g4,h4,i4,j4,k4,l4,m4,n4,o4,p4,q4,r4,s4,t4,u4,v4,w4,x4,y4,z4;
+ var a5,b5,c5,d5,e5,f5,g5,h5,i5,j5,k5,l5,m5,n5,o5,p5,q5,r5,s5,t5,u5,v5,w5,x5,y5,z5;
+ var a6,b6,c6,d6,e6,f6,g6,h6,i6,j6,k6,l6,m6,n6,o6,p6,q6,r6,s6,t6,u6,v6,w6,x6,y6,z6;
+ var a7,b7,c7,d7,e7,f7,g7,h7,i7,j7,k7,l7,m7,n7,o7,p7,q7,r7,s7,t7,u7,v7,w7,x7,y7,z7;
+ var a8,b8,c8,d8,e8,f8,g8,h8,i8,j8,k8,l8,m8,n8,o8,p8,q8,r8,s8,t8,u8,v8,w8,x8,y8,z8;
+ var a9,b9,c9,d9,e9,f9,g9,h9,i9,j9,k9,l9,m9,n9,o9,p9,q9,r9,s9,t9;
+ if (n == 0) {
+ if (active) invalidate();
+ } else {
+ bar(n);
+ }`);
+ bar = new Function('n', `
+ var a0,b0,c0,d0,e0,f0,g0,h0,i0,j0,k0,l0,m0,n0,o0,p0,q0,r0,s0,t0,u0,v0,w0,x0,y0,z0;
+ var a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,o1,p1,q1,r1,s1,t1,u1,v1,w1,x1,y1,z1;
+ var a2,b2,c2,d2,e2,f2,g2,h2,i2,j2,k2,l2,m2,n2,o2,p2,q2,r2,s2,t2,u2,v2,w2,x2,y2,z2;
+ var a3,b3,c3,d3,e3,f3,g3,h3,i3,j3,k3,l3,m3,n3,o3,p3,q3,r3,s3,t3,u3,v3,w3,x3,y3,z3;
+ var a4,b4,c4,d4,e4,f4,g4,h4,i4,j4,k4,l4,m4,n4,o4,p4,q4,r4,s4,t4,u4,v4,w4,x4,y4,z4;
+ var a5,b5,c5,d5,e5,f5,g5,h5,i5,j5,k5,l5,m5,n5,o5,p5,q5,r5,s5,t5,u5,v5,w5,x5,y5,z5;
+ var a6,b6,c6,d6,e6,f6,g6,h6,i6,j6,k6,l6,m6,n6,o6,p6,q6,r6,s6,t6,u6,v6,w6,x6,y6,z6;
+ var a7,b7,c7,d7,e7,f7,g7,h7,i7,j7,k7,l7,m7,n7,o7,p7,q7,r7,s7,t7,u7,v7,w7,x7,y7,z7;
+ var a8,b8,c8,d8,e8,f8,g8,h8,i8,j8,k8,l8,m8,n8,o8,p8,q8,r8,s8,t8,u8,v8,w8,x8,y8,z8;
+ var a9,b9,c9,d9,e9,f9,g9,h9,i9,j9,k9,l9,m9,n9,o9,p9,q9,r9,s9,t9;
+ foo(n-1);`);
+
+ with ({}) {}
+
+ // Warm up the invalidate() branch of foo to avoid FirstExecution bailouts.
+ active = true;
+ for (var i = 0; i < 10; i++) {
+ foo(2);
+ }
+
+ // Warp-compile foo, inlining bar.
+ active = false;
+ for (var i = 0; i < 30; i++) {
+ foo(2);
+ }
+
+ // Consume stack with frames that don't have to be invalidated.
+ function recurse(n) {
+ with ({}) {}
+ if (n == 0) {
+ foo(2);
+ } else {
+ recurse(n-1);
+ }
+ }
+
+ // Trigger an invalidation.
+ active = true;
+ recurse(depth);
+}
+
+// Binary search to find the right recursion depth such that
+// the invalidation bailout will cause stack overflow.
+let depth = 0;
+function probeStackLimit(increment) {
+ try {
+ while (true) {
+ test(depth + increment);
+ depth += increment;
+ }
+ } catch {}
+}
+
+probeStackLimit(8192);
+probeStackLimit(4096);
+probeStackLimit(2048);
+probeStackLimit(1024);
+probeStackLimit(512);
+probeStackLimit(256);
+probeStackLimit(128);
+probeStackLimit(64);
+probeStackLimit(32);
+probeStackLimit(16);
+probeStackLimit(8);
diff --git a/js/src/jit-test/tests/warp/bug1683306.js b/js/src/jit-test/tests/warp/bug1683306.js
new file mode 100644
index 0000000000..8d07524274
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1683306.js
@@ -0,0 +1,19 @@
+// |jit-test| --ion-offthread-compile=off; --ion-full-warmup-threshold=0; --ion-gvn=off; --warp-async; --baseline-eager
+//
+// Bug 1683306 - Assertion failure: !genObj->hasStackStorage() || genObj->isStackStorageEmpty(), at vm/GeneratorObject.cpp:144
+
+function assert(mustBeTrue, message) { }
+assert.sameValue = function (expected) {
+ assert._toString(expected)
+};
+assert._toString = function (value) {
+ return String(value);
+}
+async function fn() {
+ for await ([] of []) { }
+}
+
+fn();
+bailAfter(10);
+assert.sameValue();
+evaluate("fn();");
diff --git a/js/src/jit-test/tests/warp/bug1683309.js b/js/src/jit-test/tests/warp/bug1683309.js
new file mode 100644
index 0000000000..097bed2622
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1683309.js
@@ -0,0 +1,20 @@
+// |jit-test| slow; --ion-offthread-compile=off; --warp-async
+//
+// Bug 1683309: Assertion failure: [barrier verifier] Unmarked edge: JS Object 0xebbb6d1dee0 'object slot' edge to JS Object 0xebbb6d29f60, at gc/Verifier.cpp:392
+//
+// The following testcase crashes on mozilla-central revision 20201217-2ab4142f19bc (debug build, run with --ion-offthread-compile=off --warp-async):
+
+if (helperThreadCount() > 0) {
+ evalInWorker(`
+ try{
+ gczeal(4);
+ function f86(depth) {
+ var x = async target => ([]);
+ o62 = unescape;
+ x(o62.prop, o62);
+ f86(true + 1);
+ }
+ f86(0);
+ } catch (e) {}
+ `);
+}
diff --git a/js/src/jit-test/tests/warp/bug1683535-1.js b/js/src/jit-test/tests/warp/bug1683535-1.js
new file mode 100644
index 0000000000..c85d301c3a
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1683535-1.js
@@ -0,0 +1,6 @@
+function f(x, y) {
+ (Math.log() ? 0 : Math.abs(~y)) ^ x ? x : x;
+}
+for (let i = 0; i < 52; i++) {
+ f(0, -2147483649);
+}
diff --git a/js/src/jit-test/tests/warp/bug1683535-2.js b/js/src/jit-test/tests/warp/bug1683535-2.js
new file mode 100644
index 0000000000..b1e26473c0
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1683535-2.js
@@ -0,0 +1,10 @@
+function testMathyFunction(f, inputs) {
+ var results = [];
+ for (var j = 0; j < inputs.length; ++j)
+ for (var k = 0; k < inputs.length; ++k)
+ results.push(f(inputs[j], inputs[k]));
+}
+mathy0 = (function(x, y) {
+ return (Math.clz32((x <= x) >>> y) >> (~(0x080000000 >>> 0))) % Math.acos(~(2 ** 53)) >>> 0
+});
+testMathyFunction(mathy0, [1, 42, 0 / 0, 1 / 0, -Number.MIN_SAFE_INTEGER, -(2 ** 53), (2 ** 53), 1.7976931348623157e308]);
diff --git a/js/src/jit-test/tests/warp/bug1683614.js b/js/src/jit-test/tests/warp/bug1683614.js
new file mode 100644
index 0000000000..69fc780c15
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1683614.js
@@ -0,0 +1,14 @@
+// |jit-test| --ion-offthread-compile=off; --ion-full-warmup-threshold=0; --warp-async; --baseline-eager;
+//
+// The following testcase crashes on mozilla-central revision 20201219-3262affdccf6 (debug build, run with --fuzzing-safe --ion-offthread-compile=off --ion-full-warmup-threshold=0 --warp-async --baseline-eager):
+gczeal(9, 8);
+function s() { }
+new ReadableStream({
+ start() {
+ test();
+ }
+});
+async function test() {
+ for (let i17 = 1; i17 <= 30; i17++)
+ await s(0 + function () { return i17 });
+} \ No newline at end of file
diff --git a/js/src/jit-test/tests/warp/bug1686207.js b/js/src/jit-test/tests/warp/bug1686207.js
new file mode 100644
index 0000000000..4a2637408c
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1686207.js
@@ -0,0 +1,11 @@
+function f(x, y) {
+ x >> (y >>> 0)
+}
+
+with ({}) {}
+
+f(-1, -1)
+f(1.5, 0)
+for (var i = 0; i < 100; i++) {
+ f(0, 0);
+}
diff --git a/js/src/jit-test/tests/warp/bug1686702.js b/js/src/jit-test/tests/warp/bug1686702.js
new file mode 100644
index 0000000000..b5bf4e4b54
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1686702.js
@@ -0,0 +1,3 @@
+for (var j = 0; j < 100; j++) {
+ +(Math.fround(1) && 0);
+}
diff --git a/js/src/jit-test/tests/warp/bug1687661.js b/js/src/jit-test/tests/warp/bug1687661.js
new file mode 100644
index 0000000000..e1b90a1879
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1687661.js
@@ -0,0 +1,13 @@
+function f(x,y) {
+ return Math.trunc(+(y ? x : y) || ~y);
+}
+
+with ({}) {}
+
+for (var i = 0; i < 10; i++) {
+ f(0,1);
+ f(NaN,1);
+ f(0.1,0);
+}
+
+assertEq(f(0.1, 1), 0);
diff --git a/js/src/jit-test/tests/warp/bug1687672.js b/js/src/jit-test/tests/warp/bug1687672.js
new file mode 100644
index 0000000000..e5d1a746f3
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1687672.js
@@ -0,0 +1,14 @@
+// |jit-test| --no-threads; --baseline-warmup-threshold=1; --ion-warmup-threshold=0
+
+var input = ["", 0, "", "", "", "", "", "", "", "", "", "", "", "", {}, {}, ""];
+
+for (var i = 0; i < 10; i++) {
+ function sum_indexing(x,i) {
+ if (i == x.length) {
+ return 0;
+ } else {
+ return x[i] + sum_indexing(x, i+1);
+ }
+ }
+ sum_indexing(input, 0);
+}
diff --git a/js/src/jit-test/tests/warp/cancel-offthread-compile.js b/js/src/jit-test/tests/warp/cancel-offthread-compile.js
new file mode 100644
index 0000000000..939d128ae1
--- /dev/null
+++ b/js/src/jit-test/tests/warp/cancel-offthread-compile.js
@@ -0,0 +1,21 @@
+// |jit-test| --fast-warmup; skip-if: helperThreadCount() === 0
+
+function foo(o) {
+ return o.y;
+}
+
+with ({}) {}
+
+var sum = 0;
+
+// Trigger an off-thread Warp compile.
+for (var i = 0; i < 30; i++) {
+ sum += foo({y: 1});
+}
+
+// Attach a new stub and cancel that compile.
+for (var i = 0; i < 30; i++) {
+ sum += foo({x: 1, y: 1});
+}
+
+assertEq(sum, 60);
diff --git a/js/src/jit-test/tests/warp/catch-overflow-regexp.js b/js/src/jit-test/tests/warp/catch-overflow-regexp.js
new file mode 100644
index 0000000000..a316e5636b
--- /dev/null
+++ b/js/src/jit-test/tests/warp/catch-overflow-regexp.js
@@ -0,0 +1,8 @@
+function test() {
+ try {
+ test();
+ } catch {
+ /a/.test("a");
+ }
+}
+test();
diff --git a/js/src/jit-test/tests/warp/force-warp.js b/js/src/jit-test/tests/warp/force-warp.js
new file mode 100644
index 0000000000..b875fc0471
--- /dev/null
+++ b/js/src/jit-test/tests/warp/force-warp.js
@@ -0,0 +1,11 @@
+// A simple test to ensure WarpBuilder files are included in code-coverage builds.
+// See bug 1635097.
+
+function test() {
+ var o = {x: 0};
+ for (var i = 0; i < 10000; i++) {
+ o.x++;
+ }
+ return o;
+}
+test();
diff --git a/js/src/jit-test/tests/warp/function-load-length.js b/js/src/jit-test/tests/warp/function-load-length.js
new file mode 100644
index 0000000000..c3ef3552eb
--- /dev/null
+++ b/js/src/jit-test/tests/warp/function-load-length.js
@@ -0,0 +1,86 @@
+// Test transpiling of LoadFunctionLengthResult and cover possible bailout conditions.
+
+function empty() {}
+
+// Note: Typically won't use LoadFunctionLengthResult, because the "length"
+// property will be resolved on the first access.
+function testGlobalFunction() {
+ for (var i = 0; i < 200; ++i) {
+ assertEq(empty.length, 0);
+ }
+}
+testGlobalFunction();
+
+// Note: Typically won't use LoadFunctionLengthResult, because the "length"
+// property will be resolved on the first access.
+function testInnerFunction() {
+ function f() {}
+ for (var i = 0; i < 200; ++i) {
+ assertEq(f.length, 0);
+ }
+}
+testInnerFunction();
+
+function testPerLoopFunction() {
+ for (var i = 0; i < 200; ++i) {
+ assertEq(function(){}.length, 0);
+ }
+}
+testPerLoopFunction();
+
+// Note: Typically won't use LoadFunctionLengthResult, because the "length"
+// property will be resolved on the first access.
+function testNativeFunction() {
+ for (var i = 0; i < 200; ++i) {
+ assertEq(Math.max.length, 2);
+ }
+}
+testNativeFunction();
+
+// Note: Typically won't use LoadFunctionLengthResult, because the "length"
+// property will be resolved on the first access.
+function testSelfHostedFunction() {
+ for (var i = 0; i < 200; ++i) {
+ assertEq(Array.prototype.forEach.length, 1);
+ }
+}
+testSelfHostedFunction();
+
+// Bailout when the length doesn't fit into int32.
+function testBailoutLength() {
+ var values = [0, 0x80000000];
+ var bound = empty.bind();
+
+ for (var i = 0; i < 10; ++i) {
+ var value = values[0 + (i >= 5)];
+
+ // Define on each iteration to get the same shape.
+ Object.defineProperty(bound, "length", {value});
+
+ for (var j = 0; j < 100; ++j) {
+ var f = bound.bind();
+ assertEq(f.length, value);
+ }
+ }
+}
+testBailoutLength();
+
+// Bailout when trying to read "length" from a property with a lazy script.
+function testBailoutLazyFunction() {
+ for (var i = 0; i < 200; ++i) {
+ var values = [function(){}, function(a){}];
+ var index = 0 + (i >= 100);
+ assertEq(values[index].length, index);
+ }
+}
+testBailoutLazyFunction();
+
+// Bailout when trying to read "length" from a property with a lazy self-hosted script.
+function testBailoutLazySelfHostedFunction() {
+ for (var i = 0; i < 200; ++i) {
+ var values = [function(){}, Array.prototype.map];
+ var index = 0 + (i >= 100);
+ assertEq(values[index].length, index);
+ }
+}
+testBailoutLazySelfHostedFunction();
diff --git a/js/src/jit-test/tests/warp/function-load-name.js b/js/src/jit-test/tests/warp/function-load-name.js
new file mode 100644
index 0000000000..686ed32629
--- /dev/null
+++ b/js/src/jit-test/tests/warp/function-load-name.js
@@ -0,0 +1,100 @@
+// Test transpiling of LoadFunctionNameResult and cover possible bailout conditions.
+
+function empty() {}
+
+// Note: Typically won't use LoadFunctionNameResult, because the "name"
+// property will be resolved on the first access.
+function testGlobalFunction() {
+ for (var i = 0; i < 200; ++i) {
+ assertEq(empty.name, "empty");
+ }
+}
+testGlobalFunction();
+
+// Note: Typically won't use LoadFunctionNameResult, because the "name"
+// property will be resolved on the first access.
+function testInnerFunction() {
+ function f() {}
+ for (var i = 0; i < 200; ++i) {
+ assertEq(f.name, "f");
+ }
+}
+testInnerFunction();
+
+function testPerLoopFunction() {
+ for (var i = 0; i < 200; ++i) {
+ assertEq(function f(){}.name, "f");
+ }
+}
+testPerLoopFunction();
+
+// Note: Typically won't use LoadFunctionNameResult, because the "name"
+// property will be resolved on the first access.
+function testNativeFunction() {
+ for (var i = 0; i < 200; ++i) {
+ assertEq(Math.max.name, "max");
+ }
+}
+testNativeFunction();
+
+// Note: Typically won't use LoadFunctionNameResult, because the "name"
+// property will be resolved on the first access.
+function testSelfHostedFunction() {
+ for (var i = 0; i < 200; ++i) {
+ assertEq(Array.prototype.forEach.name, "forEach");
+ }
+}
+testSelfHostedFunction();
+
+// Bailout when the name property is resolved.
+function testBailoutResolvedName() {
+ function f1() {}
+
+ // Ensure the name property of |f1| is resolved.
+ assertEq(f1.name, "f1");
+
+ var names = ["f", "f1"];
+
+ for (var i = 0; i < 10; ++i) {
+ var name = names[0 + (i >= 5)];
+
+ for (var j = 0; j < 100; ++j) {
+ var values = [function f(){}, f1];
+ var value = values[0 + (i >= 5)];
+
+ assertEq(value.name, name);
+ }
+ }
+}
+testBailoutResolvedName();
+
+// Bailout when the HAS_BOUND_FUNCTION_NAME_PREFIX isn't set.
+function testBailoutBoundName() {
+ function f1() {}
+ function f2() {}
+
+ var bound = f1.bind();
+
+ // Ensure the name property of |bound| is resolved. That way new functions
+ // created through |bound().bind()| will have the HAS_BOUND_FUNCTION_NAME_PREFIX
+ // flag set.
+ assertEq(bound.name, "bound f1");
+
+ // |bound1| and |bound2| have the same shape, but different function flags.
+ var bound1 = bound.bind(); // HAS_BOUND_FUNCTION_NAME_PREFIX
+ var bound2 = f2.bind(); // ! HAS_BOUND_FUNCTION_NAME_PREFIX
+
+ var values = [bound1, bound2];
+ var names = ["bound bound bound f1", "bound bound f2"];
+
+ for (var i = 0; i < 10; ++i) {
+ var value = values[0 + (i >= 5)];
+ var name = names[0 + (i >= 5)];
+
+ for (var j = 0; j < 100; ++j) {
+ var f = value.bind();
+ assertEq(f.name, name);
+ }
+ }
+}
+testBailoutBoundName();
diff --git a/js/src/jit-test/tests/warp/guard-function-is-non-builtin-ctor.js b/js/src/jit-test/tests/warp/guard-function-is-non-builtin-ctor.js
new file mode 100644
index 0000000000..c2b92d4510
--- /dev/null
+++ b/js/src/jit-test/tests/warp/guard-function-is-non-builtin-ctor.js
@@ -0,0 +1,20 @@
+function test() {
+ for (var i = 0; i <= 200; ++i) {
+ // Create a fresh function in each iteration.
+ var values = [function(){}, () => {}];
+
+ // Use an arrow function in the last iteration.
+ var useArrowFn = (i === 200);
+
+ // No conditional (?:) so we don't trigger a cold-code bailout.
+ var value = values[0 + useArrowFn];
+
+ // Set or create the "prototype" property.
+ value.prototype = null;
+
+ // The "prototype" is configurable iff the function is an arrow function.
+ var desc = Object.getOwnPropertyDescriptor(value, "prototype");
+ assertEq(desc.configurable, useArrowFn);
+ }
+}
+test();
diff --git a/js/src/jit-test/tests/warp/guard-has-getter-setter.js b/js/src/jit-test/tests/warp/guard-has-getter-setter.js
new file mode 100644
index 0000000000..dc4b1d9ebd
--- /dev/null
+++ b/js/src/jit-test/tests/warp/guard-has-getter-setter.js
@@ -0,0 +1,263 @@
+// Access property once.
+function simple() {
+ var obj = {
+ get p() {
+ return 1;
+ }
+ };
+
+ // Use objects with different shapes to enter megamorphic state for
+ // the JSOp::GetProp opcode.
+ var array = [
+ Object.create(obj, {a: {value: 1}}),
+ Object.create(obj, {b: {value: 2}}),
+ Object.create(obj, {c: {value: 3}}),
+ Object.create(obj, {d: {value: 4}}),
+ Object.create(obj, {e: {value: 5}}),
+ Object.create(obj, {f: {value: 6}}),
+ Object.create(obj, {g: {value: 7}}),
+ Object.create(obj, {h: {value: 8}}),
+ ];
+
+ var r = 0;
+ for (var i = 0; i < 200; ++i) {
+ var o = array[i & 7];
+ r += o.p;
+ }
+ assertEq(r, 200);
+}
+simple();
+
+// Access property multiple times (consecutive) to test that MGuardHasGetterSetter
+// ops can be merged.
+function consecutive() {
+ var obj = {
+ get p() {
+ return 1;
+ }
+ };
+
+ // Use objects with different shapes to enter megamorphic state for
+ // the JSOp::GetProp opcode.
+ var array = [
+ Object.create(obj, {a: {value: 1}}),
+ Object.create(obj, {b: {value: 2}}),
+ Object.create(obj, {c: {value: 3}}),
+ Object.create(obj, {d: {value: 4}}),
+ Object.create(obj, {e: {value: 5}}),
+ Object.create(obj, {f: {value: 6}}),
+ Object.create(obj, {g: {value: 7}}),
+ Object.create(obj, {h: {value: 8}}),
+ ];
+
+ var r = 0;
+ for (var i = 0; i < 200; ++i) {
+ var o = array[i & 7];
+
+ r += o.p;
+ r += o.p;
+ r += o.p;
+ r += o.p;
+ }
+ assertEq(r, 4 * 200);
+}
+consecutive();
+
+// Access property multiple times (loop) to test LICM.
+function loop() {
+ var obj = {
+ get p() {
+ return 1;
+ }
+ };
+
+ // Use objects with different shapes to enter megamorphic state for
+ // the JSOp::GetProp opcode.
+ var array = [
+ Object.create(obj, {a: {value: 1}}),
+ Object.create(obj, {b: {value: 2}}),
+ Object.create(obj, {c: {value: 3}}),
+ Object.create(obj, {d: {value: 4}}),
+ Object.create(obj, {e: {value: 5}}),
+ Object.create(obj, {f: {value: 6}}),
+ Object.create(obj, {g: {value: 7}}),
+ Object.create(obj, {h: {value: 8}}),
+ ];
+
+ var r = 0;
+ for (var i = 0; i < 200; ++i) {
+ var o = array[i & 7];
+
+ for (var j = 0; j < 5; ++j) {
+ r += o.p;
+ }
+ }
+ assertEq(r, 5 * 200);
+}
+loop();
+
+// Bailout when prototype changes.
+function modifyProto() {
+ var obj = {
+ get p() {
+ return 1;
+ }
+ };
+
+ var obj2 = {
+ get p() {
+ return 2;
+ }
+ };
+
+ // Use objects with different shapes to enter megamorphic state for
+ // the JSOp::GetProp opcode.
+ var array = [
+ Object.create(obj, {a: {value: 1}}),
+ Object.create(obj, {b: {value: 2}}),
+ Object.create(obj, {c: {value: 3}}),
+ Object.create(obj, {d: {value: 4}}),
+ Object.create(obj, {e: {value: 5}}),
+ Object.create(obj, {f: {value: 6}}),
+ Object.create(obj, {g: {value: 7}}),
+ Object.create(obj, {h: {value: 8}}),
+ ];
+
+ var r = 0;
+ for (var i = 0; i < 200; ++i) {
+ var o = array[i & 7];
+
+ r += o.p;
+
+ // Always execute Object.setPrototypeOf() to avoid cold code bailouts,
+ // which would happen for conditional code like if-statements. But only
+ // actually change |o|'s prototype once.
+ var j = (i === 100) | 0;
+ var q = [{}, o][j];
+ Object.setPrototypeOf(q, obj2);
+
+ r += o.p;
+ }
+ assertEq(r, 2 * 200 + Math.floor(100 / 8) * 2 + 1);
+}
+modifyProto();
+
+// Bailout when property is changed to own data property.
+function modifyToOwnValue() {
+ var obj = {
+ get p() {
+ return 1;
+ }
+ };
+
+ // Use objects with different shapes to enter megamorphic state for
+ // the JSOp::GetProp opcode.
+ var array = [
+ Object.create(obj, {a: {value: 1}}),
+ Object.create(obj, {b: {value: 2}}),
+ Object.create(obj, {c: {value: 3}}),
+ Object.create(obj, {d: {value: 4}}),
+ Object.create(obj, {e: {value: 5}}),
+ Object.create(obj, {f: {value: 6}}),
+ Object.create(obj, {g: {value: 7}}),
+ Object.create(obj, {h: {value: 8}}),
+ ];
+
+ var r = 0;
+ for (var i = 0; i < 200; ++i) {
+ var o = array[i & 7];
+
+ r += o.p;
+
+ // Always execute Object.setPrototypeOf() to avoid cold code bailouts,
+ // which would happen for conditional code like if-statements. But only
+ // actually change |o|'s prototype once.
+ var j = (i === 100) | 0;
+ var q = [{}, o][j];
+ Object.defineProperty(q, "p", {value: 2});
+
+ r += o.p;
+ }
+ assertEq(r, 2 * 200 + Math.floor(100 / 8) * 2 + 1);
+}
+modifyToOwnValue();
+
+// Bailout when property is changed to own accessor property.
+function modifyToOwnAccessor() {
+ var obj = {
+ get p() {
+ return 1;
+ }
+ };
+
+ // Use objects with different shapes to enter megamorphic state for
+ // the JSOp::GetProp opcode.
+ var array = [
+ Object.create(obj, {a: {value: 1}}),
+ Object.create(obj, {b: {value: 2}}),
+ Object.create(obj, {c: {value: 3}}),
+ Object.create(obj, {d: {value: 4}}),
+ Object.create(obj, {e: {value: 5}}),
+ Object.create(obj, {f: {value: 6}}),
+ Object.create(obj, {g: {value: 7}}),
+ Object.create(obj, {h: {value: 8}}),
+ ];
+
+ var r = 0;
+ for (var i = 0; i < 200; ++i) {
+ var o = array[i & 7];
+
+ r += o.p;
+
+ // Always execute Object.setPrototypeOf() to avoid cold code bailouts,
+ // which would happen for conditional code like if-statements. But only
+ // actually change |o|'s prototype once.
+ var j = (i === 100) | 0;
+ var q = [{}, o][j];
+ Object.defineProperty(q, "p", {get() { return 2; }});
+
+ r += o.p;
+ }
+ assertEq(r, 2 * 200 + Math.floor(100 / 8) * 2 + 1);
+}
+modifyToOwnAccessor();
+
+// Bailout when changing accessor.
+function modifyProtoAccessor() {
+ var obj = {
+ get p() {
+ return 1;
+ }
+ };
+
+ // Use objects with different shapes to enter megamorphic state for
+ // the JSOp::GetProp opcode.
+ var array = [
+ Object.create(obj, {a: {value: 1}}),
+ Object.create(obj, {b: {value: 2}}),
+ Object.create(obj, {c: {value: 3}}),
+ Object.create(obj, {d: {value: 4}}),
+ Object.create(obj, {e: {value: 5}}),
+ Object.create(obj, {f: {value: 6}}),
+ Object.create(obj, {g: {value: 7}}),
+ Object.create(obj, {h: {value: 8}}),
+ ];
+
+ var r = 0;
+ for (var i = 0; i < 200; ++i) {
+ var o = array[i & 7];
+
+ r += o.p;
+
+ // Always execute Object.setPrototypeOf() to avoid cold code bailouts,
+ // which would happen for conditional code like if-statements. But only
+ // actually change |o|'s prototype once.
+ var j = (i === 100) | 0;
+ var q = [{}, obj][j];
+ Object.defineProperty(q, "p", {get() { return 2; }});
+
+ r += o.p;
+ }
+ assertEq(r, 2 * 200 + 100 * 2 - 1);
+}
+modifyProtoAccessor();
diff --git a/js/src/jit-test/tests/warp/guard-string-to-number-or-int32.js b/js/src/jit-test/tests/warp/guard-string-to-number-or-int32.js
new file mode 100644
index 0000000000..8a28d46f99
--- /dev/null
+++ b/js/src/jit-test/tests/warp/guard-string-to-number-or-int32.js
@@ -0,0 +1,36 @@
+function stringToNumber() {
+ function f(s) {
+ return ~~s;
+ }
+
+ var q = 0;
+ for (var i = 0; i < 200; ++i) {
+ q += f("1");
+ q += f("0x2");
+ q += f("0b11");
+ q += f("0o4");
+
+ // Invalid inputs: ~~Nan == 0
+ q += f("z");
+ q += f("0x2.3");
+ q += f("0x1.fp4");
+ }
+ assertEq(q, (1 + 2 + 3 + 4) * 200);
+}
+stringToNumber();
+
+function stringToInt32() {
+ function f(s) {
+ return s - 0;
+ }
+
+ var q = 0;
+ for (var i = 0; i < 200; ++i) {
+ q += f("1");
+ q += f("0x2");
+ q += f("0b11");
+ q += f("0o4");
+ }
+ assertEq(q, (1 + 2 + 3 + 4) * 200);
+}
+stringToInt32();
diff --git a/js/src/jit-test/tests/warp/guardproto-nursery.js b/js/src/jit-test/tests/warp/guardproto-nursery.js
new file mode 100644
index 0000000000..5093298e88
--- /dev/null
+++ b/js/src/jit-test/tests/warp/guardproto-nursery.js
@@ -0,0 +1,13 @@
+function f() {
+ var o = {x: 1, y: 3};
+ o.__proto__ = {x: 2};
+ var p = Math;
+ p.__proto__ = o;
+ p.__proto__ = {__proto__: o};
+
+ for (var i = 0; i < 3000; i++) {
+ assertEq(p.x, 1);
+ assertEq(p.y, 3);
+ }
+}
+f();
diff --git a/js/src/jit-test/tests/warp/inline-array-at.js b/js/src/jit-test/tests/warp/inline-array-at.js
new file mode 100644
index 0000000000..691695151c
--- /dev/null
+++ b/js/src/jit-test/tests/warp/inline-array-at.js
@@ -0,0 +1,17 @@
+// |jit-test| skip-if: !Array.prototype.at
+
+function f(x) {
+ assertEq(x.at(0), 1);
+ assertEq(x.at(-1), 3);
+ assertEq(x.at(10), undefined);
+}
+
+function g() {
+ for (var i = 0; i < 100; i++) {
+ f([1, 2, 3]);
+ }
+}
+
+for (var j = 0; j < 10; j++) {
+ g();
+}
diff --git a/js/src/jit-test/tests/warp/load-unboxed-typedarray-bigint.js b/js/src/jit-test/tests/warp/load-unboxed-typedarray-bigint.js
new file mode 100644
index 0000000000..736e80f3f5
--- /dev/null
+++ b/js/src/jit-test/tests/warp/load-unboxed-typedarray-bigint.js
@@ -0,0 +1,7 @@
+var ta = new BigInt64Array([0n, 1n]);
+var q = 0;
+for (var i = 0; i < 10000; ++i) {
+ if (ta[i&1]) q++;
+}
+
+assertEq(q, 5000);
diff --git a/js/src/jit-test/tests/warp/math-indirect-truncate.js b/js/src/jit-test/tests/warp/math-indirect-truncate.js
new file mode 100644
index 0000000000..9cc967ca33
--- /dev/null
+++ b/js/src/jit-test/tests/warp/math-indirect-truncate.js
@@ -0,0 +1,55 @@
+function testCeil() {
+ function ceil(a, b) {
+ return Math.ceil(a / b) | 0;
+ }
+
+ // Warm-up
+ for (var i = 0; i < 50; i++) {
+ ceil(5, 5);
+ }
+
+ assertEq(ceil(5, 3), 2);
+}
+testCeil();
+
+function testFloor() {
+ function floor(a, b) {
+ return Math.floor(a / b) | 0;
+ }
+
+ // Warm-up
+ for (var i = 0; i < 50; i++) {
+ floor(5, 5);
+ }
+
+ assertEq(floor(-5, 3), -2);
+}
+testFloor();
+
+function testRound() {
+ function round(a, b) {
+ return Math.round(a / b) | 0;
+ }
+
+ // Warm-up
+ for (var i = 0; i < 50; i++) {
+ round(5, 5);
+ }
+
+ assertEq(round(5, 3), 2);
+}
+testRound();
+
+function testTrunc() {
+ function trunc(a, b) {
+ return Math.trunc(a / b) | 0;
+ }
+
+ // Warm-up
+ for (var i = 0; i < 50; i++) {
+ trunc(5, 5);
+ }
+
+ assertEq(trunc(5, 3), 1);
+}
+testTrunc();
diff --git a/js/src/jit-test/tests/warp/mega-morphic-load-and-has-prop.js b/js/src/jit-test/tests/warp/mega-morphic-load-and-has-prop.js
new file mode 100644
index 0000000000..0d77ceb316
--- /dev/null
+++ b/js/src/jit-test/tests/warp/mega-morphic-load-and-has-prop.js
@@ -0,0 +1,99 @@
+function testMegamorphicLoadSlot(i) {
+ var xs = [
+ {p: 0},
+ {a: 0, p: 1},
+ {a: 0, b: 0, p: 2},
+ {a: 0, b: 0, c: 0, p: 3},
+ {a: 0, b: 0, c: 0, d: 0, p: 4},
+ {a: 0, b: 0, c: 0, d: 0, e: 0, p: 5},
+ {a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, p: 6},
+ {a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, g: 0, p: 7},
+ {a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, g: 0, h: 0, p: 8},
+ {a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, g: 0, h: 0, i: 0, p: 9},
+ ];
+ var called = 0;
+ var obj = {
+ get p() {
+ called++;
+ }
+ };
+
+ for (var j = 0; j <= 100; ++j) {
+ // Don't use if-statements to avoid cold code bailouts.
+ var x = xs[j % 10];
+ var y = [x, obj][(i === 1 && j === 100)|0];
+
+ // Can't DCE this instruction.
+ y.p;
+ }
+
+ assertEq(i === 0 || called === 1, true);
+}
+for (var i = 0; i < 2; ++i) testMegamorphicLoadSlot(i);
+
+function testMegamorphicLoadSlotByValue(i) {
+ var xs = [
+ {p: 0},
+ {a: 0, p: 1},
+ {a: 0, b: 0, p: 2},
+ {a: 0, b: 0, c: 0, p: 3},
+ {a: 0, b: 0, c: 0, d: 0, p: 4},
+ {a: 0, b: 0, c: 0, d: 0, e: 0, p: 5},
+ {a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, p: 6},
+ {a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, g: 0, p: 7},
+ {a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, g: 0, h: 0, p: 8},
+ {a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, g: 0, h: 0, i: 0, p: 9},
+ ];
+ var called = 0;
+ var obj = {
+ get p() {
+ called++;
+ }
+ };
+
+ var p = "p";
+ for (var j = 0; j <= 100; ++j) {
+ // Don't use if-statements to avoid cold code bailouts.
+ var x = xs[j % 10];
+ var y = [x, obj][(i === 1 && j === 100)|0];
+
+ // Can't DCE this instruction.
+ y[p];
+ }
+
+ assertEq(i === 0 || called === 1, true);
+}
+for (var i = 0; i < 2; ++i) testMegamorphicLoadSlotByValue(i);
+
+function testMegamorphicHasProp(i) {
+ var xs = [
+ {p: 0},
+ {a: 0, p: 1},
+ {a: 0, b: 0, p: 2},
+ {a: 0, b: 0, c: 0, p: 3},
+ {a: 0, b: 0, c: 0, d: 0, p: 4},
+ {a: 0, b: 0, c: 0, d: 0, e: 0, p: 5},
+ {a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, p: 6},
+ {a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, g: 0, p: 7},
+ {a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, g: 0, h: 0, p: 8},
+ {a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, g: 0, h: 0, i: 0, p: 9},
+ ];
+ var called = 0;
+ var obj = new Proxy({}, {
+ has() {
+ called++;
+ }
+ });
+
+ for (var j = 0; j <= 100; ++j) {
+ // Don't use if-statements to avoid cold code bailouts.
+ var x = xs[j % 10];
+ var y = [x, obj][(i === 1 && j === 100)|0];
+
+ // Can't DCE this instruction.
+ "p" in y;
+ }
+
+ assertEq(i === 0 || called === 1, true);
+}
+for (var i = 0; i < 2; ++i) testMegamorphicHasProp(i);
diff --git a/js/src/jit-test/tests/warp/non-int32-array-length.js b/js/src/jit-test/tests/warp/non-int32-array-length.js
new file mode 100644
index 0000000000..4213f1991c
--- /dev/null
+++ b/js/src/jit-test/tests/warp/non-int32-array-length.js
@@ -0,0 +1,10 @@
+function f(arr, len) {
+ for (var i = 0; i < 2000; i++) {
+ assertEq(arr.length, len);
+ }
+}
+var arr = [0];
+f(arr, 1);
+
+arr.length = 0xffff_ffff;
+f(arr, 0xffff_ffff);
diff --git a/js/src/jit-test/tests/warp/null-not-zero-index.js b/js/src/jit-test/tests/warp/null-not-zero-index.js
new file mode 100644
index 0000000000..b55b743b95
--- /dev/null
+++ b/js/src/jit-test/tests/warp/null-not-zero-index.js
@@ -0,0 +1,17 @@
+// |jit-test| --no-threads
+
+function f(index) {
+ var a = [123];
+ return a[index]
+}
+
+function g() {
+ for (var i = 0; i < 100; i++) {
+ // Make sure |null| is not treated like a |0| index.
+ assertEq(f(i > 90 ? null : 0), i > 90 ? undefined : 123)
+ }
+}
+
+for (var j = 0; j < 10; j++) {
+ g();
+}
diff --git a/js/src/jit-test/tests/warp/object-class-tostring.js b/js/src/jit-test/tests/warp/object-class-tostring.js
new file mode 100644
index 0000000000..d26a2d95a5
--- /dev/null
+++ b/js/src/jit-test/tests/warp/object-class-tostring.js
@@ -0,0 +1,65 @@
+function testCongruent(i) {
+ var p = {};
+ var o = {
+ // Add toString as an own property, so it'll be always found on this object,
+ // even when properties are changed on the prototype.
+ toString: Object.prototype.toString,
+
+ // Add a custom prototype, so we can add @@toStringTag without modifying the
+ // shape of this object.
+ __proto__: p,
+ };
+ var xs = [{}, p];
+ var ys = ["[object Object]", "[object Test]"];
+
+ for (var j = 0; j <= 100; ++j) {
+ // Don't use if-statements to avoid cold code bailouts
+ var x = xs[(i === 1 && j === 100)|0];
+ var y = ys[(i === 1 && j === 100)|0];
+
+ // |o.toString()| must be executed twice, because |x[Symbol.toStringTag]| may
+ // have modified |o|.
+ var r = o.toString();
+ x[Symbol.toStringTag] = "Test";
+ var e = o.toString();
+
+ assertEq(r, "[object Object]");
+ assertEq(e, y);
+ }
+}
+for (var i = 0; i < 2; ++i) testCongruent(i);
+
+function testUnobserved(i) {
+ var p = {};
+ var o = {
+ // Add toString as an own property, so it'll be always found on this object,
+ // even when properties are changed on the prototype.
+ toString: Object.prototype.toString,
+
+ // Add a custom prototype, so we can add @@toStringTag without modifying the
+ // shape of this object.
+ __proto__: p,
+ };
+ var xs = [{}, p];
+ var ys = [false, true];
+
+ for (var j = 0; j <= 100; ++j) {
+ // Don't use if-statements to avoid cold code bailouts
+ var x = xs[(i === 1 && j === 100)|0];
+ var y = ys[(i === 1 && j === 100)|0];
+
+ var executed = false;
+ Object.defineProperty(x, Symbol.toStringTag, {
+ configurable: true,
+ get() {
+ executed = true;
+ }
+ });
+
+ // |o.toString()| must be executed even when the result isn't observed.
+ o.toString();
+
+ assertEq(executed, y);
+ }
+}
+for (var i = 0; i < 2; ++i) testUnobserved(i);
diff --git a/js/src/jit-test/tests/warp/phi-specialization.js b/js/src/jit-test/tests/warp/phi-specialization.js
new file mode 100644
index 0000000000..a466a9eb9b
--- /dev/null
+++ b/js/src/jit-test/tests/warp/phi-specialization.js
@@ -0,0 +1,42 @@
+// |jit-test| --fast-warmup
+
+var sum = 0;
+
+function foo(copy, shouldThrow) {
+ switch (copy) {
+ case 0:
+ var x = 0;
+ try {
+ if (shouldThrow) { throw 0;}
+ x = 1;
+ } catch {
+ x = "a";
+ }
+ // We create a specialized phi for x here, which bails out.
+ for (var i = 0; i < 100; i++) {
+ sum += x;
+ }
+ break;
+ case 1:
+ var y = 0;
+ try {
+ if (shouldThrow) { throw 0;}
+ y = 1;
+ } catch {
+ y = "a";
+ }
+ // We do not create a specialized phi the second time.
+ for (var i = 0; i < 100; i++) {
+ sum += y;
+ }
+ break;
+ }
+}
+
+with ({}) {}
+for (var i = 0; i < 2; i++) {
+ for (var j = 0; j < 50; j++) {
+ foo(i, false);
+ }
+ foo(i, true);
+}
diff --git a/js/src/jit-test/tests/warp/property-add-shape.js b/js/src/jit-test/tests/warp/property-add-shape.js
new file mode 100644
index 0000000000..88348200bf
--- /dev/null
+++ b/js/src/jit-test/tests/warp/property-add-shape.js
@@ -0,0 +1,98 @@
+function simple() {
+ var o = {a: 1};
+ o.b = 2;
+
+ assertEq(o.a, 1);
+ assertEq(o.b, 2);
+}
+
+function condition1(b) {
+ var o = {a: 1};
+
+ if (b) {
+ o.b = 2;
+ }
+
+ o.c = 3;
+
+ assertEq(o.a, 1);
+ if (b) {
+ assertEq(o.b, 2);
+ } else {
+ assertEq('b' in o, false);
+ }
+ assertEq(o.c, 3);
+}
+
+function condition2(b) {
+ var o = {a: 1};
+
+ if (b) {
+ o.b = 2;
+ } else {
+ o.b = 3;
+ }
+
+ o.c = 3;
+
+ assertEq(o.a, 1);
+ assertEq(o.b, b ? 2 : 3);
+ assertEq(o.c, 3);
+}
+
+function condition3(b) {
+ var o = {a: 1};
+
+ if (b) {
+ o.b = 2;
+ } else {
+ o.b = 2;
+ }
+
+ o.c = 3;
+
+ assertEq(o.a, 1);
+ assertEq(o.b, 2);
+ assertEq(o.c, 3);
+}
+
+function condition4(b) {
+ var o = {a: 1};
+
+ o.bla = 2;
+ o.bla2 = 2;
+ o.bla3 = 2;
+ o.bla4 = 2;
+
+ if (b) {
+ o.b = 2;
+ } else {
+ o.c = 2;
+ }
+
+ o.d = 3;
+
+ assertEq(o.a, 1);
+ if (b) {
+ assertEq(o.b, 2);
+ assertEq('c' in o, false);
+ } else {
+ assertEq('b' in o, false);
+ assertEq(o.c, 2);
+ }
+ assertEq(o.d, 3);
+}
+
+function f() {
+ for (var i = 0; i < 10; i++) {
+ simple();
+ condition1(i % 2 == 0)
+ condition2(i % 2 == 0)
+ condition3(i % 2 == 0)
+ condition4(i % 2 == 0)
+ }
+}
+
+for (var i = 0; i < 10; i++) {
+ f();
+}
diff --git a/js/src/jit-test/tests/warp/small-inlinable-builtins.js b/js/src/jit-test/tests/warp/small-inlinable-builtins.js
new file mode 100644
index 0000000000..d346894f6a
--- /dev/null
+++ b/js/src/jit-test/tests/warp/small-inlinable-builtins.js
@@ -0,0 +1,10 @@
+// Ensure certain self-hosted built-in functions are small enough to be inlinable.
+
+assertEq(isSmallFunction(isFinite), true);
+assertEq(isSmallFunction(isNaN), true);
+
+assertEq(isSmallFunction(Number.isFinite), true);
+assertEq(isSmallFunction(Number.isNaN), true);
+
+assertEq(isSmallFunction(Number.isInteger), true);
+assertEq(isSmallFunction(Number.isSafeInteger), true);
diff --git a/js/src/jit-test/tests/warp/string-char.js b/js/src/jit-test/tests/warp/string-char.js
new file mode 100644
index 0000000000..fc41e5079a
--- /dev/null
+++ b/js/src/jit-test/tests/warp/string-char.js
@@ -0,0 +1,15 @@
+function f(x) {
+ assertEq(x.charCodeAt(1), 0x62);
+ assertEq(x.charAt(1), "b");
+ assertEq(x[1], "b");
+}
+
+function g() {
+ for (var i = 0; i < 100; i++) {
+ f("abc");
+ }
+}
+
+for (var j = 0; j < 10; j++) {
+ g();
+}
diff --git a/js/src/jit-test/tests/warp/super-native-newtarget.js b/js/src/jit-test/tests/warp/super-native-newtarget.js
new file mode 100644
index 0000000000..3f9fb24a3a
--- /dev/null
+++ b/js/src/jit-test/tests/warp/super-native-newtarget.js
@@ -0,0 +1,20 @@
+class A {}
+
+class B extends A {
+ constructor() {
+ super();
+ }
+}
+
+function h() {}
+h = h.bind();
+
+function f() {
+ for (var i = 0; i < 1000; ++i) {
+ var o = Reflect.construct(B, [], h);
+ }
+}
+
+for (var i = 0; i < 5; ++i) {
+ f();
+}
diff --git a/js/src/jit-test/tests/warp/typedarray-element-exists.js b/js/src/jit-test/tests/warp/typedarray-element-exists.js
new file mode 100644
index 0000000000..623ad672cb
--- /dev/null
+++ b/js/src/jit-test/tests/warp/typedarray-element-exists.js
@@ -0,0 +1,46 @@
+function inBounds() {
+ var ta = new Int32Array(10);
+
+ for (var i = 0; i < 100; ++i) {
+ var index = i & 7;
+ assertEq(index in ta, true);
+ }
+}
+inBounds();
+
+function outOfBounds() {
+ var ta = new Int32Array(10);
+
+ for (var i = 0; i < 100; ++i) {
+ var index = 10 + (i & 7);
+ assertEq(index in ta, false);
+
+ var largeIndex = 2147483647 - (i & 1);
+ assertEq(largeIndex in ta, false);
+ }
+}
+outOfBounds();
+
+function negativeIndex() {
+ var ta = new Int32Array(10);
+
+ for (var i = 0; i < 100; ++i) {
+ var index = -(1 + (i & 7));
+ assertEq(index in ta, false);
+
+ var largeIndex = -2147483647 - (i & 1);
+ assertEq(largeIndex in ta, false);
+ }
+}
+negativeIndex();
+
+function emptyArray() {
+ var ta = new Int32Array(0);
+
+ for (var i = 0; i < 100; ++i) {
+ var index = i & 7;
+ assertEq(index in ta, false);
+ assertEq(-index in ta, false);
+ }
+}
+emptyArray();
diff --git a/js/src/jit-test/tests/warp/typedarrayindextoint32.js b/js/src/jit-test/tests/warp/typedarrayindextoint32.js
new file mode 100644
index 0000000000..5333ada53e
--- /dev/null
+++ b/js/src/jit-test/tests/warp/typedarrayindextoint32.js
@@ -0,0 +1,10 @@
+function f(ta, i) {
+ var x = i + 0.2;
+ return ta[i] + ta[i | 0] + ta[x - 0.2];
+}
+
+var ta = new Int32Array(10);
+var xs = [0, 1, 2, -1];
+for (var i = 0; i < 100_000; ++i) {
+ assertEq(f(ta, xs[i & 3]), (i & 3) == 3 ? NaN : 0);
+}