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
|
2022-09-27 19:07:15 +00:00
|
|
|
// Flags: --expose-gc --wasm-stack-switching-stack-size=100
|
2022-10-06 12:03:16 +00:00
|
|
|
// Flags: --experimental-wasm-typed-funcref
|
2022-09-08 09:18:21 +00:00
|
|
|
|
|
|
|
// We pick a small stack size to run the stack overflow test quickly, but big
|
|
|
|
// enough to run all the tests.
|
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-08-03 16:32:08 +00:00
|
|
|
function ToPromising(wasm_export) {
|
|
|
|
let sig = WebAssembly.Function.type(wasm_export);
|
|
|
|
assertTrue(sig.parameters.length > 0);
|
|
|
|
assertEquals('externref', sig.parameters[0]);
|
|
|
|
let wrapper_sig = {
|
|
|
|
parameters: sig.parameters.slice(1),
|
|
|
|
results: ['externref']
|
|
|
|
};
|
|
|
|
return new WebAssembly.Function(
|
|
|
|
wrapper_sig, wasm_export, {promising: 'first'});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
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]);
|
2022-07-19 14:18:53 +00:00
|
|
|
let sig_v_ri = makeSig([kWasmExternRef, kWasmI32], []);
|
2022-07-11 10:16:59 +00:00
|
|
|
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-19 14:18:53 +00:00
|
|
|
function js_import(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.
|
2022-08-03 16:32:08 +00:00
|
|
|
let import_wrapper = new WebAssembly.Function(
|
|
|
|
{parameters: ['externref', 'i32'], results: []},
|
|
|
|
js_import,
|
|
|
|
{suspending: 'first'});
|
2022-02-04 16:57:10 +00:00
|
|
|
let instance = builder.instantiate({'m': {'import': import_wrapper}});
|
2022-08-03 16:32:08 +00:00
|
|
|
let export_wrapper = ToPromising(instance.exports.export);
|
2022-02-04 16:57:10 +00:00
|
|
|
|
|
|
|
// Check type errors.
|
2022-08-03 16:32:08 +00:00
|
|
|
assertThrows(() => new WebAssembly.Function(
|
|
|
|
{parameters: ['externref'], results: ['externref']},
|
|
|
|
js_import,
|
|
|
|
{suspending: 'foo'}),
|
2022-02-04 16:57:10 +00:00
|
|
|
TypeError,
|
2022-08-03 16:32:08 +00:00
|
|
|
/JS Promise Integration: Expected suspender position to be "first", "last" or "none"/);
|
|
|
|
// Bad inner signature (promising)
|
|
|
|
for (const f of [instance.exports.wrong1, instance.exports.wrong2, instance.exports.wrong3]) {
|
|
|
|
assertThrows(() => new WebAssembly.Function(
|
|
|
|
{parameters: ['i32'], results: ['externref']},
|
|
|
|
f,
|
|
|
|
{promising: 'first'}),
|
|
|
|
TypeError,
|
|
|
|
/Incompatible signature for promising function/);
|
|
|
|
}
|
|
|
|
// Signature mismatch (suspending)
|
|
|
|
assertThrows(() => new WebAssembly.Function(
|
|
|
|
{parameters: ['externref'], results: []},
|
|
|
|
new WebAssembly.Function(
|
|
|
|
{parameters: [], results: ['i32']}, js_import),
|
|
|
|
{suspending: 'first'}),
|
2022-02-04 16:57:10 +00:00
|
|
|
TypeError,
|
2022-08-03 16:32:08 +00:00
|
|
|
/Incompatible signature for suspending function/);
|
|
|
|
// Signature mismatch (promising)
|
|
|
|
assertThrows(() => new WebAssembly.Function(
|
|
|
|
{parameters: ['externref', 'i32'], results: ['i32']},
|
|
|
|
instance.exports.export,
|
|
|
|
{promising: 'first'}),
|
2022-07-11 10:16:59 +00:00
|
|
|
TypeError,
|
2022-08-03 16:32:08 +00:00
|
|
|
/Incompatible signature for promising function/);
|
2022-02-04 16:57:10 +00:00
|
|
|
|
|
|
|
// Check the wrapped export's signature.
|
|
|
|
let export_sig = WebAssembly.Function.type(export_wrapper);
|
2022-07-27 12:19:45 +00:00
|
|
|
assertEquals(['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-08-03 16:32:08 +00:00
|
|
|
assertEquals([], import_sig.results);
|
2022-02-04 16:57:10 +00:00
|
|
|
})();
|
|
|
|
|
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-08-03 16:32:08 +00:00
|
|
|
let wrapper = ToPromising(instance.exports.test);
|
2022-07-11 10:16:59 +00:00
|
|
|
})();
|
|
|
|
|
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();
|
2022-08-03 16:32:08 +00:00
|
|
|
let wrapper = ToPromising(instance.exports.test);
|
2022-07-27 12:19:45 +00:00
|
|
|
wrapper();
|
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-08-03 16:32:08 +00:00
|
|
|
let js_import = new WebAssembly.Function(
|
|
|
|
{parameters: ['externref'], results: ['i32']},
|
|
|
|
() => Promise.resolve(42),
|
|
|
|
{suspending: 'first'});
|
2022-07-08 10:06:54 +00:00
|
|
|
let instance = builder.instantiate({m: {import: js_import}});
|
2022-08-03 16:32:08 +00:00
|
|
|
let wrapped_export = ToPromising(instance.exports.test);
|
2022-07-27 12:19:45 +00:00
|
|
|
let combined_promise = wrapped_export();
|
2022-08-03 16:32:08 +00:00
|
|
|
assertPromiseResult(combined_promise, v => assertEquals(42, v));
|
2022-07-08 10:06:54 +00:00
|
|
|
|
|
|
|
// Also try with a JS function with a mismatching arity.
|
2022-08-03 16:32:08 +00:00
|
|
|
js_import = new WebAssembly.Function(
|
|
|
|
{parameters: ['externref'], results: ['i32']},
|
|
|
|
(unused) => Promise.resolve(42),
|
|
|
|
{suspending: 'first'});
|
2022-07-08 10:06:54 +00:00
|
|
|
instance = builder.instantiate({m: {import: js_import}});
|
2022-08-03 16:32:08 +00:00
|
|
|
wrapped_export = ToPromising(instance.exports.test);
|
2022-07-27 12:19:45 +00:00
|
|
|
combined_promise = wrapped_export();
|
2022-08-03 16:32:08 +00:00
|
|
|
assertPromiseResult(combined_promise, v => assertEquals(42, v));
|
2022-07-08 10:06:54 +00:00
|
|
|
|
|
|
|
// Also try with a proxy.
|
2022-08-03 16:32:08 +00:00
|
|
|
js_import = new WebAssembly.Function(
|
|
|
|
{parameters: ['externref'], results: ['i32']},
|
|
|
|
new Proxy(() => Promise.resolve(42), {}),
|
|
|
|
{suspending: "first"});
|
2022-07-08 10:06:54 +00:00
|
|
|
instance = builder.instantiate({m: {import: js_import}});
|
2022-08-03 16:32:08 +00:00
|
|
|
wrapped_export = ToPromising(instance.exports.test);
|
2022-07-27 12:19:45 +00:00
|
|
|
combined_promise = wrapped_export();
|
2022-08-03 16:32:08 +00:00
|
|
|
assertPromiseResult(combined_promise, 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 i = 0;
|
|
|
|
// The n-th call to the import returns a promise that resolves to n.
|
2022-07-27 12:19:45 +00:00
|
|
|
function js_import() {
|
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-08-03 16:32:08 +00:00
|
|
|
{parameters: ['externref'], results: ['i32']},
|
|
|
|
js_import,
|
|
|
|
{suspending: 'first'});
|
|
|
|
let instance = builder.instantiate({m: {import: wasm_js_import}});
|
|
|
|
let wrapped_export = ToPromising(instance.exports.test);
|
2022-07-27 12:19:45 +00:00
|
|
|
let chained_promise = wrapped_export();
|
2022-02-02 22:38:34 +00:00
|
|
|
assertEquals(0, instance.exports.g.value);
|
2022-08-03 16:32:08 +00:00
|
|
|
assertPromiseResult(chained_promise, _ => assertEquals(15, instance.exports.g.value));
|
2022-01-05 16:22:05 +00:00
|
|
|
})();
|
|
|
|
|
2022-07-27 12:19:45 +00:00
|
|
|
// Call the GC in the import call.
|
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();
|
2022-08-03 16:32:08 +00:00
|
|
|
let js_import = new WebAssembly.Function(
|
|
|
|
{parameters: ['externref'], results: []},
|
|
|
|
gc,
|
|
|
|
{suspending: 'first'});
|
2022-07-11 10:16:59 +00:00
|
|
|
let instance = builder.instantiate({'m': {'gc': js_import}});
|
2022-08-03 16:32:08 +00:00
|
|
|
let wrapper = ToPromising(instance.exports.test);
|
2022-07-27 12:19:45 +00:00
|
|
|
wrapper();
|
2021-12-08 10:50:38 +00:00
|
|
|
})();
|
2022-02-07 14:17:01 +00:00
|
|
|
|
2022-07-21 15:21:54 +00:00
|
|
|
// Call the GC during param conversion.
|
|
|
|
(function TestStackSwitchGC2() {
|
|
|
|
print(arguments.callee.name);
|
|
|
|
let builder = new WasmModuleBuilder();
|
2022-07-28 09:35:25 +00:00
|
|
|
let sig = makeSig([kWasmExternRef, kWasmI32], [kWasmI32]);
|
2022-07-21 15:21:54 +00:00
|
|
|
let import_index = builder.addImport('m', 'import', sig);
|
|
|
|
builder.addFunction("test", sig)
|
|
|
|
.addBody([
|
|
|
|
kExprLocalGet, 0,
|
|
|
|
kExprLocalGet, 1,
|
|
|
|
kExprCallFunction, import_index,
|
|
|
|
]).exportFunc();
|
2022-08-03 16:32:08 +00:00
|
|
|
let js_import = new WebAssembly.Function(
|
|
|
|
{parameters: ['externref', 'i32'], results: ['i32']},
|
|
|
|
(v) => { return Promise.resolve(v) },
|
|
|
|
{suspending: 'first'});
|
2022-07-21 15:21:54 +00:00
|
|
|
let instance = builder.instantiate({'m': {'import': js_import}});
|
2022-08-03 16:32:08 +00:00
|
|
|
let wrapper = ToPromising(instance.exports.test);
|
2022-07-21 15:21:54 +00:00
|
|
|
let arg = { valueOf: () => { gc(); return 24; } };
|
2022-08-03 16:32:08 +00:00
|
|
|
assertPromiseResult(wrapper(arg), v => assertEquals(arg.valueOf(), v));
|
2022-07-21 15:21:54 +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();
|
2022-07-27 12:19:45 +00:00
|
|
|
function js_import() {
|
2022-02-07 14:17:01 +00:00
|
|
|
return 42
|
|
|
|
};
|
2022-08-03 16:32:08 +00:00
|
|
|
let wasm_js_import = new WebAssembly.Function(
|
|
|
|
{parameters: ['externref'], results: ['i32']},
|
|
|
|
js_import,
|
|
|
|
{suspending: 'first'});
|
|
|
|
let instance = builder.instantiate({m: {import: wasm_js_import}});
|
|
|
|
let wrapped_export = ToPromising(instance.exports.test);
|
2022-07-27 12:19:45 +00:00
|
|
|
let result = wrapped_export();
|
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-28 09:35:25 +00:00
|
|
|
let sig = makeSig([kWasmExternRef, 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-19 14:18:53 +00:00
|
|
|
function js_import(i1, i2, i3, i4, i5, i6, f1, f2, f3, f4, f5, f6, f7) {
|
|
|
|
return Promise.resolve(reduce(Array.from(arguments)));
|
[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-08-03 16:32:08 +00:00
|
|
|
{parameters: ['externref', 'i32', 'i32', 'i32', 'i32', 'i32', 'i32', 'f32',
|
|
|
|
'f32', 'f32', 'f32', 'f32', 'f32', 'f32'], results: ['i32']},
|
|
|
|
js_import,
|
|
|
|
{suspending: 'first'});
|
[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-08-03 16:32:08 +00:00
|
|
|
let instance = builder.instantiate({m: {import: wasm_js_import}});
|
|
|
|
let wrapped_export = ToPromising(instance.exports.test);
|
2022-07-27 12:19:45 +00:00
|
|
|
let args = [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-08-03 16:32:08 +00:00
|
|
|
assertPromiseResult(combined_promise, v => assertEquals(reduce(args), 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-28 09:35:25 +00:00
|
|
|
let sig = makeSig([kWasmExternRef], [kWasmF32]);
|
2022-07-11 10:16:59 +00:00
|
|
|
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();
|
2022-07-27 12:19:45 +00:00
|
|
|
function js_import() {
|
2022-04-27 09:35:43 +00:00
|
|
|
return Promise.resolve(0.5);
|
|
|
|
};
|
|
|
|
let wasm_js_import = new WebAssembly.Function(
|
2022-08-03 16:32:08 +00:00
|
|
|
{parameters: ['externref'], results: ['f32']},
|
|
|
|
js_import,
|
|
|
|
{suspending: 'first'});
|
2022-04-27 09:35:43 +00:00
|
|
|
|
2022-08-03 16:32:08 +00:00
|
|
|
let instance = builder.instantiate({m: {import: wasm_js_import}});
|
|
|
|
let wrapped_export = ToPromising(instance.exports.test);
|
2022-07-27 12:19:45 +00:00
|
|
|
let combined_promise = wrapped_export();
|
2022-08-03 16:32:08 +00:00
|
|
|
assertPromiseResult(combined_promise, v => assertEquals(0.5, v));
|
2022-04-27 09:35:43 +00:00
|
|
|
})();
|
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();
|
2022-08-03 16:32:08 +00:00
|
|
|
let wrapper = ToPromising(instance.exports.throw);
|
2022-06-16 12:49:38 +00:00
|
|
|
try {
|
2022-07-27 12:19:45 +00:00
|
|
|
wrapper();
|
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();
|
2022-07-27 12:19:45 +00:00
|
|
|
function js_import() {
|
2022-06-16 12:49:38 +00:00
|
|
|
return Promise.resolve(42);
|
|
|
|
};
|
|
|
|
let wasm_js_import = new WebAssembly.Function(
|
2022-08-03 16:32:08 +00:00
|
|
|
{parameters: ['externref'], results: ['i32']},
|
|
|
|
js_import,
|
|
|
|
{suspending: 'first'});
|
2022-06-16 12:49:38 +00:00
|
|
|
|
2022-08-03 16:32:08 +00:00
|
|
|
let instance = builder.instantiate({m: {import: wasm_js_import, tag: tag}});
|
|
|
|
let wrapped_export = ToPromising(instance.exports.test);
|
2022-07-27 12:19:45 +00:00
|
|
|
let combined_promise = wrapped_export();
|
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();
|
2022-07-27 12:19:45 +00:00
|
|
|
function js_import() {
|
2022-06-21 14:52:09 +00:00
|
|
|
return Promise.reject(new WebAssembly.Exception(tag, [42]));
|
|
|
|
};
|
|
|
|
let wasm_js_import = new WebAssembly.Function(
|
2022-08-03 16:32:08 +00:00
|
|
|
{parameters: ['externref'], results: ['i32']},
|
|
|
|
js_import,
|
|
|
|
{suspending: 'first'});
|
2022-06-21 14:52:09 +00:00
|
|
|
|
2022-08-03 16:32:08 +00:00
|
|
|
let instance = builder.instantiate({m: {import: wasm_js_import, tag: tag}});
|
|
|
|
let wrapped_export = ToPromising(instance.exports.test);
|
2022-07-27 12:19:45 +00:00
|
|
|
let combined_promise = wrapped_export();
|
2022-06-21 14:52:09 +00:00
|
|
|
assertPromiseResult(combined_promise, v => assertEquals(v, 42));
|
|
|
|
})();
|
2022-06-21 15:39:09 +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
|
|
|
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();
|
|
|
|
|
2022-08-03 16:32:08 +00:00
|
|
|
let inner = new WebAssembly.Function(
|
|
|
|
{parameters: ['externref'], results: ['i32']},
|
|
|
|
() => suspend ? Promise.resolve(42) : 42,
|
|
|
|
{suspending: 'first'});
|
2022-06-28 16:21:51 +00:00
|
|
|
|
|
|
|
let export_inner;
|
2022-08-03 16:32:08 +00:00
|
|
|
let outer = new WebAssembly.Function(
|
|
|
|
{parameters: ['externref'], results: ['i32']},
|
|
|
|
() => export_inner(),
|
|
|
|
{suspending: 'first'});
|
2022-06-28 16:21:51 +00:00
|
|
|
|
|
|
|
let instance = builder.instantiate({m: {inner, outer}});
|
2022-08-03 16:32:08 +00:00
|
|
|
export_inner = ToPromising(instance.exports.inner);
|
|
|
|
let export_outer = ToPromising(instance.exports.outer);
|
2022-07-06 12:57:34 +00:00
|
|
|
if (suspend) {
|
2022-07-27 12:19:45 +00:00
|
|
|
assertPromiseResult(export_outer(), v => assertEquals(42, v));
|
2022-07-06 12:57:34 +00:00
|
|
|
} else {
|
2022-07-27 12:19:45 +00:00
|
|
|
assertEquals(export_outer(), 42);
|
2022-07-06 12:57:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
(function TestNestedSuspendersSuspend() {
|
2022-07-19 14:18:53 +00:00
|
|
|
print(arguments.callee.name);
|
2022-07-06 12:57:34 +00:00
|
|
|
TestNestedSuspenders(true);
|
|
|
|
})();
|
|
|
|
|
|
|
|
(function TestNestedSuspendersNoSuspend() {
|
2022-07-19 14:18:53 +00:00
|
|
|
print(arguments.callee.name);
|
2022-07-06 12:57:34 +00:00
|
|
|
TestNestedSuspenders(false);
|
|
|
|
})();
|
2022-08-25 14:00:51 +00:00
|
|
|
|
|
|
|
(function Regress13231() {
|
|
|
|
print(arguments.callee.name);
|
|
|
|
// Check that a promising function with no return is allowed.
|
|
|
|
let builder = new WasmModuleBuilder();
|
|
|
|
let sig_v_r = makeSig([kWasmExternRef], []);
|
|
|
|
builder.addFunction("export", sig_v_r).addBody([]).exportFunc();
|
|
|
|
let instance = builder.instantiate();
|
|
|
|
let export_wrapper = ToPromising(instance.exports.export);
|
|
|
|
let export_sig = WebAssembly.Function.type(export_wrapper);
|
|
|
|
assertEquals([], export_sig.parameters);
|
|
|
|
assertEquals(['externref'], export_sig.results);
|
|
|
|
})();
|
2022-09-08 09:18:21 +00:00
|
|
|
|
|
|
|
(function TestStackOverflow() {
|
|
|
|
print(arguments.callee.name);
|
|
|
|
let builder = new WasmModuleBuilder();
|
|
|
|
builder.addFunction("test", kSig_i_r)
|
|
|
|
.addBody([
|
|
|
|
kExprLocalGet, 0,
|
|
|
|
kExprCallFunction, 0
|
|
|
|
]).exportFunc();
|
|
|
|
let instance = builder.instantiate();
|
|
|
|
let wrapper = ToPromising(instance.exports.test);
|
|
|
|
assertThrows(wrapper, RangeError, /Maximum call stack size exceeded/);
|
|
|
|
})();
|
2022-09-13 18:16:46 +00:00
|
|
|
|
|
|
|
(function TestBadSuspender() {
|
|
|
|
print(arguments.callee.name);
|
|
|
|
let builder = new WasmModuleBuilder();
|
|
|
|
let import_index = builder.addImport('m', 'import', kSig_i_r);
|
|
|
|
builder.addFunction("test", kSig_i_r)
|
|
|
|
.addBody([
|
|
|
|
kExprLocalGet, 0,
|
|
|
|
kExprCallFunction, import_index, // suspend
|
|
|
|
]).exportFunc();
|
|
|
|
builder.addFunction("return_suspender", kSig_r_r)
|
|
|
|
.addBody([
|
|
|
|
kExprLocalGet, 0
|
|
|
|
]).exportFunc();
|
|
|
|
let js_import = new WebAssembly.Function(
|
|
|
|
{parameters: ['externref'], results: ['i32']},
|
|
|
|
() => Promise.resolve(42),
|
|
|
|
{suspending: 'first'});
|
|
|
|
let instance = builder.instantiate({m: {import: js_import}});
|
|
|
|
let suspender = ToPromising(instance.exports.return_suspender)();
|
|
|
|
for (s of [suspender, null, undefined, {}]) {
|
|
|
|
assertThrows(() => instance.exports.test(s),
|
|
|
|
WebAssembly.RuntimeError,
|
|
|
|
/invalid suspender object for suspend/);
|
|
|
|
}
|
|
|
|
})();
|
2022-10-06 12:03:16 +00:00
|
|
|
|
|
|
|
(function SuspendCallRef() {
|
|
|
|
print(arguments.callee.name);
|
|
|
|
let builder = new WasmModuleBuilder();
|
|
|
|
let funcref_type = builder.addType(kSig_i_r);
|
|
|
|
let table = builder.addTable(wasmRefNullType(funcref_type), 1)
|
|
|
|
.exportAs('table');
|
|
|
|
builder.addFunction("test", kSig_i_r)
|
|
|
|
.addBody([
|
|
|
|
kExprLocalGet, 0,
|
|
|
|
kExprI32Const, 0, kExprTableGet, table.index,
|
|
|
|
kExprCallRef, funcref_type,
|
|
|
|
]).exportFunc();
|
|
|
|
let instance = builder.instantiate();
|
|
|
|
|
|
|
|
let funcref = new WebAssembly.Function(
|
|
|
|
{parameters: ['externref'], results: ['i32']},
|
|
|
|
() => Promise.resolve(42),
|
|
|
|
{suspending: 'first'});
|
|
|
|
instance.exports.table.set(0, funcref);
|
|
|
|
|
|
|
|
let exp = new WebAssembly.Function(
|
|
|
|
{parameters: [], results: ['externref']},
|
|
|
|
instance.exports.test,
|
|
|
|
{promising: 'first'});
|
|
|
|
assertPromiseResult(exp(), v => assertEquals(42, v));
|
|
|
|
})();
|
|
|
|
|
|
|
|
(function SuspendCallIndirect() {
|
|
|
|
print(arguments.callee.name);
|
|
|
|
let builder = new WasmModuleBuilder();
|
|
|
|
let functype = builder.addType(kSig_i_r);
|
|
|
|
let table = builder.addTable(kWasmFuncRef, 10, 10);
|
|
|
|
let callee = builder.addImport('m', 'f', kSig_i_r);
|
|
|
|
builder.addActiveElementSegment(table, wasmI32Const(0), [callee]);
|
|
|
|
builder.addFunction("test", kSig_i_r)
|
|
|
|
.addBody([
|
|
|
|
kExprLocalGet, 0,
|
|
|
|
kExprI32Const, 0,
|
|
|
|
kExprCallIndirect, functype, table.index,
|
|
|
|
]).exportFunc();
|
|
|
|
|
|
|
|
let create_promise = new WebAssembly.Function(
|
|
|
|
{parameters: ['externref'], results: ['i32']},
|
|
|
|
() => Promise.resolve(42),
|
|
|
|
{suspending: 'first'});
|
|
|
|
|
|
|
|
let instance = builder.instantiate({m: {f: create_promise}});
|
|
|
|
|
|
|
|
let exp = new WebAssembly.Function(
|
|
|
|
{parameters: [], results: ['externref']},
|
|
|
|
instance.exports.test,
|
|
|
|
{promising: 'first'});
|
|
|
|
assertPromiseResult(exp(), v => assertEquals(42, v));
|
|
|
|
})();
|