summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--js/src/jit-test/lib/pretenure.js18
-rw-r--r--js/src/jit-test/tests/arrays/sort-trampoline.js153
-rw-r--r--js/src/jit-test/tests/basic/bug1875795.js7
-rw-r--r--js/src/jit-test/tests/basic/bug1888746.js12
-rw-r--r--js/src/jit-test/tests/basic/bug1890200.js12
-rw-r--r--js/src/jit-test/tests/cacheir/bug1888346.js8
-rw-r--r--js/src/jit-test/tests/collections/bug-1884927.js10
-rw-r--r--js/src/jit-test/tests/collections/bug-1885775.js12
-rw-r--r--js/src/jit-test/tests/collections/bug-1887939-1.js7
-rw-r--r--js/src/jit-test/tests/collections/bug-1887939-2.js7
-rw-r--r--js/src/jit-test/tests/debug/Debugger-onNativeCall-03.js18
-rw-r--r--js/src/jit-test/tests/debug/Environment-methods-toPrimitive.js21
-rw-r--r--js/src/jit-test/tests/debug/Frame-onStep-21.js19
-rw-r--r--js/src/jit-test/tests/debug/private-methods-eval-in-frame.js9
-rw-r--r--js/src/jit-test/tests/errors/bug-1886940-2.js6
-rw-r--r--js/src/jit-test/tests/errors/bug-1886940.js2
-rw-r--r--js/src/jit-test/tests/fuses/optimized-getiterator-invalidation.js37
-rw-r--r--js/src/jit-test/tests/gc/alllcation-metadata-builder-over-recursion.js22
-rw-r--r--js/src/jit-test/tests/gc/bug-1568740.js2
-rw-r--r--js/src/jit-test/tests/gc/bug-1569840.js2
-rw-r--r--js/src/jit-test/tests/gc/bug-1885819-2.js12
-rw-r--r--js/src/jit-test/tests/gc/bug-1885819.js10
-rw-r--r--js/src/jit-test/tests/gc/bug-1886466.js5
-rw-r--r--js/src/jit-test/tests/gc/bug-1888717.js3
-rw-r--r--js/src/jit-test/tests/gc/dedupe-03.js66
-rw-r--r--js/src/jit-test/tests/gc/deduplicateTenuringStrings.js1
-rw-r--r--js/src/jit-test/tests/gc/gcparam.js1
-rw-r--r--js/src/jit-test/tests/gc/pretenuring.js1
-rw-r--r--js/src/jit-test/tests/heap-analysis/byteSize-of-string.js87
-rw-r--r--js/src/jit-test/tests/ion/apply-native-arguments-object.js46
-rw-r--r--js/src/jit-test/tests/ion/apply-native-arguments.js39
-rw-r--r--js/src/jit-test/tests/ion/apply-native-array.js39
-rw-r--r--js/src/jit-test/tests/ion/apply-native-spreadcall-arguments.js39
-rw-r--r--js/src/jit-test/tests/ion/apply-native-spreadcall-array.js39
-rw-r--r--js/src/jit-test/tests/ion/apply-native-spreadcall-rest.js39
-rw-r--r--js/src/jit-test/tests/ion/apply-native-spreadnew-arguments.js39
-rw-r--r--js/src/jit-test/tests/ion/apply-native-spreadnew-array.js39
-rw-r--r--js/src/jit-test/tests/ion/apply-native-spreadnew-newtarget.js66
-rw-r--r--js/src/jit-test/tests/ion/apply-native-spreadnew-rest.js39
-rw-r--r--js/src/jit-test/tests/ion/recover-atomics-islockfree.js25
-rw-r--r--js/src/jit-test/tests/ion/recover-string-from-charcode.js13
-rw-r--r--js/src/jit-test/tests/modules/bug-1888902.js16
-rw-r--r--js/src/jit-test/tests/modules/dynamic-import-error.js2
-rw-r--r--js/src/jit-test/tests/modules/dynamic-import-module.js2
-rw-r--r--js/src/jit-test/tests/modules/inline-data-2.js12
-rw-r--r--js/src/jit-test/tests/modules/inline-data.js13
-rw-r--r--js/src/jit-test/tests/modules/shell-wrapper.js7
-rw-r--r--js/src/jit-test/tests/parser/bug1887176.js46
-rw-r--r--js/src/jit-test/tests/parser/dumpStencil-02.js8
-rw-r--r--js/src/jit-test/tests/parser/module-filename.js13
-rw-r--r--js/src/jit-test/tests/profiler/native-trampoline-2.js7
-rw-r--r--js/src/jit-test/tests/profiler/native-trampoline-3.js32
-rw-r--r--js/src/jit-test/tests/profiler/native-trampoline.js40
-rw-r--r--js/src/jit-test/tests/profiler/wasm-to-js-1.js20
-rw-r--r--js/src/jit-test/tests/profiler/wasm-to-js-2.js19
-rw-r--r--js/src/jit-test/tests/promise/allSettled-dead.js20
-rw-r--r--js/src/jit-test/tests/promise/jobqueue-interrupt-01.js23
-rw-r--r--js/src/jit-test/tests/promise/jobqueue-interrupt-02.js14
-rw-r--r--js/src/jit-test/tests/proxy/bug1885774.js25
-rw-r--r--js/src/jit-test/tests/structured-clone/bug1888727.js21
-rw-r--r--js/src/jit-test/tests/structured-clone/tenuring.js3
-rw-r--r--js/src/jit-test/tests/typedarray/resizable-typedarray-from-pinned-buffer.js9
-rw-r--r--js/src/jit-test/tests/warp/bug1876425.js62
-rw-r--r--js/src/jit-test/tests/wasm/directiveless/bug1877358.js2
-rw-r--r--js/src/jit-test/tests/wasm/gc/casting.js69
-rw-r--r--js/src/jit-test/tests/wasm/gc/i31ref.js18
-rw-r--r--js/src/jit-test/tests/wasm/regress/bug1886870.js8
-rw-r--r--js/src/jit-test/tests/wasm/regress/bug1887535.js25
-rw-r--r--js/src/jit-test/tests/wasm/regress/bug1887596.js14
69 files changed, 1523 insertions, 59 deletions
diff --git a/js/src/jit-test/lib/pretenure.js b/js/src/jit-test/lib/pretenure.js
index 214f1d44d1..c1184fefc4 100644
--- a/js/src/jit-test/lib/pretenure.js
+++ b/js/src/jit-test/lib/pretenure.js
@@ -22,8 +22,12 @@ function setupPretenureTest() {
gczeal(0);
// Restrict nursery size so we can fill it quicker, and ensure it is resized.
- gcparam("minNurseryBytes", 1024 * 1024);
- gcparam("maxNurseryBytes", 1024 * 1024);
+ let size = 1024 * 1024;
+ if (gcparam("semispaceNurseryEnabled")) {
+ size *= 2;
+ }
+ gcparam("minNurseryBytes", size);
+ gcparam("maxNurseryBytes", size);
// Limit allocation threshold so we trigger major GCs sooner.
gcparam("allocationThreshold", 1 /* MB */);
@@ -67,8 +71,14 @@ function allocateArrays(count, longLived) {
}
function gcCounts() {
- return { minor: gcparam("minorGCNumber"),
- major: gcparam("majorGCNumber") };
+ let major = gcparam("majorGCNumber")
+ let minor = gcparam("minorGCNumber");
+
+ // Only report minor collections that didn't happen as part of a major GC.
+ assertEq(minor >= major, true);
+ minor -= major;
+
+ return { minor, major };
}
function runTestAndCountCollections(thunk) {
diff --git a/js/src/jit-test/tests/arrays/sort-trampoline.js b/js/src/jit-test/tests/arrays/sort-trampoline.js
new file mode 100644
index 0000000000..b81d4628b0
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/sort-trampoline.js
@@ -0,0 +1,153 @@
+function testGC() {
+ var arr = [{n: 1}, {n: 3}, {n: 0}, {n: 5}];
+ for (var i = 0; i < 20; i++) {
+ arr.sort((x, y) => {
+ if (i === 17) {
+ gc();
+ }
+ return x.n - y.n;
+ });
+ }
+ assertEq(arr.map(x => x.n).join(""), "0135");
+}
+testGC();
+
+function testException() {
+ var arr = [{n: 1}, {n: 3}, {n: 0}, {n: 5}];
+ var ex;
+ try {
+ for (var i = 0; i < 20; i++) {
+ arr.sort((x, y) => {
+ if (i === 17) {
+ throw "fit";
+ }
+ return x.n - y.n;
+ });
+ }
+ } catch (e) {
+ ex = e;
+ }
+ assertEq(ex, "fit");
+ assertEq(i, 17);
+}
+testException();
+
+function testRectifier() {
+ var arr = [{n: 1}, {n: 3}, {n: 0}, {n: 5}];
+ for (var i = 0; i < 20; i++) {
+ arr.sort(function(x, y, a) {
+ assertEq(arguments.length, 2);
+ assertEq(a, undefined);
+ return y.n - x.n;
+ });
+ }
+ assertEq(arr.map(x => x.n).join(""), "5310");
+}
+testRectifier();
+
+function testClassConstructor() {
+ var normal = (x, y) => x.n - y.n;
+ var dummy = {};
+ var ctor = (class { constructor(x, y) {
+ assertEq(x, dummy);
+ }});
+ // Warm up the constructor.
+ for (var i = 0; i < 20; i++) {
+ new ctor(dummy, dummy);
+ }
+ for (var i = 0; i < 20; i++) {
+ var arr = [{n: 1}, {n: 3}, {n: 0}, {n: 5}];
+ var ex;
+ try {
+ arr.sort(i < 17 ? normal : ctor);
+ } catch (e) {
+ ex = e;
+ }
+ assertEq(ex instanceof TypeError, i >= 17);
+ assertEq(arr.map(x => x.n).join(""), i >= 17 ? "1305" : "0135");
+ }
+}
+testClassConstructor();
+
+function testSwitchRealms() {
+ var arr = [{n: 1}, {n: 3}, {n: 0}, {n: 5}];
+ var g = newGlobal({sameCompartmentAs: this});
+ g.foo = 123;
+ var comp = g.evaluate(`((x, y) => {
+ assertEq(foo, 123);
+ return x.n - y.n;
+ })`);
+ for (var i = 0; i < 20; i++) {
+ arr.sort(comp);
+ }
+ assertEq(arr.map(x => x.n).join(""), "0135");
+}
+testSwitchRealms();
+
+function testCrossCompartment() {
+ var arr = [{n: 1}, {n: 3}, {n: 0}, {n: 5}];
+ var g = newGlobal({newCompartment: true});
+ var wrapper = g.evaluate(`((x, y) => {
+ return x.n - y.n;
+ })`);
+ for (var i = 0; i < 20; i++) {
+ arr.sort(wrapper);
+ }
+ assertEq(arr.map(x => x.n).join(""), "0135");
+}
+testCrossCompartment();
+
+function testBound() {
+ var arr = [{n: 1}, {n: 3}, {n: 0}, {n: 5}];
+ var fun = (function(a, x, y) {
+ "use strict";
+ assertEq(this, null);
+ assertEq(a, 1);
+ return x.n - y.n;
+ }).bind(null, 1);
+ for (var i = 0; i < 20; i++) {
+ arr.sort(fun);
+ }
+ assertEq(arr.map(x => x.n).join(""), "0135");
+}
+testBound();
+
+function testExtraArgs() {
+ var arr = [{n: 1}, {n: 3}, {n: 0}, {n: 5}];
+ var cmp = (x, y) => x.n - y.n;
+ for (var i = 0; i < 20; i++) {
+ arr.sort(cmp, cmp, cmp, cmp, cmp, cmp, cmp);
+ }
+ assertEq(arr.map(x => x.n).join(""), "0135");
+}
+testExtraArgs();
+
+function testBailout() {
+ var arr = [{n: 1}, {n: 3}, {n: 0}, {n: 5}];
+ for (var i = 0; i < 110; i++) {
+ arr.sort(function(x, y) {
+ if (i === 108) {
+ bailout();
+ }
+ return x.n - y.n;
+ });
+ }
+ assertEq(arr.map(x => x.n).join(""), "0135");
+}
+testBailout();
+
+function testExceptionHandlerSwitchRealm() {
+ var g = newGlobal({sameCompartmentAs: this});
+ for (var i = 0; i < 25; i++) {
+ var ex = null;
+ try {
+ g.Array.prototype.toSorted.call([2, 3], () => {
+ throw "fit";
+ });
+ } catch (e) {
+ ex = e;
+ }
+ assertEq(ex, "fit");
+ }
+}
+testExceptionHandlerSwitchRealm();
diff --git a/js/src/jit-test/tests/basic/bug1875795.js b/js/src/jit-test/tests/basic/bug1875795.js
new file mode 100644
index 0000000000..1a5b54acfe
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug1875795.js
@@ -0,0 +1,7 @@
+// |jit-test| --fast-warmup; --no-threads; skip-if: !('oomTest' in this)
+oomTest(function() {
+ var o = {};
+ for (var p in this) {
+ o[p] = 1;
+ }
+});
diff --git a/js/src/jit-test/tests/basic/bug1888746.js b/js/src/jit-test/tests/basic/bug1888746.js
new file mode 100644
index 0000000000..8e6d0cd0b9
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug1888746.js
@@ -0,0 +1,12 @@
+function comparator(x, y) {
+ saveStack();
+ return {valueOf: function() {
+ saveStack();
+ return x - y;
+ }};
+}
+for (let i = 0; i < 20; i++) {
+ let arr = [3, 1, 2];
+ arr.sort(comparator);
+ assertEq(arr.toString(), "1,2,3");
+}
diff --git a/js/src/jit-test/tests/basic/bug1890200.js b/js/src/jit-test/tests/basic/bug1890200.js
new file mode 100644
index 0000000000..caa97fcece
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug1890200.js
@@ -0,0 +1,12 @@
+let triggerGC = false;
+let proxy = new Proxy({}, {get: function(target, key) {
+ if (key === "sameCompartmentAs" || key === "sameZoneAs") {
+ triggerGC = true;
+ return newGlobal({newCompartment: true});
+ }
+ if (triggerGC) {
+ gc();
+ triggerGC = false;
+ }
+}});
+newGlobal(proxy);
diff --git a/js/src/jit-test/tests/cacheir/bug1888346.js b/js/src/jit-test/tests/cacheir/bug1888346.js
new file mode 100644
index 0000000000..8e63d86089
--- /dev/null
+++ b/js/src/jit-test/tests/cacheir/bug1888346.js
@@ -0,0 +1,8 @@
+setJitCompilerOption("ion.frequent-bailout-threshold", 1);
+for (let i = 0; i < 49; i++) {
+ (function () {
+ let x = new (function () {})();
+ Object.defineProperty(x, "z", {});
+ x.z;
+ })();
+}
diff --git a/js/src/jit-test/tests/collections/bug-1884927.js b/js/src/jit-test/tests/collections/bug-1884927.js
new file mode 100644
index 0000000000..263d9df8a0
--- /dev/null
+++ b/js/src/jit-test/tests/collections/bug-1884927.js
@@ -0,0 +1,10 @@
+// |jit-test| --enable-symbols-as-weakmap-keys; skip-if: getBuildConfiguration("release_or_beta")
+for (x=0; x<10000; ++x) {
+ try {
+ m13 = new WeakMap;
+ sym = Symbol();
+ m13.set(sym, new Debugger);
+ startgc(1, );
+ } catch (exc) {}
+}
+
diff --git a/js/src/jit-test/tests/collections/bug-1885775.js b/js/src/jit-test/tests/collections/bug-1885775.js
new file mode 100644
index 0000000000..bc14c6d58b
--- /dev/null
+++ b/js/src/jit-test/tests/collections/bug-1885775.js
@@ -0,0 +1,12 @@
+// |jit-test| --enable-symbols-as-weakmap-keys; skip-if: getBuildConfiguration("release_or_beta")
+var code = `
+var m58 = new WeakMap;
+var sym = Symbol();
+m58.set(sym, ({ entry16: 0, length: 1 }));
+function testCompacting() {
+ gcslice(50000);
+}
+testCompacting(2, 100000, 50000);
+`;
+for (x = 0; x < 10000; ++x)
+ evaluate(code);
diff --git a/js/src/jit-test/tests/collections/bug-1887939-1.js b/js/src/jit-test/tests/collections/bug-1887939-1.js
new file mode 100644
index 0000000000..292c44d492
--- /dev/null
+++ b/js/src/jit-test/tests/collections/bug-1887939-1.js
@@ -0,0 +1,7 @@
+var map = new WeakMap();
+var sym = Symbol();
+try {
+ map.set(sym, 1);
+} catch (e) {
+ assertEq(!!e.message.match(/an unregistered symbol/), false);
+}
diff --git a/js/src/jit-test/tests/collections/bug-1887939-2.js b/js/src/jit-test/tests/collections/bug-1887939-2.js
new file mode 100644
index 0000000000..2ec4e4c585
--- /dev/null
+++ b/js/src/jit-test/tests/collections/bug-1887939-2.js
@@ -0,0 +1,7 @@
+// |jit-test| --enable-symbols-as-weakmap-keys; skip-if: getBuildConfiguration("release_or_beta")
+var map = new WeakMap();
+try {
+ map.set(1, 1);
+} catch (e) {
+ assertEq(!!e.message.match(/an unregistered symbol/), true);
+}
diff --git a/js/src/jit-test/tests/debug/Debugger-onNativeCall-03.js b/js/src/jit-test/tests/debug/Debugger-onNativeCall-03.js
index 7e9c0b280a..27ab5b2b23 100644
--- a/js/src/jit-test/tests/debug/Debugger-onNativeCall-03.js
+++ b/js/src/jit-test/tests/debug/Debugger-onNativeCall-03.js
@@ -1,4 +1,5 @@
-// Test onNativeCall's behavior when used with self-hosted functions.
+// Test onNativeCall's behavior when used with self-hosted functions
+// and trampoline natives.
load(libdir + 'eqArrayHelper.js');
@@ -18,13 +19,22 @@ dbg.onNativeCall = f => {
gdbg.executeInGlobal(`
var x = [1,3,2];
+ x.forEach((a) => {print(a)});
x.sort((a, b) => {print(a)});
+ x.sort(print);
`);
assertEqArray(rv, [
- "EnterFrame", "sort",
- "ArraySortCompare/<",
+ "EnterFrame", "forEach",
"EnterFrame", "print",
- "ArraySortCompare/<",
"EnterFrame", "print",
+ "EnterFrame", "print",
+
+ "sort",
+ "EnterFrame","print",
+ "EnterFrame","print",
+
+ "sort",
+ "print",
+ "print"
]);
diff --git a/js/src/jit-test/tests/debug/Environment-methods-toPrimitive.js b/js/src/jit-test/tests/debug/Environment-methods-toPrimitive.js
new file mode 100644
index 0000000000..106728901d
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Environment-methods-toPrimitive.js
@@ -0,0 +1,21 @@
+// removeDebuggee can be called through ToPrimitive while converting the argument
+// passed to Debugger.Environment.{find,getVariable,setVariable} to string.
+
+var g = newGlobal({newCompartment: true});
+g.eval("function f() { debugger; }");
+var dbg = new Debugger();
+var oddball = {[Symbol.toPrimitive]: () => dbg.removeDebuggee(g)};
+
+for (var method of ["find", "getVariable", "setVariable"]) {
+ dbg.addDebuggee(g);
+ dbg.onDebuggerStatement = frame => {
+ var ex;
+ try {
+ frame.environment[method](oddball, oddball);
+ } catch (e) {
+ ex = e;
+ }
+ assertEq(ex.message, "Debugger.Environment is not a debuggee environment");
+ };
+ g.f();
+}
diff --git a/js/src/jit-test/tests/debug/Frame-onStep-21.js b/js/src/jit-test/tests/debug/Frame-onStep-21.js
new file mode 100644
index 0000000000..7bea2e3a95
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onStep-21.js
@@ -0,0 +1,19 @@
+// |jit-test| error: too much recursion
+
+// Generator closed due to over-recursion shouldn't cause crash around onStep.
+
+async function* foo() {
+ const g = this.newGlobal({sameZoneAs: this});
+ g.Debugger(this).getNewestFrame().onStep = g.evaluate(`(function() {})`);
+ return {};
+}
+function f() {
+ try {
+ f.apply(undefined, f);
+ } catch {
+ drainJobQueue();
+ foo().next();
+ }
+}
+foo().next();
+f();
diff --git a/js/src/jit-test/tests/debug/private-methods-eval-in-frame.js b/js/src/jit-test/tests/debug/private-methods-eval-in-frame.js
index 5122cfa56b..318a36f614 100644
--- a/js/src/jit-test/tests/debug/private-methods-eval-in-frame.js
+++ b/js/src/jit-test/tests/debug/private-methods-eval-in-frame.js
@@ -150,13 +150,6 @@ if ('dis' in this) {
assertEq(b.ef(`var x = () => { return this.#priv(); }; x()`), 12);
assertEq(b.ef(`function x(o) { function y(o) { return o.#priv(); }; return y(o); } x(this)`), 12);
-assertEq(b.ef("B.#smethod()"), 14)
-assertEq(b.ef("B.#unusedmethod()"), 19);
-assertEq(b.ef("B.#unusedgetter"), 10);
-
-b.ef("B.#unusedsetter = 19");
-assertEq(B.setter, 19);
-
assertEq(B.f(), 14);
assertEq(B.sef(`this.#smethod()`), 14);
assertEq(B.sLayerEf(`this.#smethod()`), 14);
@@ -215,4 +208,4 @@ var x = () => {
})();
};
x()
-`), 12); \ No newline at end of file
+`), 12);
diff --git a/js/src/jit-test/tests/errors/bug-1886940-2.js b/js/src/jit-test/tests/errors/bug-1886940-2.js
new file mode 100644
index 0000000000..654071be04
--- /dev/null
+++ b/js/src/jit-test/tests/errors/bug-1886940-2.js
@@ -0,0 +1,6 @@
+oomTest(function () {
+ (function () {
+ var x = [disassemble, new Int8Array(2 ** 8 + 1)];
+ x.shift().apply([], x);
+ })();
+});
diff --git a/js/src/jit-test/tests/errors/bug-1886940.js b/js/src/jit-test/tests/errors/bug-1886940.js
new file mode 100644
index 0000000000..f8d3020d8c
--- /dev/null
+++ b/js/src/jit-test/tests/errors/bug-1886940.js
@@ -0,0 +1,2 @@
+// |jit-test| error: RangeError
+[].with(Symbol.hasInstance);
diff --git a/js/src/jit-test/tests/fuses/optimized-getiterator-invalidation.js b/js/src/jit-test/tests/fuses/optimized-getiterator-invalidation.js
new file mode 100644
index 0000000000..6505f8d023
--- /dev/null
+++ b/js/src/jit-test/tests/fuses/optimized-getiterator-invalidation.js
@@ -0,0 +1,37 @@
+
+const ITERS = 1000;
+
+// A function which when warp compiled should use
+// OptimizedGetIterator elision, and rely on invalidation
+function f(x) {
+ let sum = 0;
+ for (let i = 0; i < ITERS; i++) {
+ const [a, b, c] = x
+ sum = a + b + c;
+ }
+ return sum
+}
+
+// Run the function f 1000 times to warp compile it. Use 4 elements here to ensure
+// the return property of the ArrayIteratorPrototype is called.
+let arr = [1, 2, 3, 4];
+for (let i = 0; i < 1000; i++) {
+ f(arr);
+}
+
+// Initialize the globally scoped counter
+let counter = 0;
+const ArrayIteratorPrototype = Object.getPrototypeOf([][Symbol.iterator]());
+
+// Setting the return property should invalidate the warp script here.
+ArrayIteratorPrototype.return = function () {
+ counter++;
+ return { done: true };
+};
+
+
+// Call f one more time
+f(arr);
+
+// Use assertEq to check the value of counter.
+assertEq(counter, ITERS);
diff --git a/js/src/jit-test/tests/gc/alllcation-metadata-builder-over-recursion.js b/js/src/jit-test/tests/gc/alllcation-metadata-builder-over-recursion.js
new file mode 100644
index 0000000000..67093026b4
--- /dev/null
+++ b/js/src/jit-test/tests/gc/alllcation-metadata-builder-over-recursion.js
@@ -0,0 +1,22 @@
+// |jit-test| allow-unhandlable-oom
+
+// Over-recursion should suppress alloation metadata builder, to avoid another
+// over-recursion while generating an error object for the first over-recursion.
+//
+// This test should catch the error for the "load" testing function's arguments,
+// or crash with unhandlable OOM inside allocation metadata builder.
+
+const g = newGlobal();
+g.enableShellAllocationMetadataBuilder();
+function run() {
+ const g_load = g.load;
+ g_load.toString = run;
+ return g_load(g_load);
+}
+let caught = false;
+try {
+ run();
+} catch (e) {
+ caught = true;
+}
+assertEq(caught, true);
diff --git a/js/src/jit-test/tests/gc/bug-1568740.js b/js/src/jit-test/tests/gc/bug-1568740.js
index 6cc003cb94..5c311b855d 100644
--- a/js/src/jit-test/tests/gc/bug-1568740.js
+++ b/js/src/jit-test/tests/gc/bug-1568740.js
@@ -1,11 +1,11 @@
gczeal(0);
+gcparam("semispaceNurseryEnabled", 0);
function setAndTest(param, value) {
gcparam(param, value);
assertEq(gcparam(param), value);
}
-
// Set a large nursery size.
setAndTest("maxNurseryBytes", 1024*1024);
setAndTest("minNurseryBytes", 1024*1024);
diff --git a/js/src/jit-test/tests/gc/bug-1569840.js b/js/src/jit-test/tests/gc/bug-1569840.js
index 70d28add73..45df339405 100644
--- a/js/src/jit-test/tests/gc/bug-1569840.js
+++ b/js/src/jit-test/tests/gc/bug-1569840.js
@@ -1,5 +1,5 @@
-
gczeal(0);
+gcparam("semispaceNurseryEnabled", 0);
gcparam("maxNurseryBytes", 1024*1024);
gcparam("minNurseryBytes", 1024*1024);
diff --git a/js/src/jit-test/tests/gc/bug-1885819-2.js b/js/src/jit-test/tests/gc/bug-1885819-2.js
new file mode 100644
index 0000000000..a87e4c701a
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1885819-2.js
@@ -0,0 +1,12 @@
+let g = newGlobal();
+function f() {
+ var o = {};
+ o["prop" + Date.now()] = 1;
+ gc();
+ schedulezone("atoms");
+ schedulezone(g);
+ gc("zone");
+ let [x] = [0];
+}
+f();
+oomTest(f);
diff --git a/js/src/jit-test/tests/gc/bug-1885819.js b/js/src/jit-test/tests/gc/bug-1885819.js
new file mode 100644
index 0000000000..8341c3ff52
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1885819.js
@@ -0,0 +1,10 @@
+function f() {
+ var o = {};
+ o["prop" + Date.now()] = 1;
+ gc();
+ schedulezone("atoms");
+ gc("zone");
+ let [x] = [0];
+}
+f();
+oomTest(f);
diff --git a/js/src/jit-test/tests/gc/bug-1886466.js b/js/src/jit-test/tests/gc/bug-1886466.js
new file mode 100644
index 0000000000..4347ea3e6b
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1886466.js
@@ -0,0 +1,5 @@
+gczeal(7, 6)
+a = new WeakSet
+for (let i = 0; i < 200000; i++) {
+ a.add({})
+}
diff --git a/js/src/jit-test/tests/gc/bug-1888717.js b/js/src/jit-test/tests/gc/bug-1888717.js
new file mode 100644
index 0000000000..7e54543994
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1888717.js
@@ -0,0 +1,3 @@
+// |jit-test| --no-ggc
+gcparam("semispaceNurseryEnabled", 1);
+let o = {};
diff --git a/js/src/jit-test/tests/gc/dedupe-03.js b/js/src/jit-test/tests/gc/dedupe-03.js
new file mode 100644
index 0000000000..4e9b4c1bbc
--- /dev/null
+++ b/js/src/jit-test/tests/gc/dedupe-03.js
@@ -0,0 +1,66 @@
+// |jit-test| skip-if: !hasFunction.stringRepresentation
+
+// Test handling of tenured dependent strings pointing to nursery base strings.
+
+gczeal(0);
+
+function makeExtensibleStrFrom(str) {
+ var left = str.substr(0, str.length/2);
+ var right = str.substr(str.length/2, str.length);
+ var ropeStr = left + right;
+ return ensureLinearString(ropeStr);
+}
+
+function repr(s) {
+ return JSON.parse(stringRepresentation(s));
+}
+
+function dependsOn(s1, s2) {
+ const rep1 = JSON.parse(stringRepresentation(s1));
+ const rep2 = JSON.parse(stringRepresentation(s2));
+ return rep1.base && rep1.base.address == rep2.address;
+}
+
+// Make a string to deduplicate to.
+var original = makeExtensibleStrFrom('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklm');
+
+// Construct T1 -> Nbase.
+var Nbase = makeExtensibleStrFrom('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklm');
+var T1 = newDependentString(Nbase, 0, 60, { tenured: true });
+
+// Get prevented from creating T2 -> T1 -> Nbase
+// (will be T2 -> Nbase instead to avoid dependency chains).
+var T2 = newDependentString(T1, 30, { tenured: true });
+
+assertEq(dependsOn(T2, Nbase), "expect: T2 -> base");
+
+// Construct T1 -> Ndep1 (was Nbase) -> Nbase2.
+var Nbase2 = newRope(Nbase, "ABC");
+ensureLinearString(Nbase2);
+var Ndep1 = Nbase;
+
+assertEq(dependsOn(T1, Ndep1), "expect: T1 -> Ndep1");
+assertEq(dependsOn(Ndep1, Nbase2), "expect: Ndep1 -> Nbase2");
+
+// Fail to construct T3 -> Tbase3 -> Nbase4. It will refuse because T3 would be using
+// chars from Nbase4 that can't be updated since T3 is not in the store buffer. Instead,
+// it will allocate a new buffer for the rope root, leaving Tbase3 alone and keeping
+// T3 -> Tbase3.
+var Tbase3 = makeExtensibleStrFrom('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklm');
+minorgc();
+var T3 = newDependentString(Tbase3, 0, 30, { tenured: true });
+var Nbase4 = newRope(Tbase3, "DEF");
+ensureLinearString(Nbase4);
+assertEq(repr(Tbase3).isTenured, true, "Tbase3 is tenured");
+assertEq(repr(Tbase3).flags.includes("EXTENSIBLE"), true, "Tbase3 is extensible");
+assertEq(repr(Nbase4).flags.includes("DEPENDENT_BIT"), false, "expect: Nbase4 is not a dependent string")
+assertEq(repr(T3).flags.includes("DEPENDENT_BIT"), true, "expect: T3 is a dependent string")
+assertEq(dependsOn(T3, Tbase3), "expect: T3 -> Tbase3");
+
+function bug1879918() {
+ const s = JSON.parse('["abcdefabcdefabcdefabcdefabcdefabcdefabcdef"]')[0];
+ const dep = newDependentString(s, 1, { tenured: true });
+ minorgc();
+ assertEq(dep, "bcdefabcdefabcdefabcdefabcdefabcdefabcdef");
+}
+bug1879918();
diff --git a/js/src/jit-test/tests/gc/deduplicateTenuringStrings.js b/js/src/jit-test/tests/gc/deduplicateTenuringStrings.js
index 1b8259cc15..de2fb0c028 100644
--- a/js/src/jit-test/tests/gc/deduplicateTenuringStrings.js
+++ b/js/src/jit-test/tests/gc/deduplicateTenuringStrings.js
@@ -13,6 +13,7 @@
// We require predictable GC timing to make sure the correct
// strings are tenured together.
gczeal(0);
+gcparam('semispaceNurseryEnabled', 0);
var helperCode = `
function makeInlineStr(isLatin1) {
diff --git a/js/src/jit-test/tests/gc/gcparam.js b/js/src/jit-test/tests/gc/gcparam.js
index 05e0359088..c57b400642 100644
--- a/js/src/jit-test/tests/gc/gcparam.js
+++ b/js/src/jit-test/tests/gc/gcparam.js
@@ -60,3 +60,4 @@ testChangeParam("mallocThresholdBase");
testChangeParam("urgentThreshold");
testChangeParam("helperThreadRatio");
testChangeParam("maxHelperThreads");
+testChangeParam("semispaceNurseryEnabled");
diff --git a/js/src/jit-test/tests/gc/pretenuring.js b/js/src/jit-test/tests/gc/pretenuring.js
index 6f20706e9b..30156b0e98 100644
--- a/js/src/jit-test/tests/gc/pretenuring.js
+++ b/js/src/jit-test/tests/gc/pretenuring.js
@@ -1,6 +1,7 @@
// Test nursery string allocation and pretenuring.
gczeal(0);
+gcparam("semispaceNurseryEnabled", 0);
gcparam("minNurseryBytes", 4096 * 1024);
gcparam("maxNurseryBytes", 4096 * 1024);
diff --git a/js/src/jit-test/tests/heap-analysis/byteSize-of-string.js b/js/src/jit-test/tests/heap-analysis/byteSize-of-string.js
index aaac0c4f1f..b4cfdffb04 100644
--- a/js/src/jit-test/tests/heap-analysis/byteSize-of-string.js
+++ b/js/src/jit-test/tests/heap-analysis/byteSize-of-string.js
@@ -12,6 +12,7 @@
// stable.
gczeal(0); // Need to control when tenuring happens
+gcparam('semispaceNurseryEnabled', 0);
// Hack to skip this test if strings are not allocated in the nursery.
{
@@ -75,16 +76,20 @@ function tByteSize(str) {
// JSExternalString - limited by MaxStringLength - E
// JSThinInlineString 8 4 16 8 T
// JSFatInlineString 24 12 24 12 F
+// ThinInlineAtom 12 6 20 10 T
+// FatInlineAtom 20 10 20 10 F
// JSExtensibleString - limited by MaxStringLength - X
// Notes:
// - labels are suffixed with A for atoms and N for non-atoms
-// - atoms are 8 bytes larger than non-atoms, to store the atom's hash code.
+// - atoms store a 4 byte hash code, and some add to the size to adjust
// - Nursery-allocated strings require a header that stores the zone.
// Expected sizes based on type of string
const m32 = (getBuildConfiguration("pointer-byte-size") == 4);
-const TA = m32 ? 24 : 32; // ThinInlineString atom, includes a hash value
+const TA = m32 ? 24 : 32; // ThinInlineAtom (includes a hash value)
+const FA = m32 ? 32 : 32; // FatInlineAtom (includes a hash value)
+const NA = m32 ? 24 : 32; // NormalAtom
const TN = m32 ? 16 : 24; // ThinInlineString
const FN = m32 ? 32 : 32; // FatInlineString
const XN = m32 ? 16 : 24; // ExtensibleString, has additional storage buffer
@@ -95,8 +100,8 @@ const EN = m32 ? 16 : 24; // ExternalString
// A function that pads out a tenured size to the nursery size. We store a zone
// pointer in the nursery just before the string (4 bytes on 32-bit, 8 bytes on
// 64-bit), and the string struct itself must be 8-byte aligned (resulting in
-// +4 bytes on 32-bit, +0 bytes on 64-bit). The end result? Nursery strings are
-// 8 bytes larger.
+// +4 bytes on 32-bit, +0 bytes on 64-bit). The end result is that nursery
+// strings are 8 bytes larger.
const Nursery = m32 ? s => s + 4 + 4 : s => s + 8 + 0;
// Latin-1
@@ -130,6 +135,23 @@ assertEq(nByteSize("123456789.123456789.123456789.1"), s(Nursery(
assertEq(nByteSize("123456789.123456789.123456789.12"), s(Nursery(XN)+32,Nursery(XN)+32));
assertEq(nByteSize("123456789.123456789.123456789.123"), s(Nursery(XN)+64,Nursery(XN)+64));
+function Atom(s) { return Object.keys({ [s]: true })[0]; }
+assertEq(byteSize(Atom("1234567")), s(TA, TA));
+assertEq(byteSize(Atom("12345678")), s(TA, FA));
+assertEq(byteSize(Atom("123456789.12")), s(TA, FA));
+assertEq(byteSize(Atom("123456789.123")), s(FA, FA));
+assertEq(byteSize(Atom("123456789.12345")), s(FA, FA));
+assertEq(byteSize(Atom("123456789.123456")), s(FA, FA));
+assertEq(byteSize(Atom("123456789.1234567")), s(FA, FA));
+assertEq(byteSize(Atom("123456789.123456789.")), s(FA, FA));
+assertEq(byteSize(Atom("123456789.123456789.1")), s(NA+32, NA+32));
+assertEq(byteSize(Atom("123456789.123456789.123")), s(NA+32, NA+32));
+assertEq(byteSize(Atom("123456789.123456789.1234")), s(NA+32, NA+32));
+assertEq(byteSize(Atom("123456789.123456789.12345")), s(NA+32, NA+32));
+assertEq(byteSize(Atom("123456789.123456789.123456789.1")), s(NA+32, NA+32));
+assertEq(byteSize(Atom("123456789.123456789.123456789.12")), s(NA+32, NA+32));
+assertEq(byteSize(Atom("123456789.123456789.123456789.123")), s(NA+48, NA+48));
+
// Inline char16_t atoms.
// "Impassionate gods have never seen the red that is the Tatsuta River."
// - Ariwara no Narihira
@@ -183,20 +205,43 @@ assertEq(byteSize(rope8), s(Nurser
minorgc();
assertEq(byteSize(rope8), s(RN, RN));
var matches8 = rope8.match(/(de cuyo nombre no quiero acordarme)/);
-assertEq(byteSize(rope8), s(XN + 65536, XN + 65536));
+assertEq(byteSize(rope8), s(XN + 64 * 1024, XN + 64 * 1024));
+var ext8 = rope8; // Stop calling it what it's not (though it'll change again soon.)
// Test extensible strings.
//
// Appending another copy of the fragment should yield another rope.
//
-// Flatting that should turn the original rope into a dependent string, and
+// Flattening that should turn the original rope into a dependent string, and
// yield a new linear string, of the same size as the original.
-rope8a = rope8 + fragment8;
+var rope8a = ext8 + fragment8;
assertEq(byteSize(rope8a), s(Nursery(RN), Nursery(RN)));
rope8a.match(/x/, function() { assertEq(true, false); });
assertEq(byteSize(rope8a), s(Nursery(XN) + 65536, Nursery(XN) + 65536));
+assertEq(byteSize(ext8), s(DN, DN));
+
+// Latin-1 dependent strings in the nursery.
+assertEq(byteSize(ext8.substr(1000, 2000)), s(Nursery(DN), Nursery(DN)));
+assertEq(byteSize(matches8[0]), s(Nursery(DN), Nursery(DN)));
+assertEq(byteSize(matches8[1]), s(Nursery(DN), Nursery(DN)));
+
+// Tenure everything and do it again.
+ext8 = copyString(ext8);
+rope8a = ext8 + fragment8;
+minorgc();
+assertEq(byteSize(rope8a), s(RN, RN));
+rope8a.match(/x/, function() { assertEq(true, false); });
+assertEq(byteSize(rope8a), s(XN + 65536, XN + 65536));
assertEq(byteSize(rope8), s(RN, RN));
+// Latin-1 tenured dependent strings.
+function tenure(s) {
+ minorgc();
+ return s;
+}
+assertEq(byteSize(tenure(rope8.substr(1000, 2000))), s(DN, DN));
+assertEq(byteSize(matches8[0]), s(DN, DN));
+assertEq(byteSize(matches8[1]), s(DN, DN));
// A char16_t rope. This changes size when flattened.
// "From the Heliconian Muses let us begin to sing"
@@ -207,13 +252,11 @@ for (var i = 0; i < 10; i++) // 1024 repetitions
rope16 = rope16 + rope16;
assertEq(byteSize(rope16), s(Nursery(RN), Nursery(RN)));
let matches16 = rope16.match(/(Ἑλικωνιάδων ἀρχώμεθ᾽)/);
-assertEq(byteSize(rope16), s(Nursery(RN) + 131072, Nursery(RN) + 131072));
+assertEq(byteSize(rope16), s(Nursery(XN) + 128 * 1024, Nursery(XN) + 128 * 1024));
+var ext16 = rope16;
-// Latin-1 and char16_t dependent strings.
-assertEq(byteSize(rope8.substr(1000, 2000)), s(Nursery(DN), Nursery(DN)));
-assertEq(byteSize(rope16.substr(1000, 2000)), s(Nursery(DN), Nursery(DN)));
-assertEq(byteSize(matches8[0]), s(Nursery(DN), Nursery(DN)));
-assertEq(byteSize(matches8[1]), s(Nursery(DN), Nursery(DN)));
+// char16_t dependent strings in the nursery.
+assertEq(byteSize(ext16.substr(1000, 2000)), s(Nursery(DN), Nursery(DN)));
assertEq(byteSize(matches16[0]), s(Nursery(DN), Nursery(DN)));
assertEq(byteSize(matches16[1]), s(Nursery(DN), Nursery(DN)));
@@ -221,13 +264,23 @@ assertEq(byteSize(matches16[1]), s(Nurser
//
// Appending another copy of the fragment should yield another rope.
//
-// Flatting that should turn the original rope into a dependent string, and
+// Flattening that should turn the original rope into a dependent string, and
// yield a new linear string, of the some size as the original.
-rope16a = rope16 + fragment16;
+rope16a = ext16 + fragment16;
assertEq(byteSize(rope16a), s(Nursery(RN), Nursery(RN)));
rope16a.match(/x/, function() { assertEq(true, false); });
-assertEq(byteSize(rope16a), s(Nursery(XN) + 131072, Nursery(XN) + 131072));
-assertEq(byteSize(rope16), s(Nursery(XN), Nursery(XN)));
+assertEq(byteSize(rope16a), s(Nursery(XN) + 128 * 1024, Nursery(XN) + 128 * 1024));
+assertEq(byteSize(ext16), s(Nursery(DN), Nursery(DN)));
+
+// Tenure everything and try again. This time it should steal the extensible
+// characters and convert the root into an extensible string using them.
+ext16 = copyString(ext16);
+rope16a = ext16 + fragment16;
+minorgc();
+assertEq(byteSize(rope16a), s(RN, RN));
+rope16a.match(/x/, function() { assertEq(true, false); });
+assertEq(byteSize(rope16a), s(XN + 128 * 1024, XN + 128 * 1024));
+assertEq(byteSize(ext16), s(RN, RN));
// Test external strings.
//
diff --git a/js/src/jit-test/tests/ion/apply-native-arguments-object.js b/js/src/jit-test/tests/ion/apply-native-arguments-object.js
new file mode 100644
index 0000000000..e06a5e0965
--- /dev/null
+++ b/js/src/jit-test/tests/ion/apply-native-arguments-object.js
@@ -0,0 +1,46 @@
+load(libdir + "array-compare.js");
+
+const xs = [
+ // Zero arguments.
+ [],
+
+ // Single argument.
+ [1],
+
+ // Few arguments. Even number of arguments.
+ [1, 2],
+
+ // Few arguments. Odd number of arguments.
+ [1, 2, 3],
+
+ // Many arguments. Even number of arguments.
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 0],
+
+ // Many arguments. Odd number of arguments.
+ [1, 2, 3, 4, 5, 6, 7, 8, 9],
+];
+
+function escape() {
+ with ({}) ;
+}
+
+function f() {
+ // Let |arguments| escape to force the allocation of an arguments object.
+ escape(arguments);
+
+ // FunApply to a native function with an arguments object.
+ return Array.apply(null, arguments);
+}
+
+// Don't inline |f| into the top-level script.
+with ({}) ;
+
+for (let i = 0; i < 400; ++i) {
+ let x = xs[i % xs.length];
+
+ // NB: Array(1) creates the array `[,]`.
+ let expected = x.length !== 1 ? x : [,];
+
+ let result = f.apply(null, x);
+ assertEq(arraysEqual(result, expected), true);
+}
diff --git a/js/src/jit-test/tests/ion/apply-native-arguments.js b/js/src/jit-test/tests/ion/apply-native-arguments.js
new file mode 100644
index 0000000000..3d6729ca76
--- /dev/null
+++ b/js/src/jit-test/tests/ion/apply-native-arguments.js
@@ -0,0 +1,39 @@
+load(libdir + "array-compare.js");
+
+const xs = [
+ // Zero arguments.
+ [],
+
+ // Single argument.
+ [1],
+
+ // Few arguments. Even number of arguments.
+ [1, 2],
+
+ // Few arguments. Odd number of arguments.
+ [1, 2, 3],
+
+ // Many arguments. Even number of arguments.
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 0],
+
+ // Many arguments. Odd number of arguments.
+ [1, 2, 3, 4, 5, 6, 7, 8, 9],
+];
+
+function f() {
+ // FunApply to a native function with frame arguments.
+ return Array.apply(null, arguments);
+}
+
+// Don't inline |f| into the top-level script.
+with ({}) ;
+
+for (let i = 0; i < 400; ++i) {
+ let x = xs[i % xs.length];
+
+ // NB: Array(1) creates the array `[,]`.
+ let expected = x.length !== 1 ? x : [,];
+
+ let result = f.apply(null, x);
+ assertEq(arraysEqual(result, expected), true);
+}
diff --git a/js/src/jit-test/tests/ion/apply-native-array.js b/js/src/jit-test/tests/ion/apply-native-array.js
new file mode 100644
index 0000000000..0dfa2df947
--- /dev/null
+++ b/js/src/jit-test/tests/ion/apply-native-array.js
@@ -0,0 +1,39 @@
+load(libdir + "array-compare.js");
+
+const xs = [
+ // Zero arguments.
+ [],
+
+ // Single argument.
+ [1],
+
+ // Few arguments. Even number of arguments.
+ [1, 2],
+
+ // Few arguments. Odd number of arguments.
+ [1, 2, 3],
+
+ // Many arguments. Even number of arguments.
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 0],
+
+ // Many arguments. Odd number of arguments.
+ [1, 2, 3, 4, 5, 6, 7, 8, 9],
+];
+
+function f(x) {
+ // FunApply to a native function with an array.
+ return Array.apply(null, x);
+}
+
+// Don't inline |f| into the top-level script.
+with ({}) ;
+
+for (let i = 0; i < 400; ++i) {
+ let x = xs[i % xs.length];
+
+ // NB: Array(1) creates the array `[,]`.
+ let expected = x.length !== 1 ? x : [,];
+
+ let result = f(x);
+ assertEq(arraysEqual(result, expected), true);
+}
diff --git a/js/src/jit-test/tests/ion/apply-native-spreadcall-arguments.js b/js/src/jit-test/tests/ion/apply-native-spreadcall-arguments.js
new file mode 100644
index 0000000000..9f769e4a59
--- /dev/null
+++ b/js/src/jit-test/tests/ion/apply-native-spreadcall-arguments.js
@@ -0,0 +1,39 @@
+load(libdir + "array-compare.js");
+
+const xs = [
+ // Zero arguments.
+ [],
+
+ // Single argument.
+ [1],
+
+ // Few arguments. Even number of arguments.
+ [1, 2],
+
+ // Few arguments. Odd number of arguments.
+ [1, 2, 3],
+
+ // Many arguments. Even number of arguments.
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 0],
+
+ // Many arguments. Odd number of arguments.
+ [1, 2, 3, 4, 5, 6, 7, 8, 9],
+];
+
+function f() {
+ // SpreadCall to a native function with frame arguments.
+ return Array(...arguments);
+}
+
+// Don't inline |f| into the top-level script.
+with ({}) ;
+
+for (let i = 0; i < 400; ++i) {
+ let x = xs[i % xs.length];
+
+ // NB: Array(1) creates the array `[,]`.
+ let expected = x.length !== 1 ? x : [,];
+
+ let result = f.apply(null, x);
+ assertEq(arraysEqual(result, expected), true);
+}
diff --git a/js/src/jit-test/tests/ion/apply-native-spreadcall-array.js b/js/src/jit-test/tests/ion/apply-native-spreadcall-array.js
new file mode 100644
index 0000000000..24e5621484
--- /dev/null
+++ b/js/src/jit-test/tests/ion/apply-native-spreadcall-array.js
@@ -0,0 +1,39 @@
+load(libdir + "array-compare.js");
+
+const xs = [
+ // Zero arguments.
+ [],
+
+ // Single argument.
+ [1],
+
+ // Few arguments. Even number of arguments.
+ [1, 2],
+
+ // Few arguments. Odd number of arguments.
+ [1, 2, 3],
+
+ // Many arguments. Even number of arguments.
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 0],
+
+ // Many arguments. Odd number of arguments.
+ [1, 2, 3, 4, 5, 6, 7, 8, 9],
+];
+
+function f(x) {
+ // SpreadCall to a native function with an array.
+ return Array(...x);
+}
+
+// Don't inline |f| into the top-level script.
+with ({}) ;
+
+for (let i = 0; i < 400; ++i) {
+ let x = xs[i % xs.length];
+
+ // NB: Array(1) creates the array `[,]`.
+ let expected = x.length !== 1 ? x : [,];
+
+ let result = f(x);
+ assertEq(arraysEqual(result, expected), true);
+}
diff --git a/js/src/jit-test/tests/ion/apply-native-spreadcall-rest.js b/js/src/jit-test/tests/ion/apply-native-spreadcall-rest.js
new file mode 100644
index 0000000000..ba7038244d
--- /dev/null
+++ b/js/src/jit-test/tests/ion/apply-native-spreadcall-rest.js
@@ -0,0 +1,39 @@
+load(libdir + "array-compare.js");
+
+const xs = [
+ // Zero arguments.
+ [],
+
+ // Single argument.
+ [1],
+
+ // Few arguments. Even number of arguments.
+ [1, 2],
+
+ // Few arguments. Odd number of arguments.
+ [1, 2, 3],
+
+ // Many arguments. Even number of arguments.
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 0],
+
+ // Many arguments. Odd number of arguments.
+ [1, 2, 3, 4, 5, 6, 7, 8, 9],
+];
+
+function f(...x) {
+ // SpreadCall to a native function with rest-args.
+ return Array(...x);
+}
+
+// Don't inline |f| into the top-level script.
+with ({}) ;
+
+for (let i = 0; i < 400; ++i) {
+ let x = xs[i % xs.length];
+
+ // NB: Array(1) creates the array `[,]`.
+ let expected = x.length !== 1 ? x : [,];
+
+ let result = f.apply(null, x);
+ assertEq(arraysEqual(result, expected), true);
+}
diff --git a/js/src/jit-test/tests/ion/apply-native-spreadnew-arguments.js b/js/src/jit-test/tests/ion/apply-native-spreadnew-arguments.js
new file mode 100644
index 0000000000..7e31cdcbd6
--- /dev/null
+++ b/js/src/jit-test/tests/ion/apply-native-spreadnew-arguments.js
@@ -0,0 +1,39 @@
+load(libdir + "array-compare.js");
+
+const xs = [
+ // Zero arguments.
+ [],
+
+ // Single argument.
+ [1],
+
+ // Few arguments. Even number of arguments.
+ [1, 2],
+
+ // Few arguments. Odd number of arguments.
+ [1, 2, 3],
+
+ // Many arguments. Even number of arguments.
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 0],
+
+ // Many arguments. Odd number of arguments.
+ [1, 2, 3, 4, 5, 6, 7, 8, 9],
+];
+
+function f() {
+ // SpreadNew to a native function with frame arguments.
+ return new Array(...arguments);
+}
+
+// Don't inline |f| into the top-level script.
+with ({}) ;
+
+for (let i = 0; i < 400; ++i) {
+ let x = xs[i % xs.length];
+
+ // NB: Array(1) creates the array `[,]`.
+ let expected = x.length !== 1 ? x : [,];
+
+ let result = f.apply(null, x);
+ assertEq(arraysEqual(result, expected), true);
+}
diff --git a/js/src/jit-test/tests/ion/apply-native-spreadnew-array.js b/js/src/jit-test/tests/ion/apply-native-spreadnew-array.js
new file mode 100644
index 0000000000..5c716f48b4
--- /dev/null
+++ b/js/src/jit-test/tests/ion/apply-native-spreadnew-array.js
@@ -0,0 +1,39 @@
+load(libdir + "array-compare.js");
+
+const xs = [
+ // Zero arguments.
+ [],
+
+ // Single argument.
+ [1],
+
+ // Few arguments. Even number of arguments.
+ [1, 2],
+
+ // Few arguments. Odd number of arguments.
+ [1, 2, 3],
+
+ // Many arguments. Even number of arguments.
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 0],
+
+ // Many arguments. Odd number of arguments.
+ [1, 2, 3, 4, 5, 6, 7, 8, 9],
+];
+
+function f(x) {
+ // SpreadNew to a native function with an array.
+ return new Array(...x);
+}
+
+// Don't inline |f| into the top-level script.
+with ({}) ;
+
+for (let i = 0; i < 400; ++i) {
+ let x = xs[i % xs.length];
+
+ // NB: Array(1) creates the array `[,]`.
+ let expected = x.length !== 1 ? x : [,];
+
+ let result = f(x);
+ assertEq(arraysEqual(result, expected), true);
+}
diff --git a/js/src/jit-test/tests/ion/apply-native-spreadnew-newtarget.js b/js/src/jit-test/tests/ion/apply-native-spreadnew-newtarget.js
new file mode 100644
index 0000000000..9ffe53277b
--- /dev/null
+++ b/js/src/jit-test/tests/ion/apply-native-spreadnew-newtarget.js
@@ -0,0 +1,66 @@
+load(libdir + "array-compare.js");
+
+const xs = [
+ // Zero arguments.
+ [],
+
+ // Single argument.
+ [1],
+
+ // Few arguments. Even number of arguments.
+ [1, 2],
+
+ // Few arguments. Odd number of arguments.
+ [1, 2, 3],
+
+ // Many arguments. Even number of arguments.
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 0],
+
+ // Many arguments. Odd number of arguments.
+ [1, 2, 3, 4, 5, 6, 7, 8, 9],
+];
+
+class ArrayWithExplicitConstructor extends Array {
+ constructor(...args) {
+ super(...args);
+ }
+}
+
+class ArrayWithImplicitConstructor extends Array {
+ constructor(...args) {
+ super(...args);
+ }
+}
+
+function f(...x) {
+ return new ArrayWithExplicitConstructor(...x);
+}
+
+function g(...x) {
+ return new ArrayWithImplicitConstructor(...x);
+}
+
+// Don't inline |f| and |g| into the top-level script.
+with ({}) ;
+
+for (let i = 0; i < 400; ++i) {
+ let x = xs[i % xs.length];
+
+ // NB: Array(1) creates the array `[,]`.
+ let expected = x.length !== 1 ? x : [,];
+
+ let result = f.apply(null, x);
+ assertEq(arraysEqual(result, expected), true);
+ assertEq(Object.getPrototypeOf(result), ArrayWithExplicitConstructor.prototype);
+}
+
+for (let i = 0; i < 400; ++i) {
+ let x = xs[i % xs.length];
+
+ // NB: Array(1) creates the array `[,]`.
+ let expected = x.length !== 1 ? x : [,];
+
+ let result = g.apply(null, x);
+ assertEq(arraysEqual(result, expected), true);
+ assertEq(Object.getPrototypeOf(result), ArrayWithImplicitConstructor.prototype);
+}
diff --git a/js/src/jit-test/tests/ion/apply-native-spreadnew-rest.js b/js/src/jit-test/tests/ion/apply-native-spreadnew-rest.js
new file mode 100644
index 0000000000..58de8fa239
--- /dev/null
+++ b/js/src/jit-test/tests/ion/apply-native-spreadnew-rest.js
@@ -0,0 +1,39 @@
+load(libdir + "array-compare.js");
+
+const xs = [
+ // Zero arguments.
+ [],
+
+ // Single argument.
+ [1],
+
+ // Few arguments. Even number of arguments.
+ [1, 2],
+
+ // Few arguments. Odd number of arguments.
+ [1, 2, 3],
+
+ // Many arguments. Even number of arguments.
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 0],
+
+ // Many arguments. Odd number of arguments.
+ [1, 2, 3, 4, 5, 6, 7, 8, 9],
+];
+
+function f(...x) {
+ // SpreadNew to a native function with rest-args.
+ return new Array(...x);
+}
+
+// Don't inline |f| into the top-level script.
+with ({}) ;
+
+for (let i = 0; i < 400; ++i) {
+ let x = xs[i % xs.length];
+
+ // NB: Array(1) creates the array `[,]`.
+ let expected = x.length !== 1 ? x : [,];
+
+ let result = f.apply(null, x);
+ assertEq(arraysEqual(result, expected), true);
+}
diff --git a/js/src/jit-test/tests/ion/recover-atomics-islockfree.js b/js/src/jit-test/tests/ion/recover-atomics-islockfree.js
new file mode 100644
index 0000000000..2a57afd49b
--- /dev/null
+++ b/js/src/jit-test/tests/ion/recover-atomics-islockfree.js
@@ -0,0 +1,25 @@
+// |jit-test| --fast-warmup; --ion-offthread-compile=off
+
+function foo(n, trigger) {
+ let result = Atomics.isLockFree(n * -1);
+ if (trigger) {
+ assertEq(result, false);
+ }
+}
+
+for (var i = 0; i < 100; i++) {
+ foo(-50, false);
+}
+foo(0, true);
+
+function bar(n, trigger) {
+ let result = Atomics.isLockFree(n * 4);
+ if (trigger) {
+ assertEq(result, false);
+ }
+}
+
+for (var i = 0; i < 100; i++) {
+ bar(1, false);
+}
+bar(0x40000001, true);
diff --git a/js/src/jit-test/tests/ion/recover-string-from-charcode.js b/js/src/jit-test/tests/ion/recover-string-from-charcode.js
new file mode 100644
index 0000000000..be060be8e7
--- /dev/null
+++ b/js/src/jit-test/tests/ion/recover-string-from-charcode.js
@@ -0,0 +1,13 @@
+// |jit-test| --fast-warmup; --ion-offthread-compile=off
+
+function foo(n, trigger) {
+ let result = String.fromCharCode(n * -1);
+ if (trigger) {
+ assertEq(result, "\0");
+ }
+}
+
+for (var i = 0; i < 100; i++) {
+ foo(-50, false);
+}
+foo(0, true);
diff --git a/js/src/jit-test/tests/modules/bug-1888902.js b/js/src/jit-test/tests/modules/bug-1888902.js
new file mode 100644
index 0000000000..7804bef98a
--- /dev/null
+++ b/js/src/jit-test/tests/modules/bug-1888902.js
@@ -0,0 +1,16 @@
+// |jit-test| error:Error
+
+const v0 = `
+ function F1() {
+ const v11 = registerModule("module1", parseModule(\`import {} from "module2";
+ import {} from "module3";\`));
+ const v13 = "await 1;";
+ drainJobQueue();
+ registerModule("module2", parseModule(v13));
+ registerModule("module3", parseModule(v0));
+ moduleLink(v11);
+ moduleEvaluate(v11);
+ }
+ F1();
+`;
+eval(v0);
diff --git a/js/src/jit-test/tests/modules/dynamic-import-error.js b/js/src/jit-test/tests/modules/dynamic-import-error.js
index 98a6af75d0..56713c8485 100644
--- a/js/src/jit-test/tests/modules/dynamic-import-error.js
+++ b/js/src/jit-test/tests/modules/dynamic-import-error.js
@@ -1,5 +1,3 @@
-// |jit-test| module
-
let result = null;
let error = null;
let promise = import("nonexistent.js");
diff --git a/js/src/jit-test/tests/modules/dynamic-import-module.js b/js/src/jit-test/tests/modules/dynamic-import-module.js
index 3c004258a3..fa19b74303 100644
--- a/js/src/jit-test/tests/modules/dynamic-import-module.js
+++ b/js/src/jit-test/tests/modules/dynamic-import-module.js
@@ -1,5 +1,3 @@
-// |jit-test| module
-
function testImport(path, name, value) {
let result = null;
let error = null;
diff --git a/js/src/jit-test/tests/modules/inline-data-2.js b/js/src/jit-test/tests/modules/inline-data-2.js
new file mode 100644
index 0000000000..8dbf92574d
--- /dev/null
+++ b/js/src/jit-test/tests/modules/inline-data-2.js
@@ -0,0 +1,12 @@
+let result = null;
+let error = null;
+let promise = import("javascript: export let b = 100;");
+promise.then((ns) => {
+ result = ns;
+}).catch((e) => {
+ error = e;
+});
+
+drainJobQueue();
+assertEq(error, null);
+assertEq(result.b, 100);
diff --git a/js/src/jit-test/tests/modules/inline-data.js b/js/src/jit-test/tests/modules/inline-data.js
index 9c56856f8d..d81da0efe4 100644
--- a/js/src/jit-test/tests/modules/inline-data.js
+++ b/js/src/jit-test/tests/modules/inline-data.js
@@ -2,16 +2,3 @@
import { a } from "javascript: export let a = 42;";
assertEq(a, 42);
-
-let result = null;
-let error = null;
-let promise = import("javascript: export let b = 100;");
-promise.then((ns) => {
- result = ns;
-}).catch((e) => {
- error = e;
-});
-
-drainJobQueue();
-assertEq(error, null);
-assertEq(result.b, 100);
diff --git a/js/src/jit-test/tests/modules/shell-wrapper.js b/js/src/jit-test/tests/modules/shell-wrapper.js
index 1be1c486c6..058e574d4e 100644
--- a/js/src/jit-test/tests/modules/shell-wrapper.js
+++ b/js/src/jit-test/tests/modules/shell-wrapper.js
@@ -1,4 +1,3 @@
-// |jit-test| module
// Test shell ModuleObject wrapper's accessors and methods
load(libdir + "asserts.js");
@@ -49,10 +48,8 @@ const d = registerModule('d', parseModule(`
f();
`));
moduleLink(d);
-try {
- await moduleEvaluate(d);
-} catch (e) {
-}
+moduleEvaluate(d).catch(e => undefined);
+drainJobQueue();
assertEq(d.evaluationError instanceof ReferenceError, true);
testGetter(d, "evaluationError");
diff --git a/js/src/jit-test/tests/parser/bug1887176.js b/js/src/jit-test/tests/parser/bug1887176.js
new file mode 100644
index 0000000000..bea2db519b
--- /dev/null
+++ b/js/src/jit-test/tests/parser/bug1887176.js
@@ -0,0 +1,46 @@
+
+// This tests a case where TokenStreamAnyChars::fillExceptingContext
+// mishandled a wasm frame, leading to an assertion failure.
+
+if (!wasmIsSupported())
+ quit();
+
+const v0 = `
+ const o6 = {
+ f() {
+ function F2() {
+ if (!new.target) { throw 'must be called with new'; }
+ }
+ return F2();
+ return {}; // This can be anything, but it must be present
+ },
+ };
+
+ const o7 = {
+ "main": o6,
+ };
+
+ const v15 = new WebAssembly.Module(wasmTextToBinary(\`
+ (module
+ (import "main" "f" (func))
+ (func (export "go")
+ call 0
+ )
+ )\`));
+ const v16 = new WebAssembly.Instance(v15, o7);
+ v16.exports.go();
+`;
+
+const o27 = {
+ // Both "fileName" and null are necessary
+ "fileName": null,
+};
+
+let caught = false;
+try {
+ evaluate(v0, o27);
+} catch (e) {
+ assertEq(e, "must be called with new");
+ caught = true;
+}
+assertEq(caught, true);
diff --git a/js/src/jit-test/tests/parser/dumpStencil-02.js b/js/src/jit-test/tests/parser/dumpStencil-02.js
new file mode 100644
index 0000000000..e21962c36b
--- /dev/null
+++ b/js/src/jit-test/tests/parser/dumpStencil-02.js
@@ -0,0 +1,8 @@
+let caught = false;
+try {
+ dumpStencil("export var z;", { module : true, lineNumber: 0 });
+} catch (e) {
+ caught = true;
+ assertEq(e.message.includes("Module cannot be compiled with lineNumber == 0"), true);
+}
+assertEq(caught, true);
diff --git a/js/src/jit-test/tests/parser/module-filename.js b/js/src/jit-test/tests/parser/module-filename.js
new file mode 100644
index 0000000000..59017dd674
--- /dev/null
+++ b/js/src/jit-test/tests/parser/module-filename.js
@@ -0,0 +1,13 @@
+load(libdir + "asserts.js");
+
+compileToStencil("", { fileName: "", module: true });
+assertThrowsInstanceOf(() => {
+ compileToStencil("", { fileName: null, module: true });
+}, Error);
+
+if (helperThreadCount() > 0) {
+ offThreadCompileModuleToStencil("", { fileName: "", module: true });
+ assertThrowsInstanceOf(() => {
+ offThreadCompileModuleToStencil("", { fileName: null, module: true });
+ }, Error);
+}
diff --git a/js/src/jit-test/tests/profiler/native-trampoline-2.js b/js/src/jit-test/tests/profiler/native-trampoline-2.js
new file mode 100644
index 0000000000..a85913431b
--- /dev/null
+++ b/js/src/jit-test/tests/profiler/native-trampoline-2.js
@@ -0,0 +1,7 @@
+let arr = [1, 2, 3, 4, 5, 6, 7, 8];
+arr.sort((x, y) => {
+ enableGeckoProfilingWithSlowAssertions();
+ readGeckoProfilingStack();
+ return y - x;
+});
+assertEq(arr.toString(), "8,7,6,5,4,3,2,1");
diff --git a/js/src/jit-test/tests/profiler/native-trampoline-3.js b/js/src/jit-test/tests/profiler/native-trampoline-3.js
new file mode 100644
index 0000000000..16fe547051
--- /dev/null
+++ b/js/src/jit-test/tests/profiler/native-trampoline-3.js
@@ -0,0 +1,32 @@
+// |jit-test| skip-if: !wasmIsSupported()
+
+// Use a Wasm module to get the following stack frames:
+//
+// .. => array sort trampoline => wasmfunc comparator (Wasm) => comparator (JS)
+
+let binary = wasmTextToBinary(`
+(module
+ (import "" "comparator" (func $comparator (param i32) (param i32) (result i32)))
+ (func $wasmfunc
+ (export "wasmfunc")
+ (param $x i32)
+ (param $y i32)
+ (result i32)
+ (return (call $comparator (local.get $x) (local.get $y)))
+ )
+)`);
+let mod = new WebAssembly.Module(binary);
+let instance = new WebAssembly.Instance(mod, {"": {comparator}});
+
+function comparator(x, y) {
+ readGeckoProfilingStack();
+ return y - x;
+}
+
+enableGeckoProfilingWithSlowAssertions();
+
+for (let i = 0; i < 20; i++) {
+ let arr = [3, 1, 2, -1, 0, 4];
+ arr.sort(instance.exports.wasmfunc);
+ assertEq(arr.toString(), "4,3,2,1,0,-1");
+}
diff --git a/js/src/jit-test/tests/profiler/native-trampoline.js b/js/src/jit-test/tests/profiler/native-trampoline.js
new file mode 100644
index 0000000000..e140874a15
--- /dev/null
+++ b/js/src/jit-test/tests/profiler/native-trampoline.js
@@ -0,0 +1,40 @@
+enableGeckoProfilingWithSlowAssertions();
+
+function testBasic() {
+ var arr = [2, -1];
+ var cmp = function(x, y) {
+ readGeckoProfilingStack();
+ return x - y;
+ };
+ for (var i = 0; i < 20; i++) {
+ arr.sort(cmp);
+ }
+}
+testBasic();
+
+function testRectifierFrame() {
+ var arr = [2, -1];
+ var cmp = function(x, y, z, a) {
+ readGeckoProfilingStack();
+ return x - y;
+ };
+ for (var i = 0; i < 20; i++) {
+ arr.sort(cmp);
+ }
+}
+testRectifierFrame();
+
+function testRectifierFrameCaller() {
+ var o = {};
+ var calls = 0;
+ Object.defineProperty(o, "length", {get: function() {
+ calls++;
+ readGeckoProfilingStack();
+ return 0;
+ }});
+ for (var i = 0; i < 20; i++) {
+ Array.prototype.sort.call(o);
+ }
+ assertEq(calls, 20);
+}
+testRectifierFrameCaller();
diff --git a/js/src/jit-test/tests/profiler/wasm-to-js-1.js b/js/src/jit-test/tests/profiler/wasm-to-js-1.js
new file mode 100644
index 0000000000..2ce48f391c
--- /dev/null
+++ b/js/src/jit-test/tests/profiler/wasm-to-js-1.js
@@ -0,0 +1,20 @@
+// |jit-test| skip-if: !wasmIsSupported(); --fast-warmup
+function sample() {
+ enableGeckoProfiling();
+ readGeckoProfilingStack();
+ disableGeckoProfiling();
+}
+const text = `(module
+ (import "m" "f" (func $f))
+ (func (export "test")
+ (call $f)
+))`;
+const bytes = wasmTextToBinary(text);
+const mod = new WebAssembly.Module(bytes);
+const imports = {"m": {"f": sample}};
+const instance = new WebAssembly.Instance(mod, imports);
+sample();
+for (let i = 0; i < 5; i++) {
+ gc(this, "shrinking");
+ instance.exports.test();
+}
diff --git a/js/src/jit-test/tests/profiler/wasm-to-js-2.js b/js/src/jit-test/tests/profiler/wasm-to-js-2.js
new file mode 100644
index 0000000000..3949c3a587
--- /dev/null
+++ b/js/src/jit-test/tests/profiler/wasm-to-js-2.js
@@ -0,0 +1,19 @@
+// |jit-test| skip-if: !wasmIsSupported()
+// Ensure readGeckoProfilingStack finds at least 1 Wasm frame on the stack.
+function calledFromWasm() {
+ let frames = readGeckoProfilingStack().flat();
+ assertEq(frames.filter(f => f.kind === "wasm").length >= 1, true);
+}
+enableGeckoProfiling();
+const text = `(module
+ (import "m" "f" (func $f))
+ (func (export "test")
+ (call $f)
+))`;
+const bytes = wasmTextToBinary(text);
+const mod = new WebAssembly.Module(bytes);
+const imports = {"m": {"f": calledFromWasm}};
+const instance = new WebAssembly.Instance(mod, imports);
+for (let i = 0; i < 150; i++) {
+ instance.exports.test();
+}
diff --git a/js/src/jit-test/tests/promise/allSettled-dead.js b/js/src/jit-test/tests/promise/allSettled-dead.js
new file mode 100644
index 0000000000..8ae8e53d6b
--- /dev/null
+++ b/js/src/jit-test/tests/promise/allSettled-dead.js
@@ -0,0 +1,20 @@
+newGlobal();
+const g = newGlobal({
+ "newCompartment": true,
+});
+const p1 = g.eval(`
+Promise.resolve();
+`);
+const p2 = p1.then();
+nukeAllCCWs();
+ignoreUnhandledRejections();
+Promise.resolve = function() {
+ return p2;
+};
+let caught = false;
+Promise.allSettled([1]).catch(e => {
+ caught = true;
+ assertEq(e.message.includes("dead object"), true);
+});
+drainJobQueue();
+assertEq(caught, true);
diff --git a/js/src/jit-test/tests/promise/jobqueue-interrupt-01.js b/js/src/jit-test/tests/promise/jobqueue-interrupt-01.js
new file mode 100644
index 0000000000..758680e031
--- /dev/null
+++ b/js/src/jit-test/tests/promise/jobqueue-interrupt-01.js
@@ -0,0 +1,23 @@
+// catchTermination should undo the quit() operation and let the remaining jobs
+// run.
+
+evaluate(`
+ quit();
+`, {
+ catchTermination : true
+});
+
+const global = newGlobal({ newCompartment: true });
+
+let called = false;
+const dbg = new Debugger(global);
+dbg.onDebuggerStatement = function (frame) {
+ Promise.resolve(42).then(v => { called = true; });
+};
+global.eval(`
+ debugger;
+`);
+
+drainJobQueue();
+
+assertEq(called, true);
diff --git a/js/src/jit-test/tests/promise/jobqueue-interrupt-02.js b/js/src/jit-test/tests/promise/jobqueue-interrupt-02.js
new file mode 100644
index 0000000000..8d8f27ef91
--- /dev/null
+++ b/js/src/jit-test/tests/promise/jobqueue-interrupt-02.js
@@ -0,0 +1,14 @@
+// quit() while draining job queue leaves the remaining jobs untouched.
+
+const global = newGlobal({ newCompartment:true });
+const dbg = Debugger(global);
+dbg.onDebuggerStatement = function() {
+ Promise.resolve().then(() => {
+ quit();
+ });
+ Promise.resolve().then(() => {
+ // This shouldn't be called.
+ assertEq(true, false);
+ });
+};
+global.eval("debugger");
diff --git a/js/src/jit-test/tests/proxy/bug1885774.js b/js/src/jit-test/tests/proxy/bug1885774.js
new file mode 100644
index 0000000000..fa88cbf823
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/bug1885774.js
@@ -0,0 +1,25 @@
+// |jit-test| --no-threads; --fast-warmup
+
+var {proxy, revoke} = Proxy.revocable({x:1}, {});
+
+function foo(o) {
+ var res = 0;
+ for (var i = 0; i < 2; i++) {
+ res += o.x;
+ }
+ return res;
+}
+
+with ({}) {}
+for (var i = 0; i < 100; i++) {
+ assertEq(foo(proxy), 2);
+}
+
+revoke();
+var caught = false;
+try {
+ foo(proxy);
+} catch {
+ caught = true;
+}
+assertEq(caught, true);
diff --git a/js/src/jit-test/tests/structured-clone/bug1888727.js b/js/src/jit-test/tests/structured-clone/bug1888727.js
new file mode 100644
index 0000000000..7958781c92
--- /dev/null
+++ b/js/src/jit-test/tests/structured-clone/bug1888727.js
@@ -0,0 +1,21 @@
+function test() {
+ // Construct a structured clone of a random BigInt value.
+ const n = 0xfeeddeadbeef2dadfeeddeadbeef2dadfeeddeadbeef2dadfeeddeadbeef2dadn;
+ const s = serialize(n, [], {scope: 'DifferentProcess'});
+ assertEq(deserialize(s), n);
+
+ // Truncate it by chopping off the last 8 bytes.
+ s.clonebuffer = s.arraybuffer.slice(0, -8);
+
+ // Deserialization should now throw a catchable exception.
+ try {
+ deserialize(s);
+ // The bug was throwing an uncatchable error, so this next assertion won't
+ // be reached in either the buggy or fixed code.
+ assertEq(true, false, "should have thrown truncation error");
+ } catch (e) {
+ assertEq(e.message.includes("truncated"), true);
+ }
+}
+
+test();
diff --git a/js/src/jit-test/tests/structured-clone/tenuring.js b/js/src/jit-test/tests/structured-clone/tenuring.js
index 0fffa064fa..cec53a6956 100644
--- a/js/src/jit-test/tests/structured-clone/tenuring.js
+++ b/js/src/jit-test/tests/structured-clone/tenuring.js
@@ -1,4 +1,4 @@
-// Check that we switch to allocating in the tenure heap after the first
+// Check that we switch to allocating in the tenured heap after the first
// nursery collection.
function buildObjectTree(depth) {
@@ -82,6 +82,7 @@ function countHeapLocations(tree, objectTree, counts) {
gczeal(0);
gcparam('minNurseryBytes', 1024 * 1024);
gcparam('maxNurseryBytes', 1024 * 1024);
+gcparam('semispaceNurseryEnabled', 0);
gc();
testRoundTrip(1, true, true);
diff --git a/js/src/jit-test/tests/typedarray/resizable-typedarray-from-pinned-buffer.js b/js/src/jit-test/tests/typedarray/resizable-typedarray-from-pinned-buffer.js
new file mode 100644
index 0000000000..b17c7c0157
--- /dev/null
+++ b/js/src/jit-test/tests/typedarray/resizable-typedarray-from-pinned-buffer.js
@@ -0,0 +1,9 @@
+// |jit-test| --enable-arraybuffer-resizable
+
+let ab = new ArrayBuffer(8, {maxByteLength: 10});
+
+pinArrayBufferOrViewLength(ab);
+
+let ta = new Int8Array(ab);
+
+assertEq(ta.length, 8);
diff --git a/js/src/jit-test/tests/warp/bug1876425.js b/js/src/jit-test/tests/warp/bug1876425.js
new file mode 100644
index 0000000000..aca528aac6
--- /dev/null
+++ b/js/src/jit-test/tests/warp/bug1876425.js
@@ -0,0 +1,62 @@
+// 1) Trial inline f1 => g (g1) => h.
+// 2) Set g to g2, to fail the f1 => g1 call site.
+// 3) Set g to g1 again.
+// 4) Make g1's generic ICScript trial inline a different callee, h2.
+// 5) Bail out from f1 => g1 => h.
+//
+// The bailout must not confuse the ICScripts of h1 and h2.
+
+function noninlined1(x) {
+ with (this) {};
+ if (x === 4002) {
+ // Step 4.
+ f2();
+ // Step 5.
+ return true;
+ }
+ return false;
+}
+function noninlined2(x) {
+ with (this) {};
+ if (x === 4000) {
+ // Step 2.
+ g = (h, x) => {
+ return x + 1;
+ };
+ }
+ if (x === 4001) {
+ // Step 3.
+ g = g1;
+ }
+}
+var h = function(x) {
+ if (noninlined1(x)) {
+ // Step 5.
+ bailout();
+ }
+ return x + 1;
+};
+var g = function(callee, x) {
+ return callee(x) + 1;
+};
+var g1 = g;
+
+function f2() {
+ var h2 = x => x + 1;
+ for (var i = 0; i < 300; i++) {
+ var x = (i % 2 === 0) ? "foo" : i; // Force trial inlining.
+ g1(h2, x);
+ }
+}
+
+function f1() {
+ for (var i = 0; i < 4200; i++) {
+ var x = (i < 900 && i % 2 === 0) ? "foo" : i; // Force trial inlining.
+ g(h, x);
+ noninlined2(i);
+ if (i === 200) {
+ trialInline();
+ }
+ }
+}
+f1();
diff --git a/js/src/jit-test/tests/wasm/directiveless/bug1877358.js b/js/src/jit-test/tests/wasm/directiveless/bug1877358.js
index 10cb54398a..8d512efcfe 100644
--- a/js/src/jit-test/tests/wasm/directiveless/bug1877358.js
+++ b/js/src/jit-test/tests/wasm/directiveless/bug1877358.js
@@ -1,4 +1,4 @@
-// |jit-test| -P wasm_exceptions=false; include:wasm.js
+// |jit-test| include:wasm.js
let {test} = wasmEvalText(`(module
(func $m (import "" "m"))
diff --git a/js/src/jit-test/tests/wasm/gc/casting.js b/js/src/jit-test/tests/wasm/gc/casting.js
index a71a589db8..3b550e6415 100644
--- a/js/src/jit-test/tests/wasm/gc/casting.js
+++ b/js/src/jit-test/tests/wasm/gc/casting.js
@@ -114,3 +114,72 @@ function testAllCasts(types) {
}
}
testAllCasts(TYPES);
+
+// Test that combinations of ref.test and ref.cast compile correctly.
+// (These can be optimized together.)
+{
+ const { make, test1, test2, test3, test4 } = wasmEvalText(`(module
+ (type $a (array i32))
+ (func (export "make") (param i32) (result anyref)
+ local.get 0
+ local.get 0
+ array.new_fixed $a 2
+ )
+ (func (export "test1") (param anyref) (result i32)
+ (if (ref.test (ref $a) (local.get 0))
+ (then
+ (ref.cast (ref $a) (local.get 0))
+ (array.get $a (i32.const 0))
+ return
+ )
+ )
+ i32.const -1
+ )
+ (func (export "test2") (param anyref) (result i32)
+ (if (ref.test (ref $a) (local.get 0))
+ (then)
+ (else
+ (ref.cast (ref $a) (local.get 0))
+ (array.get $a (i32.const 0))
+ return
+ )
+ )
+ i32.const -1
+ )
+ (func (export "test3") (param anyref) (result i32)
+ (if (ref.test (ref $a) (local.get 0))
+ (then
+ (if (ref.test (ref $a) (local.get 0))
+ (then)
+ (else
+ (ref.cast (ref $a) (local.get 0))
+ (array.get $a (i32.const 0))
+ return
+ )
+ )
+ )
+ )
+ i32.const -1
+ )
+ (func (export "test4") (param anyref) (result i32)
+ (if (ref.test (ref $a) (local.get 0))
+ (then
+ (if (ref.test (ref $a) (local.get 0))
+ (then
+ local.get 0
+ ref.cast (ref $a)
+ ref.cast (ref $a)
+ (array.get $a (i32.const 0))
+ return
+ )
+ )
+ )
+ )
+ i32.const -1
+ )
+ )`).exports;
+ assertEq(test1(make(99)), 99);
+ assertEq(test2(make(99)), -1);
+ assertEq(test3(make(99)), -1);
+ assertEq(test4(make(99)), 99);
+}
diff --git a/js/src/jit-test/tests/wasm/gc/i31ref.js b/js/src/jit-test/tests/wasm/gc/i31ref.js
index 65f2fccc3f..298447e848 100644
--- a/js/src/jit-test/tests/wasm/gc/i31ref.js
+++ b/js/src/jit-test/tests/wasm/gc/i31ref.js
@@ -149,6 +149,24 @@ for (const {input, expected} of bigI32Tests) {
assertEq(getElem(), expected);
}
+// Test that (ref.i31 (i32 const value)) optimization is correct
+for (let value of WasmI31refValues) {
+ let {compare} = wasmEvalText(`(module
+ (func $innerCompare (param i32) (param i31ref) (result i32)
+ (ref.eq
+ (ref.i31 local.get 0)
+ local.get 1
+ )
+ )
+ (func (export "compare") (result i32)
+ i32.const ${value}
+ (ref.i31 i32.const ${value})
+ call $innerCompare
+ )
+)`).exports;
+ assertEq(compare(value), 1);
+}
+
const { i31GetU_null, i31GetS_null } = wasmEvalText(`(module
(func (export "i31GetU_null") (result i32)
ref.null i31
diff --git a/js/src/jit-test/tests/wasm/regress/bug1886870.js b/js/src/jit-test/tests/wasm/regress/bug1886870.js
new file mode 100644
index 0000000000..a4947bd91a
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/regress/bug1886870.js
@@ -0,0 +1,8 @@
+// Check proper handling of OOM after toQuotedString().
+
+oomTest(function () {
+ new WebAssembly.Instance(
+ new WebAssembly.Module(wasmTextToBinary('(import "m" "f" (func $f))')),
+ {}
+ );
+});
diff --git a/js/src/jit-test/tests/wasm/regress/bug1887535.js b/js/src/jit-test/tests/wasm/regress/bug1887535.js
new file mode 100644
index 0000000000..e2793831bf
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/regress/bug1887535.js
@@ -0,0 +1,25 @@
+// |jit-test| slow;
+
+// Tests the exception handling works during stack overflow.
+const v1 = newGlobal({sameZoneAs: this});
+class C2 {
+ static { }
+}
+
+function f() { v1.constructor; }
+
+const { test } = wasmEvalText(`
+(module
+ (import "" "f" (func $f))
+ (export "test" (func $f))
+)`, { "": { f, },}).exports;
+
+
+function f4() {
+ try {
+ f4();
+ } catch(_) {
+ test(); test();
+ }
+}
+f4();
diff --git a/js/src/jit-test/tests/wasm/regress/bug1887596.js b/js/src/jit-test/tests/wasm/regress/bug1887596.js
new file mode 100644
index 0000000000..8ff579fc35
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/regress/bug1887596.js
@@ -0,0 +1,14 @@
+const t = `
+ (module
+ (func $f (result f32)
+ f32.const 1.25
+ )
+ (table (export "table") 10 funcref)
+ (elem (i32.const 0) $f)
+ )`;
+const i = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(t)));
+const f = i.exports.table.get(0);
+
+// These FP equality comparisons are safe because 1.25 is representable exactly.
+assertEq(1.25, f());
+assertEq(1.25, this.wasmLosslessInvoke(f).value);