// META: global=window,dedicatedworker,jsshell // META: script=/wasm/jsapi/wasm-module-builder.js // META: script=/wasm/jsapi/jspi/testharness-additions.js promise_test(t => { let tag = new WebAssembly.Tag({ parameters: [] }); let builder = new WasmModuleBuilder(); import_index = builder.addImport('m', 'import', kSig_i_i); tag_index = builder.addImportedTag('m', 'tag', kSig_v_v); builder.addFunction("test", kSig_i_i) .addBody([ kExprLocalGet, 0, kExprCallFunction, import_index, kExprThrow, tag_index ]).exportFunc(); function js_import() { return Promise.resolve(); }; let wasm_js_import = new WebAssembly.Suspending(js_import); let instance = builder.instantiate({ 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); return promise_rejects_jspi(t, new WebAssembly.Exception(tag, []), export_promise); }, "Throw after the first suspension"); // Throw an exception before suspending. The export wrapper should return a // promise rejected with the exception. promise_test(async (t) => { let tag = new WebAssembly.Tag({ parameters: [] }); let builder = new WasmModuleBuilder(); tag_index = builder.addImportedTag('m', 'tag', kSig_v_v); builder.addFunction("test", kSig_i_v) .addBody([ kExprThrow, tag_index ]).exportFunc(); let instance = builder.instantiate({ m: { tag: tag } }); let wrapped_export = WebAssembly.promising(instance.exports.test); let export_promise = wrapped_export(); promise_rejects_jspi(t, new WebAssembly.Exception(tag, []), export_promise); }, "Throw before suspending"); // Throw an exception after the first resume event, which propagates to the // promise wrapper. promise_test(async (t) => { let tag = new WebAssembly.Tag({ parameters: [] }); let builder = new WasmModuleBuilder(); import_index = builder.addImport('m', 'import', kSig_i_v); tag_index = builder.addImportedTag('m', 'tag', kSig_v_v); builder.addFunction("test", kSig_i_v) .addBody([ kExprCallFunction, import_index, kExprThrow, tag_index ]).exportFunc(); function js_import() { return Promise.resolve(42); }; let wasm_js_import = new WebAssembly.Suspending(js_import); let instance = builder.instantiate({ m: { import: wasm_js_import, tag: tag } }); let wrapped_export = WebAssembly.promising(instance.exports.test); let export_promise = wrapped_export(); promise_rejects_jspi(t, new WebAssembly.Exception(tag, []), export_promise); }, "Throw and propagate via Promise"); promise_test(async (t) => { let builder = new WasmModuleBuilder(); builder.addFunction("test", kSig_i_v) .addBody([ kExprCallFunction, 0 ]).exportFunc(); let instance = builder.instantiate(); let wrapper = WebAssembly.promising(instance.exports.test); // Stack overflow has undefined behavior -- check if an exception was thrown. let thrown = false; try { await wrapper(); } catch (e) { thrown = true; } assert_true(thrown); }, "Stack overflow"); promise_test(async (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 builder = new WasmModuleBuilder(); let import1_index = builder.addImport("m", "import1", kSig_i_v); let import2_index = builder.addImport("m", "import2", kSig_i_v); builder.addFunction("export1", kSig_i_v) .addBody([ // export1 -> import1 (unwrapped) kExprCallFunction, import1_index, ]).exportFunc(); builder.addFunction("export2", kSig_i_v) .addBody([ // export2 -> import2 (suspending) kExprCallFunction, import2_index, ]).exportFunc(); let instance; function import1() { // import1 -> export2 (unwrapped) instance.exports.export2(); } function import2() { return Promise.resolve(0); } import2 = new WebAssembly.Suspending(import2); instance = builder.instantiate({ 'm': { 'import1': import1, 'import2': import2 } }); // export1 (promising) let wrapper = WebAssembly.promising(instance.exports.export1); promise_rejects_js(t, WebAssembly.SuspendError, wrapper(), "trying to suspend JS frames"); }, "Try to suspend JS");