diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 64dfd22f77..6ee5103b46 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -486,7 +486,14 @@ To instantiate imported strings with module |module| and |importedStr
To read the imports from a WebAssembly module |module| from imports object |importObject|, enabled builtins |builtinSetNames|, and |importedStringModule|, perform the following steps: - 1. If [=module_imports=](|module|) [=list/is empty|is not empty=], and |importObject| is missing, throw a {{TypeError}} exception. + 1. If |importObject| is missing, + 1. [=list/iterate|For each=] |import| of [=module_imports=](|module|), + 1. Let |moduleName| be |import|[0]. + 1. If |importedStringModule| is not null and |moduleName| equals |importedStringModule|, + 1. [=iteration/continue=]. + 1. If [=find a builtin|finding a builtin=] for |import| and |builtinSetNames| is not null, + 1. [=iteration/continue=]. + 1. Throw a {{TypeError}} exception. 1. Let |builtinOrStringImports| be the ordered map «[ ]». 1. [=list/iterate|For each=] |builtinSetName| of |builtinSetNames|, 1. Let |builtinSetQualifiedName| be |builtinSetName| prefixed with "wasm:" @@ -502,8 +509,10 @@ To instantiate imported strings with module |module| and |importedStr 1. If |builtinOrStringImports|[|moduleName|] [=map/exists=], 1. Let |o| be |builtinOrStringImports|[|moduleName|]. 1. If |o| [=is not an Object=] or if [=?=] [$HasProperty$](|o|, |componentName|) is false, + 1. Assert: |importObject| is not missing. 1. Set |o| to [=?=] [$Get$](|importObject|, |moduleName|). 1. Else, + 1. Assert: |importObject| is not missing. 1. Let |o| be [=?=] [$Get$](|importObject|, |moduleName|). 1. If |o| [=is not an Object=], throw a {{TypeError}} exception. 1. Let |v| be [=?=] [$Get$](|o|, |componentName|). @@ -551,6 +560,13 @@ To instantiate imported strings with module |module| and |importedStr Note: This algorithm only verifies the right kind of JavaScript values are passed. The verification of WebAssembly type requirements is deferred to the "[=instantiate the core of a WebAssembly module=]" algorithm. + +Note: |importObject| is required only for an import that is not supplied by an +enabled builtin or by the imported string constants module. If it is missing, +the opening check throws unless every import is supplied that way. Each such +import is then an own property of the object in |builtinOrStringImports| for +its module name, so the [$Get$](|importObject|, |moduleName|) steps are not +reached.
diff --git a/test/js-api/js-string/imports.any.js b/test/js-api/js-string/imports.any.js index c357760bef..267945bd99 100644 --- a/test/js-api/js-string/imports.any.js +++ b/test/js-api/js-string/imports.any.js @@ -24,3 +24,56 @@ test(() => { // reflection. assert_equals(imports.length, 0); }); + +function moduleWithBuiltin() { + const builder = new WasmModuleBuilder(); + builder.addImport( + "wasm:js-string", + "test", + {params: [kWasmExternRef], results: [kWasmI32]}); + return new WebAssembly.Module(builder.toBuffer(), {builtins: ["js-string"]}); +} + +test(() => { + const instance = new WebAssembly.Instance(moduleWithBuiltin()); + assert_equals(typeof instance.exports, "object"); +}, "A builtin-only module can be instantiated without an importObject"); + +test(() => { + const instance = new WebAssembly.Instance(moduleWithBuiltin(), undefined); + assert_equals(typeof instance.exports, "object"); +}, "A builtin-only module can be instantiated with undefined importObject"); + +promise_test(async () => { + const instance = await WebAssembly.instantiate(moduleWithBuiltin()); + assert_equals(typeof instance.exports, "object"); +}, "WebAssembly.instantiate accepts a builtin-only module without an importObject"); + +test(() => { + const builder = new WasmModuleBuilder(); + builder.addImportedGlobal("strings", "hi", kWasmExternRef, false); + builder.addExportOfKind("hi", kExternalGlobal, 0); + const module = new WebAssembly.Module(builder.toBuffer(), { + importedStringConstants: "strings", + }); + const instance = new WebAssembly.Instance(module); + assert_equals(instance.exports.hi.value, "hi"); +}, "Imported string constants do not require an importObject"); + +test(() => { + const builder = new WasmModuleBuilder(); + builder.addImport( + "wasm:js-string", + "test", + {params: [kWasmExternRef], results: [kWasmI32]}); + builder.addImport("env", "f", {params: [], results: []}); + const module = new WebAssembly.Module(builder.toBuffer(), {builtins: ["js-string"]}); + assert_throws_js(TypeError, () => new WebAssembly.Instance(module)); +}, "A non-builtin import still requires an importObject"); + +test(() => { + const builder = new WasmModuleBuilder(); + builder.addImport("wasm:js-string", "not-a-builtin", {params: [], results: []}); + const module = new WebAssembly.Module(builder.toBuffer(), {builtins: ["js-string"]}); + assert_throws_js(TypeError, () => new WebAssembly.Instance(module)); +}, "An unknown import from a builtin module requires an importObject");