summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xjs/src/jit-test/jit_test.py12
-rw-r--r--js/src/jit-test/tests/asm.js/bug1174372.js2
-rw-r--r--js/src/jit-test/tests/basic/bug1892300.js4
-rw-r--r--js/src/jit-test/tests/basic/bug1894883.js8
-rw-r--r--js/src/jit-test/tests/basic/shell-flags-fuzzing.js3
-rw-r--r--js/src/jit-test/tests/basic/shell-prefs-fuzzing.js4
-rw-r--r--js/src/jit-test/tests/basic/shell-prefs-no-fuzzing.js2
-rw-r--r--js/src/jit-test/tests/basic/testTypeofEq.js492
-rw-r--r--js/src/jit-test/tests/bug1894604.js12
-rw-r--r--js/src/jit-test/tests/debug/Debugger-dead-global.js26
-rw-r--r--js/src/jit-test/tests/debug/Debugger-shouldAvoidSideEffects.js57
-rw-r--r--js/src/jit-test/tests/debug/bug1891662.js24
-rw-r--r--js/src/jit-test/tests/debug/bug1893554.js31
-rw-r--r--js/src/jit-test/tests/environments/1890252.js15
-rw-r--r--js/src/jit-test/tests/gc/bug-1651001-1.js9
-rw-r--r--js/src/jit-test/tests/gc/bug-1651001-2.js6
-rw-r--r--js/src/jit-test/tests/gc/bug-1890670.js12
-rw-r--r--js/src/jit-test/tests/gc/bug-1892564.js50
-rw-r--r--js/src/jit-test/tests/gc/bug-1893984.js3
-rw-r--r--js/src/jit-test/tests/gc/bug-1894025.js15
-rw-r--r--js/src/jit-test/tests/gc/bug-1894442.js6
-rw-r--r--js/src/jit-test/tests/gc/bug-1894547.js14
-rw-r--r--js/src/jit-test/tests/gc/bug-1895842.js5
-rw-r--r--js/src/jit-test/tests/gc/marking-thread-count.js20
-rw-r--r--js/src/jit-test/tests/ion/bug1608256.js2
-rw-r--r--js/src/jit-test/tests/ion/bug1894456-1.js6
-rw-r--r--js/src/jit-test/tests/ion/bug1894456-2.js6
-rw-r--r--js/src/jit-test/tests/ion/depended-on-bit-1.js52
-rw-r--r--js/src/jit-test/tests/ion/depended-on-bit-2.js56
-rw-r--r--js/src/jit-test/tests/modules/dynamic-import-unsupported-attribute.js29
-rw-r--r--js/src/jit-test/tests/modules/failure-on-resume.js79
-rw-r--r--js/src/jit-test/tests/modules/import-entries.js51
-rw-r--r--js/src/jit-test/tests/modules/import-unsupported-attribute.js2
-rw-r--r--js/src/jit-test/tests/modules/requested-modules.js81
-rw-r--r--js/src/jit-test/tests/sharedbuf/size-with-uninitialized.js15
-rw-r--r--js/src/jit-test/tests/typedarray/arraybuffer-zero-length-alignment-check.js29
-rw-r--r--js/src/jit-test/tests/typedarray/sort-trampoline.js174
-rw-r--r--js/src/jit-test/tests/typedarray/sort-wrapper.js21
-rw-r--r--js/src/jit-test/tests/warp/bug1683306.js2
-rw-r--r--js/src/jit-test/tests/warp/bug1683614.js4
-rw-r--r--js/src/jit-test/tests/wasm/branch-hinting/complex_control_flow.js38
-rw-r--r--js/src/jit-test/tests/wasm/branch-hinting/directives.txt1
-rw-r--r--js/src/jit-test/tests/wasm/branch-hinting/parsing.js154
-rw-r--r--js/src/jit-test/tests/wasm/branch-hinting/simple_example.js41
-rw-r--r--js/src/jit-test/tests/wasm/builtin-modules/js-string/basic.js8
-rw-r--r--js/src/jit-test/tests/wasm/exnref/casting.js261
-rw-r--r--js/src/jit-test/tests/wasm/exnref/try-table.js53
-rw-r--r--js/src/jit-test/tests/wasm/js-promise-integration/basic.js147
-rw-r--r--js/src/jit-test/tests/wasm/js-promise-integration/basic2.js97
-rw-r--r--js/src/jit-test/tests/wasm/js-promise-integration/directives.txt1
-rw-r--r--js/src/jit-test/tests/wasm/js-promise-integration/gc-2.js69
-rw-r--r--js/src/jit-test/tests/wasm/js-promise-integration/gc.js67
-rw-r--r--js/src/jit-test/tests/wasm/js-promise-integration/js-promise-integration.new.js270
-rw-r--r--js/src/jit-test/tests/wasm/js-promise-integration/js-promise-integration.old.js406
-rw-r--r--js/src/jit-test/tests/wasm/js-promise-integration/multi.js36
-rw-r--r--js/src/jit-test/tests/wasm/regress/bug1866545.js25
-rw-r--r--js/src/jit-test/tests/wasm/regress/bug1891658.js10
-rw-r--r--js/src/jit-test/tests/wasm/tail-calls/bug1891422.js27
-rw-r--r--js/src/jit-test/tests/wasm/testing/bug1894586.js13
59 files changed, 2999 insertions, 166 deletions
diff --git a/js/src/jit-test/jit_test.py b/js/src/jit-test/jit_test.py
index d9f08a7e15..4a5a0b96da 100755
--- a/js/src/jit-test/jit_test.py
+++ b/js/src/jit-test/jit_test.py
@@ -368,6 +368,18 @@ def main(argv):
op.add_argument(
"-z", "--gc-zeal", help="GC zeal mode to use when running the shell"
)
+ op.add_argument(
+ "--show-slow",
+ action="store_true",
+ help="Show tests taking longer than a minimum time (in seconds).",
+ )
+ op.add_argument(
+ "--slow-test-threshold",
+ type=float,
+ default=5.0,
+ help="Time in seconds a test can take until it is considered slow "
+ "(default %(default)s).",
+ )
options, test_args = op.parse_known_args(argv)
js_shell = which(options.js_shell)
diff --git a/js/src/jit-test/tests/asm.js/bug1174372.js b/js/src/jit-test/tests/asm.js/bug1174372.js
index e7031ea104..d48d2a0533 100644
--- a/js/src/jit-test/tests/asm.js/bug1174372.js
+++ b/js/src/jit-test/tests/asm.js/bug1174372.js
@@ -1,4 +1,4 @@
-// |jit-test| --no-baseline; --non-writable-jitcode
+// |jit-test| --no-baseline
(function(stdlib, foreign, heap) {
"use asm";
function f() {}
diff --git a/js/src/jit-test/tests/basic/bug1892300.js b/js/src/jit-test/tests/basic/bug1892300.js
new file mode 100644
index 0000000000..e4c2b1f5b7
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug1892300.js
@@ -0,0 +1,4 @@
+newGlobal().eval(`(function () {
+ enableShellAllocationMetadataBuilder();
+ return arguments[Symbol.iterator];
+})();`);
diff --git a/js/src/jit-test/tests/basic/bug1894883.js b/js/src/jit-test/tests/basic/bug1894883.js
new file mode 100644
index 0000000000..74312c9721
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug1894883.js
@@ -0,0 +1,8 @@
+function makeObj() { return { x: 1, y: 2 }; }
+
+var o1 = makeObj();
+var o2 = makeObj();
+
+var snapshot = createShapeSnapshot(o1);
+delete o1.x;
+checkShapeSnapshot(snapshot, o2);
diff --git a/js/src/jit-test/tests/basic/shell-flags-fuzzing.js b/js/src/jit-test/tests/basic/shell-flags-fuzzing.js
new file mode 100644
index 0000000000..e6be22cf5a
--- /dev/null
+++ b/js/src/jit-test/tests/basic/shell-flags-fuzzing.js
@@ -0,0 +1,3 @@
+// |jit-test| --fuzzing-safe; --enable-foobarbaz; error:987
+// If --fuzzing-safe is used, unknown shell flags that follow it are ignored.
+throw 987;
diff --git a/js/src/jit-test/tests/basic/shell-prefs-fuzzing.js b/js/src/jit-test/tests/basic/shell-prefs-fuzzing.js
new file mode 100644
index 0000000000..29d3acb347
--- /dev/null
+++ b/js/src/jit-test/tests/basic/shell-prefs-fuzzing.js
@@ -0,0 +1,4 @@
+// |jit-test| --fuzzing-safe; --setpref=foobar=123; error:987
+// If --fuzzing-safe is used, unknown pref names are ignored, similar to unknown
+// shell flags.
+throw 987;
diff --git a/js/src/jit-test/tests/basic/shell-prefs-no-fuzzing.js b/js/src/jit-test/tests/basic/shell-prefs-no-fuzzing.js
new file mode 100644
index 0000000000..a9aa4d5d77
--- /dev/null
+++ b/js/src/jit-test/tests/basic/shell-prefs-no-fuzzing.js
@@ -0,0 +1,2 @@
+// |jit-test| --setpref=foobar=123; exitstatus: 1
+// If --fuzzing-safe is not used, unknown pref names are reported as an error.
diff --git a/js/src/jit-test/tests/basic/testTypeofEq.js b/js/src/jit-test/tests/basic/testTypeofEq.js
new file mode 100644
index 0000000000..cf42a7c6c9
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testTypeofEq.js
@@ -0,0 +1,492 @@
+var testcases = [
+ [1, "NUMBER"],
+ [1.1, "NUMBER"],
+ [true, "BOOLEAN"],
+ [false, "BOOLEAN"],
+ [null, "OBJECT"],
+ [undefined, "UNDEFINED"],
+ ["foo", "STRING"],
+ [Symbol.iterator, "SYMBOL"],
+ [function f() {}, "FUNCTION"],
+ [{}, "OBJECT"],
+];
+
+function runTest(f) {
+ for (let i = 0; i < 2000; i++) {
+ let testcase = testcases[i % testcases.length];
+ assertEq(f(testcase[0]), testcase[1]);
+ }
+}
+
+function loose_left(x) {
+ if (typeof x == "boolean") {
+ return "BOOLEAN";
+ }
+ if (typeof x == "function") {
+ return "FUNCTION";
+ }
+ if (typeof x == "number") {
+ return "NUMBER";
+ }
+ if (typeof x == "object") {
+ return "OBJECT";
+ }
+ if (typeof x == "string") {
+ return "STRING";
+ }
+ if (typeof x == "symbol") {
+ return "SYMBOL";
+ }
+ if (typeof x == "undefined") {
+ return "UNDEFINED";
+ }
+ return "???";
+}
+
+function loose_right(x) {
+ if ("boolean" == typeof x) {
+ return "BOOLEAN";
+ }
+ if ("function" == typeof x) {
+ return "FUNCTION";
+ }
+ if ("number" == typeof x) {
+ return "NUMBER";
+ }
+ if ("object" == typeof x) {
+ return "OBJECT";
+ }
+ if ("string" == typeof x) {
+ return "STRING";
+ }
+ if ("symbol" == typeof x) {
+ return "SYMBOL";
+ }
+ if ("undefined" == typeof x) {
+ return "UNDEFINED";
+ }
+ return "???";
+}
+
+function strict_left(x) {
+ if (typeof x === "boolean") {
+ return "BOOLEAN";
+ }
+ if (typeof x === "function") {
+ return "FUNCTION";
+ }
+ if (typeof x === "number") {
+ return "NUMBER";
+ }
+ if (typeof x === "object") {
+ return "OBJECT";
+ }
+ if (typeof x === "string") {
+ return "STRING";
+ }
+ if (typeof x === "symbol") {
+ return "SYMBOL";
+ }
+ if (typeof x === "undefined") {
+ return "UNDEFINED";
+ }
+ return "???";
+}
+
+function strict_right(x) {
+ if ("boolean" === typeof x) {
+ return "BOOLEAN";
+ }
+ if ("function" === typeof x) {
+ return "FUNCTION";
+ }
+ if ("number" === typeof x) {
+ return "NUMBER";
+ }
+ if ("object" === typeof x) {
+ return "OBJECT";
+ }
+ if ("string" === typeof x) {
+ return "STRING";
+ }
+ if ("symbol" === typeof x) {
+ return "SYMBOL";
+ }
+ if ("undefined" === typeof x) {
+ return "UNDEFINED";
+ }
+ return "???";
+}
+
+function loose_left_ne(x) {
+ if (typeof x != "boolean") {
+ } else {
+ return "BOOLEAN";
+ }
+ if (typeof x != "function") {
+ } else {
+ return "FUNCTION";
+ }
+ if (typeof x != "number") {
+ } else {
+ return "NUMBER";
+ }
+ if (typeof x != "object") {
+ } else {
+ return "OBJECT";
+ }
+ if (typeof x != "string") {
+ } else {
+ return "STRING";
+ }
+ if (typeof x != "symbol") {
+ } else {
+ return "SYMBOL";
+ }
+ if (typeof x != "undefined") {
+ } else {
+ return "UNDEFINED";
+ }
+ return "???";
+}
+
+function loose_right_ne(x) {
+ if ("boolean" != typeof x) {
+ } else {
+ return "BOOLEAN";
+ }
+ if ("function" != typeof x) {
+ } else {
+ return "FUNCTION";
+ }
+ if ("number" != typeof x) {
+ } else {
+ return "NUMBER";
+ }
+ if ("object" != typeof x) {
+ } else {
+ return "OBJECT";
+ }
+ if ("string" != typeof x) {
+ } else {
+ return "STRING";
+ }
+ if ("symbol" != typeof x) {
+ } else {
+ return "SYMBOL";
+ }
+ if ("undefined" != typeof x) {
+ } else {
+ return "UNDEFINED";
+ }
+ return "???";
+}
+
+function strict_left_ne(x) {
+ if (typeof x !== "boolean") {
+ } else {
+ return "BOOLEAN";
+ }
+ if (typeof x !== "function") {
+ } else {
+ return "FUNCTION";
+ }
+ if (typeof x !== "number") {
+ } else {
+ return "NUMBER";
+ }
+ if (typeof x !== "object") {
+ } else {
+ return "OBJECT";
+ }
+ if (typeof x !== "string") {
+ } else {
+ return "STRING";
+ }
+ if (typeof x !== "symbol") {
+ } else {
+ return "SYMBOL";
+ }
+ if (typeof x !== "undefined") {
+ } else {
+ return "UNDEFINED";
+ }
+ return "???";
+}
+
+function strict_right_ne(x) {
+ if ("boolean" !== typeof x) {
+ } else {
+ return "BOOLEAN";
+ }
+ if ("function" !== typeof x) {
+ } else {
+ return "FUNCTION";
+ }
+ if ("number" !== typeof x) {
+ } else {
+ return "NUMBER";
+ }
+ if ("object" !== typeof x) {
+ } else {
+ return "OBJECT";
+ }
+ if ("string" !== typeof x) {
+ } else {
+ return "STRING";
+ }
+ if ("symbol" !== typeof x) {
+ } else {
+ return "SYMBOL";
+ }
+ if ("undefined" !== typeof x) {
+ } else {
+ return "UNDEFINED";
+ }
+ return "???";
+}
+
+function loose_left_expr(x) {
+ if (typeof (0, x) == "boolean") {
+ return "BOOLEAN";
+ }
+ if (typeof (0, x) == "function") {
+ return "FUNCTION";
+ }
+ if (typeof (0, x) == "number") {
+ return "NUMBER";
+ }
+ if (typeof (0, x) == "object") {
+ return "OBJECT";
+ }
+ if (typeof (0, x) == "string") {
+ return "STRING";
+ }
+ if (typeof (0, x) == "symbol") {
+ return "SYMBOL";
+ }
+ if (typeof (0, x) == "undefined") {
+ return "UNDEFINED";
+ }
+ return "???";
+}
+
+function loose_right_expr(x) {
+ if ("boolean" == typeof (0, x)) {
+ return "BOOLEAN";
+ }
+ if ("function" == typeof (0, x)) {
+ return "FUNCTION";
+ }
+ if ("number" == typeof (0, x)) {
+ return "NUMBER";
+ }
+ if ("object" == typeof (0, x)) {
+ return "OBJECT";
+ }
+ if ("string" == typeof (0, x)) {
+ return "STRING";
+ }
+ if ("symbol" == typeof (0, x)) {
+ return "SYMBOL";
+ }
+ if ("undefined" == typeof (0, x)) {
+ return "UNDEFINED";
+ }
+ return "???";
+}
+
+function strict_left_expr(x) {
+ if (typeof (0, x) === "boolean") {
+ return "BOOLEAN";
+ }
+ if (typeof (0, x) === "function") {
+ return "FUNCTION";
+ }
+ if (typeof (0, x) === "number") {
+ return "NUMBER";
+ }
+ if (typeof (0, x) === "object") {
+ return "OBJECT";
+ }
+ if (typeof (0, x) === "string") {
+ return "STRING";
+ }
+ if (typeof (0, x) === "symbol") {
+ return "SYMBOL";
+ }
+ if (typeof (0, x) === "undefined") {
+ return "UNDEFINED";
+ }
+ return "???";
+}
+
+function strict_right_expr(x) {
+ if ("boolean" === typeof (0, x)) {
+ return "BOOLEAN";
+ }
+ if ("function" === typeof (0, x)) {
+ return "FUNCTION";
+ }
+ if ("number" === typeof (0, x)) {
+ return "NUMBER";
+ }
+ if ("object" === typeof (0, x)) {
+ return "OBJECT";
+ }
+ if ("string" === typeof (0, x)) {
+ return "STRING";
+ }
+ if ("symbol" === typeof (0, x)) {
+ return "SYMBOL";
+ }
+ if ("undefined" === typeof (0, x)) {
+ return "UNDEFINED";
+ }
+ return "???";
+}
+
+function loose_left_ne_expr(x) {
+ if (typeof (0, x) != "boolean") {
+ } else {
+ return "BOOLEAN";
+ }
+ if (typeof (0, x) != "function") {
+ } else {
+ return "FUNCTION";
+ }
+ if (typeof (0, x) != "number") {
+ } else {
+ return "NUMBER";
+ }
+ if (typeof (0, x) != "object") {
+ } else {
+ return "OBJECT";
+ }
+ if (typeof (0, x) != "string") {
+ } else {
+ return "STRING";
+ }
+ if (typeof (0, x) != "symbol") {
+ } else {
+ return "SYMBOL";
+ }
+ if (typeof (0, x) != "undefined") {
+ } else {
+ return "UNDEFINED";
+ }
+ return "???";
+}
+
+function loose_right_ne_expr(x) {
+ if ("boolean" != typeof (0, x)) {
+ } else {
+ return "BOOLEAN";
+ }
+ if ("function" != typeof (0, x)) {
+ } else {
+ return "FUNCTION";
+ }
+ if ("number" != typeof (0, x)) {
+ } else {
+ return "NUMBER";
+ }
+ if ("object" != typeof (0, x)) {
+ } else {
+ return "OBJECT";
+ }
+ if ("string" != typeof (0, x)) {
+ } else {
+ return "STRING";
+ }
+ if ("symbol" != typeof (0, x)) {
+ } else {
+ return "SYMBOL";
+ }
+ if ("undefined" != typeof (0, x)) {
+ } else {
+ return "UNDEFINED";
+ }
+ return "???";
+}
+
+function strict_left_ne_expr(x) {
+ if (typeof (0, x) !== "boolean") {
+ } else {
+ return "BOOLEAN";
+ }
+ if (typeof (0, x) !== "function") {
+ } else {
+ return "FUNCTION";
+ }
+ if (typeof (0, x) !== "number") {
+ } else {
+ return "NUMBER";
+ }
+ if (typeof (0, x) !== "object") {
+ } else {
+ return "OBJECT";
+ }
+ if (typeof (0, x) !== "string") {
+ } else {
+ return "STRING";
+ }
+ if (typeof (0, x) !== "symbol") {
+ } else {
+ return "SYMBOL";
+ }
+ if (typeof (0, x) !== "undefined") {
+ } else {
+ return "UNDEFINED";
+ }
+ return "???";
+}
+
+function strict_right_ne_expr(x) {
+ if ("boolean" !== typeof (0, x)) {
+ } else {
+ return "BOOLEAN";
+ }
+ if ("function" !== typeof (0, x)) {
+ } else {
+ return "FUNCTION";
+ }
+ if ("number" !== typeof (0, x)) {
+ } else {
+ return "NUMBER";
+ }
+ if ("object" !== typeof (0, x)) {
+ } else {
+ return "OBJECT";
+ }
+ if ("string" !== typeof (0, x)) {
+ } else {
+ return "STRING";
+ }
+ if ("symbol" !== typeof (0, x)) {
+ } else {
+ return "SYMBOL";
+ }
+ if ("undefined" !== typeof (0, x)) {
+ } else {
+ return "UNDEFINED";
+ }
+ return "???";
+}
+
+runTest(loose_left);
+runTest(loose_right);
+runTest(strict_left);
+runTest(strict_right);
+runTest(loose_left_ne);
+runTest(loose_right_ne);
+runTest(strict_left_ne);
+runTest(strict_right_ne);
+runTest(loose_left_expr);
+runTest(loose_right_expr);
+runTest(strict_left_expr);
+runTest(strict_right_expr);
+runTest(loose_left_ne_expr);
+runTest(loose_right_ne_expr);
+runTest(strict_left_ne_expr);
+runTest(strict_right_ne_expr);
diff --git a/js/src/jit-test/tests/bug1894604.js b/js/src/jit-test/tests/bug1894604.js
new file mode 100644
index 0000000000..5c14789eef
--- /dev/null
+++ b/js/src/jit-test/tests/bug1894604.js
@@ -0,0 +1,12 @@
+class C {
+ set f(val) {
+ this.f = val;
+ super.g++;
+ }
+}
+
+let c = new C();
+gczeal(14,50);
+try {
+ c.f = 1;
+} catch {}
diff --git a/js/src/jit-test/tests/debug/Debugger-dead-global.js b/js/src/jit-test/tests/debug/Debugger-dead-global.js
new file mode 100644
index 0000000000..abcb370be0
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-dead-global.js
@@ -0,0 +1,26 @@
+var g1 = newGlobal({newCompartment: true});
+
+const dbg = new Debugger();
+
+function assertThrowsDeadWrapper(f) {
+ let caught = false;
+ try {
+ f();
+ } catch (e) {
+ assertEq(e.message, "can't access dead object");
+ caught = true;
+ }
+ assertEq(caught, true);
+}
+
+nukeAllCCWs();
+
+// Debugger methods should throw explicit error for dead global object.
+assertThrowsDeadWrapper(() => dbg.addDebuggee(g1));
+assertThrowsDeadWrapper(() => dbg.removeDebuggee(g1));
+assertThrowsDeadWrapper(() => dbg.findScripts({global: g1}));
+assertThrowsDeadWrapper(() => dbg.makeGlobalObjectReference(g1));
+assertThrowsDeadWrapper(() => dbg.enableAsyncStack(g1));
+assertThrowsDeadWrapper(() => dbg.disableAsyncStack(g1));
+assertThrowsDeadWrapper(() => dbg.enableUnlimitedStacksCapturing(g1));
+assertThrowsDeadWrapper(() => dbg.disableUnlimitedStacksCapturing(g1));
diff --git a/js/src/jit-test/tests/debug/Debugger-shouldAvoidSideEffects.js b/js/src/jit-test/tests/debug/Debugger-shouldAvoidSideEffects.js
new file mode 100644
index 0000000000..62d6693d4e
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-shouldAvoidSideEffects.js
@@ -0,0 +1,57 @@
+// Test shouldAvoidSideEffects flag.
+
+const g = newGlobal({newCompartment: true});
+const dbg = Debugger(g);
+const gdbg = dbg.addDebuggee(g);
+
+gdbg.executeInGlobal(`
+var obj, result, reachedNextLine;
+`);
+
+dbg.shouldAvoidSideEffects = false;
+assertEq(dbg.shouldAvoidSideEffects, false);
+
+let result = gdbg.executeInGlobal(`
+result = undefined;
+reachedNextLine = false;
+
+obj = createSideEffectfulResolveObject();
+result = obj.test;
+reachedNextLine = true;
+"finished";
+`);
+assertEq(g.result, 42);
+assertEq(g.reachedNextLine, true);
+assertEq(result.return, "finished");
+
+dbg.shouldAvoidSideEffects = true;
+assertEq(dbg.shouldAvoidSideEffects, true);
+
+result = gdbg.executeInGlobal(`
+result = undefined;
+reachedNextLine = false;
+
+obj = createSideEffectfulResolveObject();
+result = obj.test;
+reachedNextLine = true;
+"finished";
+`);
+assertEq(g.result, undefined);
+assertEq(g.reachedNextLine, false);
+assertEq(result, null);
+
+// Resolve after abort.
+dbg.shouldAvoidSideEffects = false;
+assertEq(dbg.shouldAvoidSideEffects, false);
+
+result = gdbg.executeInGlobal(`
+result = undefined;
+reachedNextLine = false;
+
+result = obj.test;
+reachedNextLine = true;
+"finished";
+`);
+assertEq(g.result, 42);
+assertEq(g.reachedNextLine, true);
+assertEq(result.return, "finished");
diff --git a/js/src/jit-test/tests/debug/bug1891662.js b/js/src/jit-test/tests/debug/bug1891662.js
new file mode 100644
index 0000000000..0a68f33d0c
--- /dev/null
+++ b/js/src/jit-test/tests/debug/bug1891662.js
@@ -0,0 +1,24 @@
+// |jit-test| --baseline-eager
+
+var src = "";
+for (var i = 0; i < 100; i++) {
+ src += "function foo" + i + "() { foo" + (i+1) + "(); }"
+}
+eval(src);
+
+function foo100() {
+ let g = newGlobal({newCompartment: true});
+ let d = new g.Debugger(this);
+
+ // When we set this debugger hook, we will trigger 100
+ // baseline recompilations. We want an OOM to occur
+ // during one of those recompilations. We allocate
+ // about 400 times before starting recompilation, and
+ // about 30000 times total. This number is picked to
+ // leave a healthy margin on either side.
+ oomAtAllocation(5000);
+ d.onEnterFrame = () => {}
+}
+try {
+ foo0();
+} catch {}
diff --git a/js/src/jit-test/tests/debug/bug1893554.js b/js/src/jit-test/tests/debug/bug1893554.js
new file mode 100644
index 0000000000..dfe76c8b41
--- /dev/null
+++ b/js/src/jit-test/tests/debug/bug1893554.js
@@ -0,0 +1,31 @@
+let g = newGlobal({ newCompartment: true });
+g.parent = this;
+g.eval(
+ "(" +
+ function () {
+ Debugger(parent).onExceptionUnwind = function (frame) {
+ frame.older;
+ };
+ } +
+ ")()"
+);
+function f(x, y) {
+ try {
+ Object.setPrototypeOf(
+ y,
+ new Proxy(Object.getPrototypeOf(y), {
+ get(a, b, c) {
+ return undefined;
+ },
+ })
+ );
+ } catch (e) {}
+}
+function h(x, y) {
+ f(x, y);
+}
+oomTest(function () {
+ h("", undefined);
+ h("", "");
+ "".replaceAll();
+});
diff --git a/js/src/jit-test/tests/environments/1890252.js b/js/src/jit-test/tests/environments/1890252.js
new file mode 100644
index 0000000000..b44ca2253f
--- /dev/null
+++ b/js/src/jit-test/tests/environments/1890252.js
@@ -0,0 +1,15 @@
+// |jit-test| --more-compartments
+
+var threw = false;
+try {
+ const v2 = evalcx("lazy");
+ const o4 = {
+ "global": v2,
+ };
+ o4.envChainObject = v2;
+ evaluate("{ let eval = parseInt; eval()}", o4);
+} catch (e) {
+ threw = true;
+ assertEq(e.toString().includes("envChainObject"), true);
+}
+assertEq(threw, true);
diff --git a/js/src/jit-test/tests/gc/bug-1651001-1.js b/js/src/jit-test/tests/gc/bug-1651001-1.js
new file mode 100644
index 0000000000..889ab4a5b9
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1651001-1.js
@@ -0,0 +1,9 @@
+gczeal(0);
+try {
+ v2 = (x = []);
+ g1 = newGlobal({ sameZoneAs: x });
+ enableShellAllocationMetadataBuilder();
+ g1.Uint8ClampedArray.prototype = b1;
+} catch(e) {}
+startgc(9);
+recomputeWrappers();
diff --git a/js/src/jit-test/tests/gc/bug-1651001-2.js b/js/src/jit-test/tests/gc/bug-1651001-2.js
new file mode 100644
index 0000000000..ad093ddb22
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1651001-2.js
@@ -0,0 +1,6 @@
+gczeal(0);
+g1 = newGlobal({ sameZoneAs: this });
+enableShellAllocationMetadataBuilder();
+g1.Object;
+startgc(1);
+recomputeWrappers();
diff --git a/js/src/jit-test/tests/gc/bug-1890670.js b/js/src/jit-test/tests/gc/bug-1890670.js
new file mode 100644
index 0000000000..e73c5a99e6
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1890670.js
@@ -0,0 +1,12 @@
+// |jit-test| --enable-symbols-as-weakmap-keys; skip-if: getBuildConfiguration("release_or_beta")
+
+gczeal(0);
+let wm = new WeakMap();
+let s = Symbol();
+wm.set(s, new WeakMap());
+let ss = Symbol();
+wm.get(s).set(this, ss);
+let wm2 = new WeakMap();
+wm2.set(ss, "test");
+ss = null;
+gc();
diff --git a/js/src/jit-test/tests/gc/bug-1892564.js b/js/src/jit-test/tests/gc/bug-1892564.js
new file mode 100644
index 0000000000..c834615b91
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1892564.js
@@ -0,0 +1,50 @@
+try { evalInWorker(`
+gczeal(0);
+try {
+ Object.defineProperty(this, "x", {
+ value:{
+ parseInt: parseInt,
+ }
+ });
+} catch(exc) {}
+function dummyAssertCallFunction(f) {}
+try { evaluate(\`
+(function(global) {
+ var ObjectCreate = global.Object.create;
+ var ObjectDefineProperty = global.Object.defineProperty;
+ function ArrayPush(arr, val) {
+ var desc = ObjectCreate(null);
+ desc.value = val;
+ desc.enumerable = true;
+ desc.configurable = true;
+ desc.writable = true;
+ ObjectDefineProperty(arr, arr.length, desc);
+ }
+ var testCasesArray = [];
+ function TestCase(d, e, a, r) {
+ this.description = d;
+ ArrayPush(testCasesArray, this);
+ }
+ global.TestCase = TestCase;
+})(this);
+(function f42(x99) {
+ new TestCase(new ArrayBuffer());
+ f42(x99)
+ function t9() {}
+})();
+\`); } catch(exc) {}
+try { evaluate(\`
+gczeal(14);
+(function(global) {
+ global.makeIterator = function makeIterator(overrides) {
+ global.assertThrowsValue = function assertThrowsValue(f, val, msg) {};
+ }
+ global.assertDeepEq = (function(){
+ var call = Function.prototype.call,
+ Symbol_description = call.bind(Object.getOwnPropertyDescriptor(Symbol.prototype, "description").get),
+ Map_has = call.bind(Map.prototype.has),
+ Object_getOwnPropertyNames = Object.getOwnPropertyNames;
+ })();
+})(this);
+\`); } catch(exc) {}
+`); throw "x"; } catch(exc) {}
diff --git a/js/src/jit-test/tests/gc/bug-1893984.js b/js/src/jit-test/tests/gc/bug-1893984.js
new file mode 100644
index 0000000000..743be86f4e
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1893984.js
@@ -0,0 +1,3 @@
+gczeal(4, 0)
+a = /b/
+Object.defineProperty(a, this + this, {})
diff --git a/js/src/jit-test/tests/gc/bug-1894025.js b/js/src/jit-test/tests/gc/bug-1894025.js
new file mode 100644
index 0000000000..06ebd8ceb6
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1894025.js
@@ -0,0 +1,15 @@
+gczeal(0);
+
+var ex;
+function makeExtensibleStrFrom() {
+ strstrstr;
+}
+a = makeExtensibleStrFrom;
+b = newDependentString(a, 0, 50, { tenured: false })
+var exc;
+try {
+ c = newDependentString(b, 0, { tenured: true })
+} catch (e) {
+ exc = e;
+}
+assertEq(Boolean(exc), true, "b and c required to be in different heaps but are the same");
diff --git a/js/src/jit-test/tests/gc/bug-1894442.js b/js/src/jit-test/tests/gc/bug-1894442.js
new file mode 100644
index 0000000000..93bedb74de
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1894442.js
@@ -0,0 +1,6 @@
+// |jit-test| --enable-symbols-as-weakmap-keys; skip-if: helperThreadCount() === 0 || getBuildConfiguration("release_or_beta")
+evalInWorker(`
+ a = new WeakSet
+ a.add(Symbol.hasInstance)
+ gczeal(14)(0 .b)
+`)
diff --git a/js/src/jit-test/tests/gc/bug-1894547.js b/js/src/jit-test/tests/gc/bug-1894547.js
new file mode 100644
index 0000000000..78a3cff036
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1894547.js
@@ -0,0 +1,14 @@
+// |jit-test| --enable-symbols-as-weakmap-keys; skip-if: getBuildConfiguration("release_or_beta")
+
+gczeal(0);
+let wm = new WeakMap();
+let s = {};
+wm.set(s, new WeakMap());
+let ss = {x: Symbol()};
+wm.get(s).set(this, ss);
+let wm2 = new WeakMap();
+wm2.set(ss, "test");
+ss = null;
+
+// Collect only this zone and not the zone containing the symbol.
+gc({});
diff --git a/js/src/jit-test/tests/gc/bug-1895842.js b/js/src/jit-test/tests/gc/bug-1895842.js
new file mode 100644
index 0000000000..3f41d10020
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1895842.js
@@ -0,0 +1,5 @@
+// |jit-test| skip-if: helperThreadCount() === 0
+evalInWorker(`
+ enqueueMark("drain")
+ startgc()
+`)
diff --git a/js/src/jit-test/tests/gc/marking-thread-count.js b/js/src/jit-test/tests/gc/marking-thread-count.js
index 5b90e14186..3c2f7ed30d 100644
--- a/js/src/jit-test/tests/gc/marking-thread-count.js
+++ b/js/src/jit-test/tests/gc/marking-thread-count.js
@@ -1,12 +1,18 @@
// |jit-test| skip-if: helperThreadCount() === 0
-let initialGCHelperThreadCount = gcparam('helperThreadCount');
+// Allow maximum number of helper threads
+gcparam('maxHelperThreads', 8);
+gcparam('helperThreadRatio', 100);
+
+check();
-let prevHelperThreadCount = helperThreadCount();
for (let i of [0, 1, 4, 8, 4, 0]) {
- gcparam('markingThreadCount', i);
- assertEq(gcparam('markingThreadCount'), i);
- assertEq(gcparam('helperThreadCount'), initialGCHelperThreadCount);
- assertEq(true, helperThreadCount() >= Math.max(prevHelperThreadCount, i));
- prevHelperThreadCount = helperThreadCount();
+ gcparam('maxMarkingThreads', i);
+ assertEq(gcparam('maxMarkingThreads'), i);
+ check();
+}
+
+function check() {
+ assertEq(gcparam('markingThreadCount') <= gcparam('maxMarkingThreads'), true);
+ assertEq(gcparam('markingThreadCount') < gcparam('helperThreadCount'), true);
}
diff --git a/js/src/jit-test/tests/ion/bug1608256.js b/js/src/jit-test/tests/ion/bug1608256.js
index 4445a41157..0929f9d3f6 100644
--- a/js/src/jit-test/tests/ion/bug1608256.js
+++ b/js/src/jit-test/tests/ion/bug1608256.js
@@ -1,4 +1,4 @@
-// |jit-test| --no-threads; --baseline-warmup-threshold=1; --ion-full-warmup-threshold=1
+// |jit-test| --no-threads; --baseline-warmup-threshold=1
function g(obj, v) {
obj.prop = v;
}
diff --git a/js/src/jit-test/tests/ion/bug1894456-1.js b/js/src/jit-test/tests/ion/bug1894456-1.js
new file mode 100644
index 0000000000..2b8f3e0afe
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1894456-1.js
@@ -0,0 +1,6 @@
+var f32 = new Float32Array(1);
+for (var i = 0; i < 50; i++) {
+ if (f32[0] != null) {
+ }
+ try {} catch {}
+}
diff --git a/js/src/jit-test/tests/ion/bug1894456-2.js b/js/src/jit-test/tests/ion/bug1894456-2.js
new file mode 100644
index 0000000000..20b019738d
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1894456-2.js
@@ -0,0 +1,6 @@
+var f32 = new Float32Array(1);
+for (var i = 0; i < 50; i++) {
+ if (f32[0] != undefined) {
+ }
+ try {} catch {}
+}
diff --git a/js/src/jit-test/tests/ion/depended-on-bit-1.js b/js/src/jit-test/tests/ion/depended-on-bit-1.js
new file mode 100644
index 0000000000..418e7accaa
--- /dev/null
+++ b/js/src/jit-test/tests/ion/depended-on-bit-1.js
@@ -0,0 +1,52 @@
+var dependedOnStrings = [];
+
+var length = 50;
+
+function getSubstr(src, i) {
+ return src.substring(i, i + 50);
+}
+
+function checkProp(o, prop) {
+ return o[prop];
+}
+
+var substrs = [];
+var objs = [];
+
+with({})
+for (var i = 0; i < 1000; i++) {
+ var pieces = [];
+ for (var j = 0; j < 99; j++) {
+ pieces.push("a");
+ pieces.push(Math.floor(Math.random() * 10));
+ }
+ dependedOnStrings.push(pieces.join(""));
+}
+
+for (var i = 0; i < 1000; i++) {
+ // Create a bunch of substrings depending on strings in dependedOnStrings
+ substrs.push(getSubstr(dependedOnStrings[i], (i * 2) % 50));
+ objs.push({});
+}
+
+for (var i = 0; i < 1000; i++) {
+ // Use the depended on strings as keys to get them replaced with
+ // JSAtomRefStrings
+ checkProp(objs[i], dependedOnStrings[i]);
+}
+
+// Use a bunch of memory to try to ensure that we overwrite the buffers
+// that could have erroneously been freed
+for (var i = 0; i < 1000; i++) {
+ var pieces = [];
+ for (var j = 0; j < 99; j++) {
+ pieces.push("b");
+ pieces.push(Math.floor(Math.random() * 10));
+ }
+ dependedOnStrings.push(pieces.join(""));
+}
+
+// Ensure the buffers were not in fact freed
+for (var i = 0; i < 1000; i++) {
+ assertEq(substrs[i].startsWith("a"), true);
+}
diff --git a/js/src/jit-test/tests/ion/depended-on-bit-2.js b/js/src/jit-test/tests/ion/depended-on-bit-2.js
new file mode 100644
index 0000000000..d4090df949
--- /dev/null
+++ b/js/src/jit-test/tests/ion/depended-on-bit-2.js
@@ -0,0 +1,56 @@
+var dependedOnStrings = [];
+
+var length = 50;
+var reg = /q[a0-9]{50}/;
+
+function getSubstr(src, i) {
+ return reg.exec(src)[0];
+}
+
+function checkProp(o, prop) {
+ return o[prop];
+}
+
+var substrs = [];
+var objs = [];
+
+with({})
+for (var i = 0; i < 1000; i++) {
+ var pieces = [];
+ for (var j = 0; j < 99; j++) {
+ if (j == (i * 2) % 50) {
+ pieces.push("q");
+ }
+ pieces.push("a");
+ pieces.push(Math.floor(Math.random() * 10));
+ }
+ dependedOnStrings.push(pieces.join(""));
+}
+
+for (var i = 0; i < 1000; i++) {
+ // Create a bunch of substrings depending on strings in dependedOnStrings
+ substrs.push(getSubstr(dependedOnStrings[i], (i * 2) % 50));
+ objs.push({});
+}
+
+for (var i = 0; i < 1000; i++) {
+ // Use the depended on strings as keys to get them replaced with
+ // JSAtomRefStrings
+ checkProp(objs[i], dependedOnStrings[i]);
+}
+
+// Use a bunch of memory to try to ensure that we overwrite the buffers
+// that could have erroneously been freed
+for (var i = 0; i < 1000; i++) {
+ var pieces = [];
+ for (var j = 0; j < 99; j++) {
+ pieces.push("b");
+ pieces.push(Math.floor(Math.random() * 10));
+ }
+ dependedOnStrings.push(pieces.join(""));
+}
+
+// Ensure the buffers were not in fact freed
+for (var i = 0; i < 1000; i++) {
+ assertEq(substrs[i].startsWith("qa"), true);
+}
diff --git a/js/src/jit-test/tests/modules/dynamic-import-unsupported-attribute.js b/js/src/jit-test/tests/modules/dynamic-import-unsupported-attribute.js
new file mode 100644
index 0000000000..2b6ccb80bf
--- /dev/null
+++ b/js/src/jit-test/tests/modules/dynamic-import-unsupported-attribute.js
@@ -0,0 +1,29 @@
+// |jit-test| --enable-import-attributes
+
+async function test() {
+ try {
+ await import('./not-a-real-file.json', {with:{'unsupportedAttributeKey': 'json'}});
+ throw new Error("unreachable");
+ } catch (error) {
+ assertEq(error instanceof TypeError, true);
+ assertEq(error.message, "Unsupported import attribute: unsupportedAttributeKey");
+ }
+
+ try {
+ await import('./not-a-real-file.json', {with:{'unsupportedAttributeKey': 'json', type: 'json'}});
+ throw new Error("unreachable");
+ } catch (error) {
+ assertEq(error instanceof TypeError, true);
+ assertEq(error.message, "Unsupported import attribute: unsupportedAttributeKey");
+ }
+
+ try {
+ await import('./not-a-real-file.json', {with:{type: 'json', 'unsupportedAttributeKey': 'json'}});
+ throw new Error("unreachable");
+ } catch (error) {
+ assertEq(error instanceof TypeError, true);
+ assertEq(error.message, "Unsupported import attribute: unsupportedAttributeKey");
+ }
+}
+
+test(); \ No newline at end of file
diff --git a/js/src/jit-test/tests/modules/failure-on-resume.js b/js/src/jit-test/tests/modules/failure-on-resume.js
new file mode 100644
index 0000000000..d0e716b0bb
--- /dev/null
+++ b/js/src/jit-test/tests/modules/failure-on-resume.js
@@ -0,0 +1,79 @@
+const dbgGlobal = newGlobal({ newCompartment: true });
+dbgGlobal.parent = this;
+dbgGlobal.eval(`
+var entered = 0;
+var forceReturn = false;
+Debugger(parent).onEnterFrame = function () {
+ entered++;
+ if (forceReturn) {
+ return { return: "force return" };
+ }
+ return undefined;
+};
+`);
+
+{
+ function* f1() { yield 10; };
+
+ dbgGlobal.entered = 0;
+ let g = f1();
+ assertEq(dbgGlobal.entered, 1);
+ dbgGlobal.forceReturn = true;
+ let ret = g.next();
+ dbgGlobal.forceReturn = false;
+ assertEq(dbgGlobal.entered, 2);
+
+ assertEq(ret.value, "force return");
+}
+
+{
+ async function f2() { await {}; }
+
+ dbgGlobal.entered = 0;
+ let p = f2();
+ assertEq(dbgGlobal.entered, 1);
+ dbgGlobal.forceReturn = true;
+ drainJobQueue();
+ dbgGlobal.forceReturn = false;
+ assertEq(dbgGlobal.entered, 2);
+
+ let ret = null;
+ p.then(x => ret = x);
+ drainJobQueue();
+ assertEq(ret, "force return");
+}
+
+{
+ async function* f3() { await {}; }
+
+ dbgGlobal.entered = 0;
+ let g = f3();
+ assertEq(dbgGlobal.entered, 1);
+ dbgGlobal.forceReturn = true;
+ let p = g.next();
+ dbgGlobal.forceReturn = false;
+ assertEq(dbgGlobal.entered, 2);
+
+ let ret = null;
+ p.then(v => ret = v);
+ drainJobQueue();
+ assertEq(ret.value, "force return");
+}
+
+{
+ let m = registerModule("1", parseModule("await {};"));
+ moduleLink(m);
+
+ dbgGlobal.entered = 0;
+ let p = moduleEvaluate(m);
+ assertEq(dbgGlobal.entered, 1);
+ dbgGlobal.forceReturn = true;
+ drainJobQueue();
+ dbgGlobal.forceReturn = false;
+ assertEq(dbgGlobal.entered, 2);
+
+ let ret = null;
+ p.then(x => ret = x);
+ drainJobQueue();
+ assertEq(ret, undefined);
+}
diff --git a/js/src/jit-test/tests/modules/import-entries.js b/js/src/jit-test/tests/modules/import-entries.js
index e20d4e119b..ed668f0069 100644
--- a/js/src/jit-test/tests/modules/import-entries.js
+++ b/js/src/jit-test/tests/modules/import-entries.js
@@ -1,21 +1,24 @@
-// |jit-test| --enable-import-assertions
+// |jit-test| --enable-import-attributes
// Test importEntries property
-function assertionEq(actual, expected) {
- var actualAssertions = actual['assertions'];
- var expectedAssertions = expected['assertions'];
+function attributeEq(actual, expected) {
+ var actualAttributes = actual['attributes'];
+ var expectedAttributes = expected['attributes'];
- if(actualAssertions === null) {
- return expectedAssertions === actualAssertions
+ if(actualAttributes === null) {
+ return expectedAttributes === actualAttributes
}
- if(actualAssertions.length !== expectedAssertions.length) {
+ if(actualAttributes.length !== expectedAttributes.length) {
return false;
}
- for (var i = 0; i < expected.length; i++) {
- if(expected[i].type !== actual[i].type) {
+ for (var i = 0; i < expectedAttributes.length; i++) {
+ if (
+ expectedAttributes[i]['key'] !== actualAttributes[i]['key'] ||
+ expectedAttributes[i]['value'] !== actualAttributes[i]['value']
+ ) {
return false;
}
}
@@ -28,7 +31,7 @@ function importEntryEq(a, b) {
a['importName'] === b['importName'] &&
a['localName'] === b['localName'];
- return r1 && assertionEq(a['moduleRequest'], b['moduleRequest']);
+ return r1 && attributeEq(a['moduleRequest'], b['moduleRequest']);
}
function findImportEntry(array, target)
@@ -54,34 +57,34 @@ function testImportEntries(source, expected) {
testImportEntries('', []);
testImportEntries('import v from "mod";',
- [{moduleRequest: {specifier: 'mod', assertions: null}, importName: 'default', localName: 'v'}]);
+ [{moduleRequest: {specifier: 'mod', attributes: null}, importName: 'default', localName: 'v'}]);
testImportEntries('import * as ns from "mod";',
- [{moduleRequest: {specifier: 'mod', assertions: null}, importName: null, localName: 'ns'}]);
+ [{moduleRequest: {specifier: 'mod', attributes: null}, importName: null, localName: 'ns'}]);
testImportEntries('import {x} from "mod";',
- [{moduleRequest: {specifier: 'mod', assertions: null}, importName: 'x', localName: 'x'}]);
+ [{moduleRequest: {specifier: 'mod', attributes: null}, importName: 'x', localName: 'x'}]);
testImportEntries('import {x as v} from "mod";',
- [{moduleRequest: {specifier: 'mod', assertions: null}, importName: 'x', localName: 'v'}]);
+ [{moduleRequest: {specifier: 'mod', attributes: null}, importName: 'x', localName: 'v'}]);
testImportEntries('import "mod";',
[]);
testImportEntries('import {x} from "a"; import {y} from "b";',
- [{moduleRequest: {specifier: 'a', assertions: null}, importName: 'x', localName: 'x'},
- {moduleRequest: {specifier: 'b', assertions: null}, importName: 'y', localName: 'y'}]);
+ [{moduleRequest: {specifier: 'a', attributes: null}, importName: 'x', localName: 'x'},
+ {moduleRequest: {specifier: 'b', attributes: null}, importName: 'y', localName: 'y'}]);
if (getRealmConfiguration("importAttributes")) {
- testImportEntries('import v from "mod" assert {};',
- [{moduleRequest: {specifier: 'mod', assertions: null}, importName: 'default', localName: 'v'}]);
+ testImportEntries('import v from "mod" with {};',
+ [{moduleRequest: {specifier: 'mod', attributes: null}, importName: 'default', localName: 'v'}]);
- testImportEntries('import v from "mod" assert { type: "js"};',
- [{moduleRequest: {specifier: 'mod', assertions: [{ type: 'js'}]}, importName: 'default', localName: 'v'}]);
+ testImportEntries('import v from "mod" with { type: "js"};',
+ [{moduleRequest: {specifier: 'mod', attributes: [{ key: 'type', value: 'js'}]}, importName: 'default', localName: 'v'}]);
- testImportEntries('import {x} from "mod" assert { type: "js"};',
- [{moduleRequest: {specifier: 'mod', assertions: [{ type: 'js'}]}, importName: 'x', localName: 'x'}]);
+ testImportEntries('import {x} from "mod" with { type: "js"};',
+ [{moduleRequest: {specifier: 'mod', attributes: [{ key: 'type', value: 'js'}]}, importName: 'x', localName: 'x'}]);
- testImportEntries('import {x as v} from "mod" assert { type: "js"};',
- [{moduleRequest: {specifier: 'mod', assertions: [{ type: 'js'}]}, importName: 'x', localName: 'v'}]);
+ testImportEntries('import {x as v} from "mod" with { type: "js"};',
+ [{moduleRequest: {specifier: 'mod', attributes: [{ key: 'type', value: 'js'}]}, importName: 'x', localName: 'v'}]);
}
diff --git a/js/src/jit-test/tests/modules/import-unsupported-attribute.js b/js/src/jit-test/tests/modules/import-unsupported-attribute.js
new file mode 100644
index 0000000000..c771c6556b
--- /dev/null
+++ b/js/src/jit-test/tests/modules/import-unsupported-attribute.js
@@ -0,0 +1,2 @@
+// |jit-test| --enable-import-attributes; module; error: TypeError: Unsupported import attribute: unsupported
+import a from 'foo' with { unsupported: 'test'}
diff --git a/js/src/jit-test/tests/modules/requested-modules.js b/js/src/jit-test/tests/modules/requested-modules.js
index ebbf8ce6c1..e0a7fb66b8 100644
--- a/js/src/jit-test/tests/modules/requested-modules.js
+++ b/js/src/jit-test/tests/modules/requested-modules.js
@@ -1,4 +1,4 @@
-// |jit-test| --enable-import-assertions
+// |jit-test| --enable-import-attributes
// Test requestedModules property
@@ -8,15 +8,16 @@ function testRequestedModules(source, expected) {
assertEq(actual.length, expected.length);
for (var i = 0; i < actual.length; i++) {
assertEq(actual[i].moduleRequest.specifier, expected[i].specifier);
- if(expected[i].assertions === null) {
- assertEq(actual[i].moduleRequest.assertions, null);
+ if(expected[i].attributes === null) {
+ assertEq(actual[i].moduleRequest.attributes, null);
}
else {
- var expectedAssertions = expected[i].assertions;
- var actualAssertions = actual[i].moduleRequest.assertions;
- assertEq(actualAssertions.length, expectedAssertions.length);
- for (var j = 0; j < expectedAssertions.length; j++) {
- assertEq(expectedAssertions[j].type, actualAssertions[j].type);
+ var expectedAttributes = expected[i].attributes;
+ var actualAttributes = actual[i].moduleRequest.attributes;
+ assertEq(actualAttributes.length, expectedAttributes.length);
+ for (var j = 0; j < expectedAttributes.length; j++) {
+ assertEq(expectedAttributes[j]['key'], actualAttributes[j]['key']);
+ assertEq(expectedAttributes[j]['value'], actualAttributes[j]['value']);
}
}
}
@@ -25,71 +26,71 @@ function testRequestedModules(source, expected) {
testRequestedModules("", []);
testRequestedModules("import a from 'foo'", [
- { specifier: 'foo', assertions: null }
+ { specifier: 'foo', attributes: null }
]);
testRequestedModules("import a from 'foo'; import b from 'bar'", [
- { specifier: 'foo', assertions: null },
- { specifier: 'bar', assertions: null }
+ { specifier: 'foo', attributes: null },
+ { specifier: 'bar', attributes: null }
]);
testRequestedModules("import a from 'foo'; import b from 'bar'; import c from 'foo'", [
- { specifier: 'foo', assertions: null },
- { specifier: 'bar', assertions: null }
+ { specifier: 'foo', attributes: null },
+ { specifier: 'bar', attributes: null }
]);
testRequestedModules("export {} from 'foo'", [
- { specifier: 'foo', assertions: null }
+ { specifier: 'foo', attributes: null }
]);
testRequestedModules("export * from 'bar'",[
- { specifier: 'bar', assertions: null }
+ { specifier: 'bar', attributes: null }
]);
testRequestedModules("import a from 'foo'; export {} from 'bar'; export * from 'baz'", [
- { specifier: 'foo', assertions: null },
- { specifier: 'bar', assertions: null },
- { specifier: 'baz', assertions: null }
+ { specifier: 'foo', attributes: null },
+ { specifier: 'bar', attributes: null },
+ { specifier: 'baz', attributes: null }
]);
if (getRealmConfiguration("importAttributes")) {
- testRequestedModules("import a from 'foo' assert {}", [
- { specifier: 'foo', assertions: null },
+ testRequestedModules("import a from 'foo' with {}", [
+ { specifier: 'foo', attributes: null },
]);
- testRequestedModules("import a from 'foo' assert { type: 'js'}", [
- { specifier: 'foo', assertions: [ { type: 'js' } ] },
+ testRequestedModules("import a from 'foo' with { type: 'js'}", [
+ { specifier: 'foo', attributes: [ { key: 'type', value: 'js'} ] },
]);
- testRequestedModules("import a from 'foo' assert { unsupported: 'test'}", [
- { specifier: 'foo', assertions: null },
+ testRequestedModules("import a from 'foo' with { unsupported: 'test'}", [
+ { specifier: 'foo', attributes: [ { key: 'unsupported', value: 'test'} ] },
]);
- testRequestedModules("import a from 'foo' assert { unsupported: 'test', type: 'js', foo: 'bar' }", [
- { specifier: 'foo', assertions: [ { type: 'js' } ] },
+ testRequestedModules("import a from 'foo' with { unsupported: 'test', type: 'js', foo: 'bar' }", [
+ { specifier: 'foo', attributes: [ { key: 'unsupported', value: 'test'}, { key: 'type', value: 'js'}, { key: 'foo', value: 'bar'} ] },
]);
- testRequestedModules("import a from 'foo' assert { type: 'js1'}; export {} from 'bar' assert { type: 'js2'}; export * from 'baz' assert { type: 'js3'}", [
- { specifier: 'foo', assertions: [ { type: 'js1' } ] },
- { specifier: 'bar', assertions: [ { type: 'js2' } ] },
- { specifier: 'baz', assertions: [ { type: 'js3' } ] }
+ testRequestedModules("import a from 'foo' with { type: 'js1'}; export {} from 'bar' with { type: 'js2'}; export * from 'baz' with { type: 'js3'}", [
+ { specifier: 'foo', attributes: [ { key: 'type', value: 'js1'} ] },
+ { specifier: 'bar', attributes: [ { key: 'type', value: 'js2'} ] },
+ { specifier: 'baz', attributes: [ { key: 'type', value: 'js3'} ] }
]);
- testRequestedModules("export {} from 'foo' assert { type: 'js'}", [
- { specifier: 'foo', assertions: [ { type: 'js' } ] }
+ testRequestedModules("export {} from 'foo' with { type: 'js'}", [
+ { specifier: 'foo', attributes: [ { key: 'type', value: 'js'} ] }
]);
- testRequestedModules("export * from 'bar' assert { type: 'json'}",[
- { specifier: 'bar', assertions: [ { type: 'json' } ] }
+ testRequestedModules("export * from 'bar' with { type: 'json'}",[
+ { specifier: 'bar', attributes: [ { key: 'type', value: 'json'} ] }
]);
- testRequestedModules("import a from 'foo'; import b from 'bar' assert { type: 'json' };", [
- { specifier: 'foo', assertions: null },
- { specifier: 'bar', assertions: [ { type: 'json' } ] },
+ testRequestedModules("import a from 'foo'; import b from 'bar' with { type: 'json' };", [
+ { specifier: 'foo', attributes: null },
+ { specifier: 'bar', attributes: [ { key: 'type', value: 'json'} ] },
]);
- testRequestedModules("import b from 'bar' assert { type: 'json' }; import a from 'foo';", [
- { specifier: 'bar', assertions: [ { type: 'json' } ] },
- { specifier: 'foo', assertions: null },
+ testRequestedModules("import b from 'bar' with { type: 'json' }; import a from 'foo';", [
+ { specifier: 'bar', attributes: [ { key: 'type', value: 'json'} ] },
+ { specifier: 'foo', attributes: null },
]);
}
diff --git a/js/src/jit-test/tests/sharedbuf/size-with-uninitialized.js b/js/src/jit-test/tests/sharedbuf/size-with-uninitialized.js
new file mode 100644
index 0000000000..14f6e038ce
--- /dev/null
+++ b/js/src/jit-test/tests/sharedbuf/size-with-uninitialized.js
@@ -0,0 +1,15 @@
+// OOM during SharedArrayBuffer initialization can expose partially initialized
+// object to metadata builder.
+// It shouldn't crash.
+
+newGlobal({ newCompartment: true }).Debugger(this).memory.trackingAllocationSites = true;
+for (let i = 0; i < 9; i++) {
+ oomTest(function () {
+ class C extends WebAssembly.Memory {}
+ new C({
+ initial: 0,
+ maximum: 1,
+ shared: 1,
+ });
+ });
+}
diff --git a/js/src/jit-test/tests/typedarray/arraybuffer-zero-length-alignment-check.js b/js/src/jit-test/tests/typedarray/arraybuffer-zero-length-alignment-check.js
new file mode 100644
index 0000000000..d706977a6e
--- /dev/null
+++ b/js/src/jit-test/tests/typedarray/arraybuffer-zero-length-alignment-check.js
@@ -0,0 +1,29 @@
+// Iterate a few times to increase the likelihood for malloc(0) to return a
+// non-aligned memory.
+for (let i = 0; i < 100; ++i) {
+ // Create a zero-length buffer with malloc'ed memory.
+ let ab = createExternalArrayBuffer(0);
+
+ // Create a typed array which requires 8-byte alignment.
+ let source = new Float64Array(ab);
+
+ // This call shouldn't assert when copying zero bytes from |source|, even when
+ // the memory is non-aligned.
+ let target = new Float64Array(source);
+
+ // Add some uses of the objects.
+ assertEq(ab.byteLength, 0);
+ assertEq(source.byteLength, 0);
+ assertEq(target.byteLength, 0);
+}
+
+// Repeat the above tests with the |createUserArrayBuffer| testing function.
+for (let i = 0; i < 100; ++i) {
+ let ab = createUserArrayBuffer(0);
+ let source = new Float64Array(ab);
+ let target = new Float64Array(source);
+
+ assertEq(ab.byteLength, 0);
+ assertEq(source.byteLength, 0);
+ assertEq(target.byteLength, 0);
+}
diff --git a/js/src/jit-test/tests/typedarray/sort-trampoline.js b/js/src/jit-test/tests/typedarray/sort-trampoline.js
new file mode 100644
index 0000000000..9af8080b52
--- /dev/null
+++ b/js/src/jit-test/tests/typedarray/sort-trampoline.js
@@ -0,0 +1,174 @@
+function testGC() {
+ for (var i = 0; i < 20; i++) {
+ var arr = new BigInt64Array([1n, 3n, 0n, 12345678901234n, -12345678901234567n]);
+ arr.sort((x, y) => {
+ if (i === 17) {
+ gc();
+ }
+ return Number(x) - Number(y);
+ });
+ assertEq(arr.join(), "-12345678901234567,0,1,3,12345678901234");
+ }
+}
+testGC();
+
+function testDetach() {
+ for (var i = 0; i < 20; i++) {
+ var arr = new Float32Array([1, 2.5, -0, 3]);
+ arr.sort((x, y) => {
+ if (i > 15) {
+ detachArrayBuffer(arr.buffer);
+ }
+ return x - y;
+ });
+ if (i > 15) {
+ assertEq(arr.length, 0);
+ assertEq(arr[0], undefined);
+ } else {
+ assertEq(arr.join(","), "0,1,2.5,3");
+ }
+ }
+}
+testDetach();
+
+function testException() {
+ var arr = new BigInt64Array([1n, 3n, 0n, 4n, 1n]);
+ var ex;
+ try {
+ for (var i = 0; i < 20; i++) {
+ arr.sort((x, y) => {
+ if (i === 17) {
+ throw "fit";
+ }
+ return Number(x) - Number(y);
+ });
+ }
+ } catch (e) {
+ ex = e;
+ }
+ assertEq(ex, "fit");
+ assertEq(i, 17);
+ assertEq(arr.join(), "0,1,1,3,4");
+
+}
+testException();
+
+function testRectifier() {
+ var arr = new Uint32Array([0xffff, 0xffff_ffff, -1, 0]);
+ for (var i = 0; i < 20; i++) {
+ arr.sort(function(x, y, a) {
+ assertEq(arguments.length, 2);
+ assertEq(a, undefined);
+ return y - x;
+ });
+ }
+ assertEq(arr.join(), "4294967295,4294967295,65535,0");
+}
+testRectifier();
+
+function testClassConstructor() {
+ var normal = (x, y) => x - y;
+ 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 = new Uint8Array([0, 5, 1, 3]);
+ var ex;
+ try {
+ arr.sort(i < 17 ? normal : ctor);
+ } catch (e) {
+ ex = e;
+ }
+ assertEq(ex instanceof TypeError, i >= 17);
+ assertEq(arr.join(""), i >= 17 ? "0513" : "0135");
+ }
+}
+testClassConstructor();
+
+function testSwitchRealms() {
+ var arr = new Uint8ClampedArray([5, 3, 0, 1]);
+ var g = newGlobal({sameCompartmentAs: this});
+ g.foo = 123;
+ var comp = g.evaluate(`((x, y) => {
+ assertEq(foo, 123);
+ return x - y;
+ })`);
+ for (var i = 0; i < 20; i++) {
+ arr.sort(comp);
+ }
+ assertEq(arr.join(""), "0135");
+}
+testSwitchRealms();
+
+function testCrossCompartment() {
+ var g = newGlobal({newCompartment: true});
+ var wrapper = g.evaluate(`((x, y) => {
+ return Number(x) - Number(y);
+ })`);
+ for (var i = 0; i < 20; i++) {
+ var arr = new BigUint64Array([1n, 0n, 1234567890123n, 98765432109876n, 0n]);
+ arr.sort(wrapper);
+ assertEq(arr.join(), "0,0,1,1234567890123,98765432109876");
+ }
+}
+testCrossCompartment();
+
+function testBound() {
+ var fun = (function(a, x, y) {
+ "use strict";
+ assertEq(this, null);
+ assertEq(a, 1);
+ return Number(x) - Number(y);
+ }).bind(null, 1);
+ for (var i = 0; i < 20; i++) {
+ var arr = new BigUint64Array([1n, 0n, 1234567890123n, 98765432109876n, 0n]);
+ arr.sort(fun);
+ assertEq(arr.join(), "0,0,1,1234567890123,98765432109876");
+ }
+}
+testBound();
+
+function testExtraArgs() {
+ var arr = new Int8Array([1, 3, 5, 0]);
+ var cmp = (x, y) => x - y - 1;
+ for (var i = 0; i < 20; i++) {
+ arr.sort(cmp, cmp, cmp, cmp, cmp, cmp, cmp);
+ }
+ assertEq(arr.join(""), "1035");
+}
+testExtraArgs();
+
+function testBailout() {
+ for (var i = 0; i < 110; i++) {
+ var arr = new Float64Array([1, 3.3, 5.5, -0, NaN]);
+ arr.sort(function(x, y) {
+ if (i === 108) {
+ bailout();
+ }
+ return x - y;
+ });
+ assertEq(arr.join(","), "0,1,3.3,5.5,NaN");
+ }
+}
+testBailout();
+
+function testExceptionHandlerSwitchRealm() {
+ var g = newGlobal({sameCompartmentAs: this});
+ for (var i = 0; i < 25; i++) {
+ var ex = null;
+ try {
+ Int8Array.prototype.toSorted.call(new Int8Array([1, 2, 3]), () => {
+ throw "fit";
+ });
+ } catch (e) {
+ ex = e;
+ }
+ assertEq(ex, "fit");
+ }
+}
+testExceptionHandlerSwitchRealm();
diff --git a/js/src/jit-test/tests/typedarray/sort-wrapper.js b/js/src/jit-test/tests/typedarray/sort-wrapper.js
new file mode 100644
index 0000000000..f646ccd0a5
--- /dev/null
+++ b/js/src/jit-test/tests/typedarray/sort-wrapper.js
@@ -0,0 +1,21 @@
+function test() {
+ var g = newGlobal({ newCompartment: true });
+ var wrapped = g.evaluate("new Int32Array([1, 3, 2, 0])");
+ var wrappedOther = g.evaluate("({})");
+ var unwrapped = new Int32Array(10);
+
+ var ex;
+ try {
+ unwrapped.sort.call(wrappedOther);
+ } catch (e) {
+ ex = e;
+ }
+ assertEq(ex instanceof TypeError, true);
+
+ assertEq(unwrapped.sort.call(wrapped), wrapped);
+ assertEq(wrapped.toString(), "0,1,2,3");
+
+ assertEq(unwrapped.sort.call(wrapped, (a, b) => b - a), wrapped);
+ assertEq(wrapped.toString(), "3,2,1,0");
+}
+test();
diff --git a/js/src/jit-test/tests/warp/bug1683306.js b/js/src/jit-test/tests/warp/bug1683306.js
index 3c74c3f612..193da36af4 100644
--- a/js/src/jit-test/tests/warp/bug1683306.js
+++ b/js/src/jit-test/tests/warp/bug1683306.js
@@ -1,4 +1,4 @@
-// |jit-test| --ion-offthread-compile=off; --ion-full-warmup-threshold=0; --ion-gvn=off; --baseline-eager
+// |jit-test| --ion-offthread-compile=off; --ion-gvn=off; --baseline-eager
//
// Bug 1683306 - Assertion failure: !genObj->hasStackStorage() || genObj->isStackStorageEmpty(), at vm/GeneratorObject.cpp:144
diff --git a/js/src/jit-test/tests/warp/bug1683614.js b/js/src/jit-test/tests/warp/bug1683614.js
index 1d0a4724ff..58c67c7a91 100644
--- a/js/src/jit-test/tests/warp/bug1683614.js
+++ b/js/src/jit-test/tests/warp/bug1683614.js
@@ -1,4 +1,4 @@
-// |jit-test| --ion-offthread-compile=off; --ion-full-warmup-threshold=0; --baseline-eager; skip-if: !this.hasOwnProperty("ReadableStream")
+// |jit-test| --ion-offthread-compile=off; --baseline-eager; skip-if: !this.hasOwnProperty("ReadableStream")
gczeal(9, 8);
function s() { }
@@ -10,4 +10,4 @@ new ReadableStream({
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/wasm/branch-hinting/complex_control_flow.js b/js/src/jit-test/tests/wasm/branch-hinting/complex_control_flow.js
new file mode 100644
index 0000000000..727a3156fb
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/branch-hinting/complex_control_flow.js
@@ -0,0 +1,38 @@
+// Test branch hinting with nested if.
+
+var imports = { "":{inc() { counter++ }} };
+counter = 0;
+
+let module = new WebAssembly.Module(wasmTextToBinary(`(module
+ (import "" "inc" (func (result i32)))
+ (func
+ (result i32)
+ (@metadata.code.branch_hint "\\00") (if (result i32)
+ (i32.const 1)
+ (then
+ (@metadata.code.branch_hint "\\00") (if (result i32)
+ (i32.const 2)
+ (then
+ (@metadata.code.branch_hint "\\00") (if (result i32)
+ (i32.const 3)
+ (then
+ (@metadata.code.branch_hint "\\00") (if (result i32)
+ (i32.const 0)
+ (then (call 0))
+ (else (i32.const 42))
+ )
+ )
+ (else (call 0))
+ )
+ )
+ (else (call 0))
+ )
+ )
+ (else (call 0))
+ )
+ )
+ (export "run" (func 1))
+)`, 42, imports));
+
+assertEq(counter, 0);
+assertEq(wasmParsedBranchHints(module), true);
diff --git a/js/src/jit-test/tests/wasm/branch-hinting/directives.txt b/js/src/jit-test/tests/wasm/branch-hinting/directives.txt
new file mode 100644
index 0000000000..8fe3d1e8e4
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/branch-hinting/directives.txt
@@ -0,0 +1 @@
+|jit-test| --setpref=wasm_branch_hinting=true; --wasm-compiler=ion; test-also=--wasm-compiler=baseline;skip-if: !wasmBranchHintingEnabled(); include:wasm.js
diff --git a/js/src/jit-test/tests/wasm/branch-hinting/parsing.js b/js/src/jit-test/tests/wasm/branch-hinting/parsing.js
new file mode 100644
index 0000000000..0ff9b0f557
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/branch-hinting/parsing.js
@@ -0,0 +1,154 @@
+// Make sure we are correctly parsing this custom section.
+var code =`
+(module
+ (func $$dummy)
+ (func $main (param i32) (result i32)
+ i32.const 0
+ local.get 0
+ i32.eq
+ ;; Only allowed on br_if and if
+ (@metadata.code.branch_hint "\\00") if
+ call $$dummy
+ i32.const 1
+ return
+ else
+ call $$dummy
+ i32.const 0
+ return
+ end
+ i32.const 3
+ return
+ )
+
+ (export "_main" (func $main))
+)`;
+
+let branchHintsModule = new WebAssembly.Module(wasmTextToBinary(code));
+assertEq(WebAssembly.Module.customSections(branchHintsModule, "metadata.code.branch_hint").length, 1);
+assertEq(wasmParsedBranchHints(branchHintsModule), true);
+
+let instance = new WebAssembly.Instance(branchHintsModule);
+assertEq(instance.exports._main(0), 1);
+
+// Testing branch hints parsing on `if` and `br_if`
+branchHintsModule = new WebAssembly.Module(wasmTextToBinary(`
+(module
+ (func $main
+ i32.const 0
+ (@metadata.code.branch_hint "\\00")
+ if
+ i32.const 0
+ (@metadata.code.branch_hint "\\01")
+ br_if 0
+ end
+ )
+ (export "_main" (func $main))
+)`));
+assertEq(wasmParsedBranchHints(branchHintsModule), true);
+instance = new WebAssembly.Instance(branchHintsModule);
+instance.exports._main();
+
+let m = new WebAssembly.Module(wasmTextToBinary(`
+(module
+ (type (;0;) (func))
+ (type (;1;) (func (param i32) (result i32)))
+ (type (;2;) (func (result i32)))
+ (func $__wasm_nullptr (type 0)
+ unreachable)
+ (func $main (type 2) (result i32)
+ (local i32 i32 i32 i32)
+ i32.const 0
+ local.tee 2
+ local.set 3
+ loop
+ local.get 2
+ i32.const 50000
+ i32.eq
+ (@metadata.code.branch_hint "\\00") if
+ i32.const 1
+ local.set 3
+ end
+ local.get 2
+ i32.const 1
+ i32.add
+ local.tee 2
+ i32.const 100000
+ i32.ne
+ (@metadata.code.branch_hint "\\01") br_if 0 (;@1;)
+ end
+ local.get 3)
+ (table (;0;) 1 1 funcref)
+ (memory (;0;) 17 128)
+ (global (;0;) (mut i32) (i32.const 42))
+ (export "memory" (memory 0))
+ (export "_main" (func $main))
+ (elem (;0;) (i32.const 0) func $__wasm_nullptr)
+ (type (;0;) (func (param i32)))
+)`));
+
+assertEq(wasmParsedBranchHints(m), true);
+instance = new WebAssembly.Instance(m);
+assertEq(instance.exports._main(0), 1);
+
+// Testing invalid values for branch hints
+assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(`
+(module
+ (func $main (param i32) (result i32)
+ i32.const 0
+ (@metadata.code.branch_hint "\\0000000") if
+ i32.const 1
+ return
+ end
+ i32.const 42
+ return
+ )
+ )
+`)), SyntaxError, /invalid value for branch hint/);
+
+assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(`
+(module
+ (func $main (param i32) (result i32)
+ i32.const 0
+ (@metadata.code.branch_hint "\\02") if
+ i32.const 1
+ return
+ end
+ i32.const 42
+ return
+ )
+ )
+`)), SyntaxError, /invalid value for branch hint/);
+
+assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(`
+(module
+ (func $main (param i32) (result i32)
+ i32.const 0
+ (@metadata.code.branch_hint "\\aaaa") if
+ i32.const 1
+ return
+ end
+ i32.const 42
+ return
+ )
+ )
+`)), SyntaxError, /wasm text error/);
+
+assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(`
+(module
+ (func $main (param i32) (result i32)
+ i32.const 0
+ (@metadata.code.branch_hint) if
+ i32.const 1
+ return
+ end
+ i32.const 42
+ return
+ )
+ )
+`)), SyntaxError, /wasm text error/);
+
+assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(`
+(module
+ (@metadata.code.branch_hint)
+)
+`)), SyntaxError, /wasm text error/);
diff --git a/js/src/jit-test/tests/wasm/branch-hinting/simple_example.js b/js/src/jit-test/tests/wasm/branch-hinting/simple_example.js
new file mode 100644
index 0000000000..141ee02fef
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/branch-hinting/simple_example.js
@@ -0,0 +1,41 @@
+// Branch Hinting proposal
+
+function runModule(hint) {
+ let code =`
+ (module
+ (func $$dummy)
+ (func $main (param i32) (result i32)
+ i32.const 0
+ local.get 0
+ i32.eq
+ ;; Only allowed on br_if and if
+ (@metadata.code.branch_hint "${hint}") if
+ call $$dummy
+ i32.const 1
+ return
+ else
+ call $$dummy
+ i32.const 0
+ return
+ end
+ i32.const 3
+ return
+ )
+ (export "_main" (func $main))
+ )`;
+ let branchHintsModule = new WebAssembly.Module(wasmTextToBinary(code));
+ assertEq(wasmParsedBranchHints(branchHintsModule), true);
+
+ let instance = new WebAssembly.Instance(branchHintsModule);
+ assertEq(instance.exports._main(0), 1);
+}
+
+// Ensure that we have the same result with different branch hints.
+runModule("\\00");
+runModule("\\01");
+
+let module = new WebAssembly.Module(wasmTextToBinary(`
+ (func i32.const 0 (@metadata.code.branch_hint "\\00") if end)
+`))
+
+assertEq(wasmParsedBranchHints(module), true);
diff --git a/js/src/jit-test/tests/wasm/builtin-modules/js-string/basic.js b/js/src/jit-test/tests/wasm/builtin-modules/js-string/basic.js
index 2c0ecb89c5..4c789dda19 100644
--- a/js/src/jit-test/tests/wasm/builtin-modules/js-string/basic.js
+++ b/js/src/jit-test/tests/wasm/builtin-modules/js-string/basic.js
@@ -34,14 +34,14 @@ let testModule = `(module
(func
(import "wasm:js-string" "fromCharCode")
(param i32)
- (result externref)
+ (result (ref extern))
)
(export "fromCharCode" (func 4))
(func
(import "wasm:js-string" "fromCodePoint")
(param i32)
- (result externref)
+ (result (ref extern))
)
(export "fromCodePoint" (func 5))
@@ -69,14 +69,14 @@ let testModule = `(module
(func
(import "wasm:js-string" "concat")
(param externref externref)
- (result externref)
+ (result (ref extern))
)
(export "concat" (func 9))
(func
(import "wasm:js-string" "substring")
(param externref i32 i32)
- (result externref)
+ (result (ref extern))
)
(export "substring" (func 10))
diff --git a/js/src/jit-test/tests/wasm/exnref/casting.js b/js/src/jit-test/tests/wasm/exnref/casting.js
index fa433fc152..20fbd145fe 100644
--- a/js/src/jit-test/tests/wasm/exnref/casting.js
+++ b/js/src/jit-test/tests/wasm/exnref/casting.js
@@ -1,110 +1,199 @@
// |jit-test| skip-if: !wasmGcEnabled()
-const {
- refCast,
- refTest,
- branch,
- branchFail,
- refCastNullable,
- refTestNullable,
- branchNullable,
- branchFailNullable,
-} = wasmEvalText(`(module
- (tag $a)
- (func $make (param $null i32) (result exnref)
- (if (local.get $null)
- (then
- (return (ref.null exn))
+// Test exnref
+{
+ const {
+ refCast,
+ refTest,
+ branch,
+ branchFail,
+ refCastNullable,
+ refTestNullable,
+ branchNullable,
+ branchFailNullable,
+ } = wasmEvalText(`(module
+ (tag $a)
+ (func $make (param $null i32) (result exnref)
+ (if (local.get $null)
+ (then
+ (return (ref.null exn))
+ )
)
- )
- try_table (catch_all_ref 0)
- throw $a
- end
- unreachable
- )
+ try_table (catch_all_ref 0)
+ throw $a
+ end
+ unreachable
+ )
- (func (export "refCast") (param $null i32)
- (call $make (local.get $null))
- ref.cast (ref exn)
- drop
- )
- (func (export "refTest") (param $null i32) (result i32)
- (call $make (local.get $null))
- ref.test (ref exn)
- )
- (func (export "branch") (param $null i32) (result i32)
- (block (result (ref exn))
+ (func (export "refCast") (param $null i32)
(call $make (local.get $null))
- br_on_cast 0 exnref (ref exn)
+ ref.cast (ref exn)
drop
- (return (i32.const 0))
)
- drop
- (return (i32.const 1))
- )
- (func (export "branchFail") (param $null i32) (result i32)
- (block (result exnref)
+ (func (export "refTest") (param $null i32) (result i32)
(call $make (local.get $null))
- br_on_cast_fail 0 exnref (ref exn)
+ ref.test (ref exn)
+ )
+ (func (export "branch") (param $null i32) (result i32)
+ (block (result (ref exn))
+ (call $make (local.get $null))
+ br_on_cast 0 exnref (ref exn)
+ drop
+ (return (i32.const 0))
+ )
drop
(return (i32.const 1))
)
- drop
- (return (i32.const 0))
- )
+ (func (export "branchFail") (param $null i32) (result i32)
+ (block (result exnref)
+ (call $make (local.get $null))
+ br_on_cast_fail 0 exnref (ref exn)
+ drop
+ (return (i32.const 1))
+ )
+ drop
+ (return (i32.const 0))
+ )
- (func (export "refCastNullable") (param $null i32)
- (call $make (local.get $null))
- ref.cast exnref
- drop
- )
- (func (export "refTestNullable") (param $null i32) (result i32)
- (call $make (local.get $null))
- ref.test exnref
- )
- (func (export "branchNullable") (param $null i32) (result i32)
- (block (result exnref)
+ (func (export "refCastNullable") (param $null i32)
(call $make (local.get $null))
- br_on_cast 0 exnref exnref
+ ref.cast exnref
drop
- (return (i32.const 0))
)
- drop
- (return (i32.const 1))
- )
- (func (export "branchFailNullable") (param $null i32) (result i32)
- (block (result exnref)
+ (func (export "refTestNullable") (param $null i32) (result i32)
(call $make (local.get $null))
- br_on_cast_fail 0 exnref exnref
+ ref.test exnref
+ )
+ (func (export "branchNullable") (param $null i32) (result i32)
+ (block (result exnref)
+ (call $make (local.get $null))
+ br_on_cast 0 exnref exnref
+ drop
+ (return (i32.const 0))
+ )
drop
(return (i32.const 1))
)
- drop
- (return (i32.const 0))
- )
-)`).exports;
+ (func (export "branchFailNullable") (param $null i32) (result i32)
+ (block (result exnref)
+ (call $make (local.get $null))
+ br_on_cast_fail 0 exnref exnref
+ drop
+ (return (i32.const 1))
+ )
+ drop
+ (return (i32.const 0))
+ )
+ )`).exports;
-// cast non-null exnref -> (ref exn)
-refCast(0);
-assertEq(refTest(0), 1);
-assertEq(branch(0), 1);
-assertEq(branchFail(0), 1);
+ // cast non-null exnref -> (ref exn)
+ refCast(0);
+ assertEq(refTest(0), 1);
+ assertEq(branch(0), 1);
+ assertEq(branchFail(0), 1);
-// cast non-null exnref -> exnref
-refCastNullable(0);
-assertEq(refTestNullable(0), 1);
-assertEq(branchNullable(0), 1);
-assertEq(branchFailNullable(0), 1);
+ // cast non-null exnref -> exnref
+ refCastNullable(0);
+ assertEq(refTestNullable(0), 1);
+ assertEq(branchNullable(0), 1);
+ assertEq(branchFailNullable(0), 1);
+
+ // cast null exnref -> (ref exn)
+ assertErrorMessage(() => refCast(1), WebAssembly.RuntimeError, /bad cast/);
+ assertEq(refTest(1), 0);
+ assertEq(branch(1), 0);
+ assertEq(branchFail(1), 0);
+
+ // cast null exnref -> exnref
+ refCastNullable(1);
+ assertEq(refTestNullable(1), 1);
+ assertEq(branchNullable(1), 1);
+ assertEq(branchFailNullable(1), 1);
+}
+
+
+// Test nullexnref
+{
+ const {
+ refCastNull,
+ refCastNonNull,
+ refTestNull,
+ refTestNonNull,
+ branchNull,
+ branchNonNull,
+ branchFailNull,
+ branchFailNonNull,
+ } = wasmEvalText(`(module
+ (func (export "refCastNull")
+ ref.null noexn
+ ref.cast nullexnref
+ drop
+ )
+ (func (export "refCastNonNull")
+ ref.null noexn
+ ref.cast (ref noexn)
+ drop
+ )
+ (func (export "refTestNull") (result i32)
+ ref.null noexn
+ ref.test nullexnref
+ )
+ (func (export "refTestNonNull") (result i32)
+ ref.null noexn
+ ref.test (ref noexn)
+ )
+ (func (export "branchNull") (result i32)
+ (block (result nullexnref)
+ ref.null noexn
+ br_on_cast 0 exnref nullexnref
+ drop
+ (return (i32.const 0))
+ )
+ drop
+ (return (i32.const 1))
+ )
+ (func (export "branchNonNull") (result i32)
+ (block (result (ref noexn))
+ ref.null noexn
+ br_on_cast 0 exnref (ref noexn)
+ drop
+ (return (i32.const 0))
+ )
+ drop
+ (return (i32.const 1))
+ )
+ (func (export "branchFailNull") (result i32)
+ (block (result exnref)
+ ref.null noexn
+ br_on_cast_fail 0 exnref (ref noexn)
+ drop
+ (return (i32.const 1))
+ )
+ drop
+ (return (i32.const 0))
+ )
+ (func (export "branchFailNonNull") (result i32)
+ (block (result (ref exn))
+ ref.null noexn
+ br_on_cast_fail 0 exnref (ref null noexn)
+ drop
+ (return (i32.const 1))
+ )
+ drop
+ (return (i32.const 0))
+ )
+ )`).exports;
-// cast null exnref -> (ref exn)
-assertErrorMessage(() => refCast(1), WebAssembly.RuntimeError, /bad cast/);
-assertEq(refTest(1), 0);
-assertEq(branch(1), 0);
-assertEq(branchFail(1), 0);
+ // null exceptions can be casted to nullexnref
+ refCastNull();
+ assertEq(refTestNull(), 1);
+ assertEq(branchNull(), 1);
+ assertEq(branchFailNull(), 0);
-// cast null exnref -> exnref
-refCastNullable(1);
-assertEq(refTestNullable(1), 1);
-assertEq(branchNullable(1), 1);
-assertEq(branchFailNullable(1), 1);
+ // null exceptions cannot be casted to (ref noexn)
+ assertErrorMessage(() => refCastNonNull(), WebAssembly.RuntimeError, /bad cast/);
+ assertEq(refTestNonNull(), 0);
+ assertEq(branchNonNull(), 0);
+ assertEq(branchFailNonNull(), 1);
+}
diff --git a/js/src/jit-test/tests/wasm/exnref/try-table.js b/js/src/jit-test/tests/wasm/exnref/try-table.js
index c89330917c..407d6db133 100644
--- a/js/src/jit-test/tests/wasm/exnref/try-table.js
+++ b/js/src/jit-test/tests/wasm/exnref/try-table.js
@@ -382,3 +382,56 @@
}
}
}
+
+// WebAssembly.JSTag property is read-only and enumerable
+WebAssembly.JSTag = null;
+assertEq(WebAssembly.JSTag !== null, true);
+assertEq(WebAssembly.propertyIsEnumerable('JSTag'), true);
+
+// Test try_table catching JS exceptions and unpacking them using JSTag
+{
+ let tag = WebAssembly.JSTag;
+ let values = [...WasmExternrefValues];
+ function throwJS(value) {
+ throw value;
+ }
+ let {test} = wasmEvalText(`(module
+ (import "" "tag" (tag $tag (param externref)))
+ (import "" "throwJS" (func $throwJS (param externref)))
+ (func (export "test") (param externref) (result externref)
+ try_table (catch $tag 0)
+ local.get 0
+ call $throwJS
+ end
+ unreachable
+ )
+ )`, {"": {tag, throwJS}}).exports;
+
+ for (let value of values) {
+ assertEq(value, test(value));
+ }
+}
+
+// Test try_table catching JS exceptions using JSTag and unpacking them using JSTag
+{
+ let tag = WebAssembly.JSTag;
+ let values = [...WasmExternrefValues];
+ function throwJS(value) {
+ throw new WebAssembly.Exception(tag, [value]);
+ }
+ let {test} = wasmEvalText(`(module
+ (import "" "tag" (tag $tag (param externref)))
+ (import "" "throwJS" (func $throwJS (param externref)))
+ (func (export "test") (param externref) (result externref)
+ try_table (catch $tag 0)
+ local.get 0
+ call $throwJS
+ end
+ unreachable
+ )
+ )`, {"": {tag, throwJS}}).exports;
+
+ for (let value of values) {
+ assertEq(value, test(value));
+ }
+}
diff --git a/js/src/jit-test/tests/wasm/js-promise-integration/basic.js b/js/src/jit-test/tests/wasm/js-promise-integration/basic.js
new file mode 100644
index 0000000000..8603886b07
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/js-promise-integration/basic.js
@@ -0,0 +1,147 @@
+// Example from the proposal.
+
+var compute_delta = async (i) => Promise.resolve(i / 100 || 1);
+
+var suspending_compute_delta = new WebAssembly.Function(
+ { parameters: ['externref', 'i32'], results: ['f64'] },
+ compute_delta,
+ { suspending: "first" }
+);
+
+var ins = wasmEvalText(`(module
+ (import "js" "init_state" (func $init_state (result f64)))
+ (import "js" "compute_delta"
+ (func $compute_delta_import (param externref) (param i32) (result f64)))
+
+ (global $suspender (mut externref) (ref.null extern))
+ (global $state (mut f64) (f64.const nan))
+ (func $init (global.set $state (call $init_state)))
+ (start $init)
+
+ (func $compute_delta (param i32) (result f64)
+ (local $suspender_copy externref)
+ (;return (f64.const 0.3);)
+ (;unreachable;)
+ (global.get $suspender)
+ (local.tee $suspender_copy)
+ (local.get 0)
+ (call $compute_delta_import)
+ (local.get $suspender_copy)
+ (global.set $suspender)
+ (return)
+ )
+ (func $get_state (export "get_state") (result f64) (global.get $state))
+ (func $update_state (param i32) (result f64)
+ (global.set $state (f64.add
+ (global.get $state) (call $compute_delta (local.get 0))))
+ (global.get $state)
+ )
+
+ (func (export "update_state_export")
+ (param $suspender externref) (param i32) (result f64)
+ (local.get $suspender)
+ (global.set $suspender)
+ (local.get 1)
+ (call $update_state)
+ (return)
+ )
+)`, {
+ js: {
+ init_state() { return 0; },
+ compute_delta: suspending_compute_delta,
+ },
+});
+
+var update_state = new WebAssembly.Function(
+ { parameters: ['i32'], results: ['externref'] },
+ ins.exports.update_state_export,
+ { promising: "first" }
+);
+
+var res = update_state(4);
+var tasks = res.then((r) => {
+ print(r);
+ assertEq(ins.exports.get_state(), .04);
+});
+
+assertEq(ins.exports.get_state(), 0);
+
+// Also test with exceptions/traps.
+
+async function test(c) {
+ var compute_delta = (i) => Promise.resolve(i/100 || 1);
+ if (c == 1) compute_delta = async (i) => {throw "ff"};
+ if (c == 2) compute_delta = () => {throw "ff";}
+
+ var suspending_compute_delta = new WebAssembly.Function(
+ {parameters:['externref', 'i32'], results:['f64']},
+ compute_delta,
+ {suspending:"first"}
+ );
+
+ var ins = wasmEvalText(`(module
+ (import "js" "init_state" (func $init_state (result f64)))
+ (import "js" "compute_delta"
+ (func $compute_delta_import (param externref) (param i32) (result f64)))
+
+ (global $suspender (mut externref) (ref.null extern))
+ (global $state (mut f64) (f64.const nan))
+ (func $init (global.set $state (call $init_state)))
+ (start $init)
+
+ (func $compute_delta (param i32) (result f64)
+ (local $suspender_copy externref)
+ (;return (f64.const 0.3);)
+ ${c == 3 ? "(unreachable)" : ""}
+ (global.get $suspender)
+ (local.tee $suspender_copy)
+ (local.get 0)
+ (call $compute_delta_import)
+ ${c == 4 ? "(unreachable)" : ""}
+ (local.get $suspender_copy)
+ (global.set $suspender)
+ (return)
+ )
+ (func $get_state (export "get_state") (result f64) (global.get $state))
+ (func $update_state (param i32) (result f64)
+ (global.set $state (f64.add
+ (global.get $state) (call $compute_delta (local.get 0))))
+ (global.get $state)
+ )
+
+ (func (export "update_state_export")
+ (param $suspender externref) (param i32) (result f64)
+ (local.get $suspender)
+ (global.set $suspender)
+ (local.get 1)
+ (call $update_state)
+ (return)
+ )
+ )`, {
+ js: {
+ init_state() { return 0; },
+ compute_delta: suspending_compute_delta,
+ },
+ });
+
+ var update_state = new WebAssembly.Function(
+ {parameters:['i32'], results:['externref']},
+ ins.exports.update_state_export,
+ {promising : "first"}
+ );
+
+ var res = update_state(4);
+ var p = res.then((r) => {
+ assertEq(c, 0);
+ assertEq(ins.exports.get_state(), .04);
+ }).catch(_ => {
+ assertEq(c > 0, true);
+ });
+
+ assertEq(ins.exports.get_state(), 0);
+ await p;
+}
+
+for (let c = 0; c < 5; c++) {
+ tasks = tasks.then(() => test(c));
+}
diff --git a/js/src/jit-test/tests/wasm/js-promise-integration/basic2.js b/js/src/jit-test/tests/wasm/js-promise-integration/basic2.js
new file mode 100644
index 0000000000..d381951b2c
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/js-promise-integration/basic2.js
@@ -0,0 +1,97 @@
+// New API experiments.
+// Example from the proposal.
+
+var compute_delta = async (i) => Promise.resolve(i / 100 || 1);
+
+var suspending_compute_delta = new WebAssembly.Suspending(
+ compute_delta
+);
+var ins = wasmEvalText(`(module
+ (import "js" "init_state" (func $init_state (result f64)))
+ (import "js" "compute_delta"
+ (func $compute_delta (param i32) (result f64)))
+
+ (global $suspender (mut externref) (ref.null extern))
+ (global $state (mut f64) (f64.const nan))
+ (func $init (global.set $state (call $init_state)))
+ (start $init)
+
+ (func $get_state (export "get_state") (result f64) (global.get $state))
+ (func (export "update_state_export") (param i32) (result f64)
+ (global.set $state (f64.add
+ (global.get $state) (call $compute_delta (local.get 0))))
+ (global.get $state)
+ )
+)`, {
+ js: {
+ init_state() { return 0; },
+ compute_delta: suspending_compute_delta,
+ },
+});
+
+var update_state = WebAssembly.promising(
+ ins.exports.update_state_export
+);
+
+var res = update_state(4);
+var tasks = res.then((r) => {
+ print(r);
+ assertEq(ins.exports.get_state(), .04);
+});
+
+assertEq(ins.exports.get_state(), 0);
+
+// Also test with exceptions/traps.
+
+async function test(c) {
+ var compute_delta = (i) => Promise.resolve(i/100 || 1);
+ if (c == 1) compute_delta = async (i) => {throw "ff"};
+ if (c == 2) compute_delta = () => {throw "ff";}
+
+ var suspending_compute_delta = new WebAssembly.Suspending(
+ compute_delta
+ );
+ var ins = wasmEvalText(`(module
+ (import "js" "init_state" (func $init_state (result f64)))
+ (import "js" "compute_delta"
+ (func $compute_delta (param i32) (result f64)))
+
+ (global $suspender (mut externref) (ref.null extern))
+ (global $state (mut f64) (f64.const nan))
+ (func $init (global.set $state (call $init_state)))
+ (start $init)
+
+ (func $get_state (export "get_state") (result f64) (global.get $state))
+ (func (export "update_state_export") (param i32) (result f64)
+ ${c == 3 ? "(unreachable)" : ""}
+ (global.set $state (f64.add
+ (global.get $state) (call $compute_delta (local.get 0))))
+ ${c == 4 ? "(unreachable)" : ""}
+ (global.get $state)
+ )
+ )`, {
+ js: {
+ init_state() { return 0; },
+ compute_delta: suspending_compute_delta,
+ },
+ });
+
+ var update_state = WebAssembly.promising(
+ ins.exports.update_state_export
+);
+
+ var res = update_state(4);
+ var p = res.then((r) => {
+ assertEq(c, 0);
+ assertEq(ins.exports.get_state(), .04);
+ }).catch(_ => {
+ assertEq(c > 0, true);
+ });
+
+ assertEq(ins.exports.get_state(), 0);
+ await p;
+}
+
+for (let c = 0; c < 5; c++) {
+ tasks = tasks.then(() => test(c));
+}
diff --git a/js/src/jit-test/tests/wasm/js-promise-integration/directives.txt b/js/src/jit-test/tests/wasm/js-promise-integration/directives.txt
new file mode 100644
index 0000000000..b15152352a
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/js-promise-integration/directives.txt
@@ -0,0 +1 @@
+|jit-test| include:wasm.js; --setpref=wasm_js_promise_integration=true; skip-if: !wasmJSPromiseIntegrationEnabled()
diff --git a/js/src/jit-test/tests/wasm/js-promise-integration/gc-2.js b/js/src/jit-test/tests/wasm/js-promise-integration/gc-2.js
new file mode 100644
index 0000000000..d17539807e
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/js-promise-integration/gc-2.js
@@ -0,0 +1,69 @@
+// Example from the proposal.
+
+gczeal(2,5);
+
+var compute_delta = (i) => Promise.resolve(i / 100 || 1);
+
+var suspending_compute_delta = new WebAssembly.Function(
+ { parameters: ['externref', 'i32'], results: ['f64'] },
+ compute_delta,
+ { suspending: "first" }
+);
+
+var ins = wasmEvalText(`(module
+ (import "js" "init_state" (func $init_state (result f64)))
+ (import "js" "compute_delta"
+ (func $compute_delta_import (param externref) (param i32) (result f64)))
+
+ (global $suspender (mut externref) (ref.null extern))
+ (global $state (mut f64) (f64.const nan))
+ (func $init (global.set $state (call $init_state)))
+ (start $init)
+
+ (func $compute_delta (param i32) (result f64)
+ (local $suspender_copy externref)
+ (;return (f64.const 0.3);)
+ (;unreachable;)
+ (global.get $suspender)
+ (local.tee $suspender_copy)
+ (local.get 0)
+ (call $compute_delta_import)
+ (local.get $suspender_copy)
+ (global.set $suspender)
+ (return)
+ )
+ (func $get_state (export "get_state") (result f64) (global.get $state))
+ (func $update_state (param i32) (result f64)
+ (global.set $state (f64.add
+ (global.get $state) (call $compute_delta (local.get 0))))
+ (global.get $state)
+ )
+
+ (func (export "update_state_export")
+ (param $suspender externref) (param i32) (result f64)
+ (local.get $suspender)
+ (global.set $suspender)
+ (local.get 1)
+ (call $update_state)
+ (return)
+ )
+)`, {
+ js: {
+ init_state() { return 0; },
+ compute_delta: suspending_compute_delta,
+ },
+});
+
+var update_state = new WebAssembly.Function(
+ { parameters: ['i32'], results: ['externref'] },
+ ins.exports.update_state_export,
+ { promising: "first" }
+);
+
+var res = update_state(4);
+var tasks = res.then((r) => {
+ print(r);
+ assertEq(ins.exports.get_state(), .04);
+});
+
+assertEq(ins.exports.get_state(), 0);
diff --git a/js/src/jit-test/tests/wasm/js-promise-integration/gc.js b/js/src/jit-test/tests/wasm/js-promise-integration/gc.js
new file mode 100644
index 0000000000..c688b99cb5
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/js-promise-integration/gc.js
@@ -0,0 +1,67 @@
+// Test if we can trace roots on the alternative stack.
+
+let i = 0;
+function js_import() {
+ return Promise.resolve({i: ++i});
+};
+let wasm_js_import = new WebAssembly.Function(
+ {parameters: ['externref'], results: ['externref']},
+ js_import,
+ {suspending: 'first'});
+
+let wasm_gc_import = new WebAssembly.Function(
+ {parameters: ['externref'], results: []},
+ async () => { gc(); },
+ {suspending: 'first'});
+
+var ins = wasmEvalText(`(module
+ (import "m" "import"
+ (func (param externref) (result externref)))
+ (import "m" "gc" (func (param externref)))
+ (import "m" "conv"
+ (func (param externref) (result i32)))
+
+ (global (export "g") (mut i32) (i32.const 0))
+
+ (func (export "test") (param externref)
+ (local i32)
+ i32.const 5
+ local.set 1
+ loop
+ local.get 0
+ call 0
+ local.get 0
+ call 1
+ call 2
+ global.get 0
+ i32.add
+ global.set 0
+ local.get 1
+ i32.const 1
+ i32.sub
+ local.tee 1
+ br_if 0
+ end
+ )
+
+)`, {
+ m: {
+ import: wasm_js_import,
+ gc: wasm_gc_import,
+ conv: ({i}) => i,
+ },
+});
+
+
+let wrapped_export = new WebAssembly.Function(
+ {parameters:[], results:['externref']},
+ ins.exports.test,
+ {promising : "first"}
+);
+
+let export_promise = wrapped_export();
+assertEq(0, ins.exports.g.value);
+assertEq(true, export_promise instanceof Promise);
+export_promise.then(() =>
+ assertEq(15, ins.exports.g.value)
+);
diff --git a/js/src/jit-test/tests/wasm/js-promise-integration/js-promise-integration.new.js b/js/src/jit-test/tests/wasm/js-promise-integration/js-promise-integration.new.js
new file mode 100644
index 0000000000..d45d47b072
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/js-promise-integration/js-promise-integration.new.js
@@ -0,0 +1,270 @@
+// New version of JS promise integration API
+// Modified https://github.com/WebAssembly/js-promise-integration/tree/main/test/js-api/js-promise-integration
+
+var tests = Promise.resolve();
+function test(fn, n) {
+
+ tests = tests.then(() => {
+ let t = {res: null};
+ print("# " + n);
+ fn(t);
+ return t.res;
+ });
+}
+function promise_test(fn, n) {
+ tests = tests.then(() => {
+ print("# " + n);
+ return fn();
+ });
+}
+function assert_true(f) { assertEq(f, true); }
+function assert_equals(a, b) { assertEq(a, b); }
+function assert_array_equals(a, b) {
+ assert_equals(a.length, a.length);
+ for (let i = 0; i < a.length; i++) {
+ assert_equals(a[i], b[i]);
+ }
+}
+function assert_throws(ex, fn) {
+ try {
+ fn(); assertEq(false, true);
+ } catch(e) {
+ assertEq(e instanceof ex, true);
+ }
+}
+function promise_rejects(t, obj, p) {
+ t.res = p.then(() => {
+ assertEq(true, false);
+ }, (e) => {
+ assertEq(e instanceof obj.constructor, true);
+ });
+}
+
+function ToPromising(wasm_export) {
+ let sig = wasm_export.type();
+ assert_true(sig.parameters.length > 0);
+ assert_equals('externref', sig.parameters[0]);
+ let wrapper_sig = {
+ parameters: sig.parameters.slice(1),
+ results: ['externref']
+ };
+ return new WebAssembly.Function(
+ wrapper_sig, wasm_export, {promising: 'first'});
+}
+
+promise_test(async () => {
+ let js_import = new WebAssembly.Suspending(
+ () => Promise.resolve(42)
+ );
+ let instance = wasmEvalText(`(module
+ (import "m" "import" (func $import (result i32)))
+ (func (export "test") (result i32)
+ call $import
+ )
+ )`, {m: {import: js_import}});
+ let wrapped_export = WebAssembly.promising(instance.exports.test);
+ let export_promise = wrapped_export();
+ assert_true(export_promise instanceof Promise);
+ assert_equals(42, await export_promise);
+}, "Suspend once");
+
+promise_test(async () => {
+ let i = 0;
+ function js_import() {
+ return Promise.resolve(++i);
+ };
+ let wasm_js_import = new WebAssembly.Suspending(js_import);
+ // void test() {
+ // for (i = 0; i < 5; ++i) {
+ // g = g + await import();
+ // }
+ // }
+ let instance = wasmEvalText(`(module
+ (import "m" "import" (func $import (param externref) (result i32)))
+ (global (export "g") (mut i32) (i32.const 0))
+ (func (export "test") (param externref)
+ (local i32)
+ i32.const 5
+ local.set 1
+ loop
+ local.get 0
+ call $import
+ global.get 0
+ i32.add
+ global.set 0
+ local.get 1
+ i32.const 1
+ i32.sub
+ local.tee 1
+ br_if 0
+ end
+ )
+ )`, {m: {import: wasm_js_import}});
+ let wrapped_export = WebAssembly.promising(instance.exports.test);
+ let export_promise = wrapped_export();
+ assert_equals(0, instance.exports.g.value);
+ assert_true(export_promise instanceof Promise);
+ await export_promise;
+ assert_equals(15, instance.exports.g.value);
+}, "Suspend/resume in a loop");
+
+promise_test(async () => {
+ function js_import() {
+ return 42
+ };
+ let wasm_js_import = new WebAssembly.Suspending(js_import);
+ let instance = wasmEvalText(`(module
+ (import "m" "import" (func $import (param externref) (result i32)))
+ (global (export "g") (mut i32) (i32.const 0))
+ (func (export "test") (param externref) (result i32)
+ local.get 0
+ call $import
+ global.set 0
+ global.get 0
+ )
+ )`, {m: {import: wasm_js_import}});
+ let wrapped_export = WebAssembly.promising(instance.exports.test);
+ await wrapped_export();
+ assert_equals(42, instance.exports.g.value);
+}, "Do not suspend if the import's return value is not a Promise");
+
+test(t => {
+ let tag = new WebAssembly.Tag({parameters: []});
+ function js_import() {
+ return Promise.resolve();
+ };
+ let wasm_js_import = new WebAssembly.Suspending(js_import);
+ function js_throw() {
+ throw new Error();
+ }
+
+ let instance = wasmEvalText(`(module
+ (import "m" "import" (func $import (param externref) (result i32)))
+ (import "m" "js_throw" (func $js_throw))
+ (func (export "test") (param externref) (result i32)
+ local.get 0
+ call $import
+ call $js_throw
+ )
+ )`, {m: {import: wasm_js_import, js_throw}});
+ let wrapped_export = WebAssembly.promising(instance.exports.test);
+ let export_promise = wrapped_export();
+ assert_true(export_promise instanceof Promise);
+ promise_rejects(t, new Error(), export_promise);
+}, "Throw after the first suspension");
+
+// TODO: Use wasm exception handling to check that the exception can be caught in wasm.
+
+test(t => {
+ let tag = new WebAssembly.Tag({parameters: ['i32']});
+ function js_import() {
+ return Promise.reject(new Error());
+ };
+ let wasm_js_import = new WebAssembly.Suspending(js_import);
+
+ let instance = wasmEvalText(`(module
+ (import "m" "import" (func $import (param externref) (result i32)))
+ (func (export "test") (param externref) (result i32)
+ local.get 0
+ call $import
+ )
+ )`, {m: {import: wasm_js_import, tag: tag}});
+ let wrapped_export = WebAssembly.promising(instance.exports.test);
+ let export_promise = wrapped_export();
+ assert_true(export_promise instanceof Promise);
+ promise_rejects(t, new Error(), export_promise);
+}, "Rejecting promise");
+
+async function TestNestedSuspenders(suspend) {
+ // Nest two suspenders. The call chain looks like:
+ // outer (wasm) -> outer (js) -> inner (wasm) -> inner (js)
+ // If 'suspend' is true, the inner JS function returns a Promise, which
+ // suspends the inner wasm function, which returns a Promise, which suspends
+ // the outer wasm function, which returns a Promise. The inner Promise
+ // resolves first, which resumes the inner continuation. Then the outer
+ // promise resolves which resumes the outer continuation.
+ // If 'suspend' is false, the inner and outer JS functions return a regular
+ // value and no computation is suspended.
+
+ let inner = new WebAssembly.Suspending(
+ () => suspend ? Promise.resolve(42) : 43,
+ );
+
+ let export_inner;
+ let outer = new WebAssembly.Suspending(
+ () => suspend ? export_inner() : 42,
+ );
+
+ let instance = wasmEvalText(`(module
+ (import "m" "inner" (func $inner (param externref) (result i32)))
+ (import "m" "outer" (func $outer (param externref) (result i32)))
+ (func (export "outer") (param externref) (result i32)
+ local.get 0
+ call $outer
+ )
+ (func (export "inner") (param externref) (result i32)
+ local.get 0
+ call $inner
+ )
+ )`, {m: {inner, outer}});
+ export_inner = WebAssembly.promising(instance.exports.inner);
+ let export_outer = WebAssembly.promising(instance.exports.outer);
+ let result = export_outer();
+ assert_true(result instanceof Promise);
+ assert_equals(42, await result);
+}
+
+promise_test(async () => {
+ return TestNestedSuspenders(true);
+}, "Test nested suspenders with suspension");
+
+promise_test(async () => {
+ return TestNestedSuspenders(false);
+}, "Test nested suspenders with no suspension");
+
+
+test(t => {
+ let instance = wasmEvalText(`(module
+ (func (export "test") (result i32)
+ call 0
+ )
+ )`);
+ let wrapper = WebAssembly.promising(instance.exports.test);
+ promise_rejects(t, new InternalError(), wrapper());
+}, "Stack overflow");
+
+// TODO: Test suspension with funcref.
+
+test(t => {
+ // The call stack of this test looks like:
+ // export1 -> import1 -> export2 -> import2
+ // Where export1 is "promising" and import2 is "suspending". Returning a
+ // promise from import2 should trap because of the JS import in the middle.
+ let instance;
+ function import1() {
+ // import1 -> export2 (unwrapped)
+ instance.exports.export2();
+ }
+ function import2() {
+ return Promise.resolve(0);
+ }
+ import2 = new WebAssembly.Suspending(import2);
+ instance = wasmEvalText(`(module
+ (import "m" "import1" (func $import1 (result i32)))
+ (import "m" "import2" (func $import2 (result i32)))
+ (func (export "export1") (result i32)
+ ;; export1 -> import1 (unwrapped)
+ call $import1
+ )
+ (func (export "export2") (result i32)
+ ;; export2 -> import2 (suspending)
+ call $import2
+ )
+ )`,
+ {'m': {'import1': import1, 'import2': import2}});
+ // export1 (promising)
+ let wrapper = WebAssembly.promising(instance.exports.export1);
+ promise_rejects(t, new WebAssembly.RuntimeError(), wrapper());
+}, "Test that trying to suspend JS frames traps");
+
+tests.then(() => print('Done'));
diff --git a/js/src/jit-test/tests/wasm/js-promise-integration/js-promise-integration.old.js b/js/src/jit-test/tests/wasm/js-promise-integration/js-promise-integration.old.js
new file mode 100644
index 0000000000..cc743eeaaa
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/js-promise-integration/js-promise-integration.old.js
@@ -0,0 +1,406 @@
+// Old version of JS promise integration API
+// Modified https://github.com/WebAssembly/js-promise-integration/tree/main/test/js-api/js-promise-integration
+
+var tests = Promise.resolve();
+function test(fn, n) {
+
+ tests = tests.then(() => {
+ let t = {res: null};
+ print("# " + n);
+ fn(t);
+ return t.res;
+ });
+}
+function promise_test(fn, n) {
+ tests = tests.then(() => {
+ print("# " + n);
+ return fn();
+ });
+}
+function assert_true(f) { assertEq(f, true); }
+function assert_equals(a, b) { assertEq(a, b); }
+function assert_array_equals(a, b) {
+ assert_equals(a.length, a.length);
+ for (let i = 0; i < a.length; i++) {
+ assert_equals(a[i], b[i]);
+ }
+}
+function assert_throws(ex, fn) {
+ try {
+ fn(); assertEq(false, true);
+ } catch(e) {
+ assertEq(e instanceof ex, true);
+ }
+}
+function promise_rejects(t, obj, p) {
+ t.res = p.then(() => {
+ assertEq(true, false);
+ }, (e) => {
+ assertEq(e instanceof obj.constructor, true);
+ });
+}
+
+function ToPromising(wasm_export) {
+ let sig = wasm_export.type();
+ assert_true(sig.parameters.length > 0);
+ assert_equals('externref', sig.parameters[0]);
+ let wrapper_sig = {
+ parameters: sig.parameters.slice(1),
+ results: ['externref']
+ };
+ return new WebAssembly.Function(
+ wrapper_sig, wasm_export, {promising: 'first'});
+}
+
+test(() => {
+ function js_import(i) {}
+
+ let import_wrapper = new WebAssembly.Function(
+ {parameters: ['externref', 'i32'], results: []},
+ js_import,
+ {suspending: 'first'});
+ let instance = wasmEvalText(`(module
+ (import "m" "import" (func (param externref i32)))
+ (func (export "export") (param externref i32) (result i32)
+ local.get 1
+ )
+ (func (export "void_export") (param externref))
+ )`, {'m': {'import': import_wrapper}});
+ let export_wrapper = ToPromising(instance.exports.export);
+
+ // Bad flag value.
+ assert_throws(TypeError, () => new WebAssembly.Function(
+ {parameters: ['externref', 'i32'], results: []},
+ js_import,
+ {suspending: 'foo'}));
+
+ assert_throws(TypeError, () => new WebAssembly.Function(
+ {parameters: ['i32'], results: ['externref']},
+ instance.exports.export,
+ {promising: 'foo'}));
+
+ // Signature mismatch.
+ assert_throws(Error /*TypeError*/, () => new WebAssembly.Function(
+ {parameters: ['externref'], results: []},
+ new WebAssembly.Function(
+ {parameters: [], results: ['i32']}, js_import),
+ {suspending: 'first'}));
+
+ assert_throws(TypeError, () => new WebAssembly.Function(
+ {parameters: ['externref', 'i32'], results: ['i32']},
+ instance.exports.export,
+ {promising: 'first'}));
+
+ // Check the wrapper signatures.
+ // let export_sig = export_wrapper.type();
+ // assert_array_equals(['i32'], export_sig.parameters);
+ // assert_array_equals(['externref'], export_sig.results);
+
+ let import_sig = import_wrapper.type();
+ assert_array_equals(['externref', 'i32'], import_sig.parameters);
+ assert_array_equals([], import_sig.results);
+ // let void_export_wrapper = ToPromising(instance.exports.void_export);
+ // let void_export_sig = void_export_wrapper.type();
+ // assert_array_equals([], void_export_sig.parameters);
+ // assert_array_equals(['externref'], void_export_sig.results);
+}, "Test import and export type checking");
+
+promise_test(async () => {
+ let js_import = new WebAssembly.Function(
+ {parameters: ['externref'], results: ['i32']},
+ () => Promise.resolve(42),
+ {suspending: 'first'});
+ let instance = wasmEvalText(`(module
+ (import "m" "import" (func $import (param externref) (result i32)))
+ (func (export "test") (param externref) (result i32)
+ local.get 0
+ call $import
+ )
+ )`, {m: {import: js_import}});
+ let wrapped_export = ToPromising(instance.exports.test);
+ let export_promise = wrapped_export();
+ assert_true(export_promise instanceof Promise);
+ assert_equals(42, await export_promise);
+}, "Suspend once");
+
+promise_test(async () => {
+ let i = 0;
+ function js_import() {
+ return Promise.resolve(++i);
+ };
+ let wasm_js_import = new WebAssembly.Function(
+ {parameters: ['externref'], results: ['i32']},
+ js_import,
+ {suspending: 'first'});
+ // void test() {
+ // for (i = 0; i < 5; ++i) {
+ // g = g + await import();
+ // }
+ // }
+ let instance = wasmEvalText(`(module
+ (import "m" "import" (func $import (param externref) (result i32)))
+ (global (export "g") (mut i32) (i32.const 0))
+ (func (export "test") (param externref)
+ (local i32)
+ i32.const 5
+ local.set 1
+ loop
+ local.get 0
+ call $import
+ global.get 0
+ i32.add
+ global.set 0
+ local.get 1
+ i32.const 1
+ i32.sub
+ local.tee 1
+ br_if 0
+ end
+ )
+ )`, {m: {import: wasm_js_import}});
+ let wrapped_export = ToPromising(instance.exports.test);
+ let export_promise = wrapped_export();
+ assert_equals(0, instance.exports.g.value);
+ assert_true(export_promise instanceof Promise);
+ await export_promise;
+ assert_equals(15, instance.exports.g.value);
+}, "Suspend/resume in a loop");
+
+promise_test(async () => {
+ function js_import() {
+ return 42
+ };
+ let wasm_js_import = new WebAssembly.Function(
+ {parameters: ['externref'], results: ['i32']},
+ js_import,
+ {suspending: 'first'});
+ let instance = wasmEvalText(`(module
+ (import "m" "import" (func $import (param externref) (result i32)))
+ (global (export "g") (mut i32) (i32.const 0))
+ (func (export "test") (param externref) (result i32)
+ local.get 0
+ call $import
+ global.set 0
+ global.get 0
+ )
+ )`, {m: {import: wasm_js_import}});
+ let wrapped_export = ToPromising(instance.exports.test);
+ await wrapped_export();
+ assert_equals(42, instance.exports.g.value);
+}, "Do not suspend if the import's return value is not a Promise");
+
+test(t => {
+ let tag = new WebAssembly.Tag({parameters: []});
+ function js_import() {
+ return Promise.resolve();
+ };
+ let wasm_js_import = new WebAssembly.Function(
+ {parameters: ['externref'], results: ['i32']},
+ js_import,
+ {suspending: 'first'});
+ function js_throw() {
+ throw new Error();
+ }
+
+ let instance = wasmEvalText(`(module
+ (import "m" "import" (func $import (param externref) (result i32)))
+ (import "m" "js_throw" (func $js_throw))
+ (func (export "test") (param externref) (result i32)
+ local.get 0
+ call $import
+ call $js_throw
+ )
+ )`, {m: {import: wasm_js_import, js_throw}});
+ let wrapped_export = ToPromising(instance.exports.test);
+ let export_promise = wrapped_export();
+ assert_true(export_promise instanceof Promise);
+ promise_rejects(t, new Error(), export_promise);
+}, "Throw after the first suspension");
+
+// TODO: Use wasm exception handling to check that the exception can be caught in wasm.
+
+test(t => {
+ let tag = new WebAssembly.Tag({parameters: ['i32']});
+ function js_import() {
+ return Promise.reject(new Error());
+ };
+ let wasm_js_import = new WebAssembly.Function(
+ {parameters: ['externref'], results: ['i32']},
+ js_import,
+ {suspending: 'first'});
+
+ let instance = wasmEvalText(`(module
+ (import "m" "import" (func $import (param externref) (result i32)))
+ (func (export "test") (param externref) (result i32)
+ local.get 0
+ call $import
+ )
+ )`, {m: {import: wasm_js_import, tag: tag}});
+ let wrapped_export = ToPromising(instance.exports.test);
+ let export_promise = wrapped_export();
+ assert_true(export_promise instanceof Promise);
+ promise_rejects(t, new Error(), export_promise);
+}, "Rejecting promise");
+
+async function TestNestedSuspenders(suspend) {
+ // Nest two suspenders. The call chain looks like:
+ // outer (wasm) -> outer (js) -> inner (wasm) -> inner (js)
+ // If 'suspend' is true, the inner JS function returns a Promise, which
+ // suspends the inner wasm function, which returns a Promise, which suspends
+ // the outer wasm function, which returns a Promise. The inner Promise
+ // resolves first, which resumes the inner continuation. Then the outer
+ // promise resolves which resumes the outer continuation.
+ // If 'suspend' is false, the inner and outer JS functions return a regular
+ // value and no computation is suspended.
+
+ let inner = new WebAssembly.Function(
+ {parameters: ['externref'], results: ['i32']},
+ () => suspend ? Promise.resolve(42) : 43,
+ {suspending: 'first'});
+
+ let export_inner;
+ let outer = new WebAssembly.Function(
+ {parameters: ['externref'], results: ['i32']},
+ () => suspend ? export_inner() : 42,
+ {suspending: 'first'});
+
+ let instance = wasmEvalText(`(module
+ (import "m" "inner" (func $inner (param externref) (result i32)))
+ (import "m" "outer" (func $outer (param externref) (result i32)))
+ (func (export "outer") (param externref) (result i32)
+ local.get 0
+ call $outer
+ )
+ (func (export "inner") (param externref) (result i32)
+ local.get 0
+ call $inner
+ )
+ )`, {m: {inner, outer}});
+ export_inner = ToPromising(instance.exports.inner);
+ let export_outer = ToPromising(instance.exports.outer);
+ let result = export_outer();
+ assert_true(result instanceof Promise);
+ assert_equals(42, await result);
+}
+
+promise_test(async () => {
+ return TestNestedSuspenders(true);
+}, "Test nested suspenders with suspension");
+
+promise_test(async () => {
+ return TestNestedSuspenders(false);
+}, "Test nested suspenders with no suspension");
+
+test(() => {
+ let js_import = new WebAssembly.Function(
+ {parameters: ['externref'], results: ['i32']},
+ () => Promise.resolve(42),
+ {suspending: 'first'});
+ let instance = wasmEvalText(`(module
+ (import "m" "import" (func $import (param externref) (result i32)))
+ (func (export "test") (param externref) (result i32)
+ local.get 0
+ call $import
+ )
+ (func (export "return_suspender") (param externref) (result externref)
+ local.get 0
+ )
+ )`, {m: {import: js_import}});
+ let suspender = ToPromising(instance.exports.return_suspender)();
+ for (s of [suspender, null, undefined, {}]) {
+ assert_throws(WebAssembly.RuntimeError, () => instance.exports.test(s));
+ }
+}, "Call import with an invalid suspender");
+
+test(t => {
+ let instance = wasmEvalText(`(module
+ (func (export "test") (param externref) (result i32)
+ local.get 0
+ call 0
+ )
+ )`);
+ let wrapper = ToPromising(instance.exports.test);
+ promise_rejects(t, new InternalError(), wrapper());
+}, "Stack overflow");
+
+test (() => {
+ let js_import = new WebAssembly.Function(
+ {parameters: ['externref'], results: ['i32']},
+ () => Promise.resolve(42),
+ {suspending: 'first'});
+ let instance = wasmEvalText(`(module
+ (import "m" "import" (func $import (param externref) (result i32)))
+ (func (export "test") (param externref) (result i32)
+ local.get 0
+ call $import
+ )
+ (func (export "return_suspender") (param externref) (result externref)
+ local.get 0
+ )
+ )`, {m: {import: js_import}});
+ let suspender = ToPromising(instance.exports.return_suspender)();
+ for (s of [suspender, null, undefined, {}]) {
+ assert_throws(WebAssembly.RuntimeError, () => instance.exports.test(s));
+ }
+}, "Pass an invalid suspender");
+
+// TODO: Test suspension with funcref.
+
+test(t => {
+ // The call stack of this test looks like:
+ // export1 -> import1 -> export2 -> import2
+ // Where export1 is "promising" and import2 is "suspending". Returning a
+ // promise from import2 should trap because of the JS import in the middle.
+ let instance;
+ function import1() {
+ // import1 -> export2 (unwrapped)
+ instance.exports.export2();
+ }
+ function import2() {
+ return Promise.resolve(0);
+ }
+ import2 = new WebAssembly.Function(
+ {parameters: ['externref'], results: ['i32']},
+ import2,
+ {suspending: 'first'});
+ instance = wasmEvalText(`(module
+ (import "m" "import1" (func $import1 (result i32)))
+ (import "m" "import2" (func $import2 (param externref) (result i32)))
+ (global (mut externref) (ref.null extern))
+ (func (export "export1") (param externref) (result i32)
+ ;; export1 -> import1 (unwrapped)
+ local.get 0
+ global.set 0
+ call $import1
+ )
+ (func (export "export2") (result i32)
+ ;; export2 -> import2 (suspending)
+ global.get 0
+ call $import2
+ )
+ )`,
+ {'m': {'import1': import1, 'import2': import2}});
+ // export1 (promising)
+ let wrapper = new WebAssembly.Function(
+ {parameters: [], results: ['externref']},
+ instance.exports.export1,
+ {promising: 'first'});
+ promise_rejects(t, new WebAssembly.RuntimeError(), wrapper());
+}, "Test that trying to suspend JS frames traps");
+
+"Invalid test. Skipping..." || test(() => {
+ let js_import = new WebAssembly.Function(
+ {parameters: ['externref'], results: ['i32']},
+ () => 42,
+ {suspending: 'first'});
+ let instance = wasmEvalText(`(module
+ (import "m" "import" (func $import (param externref) (result i32)))
+ (func (export "test") (param externref) (result i32)
+ local.get 0
+ call $import
+ )
+ )`, {m: {import: js_import}});
+ assert_equals(42, instance.exports.test(null));
+}, "Pass an invalid suspender to the import and return a non-promise");
+
+tests.then(() => print('Done'));
diff --git a/js/src/jit-test/tests/wasm/js-promise-integration/multi.js b/js/src/jit-test/tests/wasm/js-promise-integration/multi.js
new file mode 100644
index 0000000000..7713637642
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/js-promise-integration/multi.js
@@ -0,0 +1,36 @@
+// Multiple promises at the same time.
+
+function js_import() {
+ return Promise.resolve(42);
+}
+var wasm_js_import = new WebAssembly.Function(
+ { parameters: ['externref'], results: ['i32'] },
+ js_import,
+ { suspending: 'first' });
+
+var ins = wasmEvalText(`(module
+ (import "m" "import" (func $f (param externref) (result i32)))
+ (func (export "test") (param externref) (result i32)
+ local.get 0
+ call $f
+ )
+)`, {"m": {import: wasm_js_import}});
+
+let wrapped_export = new WebAssembly.Function(
+ {
+ parameters: [],
+ results: ['externref']
+ },
+ ins.exports.test, { promising: 'first' });
+
+Promise.resolve().then(() => {
+ wrapped_export().then(i => {
+ assertEq(42, i)
+ });
+});
+
+Promise.resolve().then(() => {
+ wrapped_export().then(i => {
+ assertEq(42, i)
+ });
+});
diff --git a/js/src/jit-test/tests/wasm/regress/bug1866545.js b/js/src/jit-test/tests/wasm/regress/bug1866545.js
new file mode 100644
index 0000000000..6c6a92c0ab
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/regress/bug1866545.js
@@ -0,0 +1,25 @@
+// Tests stack alignment during tail calls (in Ion).
+
+var ins = wasmEvalText(`
+ (module
+ (func $trap
+ (param $i i32) (param $arr i32)
+ unreachable
+ )
+ (func $second
+ (return_call $trap
+ (i32.const 33)
+ (i32.const 66)
+ )
+ )
+ (func (export "test")
+ (call $second)
+ )
+ )
+`);
+
+assertErrorMessage(
+ () => ins.exports.test(),
+ WebAssembly.RuntimeError,
+ "unreachable executed",
+);
diff --git a/js/src/jit-test/tests/wasm/regress/bug1891658.js b/js/src/jit-test/tests/wasm/regress/bug1891658.js
new file mode 100644
index 0000000000..304ea0f5ea
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/regress/bug1891658.js
@@ -0,0 +1,10 @@
+// Tests OOM during wasmLosslessInvoke.
+
+var ins = wasmEvalText('(module (func (export "f")(result i32) i32.const 1))');
+
+oomAtAllocation(1);
+try {
+ wasmLosslessInvoke(ins.exports.f);
+} catch (e) {
+ assertEq(e, "out of memory");
+}
diff --git a/js/src/jit-test/tests/wasm/tail-calls/bug1891422.js b/js/src/jit-test/tests/wasm/tail-calls/bug1891422.js
new file mode 100644
index 0000000000..c5c43d006f
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/tail-calls/bug1891422.js
@@ -0,0 +1,27 @@
+// |jit-test| --more-compartments; skip-variant-if: --setpref=wasm_test_serialization=true, true; skip-variant-if: --wasm-compiler=ion, true
+
+a = newGlobal({ newCompartment: true });
+a.b = this;
+a.eval(`Debugger(b).onExceptionUnwind = function () {};`);
+
+var ins0 = wasmEvalText(`(module
+ (func $fac-acc (export "e") (param i64 i64)
+ unreachable
+ )
+)`);
+var ins = wasmEvalText(`(module
+ (import "" "e" (func $fac-acc (param i64 i64)))
+ (type $tz (func (param i64)))
+ (table $t 1 1 funcref)
+ (func $f (export "fac") (param i64)
+ local.get 0
+ i32.const 0
+ return_call_indirect $t (type $tz)
+ )
+ (elem $t (i32.const 0) $fac-acc)
+)`, {"": {e: ins0.exports.e}});
+
+
+assertErrorMessage(() => {
+ ins.exports.fac(5n);
+}, WebAssembly.RuntimeError, /indirect call signature mismatch/);
diff --git a/js/src/jit-test/tests/wasm/testing/bug1894586.js b/js/src/jit-test/tests/wasm/testing/bug1894586.js
new file mode 100644
index 0000000000..eb19cc0a69
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/testing/bug1894586.js
@@ -0,0 +1,13 @@
+var it = 100;
+function f() {
+ if (--it < 0) {
+ return;
+ }
+ wasmDumpIon(
+ wasmTextToBinary(
+ "(type $x (struct))(global $g (ref null $x) ref.null $x)(func $h)"
+ )
+ );
+ oomTest(f);
+}
+f();