2021-10-26 10:27:07 +00:00
|
|
|
// Copyright 2021 the V8 project authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
2022-01-05 16:22:05 +00:00
|
|
|
// Flags: --allow-natives-syntax --experimental-wasm-stack-switching
|
|
|
|
// Flags: --experimental-wasm-type-reflection --expose-gc
|
2021-10-26 10:27:07 +00:00
|
|
|
|
|
|
|
load("test/mjsunit/wasm/wasm-module-builder.js");
|
|
|
|
|
2021-11-05 14:02:33 +00:00
|
|
|
(function TestSuspender() {
|
|
|
|
print(arguments.callee.name);
|
|
|
|
let suspender = new WebAssembly.Suspender();
|
|
|
|
assertTrue(suspender.toString() == "[object WebAssembly.Suspender]");
|
|
|
|
assertThrows(() => WebAssembly.Suspender(), TypeError,
|
|
|
|
/WebAssembly.Suspender must be invoked with 'new'/);
|
|
|
|
})();
|
|
|
|
|
2022-02-04 16:57:10 +00:00
|
|
|
(function TestSuspenderTypes() {
|
|
|
|
print(arguments.callee.name);
|
|
|
|
let builder = new WasmModuleBuilder();
|
2022-07-11 10:16:59 +00:00
|
|
|
let sig_i_ri = makeSig([kWasmExternRef, kWasmI32], [kWasmI32]);
|
|
|
|
let sig_ii_r = makeSig([kWasmExternRef], [kWasmI32, kWasmI32]);
|
|
|
|
let sig_v_ri = makeSig([kWasmExternRef, kWasmI32], [kWasmI32]);
|
|
|
|
builder.addImport('m', 'import', sig_v_ri);
|
|
|
|
builder.addFunction("export", sig_i_ri)
|
|
|
|
.addBody([kExprLocalGet, 1]).exportFunc();
|
|
|
|
builder.addFunction("wrong1", sig_ii_r)
|
2022-02-04 16:57:10 +00:00
|
|
|
.addBody([kExprI32Const, 0, kExprI32Const, 0]).exportFunc();
|
2022-07-11 10:16:59 +00:00
|
|
|
builder.addFunction("wrong2", kSig_v_r)
|
2022-02-04 16:57:10 +00:00
|
|
|
.addBody([]).exportFunc();
|
2022-07-11 10:16:59 +00:00
|
|
|
builder.addFunction("wrong3", kSig_i_v)
|
|
|
|
.addBody([kExprI32Const, 0]).exportFunc();
|
2022-02-04 16:57:10 +00:00
|
|
|
let suspender = new WebAssembly.Suspender();
|
2022-07-11 10:16:59 +00:00
|
|
|
function js_import(suspender, i) {
|
2022-02-15 13:12:19 +00:00
|
|
|
return Promise.resolve(42);
|
2022-02-04 16:57:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Wrap the import, instantiate the module, and wrap the export.
|
|
|
|
let wasm_js_import = new WebAssembly.Function(
|
2022-07-11 10:16:59 +00:00
|
|
|
{parameters: ['externref', 'i32'], results: ['externref']}, js_import);
|
2022-07-11 14:08:59 +00:00
|
|
|
let import_wrapper = WebAssembly.suspendOnReturnedPromise(wasm_js_import);
|
2022-02-04 16:57:10 +00:00
|
|
|
let instance = builder.instantiate({'m': {'import': import_wrapper}});
|
|
|
|
let export_wrapper =
|
2022-07-11 14:08:59 +00:00
|
|
|
WebAssembly.returnPromiseOnSuspend(instance.exports.export);
|
2022-02-04 16:57:10 +00:00
|
|
|
|
|
|
|
// Check type errors.
|
|
|
|
wasm_js_import = new WebAssembly.Function(
|
2022-07-11 10:16:59 +00:00
|
|
|
{parameters: ['externref'], results: ['i32']}, js_import);
|
2022-07-11 14:08:59 +00:00
|
|
|
assertThrows(() => WebAssembly.suspendOnReturnedPromise(wasm_js_import),
|
2022-02-04 16:57:10 +00:00
|
|
|
TypeError, /Expected a WebAssembly.Function with return type externref/);
|
2022-07-11 14:08:59 +00:00
|
|
|
assertThrows(() => WebAssembly.suspendOnReturnedPromise(
|
2022-07-11 10:16:59 +00:00
|
|
|
new WebAssembly.Function(
|
|
|
|
{parameters: ['i32'], results: ['externref']},
|
|
|
|
() => {})),
|
|
|
|
TypeError,
|
2022-07-11 14:08:59 +00:00
|
|
|
/Expected at least one parameter of type externref/);
|
|
|
|
assertThrows(() => WebAssembly.returnPromiseOnSuspend(instance.exports.wrong1),
|
2022-02-04 16:57:10 +00:00
|
|
|
TypeError,
|
|
|
|
/Expected a WebAssembly.Function with exactly one return type/);
|
2022-07-11 14:08:59 +00:00
|
|
|
assertThrows(() => WebAssembly.returnPromiseOnSuspend(instance.exports.wrong2),
|
2022-02-04 16:57:10 +00:00
|
|
|
TypeError,
|
|
|
|
/Expected a WebAssembly.Function with exactly one return type/);
|
2022-07-11 14:08:59 +00:00
|
|
|
assertThrows(() => WebAssembly.returnPromiseOnSuspend(instance.exports.wrong3),
|
2022-07-11 10:16:59 +00:00
|
|
|
TypeError,
|
2022-07-11 14:08:59 +00:00
|
|
|
/Expected at least one parameter of type externref/);
|
2022-02-04 16:57:10 +00:00
|
|
|
// Signature mismatch (link error).
|
|
|
|
let wrong_import = new WebAssembly.Function(
|
2022-07-11 10:16:59 +00:00
|
|
|
{parameters: ['externref', 'f32'], results: ['externref']}, () => {});
|
2022-07-11 14:08:59 +00:00
|
|
|
wrong_import = WebAssembly.suspendOnReturnedPromise(wrong_import);
|
2022-02-04 16:57:10 +00:00
|
|
|
assertThrows(() => builder.instantiate({'m': {'import': wrong_import}}),
|
|
|
|
WebAssembly.LinkError,
|
|
|
|
/imported function does not match the expected type/);
|
|
|
|
|
|
|
|
// Check the wrapped export's signature.
|
|
|
|
let export_sig = WebAssembly.Function.type(export_wrapper);
|
2022-07-11 10:16:59 +00:00
|
|
|
assertEquals(['externref', 'i32'], export_sig.parameters);
|
2022-02-04 16:57:10 +00:00
|
|
|
assertEquals(['externref'], export_sig.results);
|
|
|
|
|
|
|
|
// Check the wrapped import's signature.
|
|
|
|
let import_sig = WebAssembly.Function.type(import_wrapper);
|
2022-07-11 10:16:59 +00:00
|
|
|
assertEquals(['externref', 'i32'], import_sig.parameters);
|
2022-02-04 16:57:10 +00:00
|
|
|
assertEquals(['externref'], import_sig.results);
|
|
|
|
})();
|
|
|
|
|
2022-07-11 10:16:59 +00:00
|
|
|
(function TestStackSwitchSuspenderType() {
|
|
|
|
print(arguments.callee.name);
|
|
|
|
let builder = new WasmModuleBuilder();
|
|
|
|
builder.addFunction("test", kSig_i_r)
|
|
|
|
.addBody([kExprI32Const, 0]).exportFunc();
|
|
|
|
let instance = builder.instantiate();
|
|
|
|
let suspender = new WebAssembly.Suspender();
|
2022-07-11 14:08:59 +00:00
|
|
|
let wrapper = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
|
2022-07-11 10:16:59 +00:00
|
|
|
assertThrows(() => wrapper(undefined),
|
|
|
|
WebAssembly.RuntimeError,
|
|
|
|
/type incompatibility when transforming from\/to JS/);
|
|
|
|
})();
|
|
|
|
|
2021-10-26 10:27:07 +00:00
|
|
|
(function TestStackSwitchNoSuspend() {
|
|
|
|
print(arguments.callee.name);
|
|
|
|
let builder = new WasmModuleBuilder();
|
|
|
|
builder.addGlobal(kWasmI32, true).exportAs('g');
|
2022-07-11 10:16:59 +00:00
|
|
|
builder.addFunction("test", kSig_i_r)
|
2022-02-04 16:57:10 +00:00
|
|
|
.addBody([
|
|
|
|
kExprI32Const, 42,
|
|
|
|
kExprGlobalSet, 0,
|
|
|
|
kExprI32Const, 0]).exportFunc();
|
2021-10-26 10:27:07 +00:00
|
|
|
let instance = builder.instantiate();
|
2021-11-05 16:52:18 +00:00
|
|
|
let suspender = new WebAssembly.Suspender();
|
2022-07-11 14:08:59 +00:00
|
|
|
let wrapper = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
|
2022-07-11 10:16:59 +00:00
|
|
|
wrapper(suspender);
|
2021-10-26 10:27:07 +00:00
|
|
|
assertEquals(42, instance.exports.g.value);
|
|
|
|
})();
|
2021-12-08 10:50:38 +00:00
|
|
|
|
2022-01-05 16:22:05 +00:00
|
|
|
(function TestStackSwitchSuspend() {
|
|
|
|
print(arguments.callee.name);
|
|
|
|
let builder = new WasmModuleBuilder();
|
2022-07-11 10:16:59 +00:00
|
|
|
import_index = builder.addImport('m', 'import', kSig_i_r);
|
|
|
|
builder.addFunction("test", kSig_i_r)
|
2022-01-05 16:22:05 +00:00
|
|
|
.addBody([
|
2022-07-11 10:16:59 +00:00
|
|
|
kExprLocalGet, 0,
|
2022-01-05 16:22:05 +00:00
|
|
|
kExprCallFunction, import_index, // suspend
|
|
|
|
]).exportFunc();
|
2022-07-11 14:08:59 +00:00
|
|
|
let js_import = WebAssembly.suspendOnReturnedPromise(
|
2022-07-08 10:06:54 +00:00
|
|
|
new WebAssembly.Function(
|
2022-07-11 10:16:59 +00:00
|
|
|
{parameters: ['externref'], results: ['externref']},
|
2022-07-08 10:06:54 +00:00
|
|
|
() => Promise.resolve(42)));
|
|
|
|
let instance = builder.instantiate({m: {import: js_import}});
|
2022-07-11 14:08:59 +00:00
|
|
|
let wrapped_export = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
|
|
|
|
let suspender = new WebAssembly.Suspender();
|
2022-07-11 10:16:59 +00:00
|
|
|
let combined_promise = wrapped_export(suspender);
|
2022-07-08 10:06:54 +00:00
|
|
|
combined_promise.then(v => assertEquals(42, v));
|
|
|
|
|
|
|
|
// Also try with a JS function with a mismatching arity.
|
2022-07-11 14:08:59 +00:00
|
|
|
js_import = WebAssembly.suspendOnReturnedPromise(
|
2022-07-08 10:06:54 +00:00
|
|
|
new WebAssembly.Function(
|
2022-07-11 10:16:59 +00:00
|
|
|
{parameters: ['externref'], results: ['externref']},
|
2022-07-08 10:06:54 +00:00
|
|
|
(unused) => Promise.resolve(42)));
|
|
|
|
instance = builder.instantiate({m: {import: js_import}});
|
2022-07-11 14:08:59 +00:00
|
|
|
wrapped_export = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
|
|
|
|
suspender = new WebAssembly.Suspender();
|
2022-07-11 10:16:59 +00:00
|
|
|
combined_promise = wrapped_export(suspender);
|
2022-07-08 10:06:54 +00:00
|
|
|
combined_promise.then(v => assertEquals(42, v));
|
|
|
|
|
|
|
|
// Also try with a proxy.
|
2022-07-11 14:08:59 +00:00
|
|
|
js_import = WebAssembly.suspendOnReturnedPromise(
|
2022-07-08 10:06:54 +00:00
|
|
|
new WebAssembly.Function(
|
2022-07-11 10:16:59 +00:00
|
|
|
{parameters: ['externref'], results: ['externref']},
|
2022-07-08 10:06:54 +00:00
|
|
|
new Proxy(() => Promise.resolve(42), {})));
|
|
|
|
instance = builder.instantiate({m: {import: js_import}});
|
2022-07-11 14:08:59 +00:00
|
|
|
wrapped_export = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
|
|
|
|
suspender = new WebAssembly.Suspender();
|
2022-07-11 10:16:59 +00:00
|
|
|
combined_promise = wrapped_export(suspender);
|
[wasm] Handle arguments in stack-switching export wrapper
Use the existing generic js-to-wasm wrapper to handle arguments in
the stack-switching export wrapper, by combining them into a single
helper function parameterized by a boolean.
If the stack_switch parameter is false, the generated js-to-wasm wrapper
is the same as before.
If the stack_switch parameter is true, we allocate and switch to the new
stack before starting to process the parameters. To load the parameters,
we also keep a pointer to the old stack.
After the call, we convert the return value according to the return type
as usual, and then switch back to the parent stack (which may be
different than the original stack, but has a compatible stack frame
layout).
If the stack suspends during the call, control-flow jumps right before
we deconstruct and leave the frame, and returns the Promise as an
externref in the return register.
R=ahaas@chromium.org,jkummerow@chromium.org
CC=fgm@chromium.org
Bug: v8:12191
Change-Id: If3f8eaba8edebe6e98d4738f79f895fdb5322adc
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3460410
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79148}
2022-02-15 14:46:22 +00:00
|
|
|
combined_promise.then(v => assertEquals(42, v));
|
2022-02-02 22:38:34 +00:00
|
|
|
})();
|
|
|
|
|
|
|
|
// Check that we can suspend back out of a resumed computation.
|
|
|
|
(function TestStackSwitchSuspendLoop() {
|
|
|
|
print(arguments.callee.name);
|
|
|
|
let builder = new WasmModuleBuilder();
|
|
|
|
builder.addGlobal(kWasmI32, true).exportAs('g');
|
2022-07-11 10:16:59 +00:00
|
|
|
import_index = builder.addImport('m', 'import', kSig_i_r);
|
2022-02-02 22:38:34 +00:00
|
|
|
// Pseudo-code for the wasm function:
|
|
|
|
// for (i = 0; i < 5; ++i) {
|
|
|
|
// g = g + import();
|
|
|
|
// }
|
2022-07-11 10:16:59 +00:00
|
|
|
builder.addFunction("test", kSig_i_r)
|
2022-02-02 22:38:34 +00:00
|
|
|
.addLocals(kWasmI32, 1)
|
|
|
|
.addBody([
|
|
|
|
kExprI32Const, 5,
|
2022-07-11 10:16:59 +00:00
|
|
|
kExprLocalSet, 1,
|
2022-02-02 22:38:34 +00:00
|
|
|
kExprLoop, kWasmVoid,
|
2022-07-11 10:16:59 +00:00
|
|
|
kExprLocalGet, 0,
|
2022-02-02 22:38:34 +00:00
|
|
|
kExprCallFunction, import_index, // suspend
|
|
|
|
kExprGlobalGet, 0, // resume
|
|
|
|
kExprI32Add,
|
|
|
|
kExprGlobalSet, 0,
|
2022-07-11 10:16:59 +00:00
|
|
|
kExprLocalGet, 1,
|
2022-02-02 22:38:34 +00:00
|
|
|
kExprI32Const, 1,
|
|
|
|
kExprI32Sub,
|
2022-07-11 10:16:59 +00:00
|
|
|
kExprLocalTee, 1,
|
2022-02-02 22:38:34 +00:00
|
|
|
kExprBrIf, 0,
|
|
|
|
kExprEnd,
|
2022-02-04 16:57:10 +00:00
|
|
|
kExprI32Const, 0,
|
2022-02-02 22:38:34 +00:00
|
|
|
]).exportFunc();
|
|
|
|
let suspender = new WebAssembly.Suspender();
|
|
|
|
let i = 0;
|
|
|
|
// The n-th call to the import returns a promise that resolves to n.
|
2022-07-11 14:08:59 +00:00
|
|
|
function js_import(suspender) {
|
2022-02-15 13:12:19 +00:00
|
|
|
return Promise.resolve(++i);
|
2022-02-02 22:38:34 +00:00
|
|
|
};
|
2022-02-04 16:57:10 +00:00
|
|
|
let wasm_js_import = new WebAssembly.Function(
|
2022-07-11 10:16:59 +00:00
|
|
|
{parameters: ['externref'], results: ['externref']}, js_import);
|
2022-02-04 16:57:10 +00:00
|
|
|
let suspending_wasm_js_import =
|
2022-07-11 14:08:59 +00:00
|
|
|
WebAssembly.suspendOnReturnedPromise(wasm_js_import);
|
2022-02-02 22:38:34 +00:00
|
|
|
let instance = builder.instantiate({m: {import: suspending_wasm_js_import}});
|
2022-07-11 14:08:59 +00:00
|
|
|
let wrapped_export = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
|
2022-07-11 10:16:59 +00:00
|
|
|
let chained_promise = wrapped_export(suspender);
|
2022-02-02 22:38:34 +00:00
|
|
|
assertEquals(0, instance.exports.g.value);
|
|
|
|
chained_promise.then(_ => assertEquals(15, instance.exports.g.value));
|
2022-01-05 16:22:05 +00:00
|
|
|
})();
|
|
|
|
|
2021-12-08 10:50:38 +00:00
|
|
|
(function TestStackSwitchGC() {
|
|
|
|
print(arguments.callee.name);
|
|
|
|
let builder = new WasmModuleBuilder();
|
2022-07-11 10:16:59 +00:00
|
|
|
let gc_index = builder.addImport('m', 'gc', kSig_v_r);
|
|
|
|
builder.addFunction("test", kSig_i_r)
|
|
|
|
.addBody([
|
|
|
|
kExprLocalGet, 0,
|
|
|
|
kExprCallFunction, gc_index,
|
|
|
|
kExprI32Const, 0
|
|
|
|
]).exportFunc();
|
2021-12-08 10:50:38 +00:00
|
|
|
let suspender = new WebAssembly.Suspender();
|
2022-07-11 14:08:59 +00:00
|
|
|
let js_import = WebAssembly.suspendOnReturnedPromise(
|
2022-07-11 10:16:59 +00:00
|
|
|
new WebAssembly.Function(
|
|
|
|
{parameters: ['externref'], results: ['externref']},
|
2022-07-11 14:08:59 +00:00
|
|
|
suspender => gc()));
|
2022-07-11 10:16:59 +00:00
|
|
|
let instance = builder.instantiate({'m': {'gc': js_import}});
|
2022-07-11 14:08:59 +00:00
|
|
|
let wrapper = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
|
2022-07-11 10:16:59 +00:00
|
|
|
wrapper(suspender);
|
2021-12-08 10:50:38 +00:00
|
|
|
})();
|
2022-02-07 14:17:01 +00:00
|
|
|
|
|
|
|
// Check that the suspender does not suspend if the import's
|
|
|
|
// return value is not a promise.
|
|
|
|
(function TestStackSwitchNoPromise() {
|
|
|
|
print(arguments.callee.name);
|
|
|
|
let builder = new WasmModuleBuilder();
|
|
|
|
builder.addGlobal(kWasmI32, true).exportAs('g');
|
2022-07-11 10:16:59 +00:00
|
|
|
import_index = builder.addImport('m', 'import', kSig_i_r);
|
|
|
|
builder.addFunction("test", kSig_i_r)
|
2022-02-07 14:17:01 +00:00
|
|
|
.addBody([
|
2022-07-11 10:16:59 +00:00
|
|
|
kExprLocalGet, 0,
|
2022-02-07 14:17:01 +00:00
|
|
|
kExprCallFunction, import_index, // suspend
|
|
|
|
kExprGlobalSet, 0, // resume
|
|
|
|
kExprGlobalGet, 0,
|
|
|
|
]).exportFunc();
|
|
|
|
let suspender = new WebAssembly.Suspender();
|
2022-07-11 14:08:59 +00:00
|
|
|
function js_import(suspender) {
|
2022-02-07 14:17:01 +00:00
|
|
|
return 42
|
|
|
|
};
|
2022-07-11 10:16:59 +00:00
|
|
|
let wasm_js_import = new WebAssembly.Function({parameters: ['externref'], results: ['externref']}, js_import);
|
2022-07-11 14:08:59 +00:00
|
|
|
let suspending_wasm_js_import = WebAssembly.suspendOnReturnedPromise(wasm_js_import);
|
2022-02-07 14:17:01 +00:00
|
|
|
let instance = builder.instantiate({m: {import: suspending_wasm_js_import}});
|
2022-07-11 14:08:59 +00:00
|
|
|
let wrapped_export = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
|
2022-07-11 10:16:59 +00:00
|
|
|
let result = wrapped_export(suspender);
|
2022-02-07 14:17:01 +00:00
|
|
|
assertEquals(42, instance.exports.g.value);
|
|
|
|
})();
|
[wasm] Handle arguments in stack-switching export wrapper
Use the existing generic js-to-wasm wrapper to handle arguments in
the stack-switching export wrapper, by combining them into a single
helper function parameterized by a boolean.
If the stack_switch parameter is false, the generated js-to-wasm wrapper
is the same as before.
If the stack_switch parameter is true, we allocate and switch to the new
stack before starting to process the parameters. To load the parameters,
we also keep a pointer to the old stack.
After the call, we convert the return value according to the return type
as usual, and then switch back to the parent stack (which may be
different than the original stack, but has a compatible stack frame
layout).
If the stack suspends during the call, control-flow jumps right before
we deconstruct and leave the frame, and returns the Promise as an
externref in the return register.
R=ahaas@chromium.org,jkummerow@chromium.org
CC=fgm@chromium.org
Bug: v8:12191
Change-Id: If3f8eaba8edebe6e98d4738f79f895fdb5322adc
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3460410
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79148}
2022-02-15 14:46:22 +00:00
|
|
|
|
|
|
|
(function TestStackSwitchSuspendArgs() {
|
|
|
|
print(arguments.callee.name);
|
|
|
|
function reduce(array) {
|
|
|
|
// a[0] + a[1] * 2 + a[2] * 3 + ...
|
|
|
|
return array.reduce((prev, cur, i) => prev + cur * (i + 1));
|
|
|
|
}
|
|
|
|
let builder = new WasmModuleBuilder();
|
|
|
|
// Number of param registers + 1 for both types.
|
2022-07-11 10:16:59 +00:00
|
|
|
let sig = makeSig([kWasmAnyRef, kWasmI32, kWasmI32, kWasmI32, kWasmI32, kWasmI32, kWasmI32,
|
[wasm] Handle arguments in stack-switching export wrapper
Use the existing generic js-to-wasm wrapper to handle arguments in
the stack-switching export wrapper, by combining them into a single
helper function parameterized by a boolean.
If the stack_switch parameter is false, the generated js-to-wasm wrapper
is the same as before.
If the stack_switch parameter is true, we allocate and switch to the new
stack before starting to process the parameters. To load the parameters,
we also keep a pointer to the old stack.
After the call, we convert the return value according to the return type
as usual, and then switch back to the parent stack (which may be
different than the original stack, but has a compatible stack frame
layout).
If the stack suspends during the call, control-flow jumps right before
we deconstruct and leave the frame, and returns the Promise as an
externref in the return register.
R=ahaas@chromium.org,jkummerow@chromium.org
CC=fgm@chromium.org
Bug: v8:12191
Change-Id: If3f8eaba8edebe6e98d4738f79f895fdb5322adc
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3460410
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79148}
2022-02-15 14:46:22 +00:00
|
|
|
kWasmF32, kWasmF32, kWasmF32, kWasmF32, kWasmF32, kWasmF32, kWasmF32], [kWasmI32]);
|
|
|
|
import_index = builder.addImport('m', 'import', sig);
|
|
|
|
builder.addFunction("test", sig)
|
|
|
|
.addBody([
|
|
|
|
kExprLocalGet, 0, kExprLocalGet, 1, kExprLocalGet, 2, kExprLocalGet, 3,
|
|
|
|
kExprLocalGet, 4, kExprLocalGet, 5, kExprLocalGet, 6, kExprLocalGet, 7,
|
|
|
|
kExprLocalGet, 8, kExprLocalGet, 9, kExprLocalGet, 10, kExprLocalGet, 11,
|
2022-07-11 10:16:59 +00:00
|
|
|
kExprLocalGet, 12, kExprLocalGet, 13,
|
[wasm] Handle arguments in stack-switching export wrapper
Use the existing generic js-to-wasm wrapper to handle arguments in
the stack-switching export wrapper, by combining them into a single
helper function parameterized by a boolean.
If the stack_switch parameter is false, the generated js-to-wasm wrapper
is the same as before.
If the stack_switch parameter is true, we allocate and switch to the new
stack before starting to process the parameters. To load the parameters,
we also keep a pointer to the old stack.
After the call, we convert the return value according to the return type
as usual, and then switch back to the parent stack (which may be
different than the original stack, but has a compatible stack frame
layout).
If the stack suspends during the call, control-flow jumps right before
we deconstruct and leave the frame, and returns the Promise as an
externref in the return register.
R=ahaas@chromium.org,jkummerow@chromium.org
CC=fgm@chromium.org
Bug: v8:12191
Change-Id: If3f8eaba8edebe6e98d4738f79f895fdb5322adc
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3460410
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79148}
2022-02-15 14:46:22 +00:00
|
|
|
kExprCallFunction, import_index, // suspend
|
|
|
|
]).exportFunc();
|
|
|
|
let suspender = new WebAssembly.Suspender();
|
2022-07-11 10:16:59 +00:00
|
|
|
function js_import(suspender, i1, i2, i3, i4, i5, i6, f1, f2, f3, f4, f5, f6, f7) {
|
|
|
|
return Promise.resolve(reduce(Array.from(arguments).slice(1)));
|
[wasm] Handle arguments in stack-switching export wrapper
Use the existing generic js-to-wasm wrapper to handle arguments in
the stack-switching export wrapper, by combining them into a single
helper function parameterized by a boolean.
If the stack_switch parameter is false, the generated js-to-wasm wrapper
is the same as before.
If the stack_switch parameter is true, we allocate and switch to the new
stack before starting to process the parameters. To load the parameters,
we also keep a pointer to the old stack.
After the call, we convert the return value according to the return type
as usual, and then switch back to the parent stack (which may be
different than the original stack, but has a compatible stack frame
layout).
If the stack suspends during the call, control-flow jumps right before
we deconstruct and leave the frame, and returns the Promise as an
externref in the return register.
R=ahaas@chromium.org,jkummerow@chromium.org
CC=fgm@chromium.org
Bug: v8:12191
Change-Id: If3f8eaba8edebe6e98d4738f79f895fdb5322adc
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3460410
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79148}
2022-02-15 14:46:22 +00:00
|
|
|
};
|
|
|
|
let wasm_js_import = new WebAssembly.Function(
|
2022-07-11 10:16:59 +00:00
|
|
|
{parameters: ['externref', 'i32', 'i32', 'i32', 'i32', 'i32', 'i32', 'f32', 'f32',
|
[wasm] Handle arguments in stack-switching export wrapper
Use the existing generic js-to-wasm wrapper to handle arguments in
the stack-switching export wrapper, by combining them into a single
helper function parameterized by a boolean.
If the stack_switch parameter is false, the generated js-to-wasm wrapper
is the same as before.
If the stack_switch parameter is true, we allocate and switch to the new
stack before starting to process the parameters. To load the parameters,
we also keep a pointer to the old stack.
After the call, we convert the return value according to the return type
as usual, and then switch back to the parent stack (which may be
different than the original stack, but has a compatible stack frame
layout).
If the stack suspends during the call, control-flow jumps right before
we deconstruct and leave the frame, and returns the Promise as an
externref in the return register.
R=ahaas@chromium.org,jkummerow@chromium.org
CC=fgm@chromium.org
Bug: v8:12191
Change-Id: If3f8eaba8edebe6e98d4738f79f895fdb5322adc
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3460410
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79148}
2022-02-15 14:46:22 +00:00
|
|
|
'f32', 'f32', 'f32', 'f32', 'f32'], results: ['externref']}, js_import);
|
|
|
|
let suspending_wasm_js_import =
|
2022-07-11 14:08:59 +00:00
|
|
|
WebAssembly.suspendOnReturnedPromise(wasm_js_import);
|
[wasm] Handle arguments in stack-switching export wrapper
Use the existing generic js-to-wasm wrapper to handle arguments in
the stack-switching export wrapper, by combining them into a single
helper function parameterized by a boolean.
If the stack_switch parameter is false, the generated js-to-wasm wrapper
is the same as before.
If the stack_switch parameter is true, we allocate and switch to the new
stack before starting to process the parameters. To load the parameters,
we also keep a pointer to the old stack.
After the call, we convert the return value according to the return type
as usual, and then switch back to the parent stack (which may be
different than the original stack, but has a compatible stack frame
layout).
If the stack suspends during the call, control-flow jumps right before
we deconstruct and leave the frame, and returns the Promise as an
externref in the return register.
R=ahaas@chromium.org,jkummerow@chromium.org
CC=fgm@chromium.org
Bug: v8:12191
Change-Id: If3f8eaba8edebe6e98d4738f79f895fdb5322adc
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3460410
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79148}
2022-02-15 14:46:22 +00:00
|
|
|
|
|
|
|
let instance = builder.instantiate({m: {import: suspending_wasm_js_import}});
|
2022-07-11 14:08:59 +00:00
|
|
|
let wrapped_export = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
|
2022-07-11 10:16:59 +00:00
|
|
|
let args = [suspender, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
|
[wasm] Handle arguments in stack-switching export wrapper
Use the existing generic js-to-wasm wrapper to handle arguments in
the stack-switching export wrapper, by combining them into a single
helper function parameterized by a boolean.
If the stack_switch parameter is false, the generated js-to-wasm wrapper
is the same as before.
If the stack_switch parameter is true, we allocate and switch to the new
stack before starting to process the parameters. To load the parameters,
we also keep a pointer to the old stack.
After the call, we convert the return value according to the return type
as usual, and then switch back to the parent stack (which may be
different than the original stack, but has a compatible stack frame
layout).
If the stack suspends during the call, control-flow jumps right before
we deconstruct and leave the frame, and returns the Promise as an
externref in the return register.
R=ahaas@chromium.org,jkummerow@chromium.org
CC=fgm@chromium.org
Bug: v8:12191
Change-Id: If3f8eaba8edebe6e98d4738f79f895fdb5322adc
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3460410
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79148}
2022-02-15 14:46:22 +00:00
|
|
|
let combined_promise =
|
|
|
|
wrapped_export.apply(null, args);
|
2022-07-11 10:16:59 +00:00
|
|
|
combined_promise.then(v => assertEquals(reduce(args.slice(1)), v));
|
[wasm] Handle arguments in stack-switching export wrapper
Use the existing generic js-to-wasm wrapper to handle arguments in
the stack-switching export wrapper, by combining them into a single
helper function parameterized by a boolean.
If the stack_switch parameter is false, the generated js-to-wasm wrapper
is the same as before.
If the stack_switch parameter is true, we allocate and switch to the new
stack before starting to process the parameters. To load the parameters,
we also keep a pointer to the old stack.
After the call, we convert the return value according to the return type
as usual, and then switch back to the parent stack (which may be
different than the original stack, but has a compatible stack frame
layout).
If the stack suspends during the call, control-flow jumps right before
we deconstruct and leave the frame, and returns the Promise as an
externref in the return register.
R=ahaas@chromium.org,jkummerow@chromium.org
CC=fgm@chromium.org
Bug: v8:12191
Change-Id: If3f8eaba8edebe6e98d4738f79f895fdb5322adc
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3460410
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79148}
2022-02-15 14:46:22 +00:00
|
|
|
})();
|
2022-04-27 09:35:43 +00:00
|
|
|
|
|
|
|
(function TestStackSwitchReturnFloat() {
|
|
|
|
print(arguments.callee.name);
|
|
|
|
let builder = new WasmModuleBuilder();
|
2022-07-11 10:16:59 +00:00
|
|
|
let sig = makeSig([kWasmAnyRef], [kWasmF32]);
|
|
|
|
import_index = builder.addImport('m', 'import', sig);
|
|
|
|
builder.addFunction("test", sig)
|
2022-04-27 09:35:43 +00:00
|
|
|
.addBody([
|
2022-07-11 10:16:59 +00:00
|
|
|
kExprLocalGet, 0,
|
2022-04-27 09:35:43 +00:00
|
|
|
kExprCallFunction, import_index, // suspend
|
|
|
|
]).exportFunc();
|
|
|
|
let suspender = new WebAssembly.Suspender();
|
2022-07-11 14:08:59 +00:00
|
|
|
function js_import(suspender) {
|
2022-04-27 09:35:43 +00:00
|
|
|
return Promise.resolve(0.5);
|
|
|
|
};
|
|
|
|
let wasm_js_import = new WebAssembly.Function(
|
2022-07-11 10:16:59 +00:00
|
|
|
{parameters: ['externref'], results: ['externref']}, js_import);
|
2022-04-27 09:35:43 +00:00
|
|
|
let suspending_wasm_js_import =
|
2022-07-11 14:08:59 +00:00
|
|
|
WebAssembly.suspendOnReturnedPromise(wasm_js_import);
|
2022-04-27 09:35:43 +00:00
|
|
|
|
|
|
|
let instance = builder.instantiate({m: {import: suspending_wasm_js_import}});
|
2022-07-11 14:08:59 +00:00
|
|
|
let wrapped_export = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
|
2022-07-11 10:16:59 +00:00
|
|
|
let combined_promise = wrapped_export(suspender);
|
2022-04-27 09:35:43 +00:00
|
|
|
combined_promise.then(v => assertEquals(0.5, v));
|
|
|
|
})();
|
2022-06-16 12:49:38 +00:00
|
|
|
|
|
|
|
// Throw an exception after the initial prompt.
|
|
|
|
(function TestStackSwitchException1() {
|
|
|
|
print(arguments.callee.name);
|
|
|
|
let builder = new WasmModuleBuilder();
|
|
|
|
let tag = builder.addTag(kSig_v_v);
|
2022-07-11 10:16:59 +00:00
|
|
|
builder.addFunction("throw", kSig_i_r)
|
2022-06-16 12:49:38 +00:00
|
|
|
.addBody([kExprThrow, tag]).exportFunc();
|
|
|
|
let instance = builder.instantiate();
|
|
|
|
let suspender = new WebAssembly.Suspender();
|
2022-07-11 14:08:59 +00:00
|
|
|
let wrapper = WebAssembly.returnPromiseOnSuspend(instance.exports.throw);
|
2022-06-16 12:49:38 +00:00
|
|
|
try {
|
2022-07-11 10:16:59 +00:00
|
|
|
wrapper(suspender);
|
2022-06-16 12:49:38 +00:00
|
|
|
assertUnreachable();
|
|
|
|
} catch (e) {
|
|
|
|
assertTrue(e instanceof WebAssembly.Exception);
|
|
|
|
}
|
|
|
|
})();
|
|
|
|
|
|
|
|
// Throw an exception after the first resume event, which propagates to the
|
|
|
|
// promise wrapper.
|
|
|
|
(function TestStackSwitchException2() {
|
|
|
|
print(arguments.callee.name);
|
|
|
|
let tag = new WebAssembly.Tag({parameters: []});
|
|
|
|
let builder = new WasmModuleBuilder();
|
2022-07-11 10:16:59 +00:00
|
|
|
import_index = builder.addImport('m', 'import', kSig_i_r);
|
2022-06-16 12:49:38 +00:00
|
|
|
tag_index = builder.addImportedTag('m', 'tag', kSig_v_v);
|
2022-07-11 10:16:59 +00:00
|
|
|
builder.addFunction("test", kSig_i_r)
|
2022-06-16 12:49:38 +00:00
|
|
|
.addBody([
|
2022-07-11 10:16:59 +00:00
|
|
|
kExprLocalGet, 0,
|
2022-06-16 12:49:38 +00:00
|
|
|
kExprCallFunction, import_index,
|
|
|
|
kExprThrow, tag_index
|
|
|
|
]).exportFunc();
|
|
|
|
let suspender = new WebAssembly.Suspender();
|
2022-07-11 14:08:59 +00:00
|
|
|
function js_import(suspender) {
|
2022-06-16 12:49:38 +00:00
|
|
|
return Promise.resolve(42);
|
|
|
|
};
|
|
|
|
let wasm_js_import = new WebAssembly.Function(
|
2022-07-11 10:16:59 +00:00
|
|
|
{parameters: ['externref'], results: ['externref']}, js_import);
|
2022-06-16 12:49:38 +00:00
|
|
|
let suspending_wasm_js_import =
|
2022-07-11 14:08:59 +00:00
|
|
|
WebAssembly.suspendOnReturnedPromise(wasm_js_import);
|
2022-06-16 12:49:38 +00:00
|
|
|
|
|
|
|
let instance = builder.instantiate({m: {import: suspending_wasm_js_import, tag: tag}});
|
2022-07-11 14:08:59 +00:00
|
|
|
let wrapped_export = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
|
2022-07-11 10:16:59 +00:00
|
|
|
let combined_promise = wrapped_export(suspender);
|
2022-06-16 12:49:38 +00:00
|
|
|
assertThrowsAsync(combined_promise, WebAssembly.Exception);
|
|
|
|
})();
|
2022-06-21 14:52:09 +00:00
|
|
|
|
|
|
|
(function TestStackSwitchPromiseReject() {
|
|
|
|
print(arguments.callee.name);
|
|
|
|
let tag = new WebAssembly.Tag({parameters: ['i32']});
|
|
|
|
let builder = new WasmModuleBuilder();
|
2022-07-11 10:16:59 +00:00
|
|
|
import_index = builder.addImport('m', 'import', kSig_i_r);
|
2022-06-21 14:52:09 +00:00
|
|
|
tag_index = builder.addImportedTag('m', 'tag', kSig_v_i);
|
2022-07-11 10:16:59 +00:00
|
|
|
builder.addFunction("test", kSig_i_r)
|
2022-06-21 14:52:09 +00:00
|
|
|
.addBody([
|
|
|
|
kExprTry, kWasmI32,
|
2022-07-11 10:16:59 +00:00
|
|
|
kExprLocalGet, 0,
|
2022-06-21 14:52:09 +00:00
|
|
|
kExprCallFunction, import_index,
|
|
|
|
kExprCatch, tag_index,
|
|
|
|
kExprEnd,
|
|
|
|
]).exportFunc();
|
|
|
|
let suspender = new WebAssembly.Suspender();
|
2022-07-11 14:08:59 +00:00
|
|
|
function js_import(suspender) {
|
2022-06-21 14:52:09 +00:00
|
|
|
return Promise.reject(new WebAssembly.Exception(tag, [42]));
|
|
|
|
};
|
|
|
|
let wasm_js_import = new WebAssembly.Function(
|
2022-07-11 10:16:59 +00:00
|
|
|
{parameters: ['externref'], results: ['externref']}, js_import);
|
2022-06-21 14:52:09 +00:00
|
|
|
let suspending_wasm_js_import =
|
2022-07-11 14:08:59 +00:00
|
|
|
WebAssembly.suspendOnReturnedPromise(wasm_js_import);
|
2022-06-21 14:52:09 +00:00
|
|
|
|
|
|
|
let instance = builder.instantiate({m: {import: suspending_wasm_js_import, tag: tag}});
|
2022-07-11 14:08:59 +00:00
|
|
|
let wrapped_export = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
|
2022-07-11 10:16:59 +00:00
|
|
|
let combined_promise = wrapped_export(suspender);
|
2022-06-21 14:52:09 +00:00
|
|
|
assertPromiseResult(combined_promise, v => assertEquals(v, 42));
|
|
|
|
})();
|
2022-06-21 15:39:09 +00:00
|
|
|
|
|
|
|
(function TestReenterActiveSuspenderFails() {
|
|
|
|
print(arguments.callee.name);
|
|
|
|
let builder = new WasmModuleBuilder();
|
2022-07-11 10:16:59 +00:00
|
|
|
let import_index = builder.addImport("m", "i", kSig_v_r);
|
|
|
|
builder.addFunction("test", kSig_i_r)
|
2022-06-21 15:39:09 +00:00
|
|
|
.addBody([
|
2022-07-11 10:16:59 +00:00
|
|
|
kExprLocalGet, 0,
|
2022-06-21 15:39:09 +00:00
|
|
|
kExprCallFunction, import_index,
|
|
|
|
kExprI32Const, 0
|
|
|
|
]).exportFunc();
|
|
|
|
let wrapped_export;
|
2022-07-11 10:16:59 +00:00
|
|
|
function js_import(suspender) {
|
|
|
|
wrapped_export(suspender); // Re-enter the same wrapped export.
|
2022-06-21 15:39:09 +00:00
|
|
|
}
|
|
|
|
let instance = builder.instantiate({m: {i: js_import}});
|
|
|
|
let suspender = new WebAssembly.Suspender();
|
2022-07-11 14:08:59 +00:00
|
|
|
wrapped_export = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
|
2022-07-11 10:16:59 +00:00
|
|
|
assertThrows(() => wrapped_export(suspender), WebAssembly.RuntimeError,
|
2022-06-21 15:39:09 +00:00
|
|
|
/re-entering an active\/suspended suspender/);
|
|
|
|
})();
|
|
|
|
|
|
|
|
(function TestReenterSuspendedSuspenderFails() {
|
|
|
|
print(arguments.callee.name);
|
|
|
|
let builder = new WasmModuleBuilder();
|
2022-07-11 10:16:59 +00:00
|
|
|
let import_index = builder.addImport("m", "i", kSig_v_r);
|
|
|
|
builder.addFunction("test", kSig_i_r)
|
2022-06-21 15:39:09 +00:00
|
|
|
.addBody([
|
2022-07-11 10:16:59 +00:00
|
|
|
kExprLocalGet, 0,
|
2022-06-21 15:39:09 +00:00
|
|
|
kExprCallFunction, import_index,
|
|
|
|
kExprI32Const, 0
|
|
|
|
]).exportFunc();
|
|
|
|
let suspender = new WebAssembly.Suspender();
|
2022-07-11 14:08:59 +00:00
|
|
|
let i = WebAssembly.suspendOnReturnedPromise(
|
2022-07-06 12:57:34 +00:00
|
|
|
new WebAssembly.Function(
|
2022-07-11 10:16:59 +00:00
|
|
|
{parameters: ['externref'], results: ['externref']},
|
2022-07-06 12:57:34 +00:00
|
|
|
() => Promise.resolve(0)));
|
|
|
|
let instance = builder.instantiate({m: {i}});
|
2022-07-11 14:08:59 +00:00
|
|
|
let wrapped_export = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
|
2022-07-11 10:16:59 +00:00
|
|
|
let promise1 = wrapped_export(suspender);
|
2022-06-21 15:39:09 +00:00
|
|
|
// Re-enter the suspender before resolving the promise.
|
2022-07-11 10:16:59 +00:00
|
|
|
assertThrows(() => wrapped_export(suspender), WebAssembly.RuntimeError,
|
2022-06-21 15:39:09 +00:00
|
|
|
/re-entering an active\/suspended suspender/);
|
|
|
|
})();
|
2022-06-28 16:21:51 +00:00
|
|
|
|
2022-07-06 12:57:34 +00:00
|
|
|
function TestNestedSuspenders(suspend) {
|
2022-06-28 16:21:51 +00:00
|
|
|
// Nest two suspenders. The call chain looks like:
|
|
|
|
// outer (wasm) -> outer (js) -> inner (wasm) -> inner (js)
|
2022-07-06 12:57:34 +00:00
|
|
|
// 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 JS function returns a regular value and
|
|
|
|
// no computation is suspended.
|
2022-06-28 16:21:51 +00:00
|
|
|
print(arguments.callee.name);
|
|
|
|
let builder = new WasmModuleBuilder();
|
2022-07-11 10:16:59 +00:00
|
|
|
inner_index = builder.addImport('m', 'inner', kSig_i_r);
|
|
|
|
outer_index = builder.addImport('m', 'outer', kSig_i_r);
|
|
|
|
builder.addFunction("outer", kSig_i_r)
|
2022-06-28 16:21:51 +00:00
|
|
|
.addBody([
|
2022-07-11 10:16:59 +00:00
|
|
|
kExprLocalGet, 0,
|
2022-06-28 16:21:51 +00:00
|
|
|
kExprCallFunction, outer_index
|
|
|
|
]).exportFunc();
|
2022-07-11 10:16:59 +00:00
|
|
|
builder.addFunction("inner", kSig_i_r)
|
2022-06-28 16:21:51 +00:00
|
|
|
.addBody([
|
2022-07-11 10:16:59 +00:00
|
|
|
kExprLocalGet, 0,
|
2022-06-28 16:21:51 +00:00
|
|
|
kExprCallFunction, inner_index
|
|
|
|
]).exportFunc();
|
|
|
|
let outer_suspender = new WebAssembly.Suspender();
|
|
|
|
let inner_suspender = new WebAssembly.Suspender();
|
|
|
|
|
2022-07-11 14:08:59 +00:00
|
|
|
let inner = WebAssembly.suspendOnReturnedPromise(
|
2022-06-28 16:21:51 +00:00
|
|
|
new WebAssembly.Function(
|
2022-07-11 10:16:59 +00:00
|
|
|
{parameters: ['externref'], results: ['externref']},
|
2022-07-06 12:57:34 +00:00
|
|
|
() => suspend ? Promise.resolve(42) : 42));
|
2022-06-28 16:21:51 +00:00
|
|
|
|
|
|
|
let export_inner;
|
2022-07-11 14:08:59 +00:00
|
|
|
let outer = WebAssembly.suspendOnReturnedPromise(
|
2022-06-28 16:21:51 +00:00
|
|
|
new WebAssembly.Function(
|
2022-07-11 10:16:59 +00:00
|
|
|
{parameters: ['externref'], results: ['externref']},
|
2022-07-11 14:08:59 +00:00
|
|
|
(suspender) => export_inner(inner_suspender)));
|
2022-06-28 16:21:51 +00:00
|
|
|
|
|
|
|
let instance = builder.instantiate({m: {inner, outer}});
|
2022-07-11 14:08:59 +00:00
|
|
|
export_inner = WebAssembly.returnPromiseOnSuspend(instance.exports.inner);
|
|
|
|
let export_outer = WebAssembly.returnPromiseOnSuspend(instance.exports.outer);
|
2022-07-06 12:57:34 +00:00
|
|
|
if (suspend) {
|
2022-07-11 10:16:59 +00:00
|
|
|
assertPromiseResult(export_outer(outer_suspender), v => assertEquals(42, v));
|
2022-07-06 12:57:34 +00:00
|
|
|
} else {
|
2022-07-11 10:16:59 +00:00
|
|
|
assertEquals(export_outer(outer_suspender), 42);
|
2022-07-06 12:57:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
(function TestNestedSuspendersSuspend() {
|
|
|
|
TestNestedSuspenders(true);
|
|
|
|
})();
|
|
|
|
|
|
|
|
(function TestNestedSuspendersNoSuspend() {
|
|
|
|
TestNestedSuspenders(false);
|
|
|
|
})();
|
|
|
|
|
|
|
|
(function TestReenterInactiveSuspender() {
|
|
|
|
print(arguments.callee.name);
|
|
|
|
let builder = new WasmModuleBuilder();
|
2022-07-11 10:16:59 +00:00
|
|
|
let import_index = builder.addImport("m", "i", kSig_i_r);
|
|
|
|
builder.addFunction("test", kSig_i_r)
|
2022-07-06 12:57:34 +00:00
|
|
|
.addBody([
|
2022-07-11 10:16:59 +00:00
|
|
|
kExprLocalGet, 0,
|
2022-07-06 12:57:34 +00:00
|
|
|
kExprCallFunction, import_index,
|
|
|
|
]).exportFunc();
|
|
|
|
let suspender = new WebAssembly.Suspender();
|
2022-07-11 14:08:59 +00:00
|
|
|
let i = WebAssembly.suspendOnReturnedPromise(
|
2022-07-06 12:57:34 +00:00
|
|
|
new WebAssembly.Function(
|
2022-07-11 10:16:59 +00:00
|
|
|
{parameters: ['externref'], results: ['externref']},
|
2022-07-06 12:57:34 +00:00
|
|
|
() => Promise.resolve(0)));
|
|
|
|
let instance = builder.instantiate({m: {i}});
|
2022-07-11 14:08:59 +00:00
|
|
|
let wrapped_export = WebAssembly.returnPromiseOnSuspend(instance.exports.test);
|
2022-07-06 12:57:34 +00:00
|
|
|
assertPromiseResult(
|
2022-07-11 10:16:59 +00:00
|
|
|
wrapped_export(suspender),
|
2022-07-06 12:57:34 +00:00
|
|
|
() => assertPromiseResult(
|
2022-07-11 10:16:59 +00:00
|
|
|
wrapped_export(suspender),
|
2022-07-06 12:57:34 +00:00
|
|
|
v => assertEquals(v, 0)));
|
2022-06-28 16:21:51 +00:00
|
|
|
})();
|