Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 69 additions & 99 deletions document/js-api/index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -512,16 +512,7 @@ To <dfn>instantiate imported strings</dfn> with module |module| and |importedStr
<div algorithm="read-the-imports">
To <dfn>read the imports</dfn> from a WebAssembly module |module| from imports object |importObject|, enabled builtins |builtinSetNames|, and |importedStringModule|, perform the following steps:
1. If |module|.[=imports=] [=list/is empty|is not empty=], and |importObject| is undefined, 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:"
1. Assert: |builtinOrStringImports| does not contain |builtinSetQualifiedName|
1. If |builtinSetName| does not refer to a builtin set, then [=iteration/continue=].
1. Let |exportsObject| be the result of [=instantiate a builtin set=] with |builtinSetName|
1. [=map/set|Set=] |builtinOrStringImports|[|builtinSetQualifiedName|] to |exportsObject|
1. If |importedStringModule| is not null,
1. Let |exportsObject| be the result of [=instantiate imported strings=] with |module| and |importedStringModule|
1. [=map/set|Set=] |builtinOrStringImports|[|importedStringModule|] to |exportsObject|
1. Let |builtinOrStringImports| be the result of [=instantiate the builtin and string imports=] of |module| with |builtinSetNames| and |importedStringModule|.
1. Let |imports| be « ».
1. [=list/iterate|For each=] (|moduleName|, |componentName|, |externtype|) of [=module_imports=](|module|),
1. If |builtinOrStringImports| [=map/exist|contains=] |moduleName|,
Expand All @@ -532,53 +523,73 @@ To <dfn>instantiate imported strings</dfn> with module |module| and |importedStr
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|).
1. If |externtype| is of the form [=external-type/func=] |functype|,
1. If [$IsCallable$](|v|) is false, throw a {{LinkError}} exception.
1. If |v| has a \[[FunctionAddress]] internal slot, and therefore is an [=Exported Function=],
1. Let |funcaddr| be the value of |v|'s \[[FunctionAddress]] internal slot.
1. Otherwise,
1. [=Create a host function=] from |v| and |functype|, and let |funcaddr| be the result.
1. Let |index| be the number of external functions in |imports|. This value |index| is known as the <dfn>index of the host function</dfn> |funcaddr|.
1. Let |externfunc| be the [=external value=] [=external value|func=] |funcaddr|.
1. [=list/Append=] |externfunc| to |imports|.
1. If |externtype| is of the form [=external-type/global=] <var ignore>mut</var> |valtype|,
1. If |v| [=implements=] {{Global}},
1. Let |globaladdr| be |v|.\[[Global]].
1. Otherwise,
1. If |valtype| is [=i64=] and |v| [=is not a BigInt=],
1. Throw a {{LinkError}} exception.
1. If |valtype| is one of [=i32=], [=f32=] or [=f64=] and |v| [=is not a Number=],
1. Throw a {{LinkError}} exception.
1. If |valtype| is [=v128=],
1. Throw a {{LinkError}} exception.
1. Let |value| be [=ToWebAssemblyValue=](|v|, |valtype|). If this operation throws a {{TypeError}}, catch it, and throw a {{LinkError}} exception.
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
1. Let (|store|, |globaladdr|) be [=global_alloc=](|store|, [=const=] |valtype|, |value|).
1. Set the [=surrounding agent=]'s [=associated store=] to |store|.
1. Let |externglobal| be [=external value|global=] |globaladdr|.
1. [=list/Append=] |externglobal| to |imports|.
1. If |externtype| is of the form [=external-type/mem=] <var ignore>memtype</var>,
1. If |v| does not [=implement=] {{Memory}}, throw a {{LinkError}} exception.
1. Let |externmem| be the [=external value=] [=external value|mem=] |v|.\[[Memory]].
1. [=list/Append=] |externmem| to |imports|.
1. If |externtype| is of the form [=external-type/table=] <var ignore>tabletype</var>,
1. If |v| does not [=implement=] {{Table}}, throw a {{LinkError}} exception.
1. Let |tableaddr| be |v|.\[[Table]].
1. Let |externtable| be the [=external value=] [=external value|table=] |tableaddr|.
1. [=list/Append=] |externtable| to |imports|.
1. If |externtype| is of the form [=external-type/tag=] |attribute| <var ignore>functype</var>,
1. Assert: |attribute| is [=tagtype/attribute/exception=].
1. If |v| does not [=implement=] {{Tag}}, throw a {{LinkError}} exception.
1. Let |tagaddr| be |v|.\[[Address]].
1. Let |externtag| be the [=external value=] [=external value/tag=] |tagaddr|.
1. [=list/Append=] |externtag| to |imports|.
1. [=Read an import value=] |v| of type |externtype| into |imports|.
1. Return |imports|.

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.
</div>

<div algorithm>
To <dfn>instantiate the builtin and string imports</dfn> of a WebAssembly module |module| with enabled builtins |builtinSetNames| and |importedStringModule|, perform the following steps:
1. Let |builtinOrStringImports| be the ordered map « ».
1. [=list/iterate|For each=] |builtinSetName| of |builtinSetNames|,
1. Let |builtinSetQualifiedName| be |builtinSetName| prefixed with "wasm:"
1. Assert: |builtinOrStringImports| does not contain |builtinSetQualifiedName|
1. If |builtinSetName| does not refer to a builtin set, then [=iteration/continue=].
1. Let |exportsObject| be the result of [=instantiate a builtin set=] with |builtinSetName|
1. [=map/set|Set=] |builtinOrStringImports|[|builtinSetQualifiedName|] to |exportsObject|
1. If |importedStringModule| is not null,
1. Let |exportsObject| be the result of [=instantiate imported strings=] with |module| and |importedStringModule|
1. [=map/set|Set=] |builtinOrStringImports|[|importedStringModule|] to |exportsObject|
1. Return |builtinOrStringImports|.
</div>

<div algorithm="read an import value">
To <dfn>read an import value</dfn> |v| of type |externtype| into imports list |imports|, perform the following steps:
1. If |externtype| is of the form [=external-type/func=] |functype|,
1. If [$IsCallable$](|v|) is false, throw a {{LinkError}} exception.
1. If |v| has a \[[FunctionAddress]] internal slot, and therefore is an [=Exported Function=],
1. Let |funcaddr| be the value of |v|'s \[[FunctionAddress]] internal slot.
1. Otherwise,
1. [=Create a host function=] from |v| and |functype|, and let |funcaddr| be the result.
1. Let |index| be the number of external functions in |imports|. This value |index| is known as the <dfn>index of the host function</dfn> |funcaddr|.
1. Let |externfunc| be the [=external value=] [=external value|func=] |funcaddr|.
1. [=list/Append=] |externfunc| to |imports|.
1. If |externtype| is of the form [=external-type/global=] <var ignore>mut</var> |valtype|,
1. If |v| [=implements=] {{Global}},
1. Let |globaladdr| be |v|.\[[Global]].
1. Otherwise,
1. If |valtype| is [=i64=] and |v| [=is not a BigInt=],
1. Throw a {{LinkError}} exception.
1. If |valtype| is one of [=i32=], [=f32=] or [=f64=] and |v| [=is not a Number=],
1. Throw a {{LinkError}} exception.
1. If |valtype| is [=v128=],
1. Throw a {{LinkError}} exception.
1. Let |value| be [=ToWebAssemblyValue=](|v|, |valtype|). If this operation throws a {{TypeError}}, catch it, and throw a {{LinkError}} exception.
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
1. Let (|store|, |globaladdr|) be [=global_alloc=](|store|, [=const=] |valtype|, |value|).
Comment on lines +560 to +572

@chicoxyzzy chicoxyzzy Sep 25, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

read an import value drops mut and always does global_alloc of a const global.

ExecuteModule used to throw a LinkError before any allocation. One case is a var import that is not already a Global. The other is a const import of a var Global. Both still fail in module_instantiate. The var case now leaves that const global in the store on the way there.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is actually pre-existing in the WebAssembly.instantiate spec itself, which we are now following.

Therefore if we want to address this I think it would need to be an upstream PR.

1. Set the [=surrounding agent=]'s [=associated store=] to |store|.
1. Let |externglobal| be [=external value|global=] |globaladdr|.
1. [=list/Append=] |externglobal| to |imports|.
1. If |externtype| is of the form [=external-type/mem=] <var ignore>memtype</var>,
1. If |v| does not [=implement=] {{Memory}}, throw a {{LinkError}} exception.
1. Let |externmem| be the [=external value=] [=external value|mem=] |v|.\[[Memory]].
1. [=list/Append=] |externmem| to |imports|.
1. If |externtype| is of the form [=external-type/table=] <var ignore>tabletype</var>,
1. If |v| does not [=implement=] {{Table}}, throw a {{LinkError}} exception.
1. Let |tableaddr| be |v|.\[[Table]].
1. Let |externtable| be the [=external value=] [=external value|table=] |tableaddr|.
1. [=list/Append=] |externtable| to |imports|.
1. If |externtype| is of the form [=external-type/tag=] |attribute| <var ignore>functype</var>,
1. Assert: |attribute| is [=tagtype/attribute/exception=].
1. If |v| does not [=implement=] {{Tag}}, throw a {{LinkError}} exception.
1. Let |tagaddr| be |v|.\[[Address]].
1. Let |externtag| be the [=external value=] [=external value/tag=] |tagaddr|.
1. [=list/Append=] |externtag| to |imports|.
</div>

<div algorithm>
To <dfn>create an exports object</dfn> from a WebAssembly module |module| and instance |instance|, perform the following steps:
1. Let |exportsObject| be [=!=] [$OrdinaryObjectCreate$](null).
Expand Down Expand Up @@ -2320,6 +2331,7 @@ To <dfn export>parse a WebAssembly module</dfn> given a <a>byte sequence</a> |by
1. If |module| is [=error=], throw a {{CompileError}} exception.
1. Let |builtinSetNames| be « "js-string" ».
1. Let |importedStringModule| be "wasm:js/string-constants".
1. If [=validate builtins and imported string for a WebAssembly module|validating builtins and imported strings=] for |module| with |builtinSetNames| and |importedStringModule| is false, throw a {{CompileError}} exception.
1. [=Construct a WebAssembly module object=] from |module|, |bytes|, |builtinSetNames| and |importedStringModule|, and let |module| be the result.
1. Let |requestedModules| be a set.
1. For each (|moduleName|, |name|, <var ignore>type</var>) of the [=external imports=] of |module|,
Expand Down Expand Up @@ -2417,25 +2429,14 @@ WebAssembly Module Records have the following methods:
1. Let |module| be |moduleObject|.\[[Module]].
1. Let |builtinSetNames| be |moduleObject|.\[[BuiltinSets]].
1. Let |importedStringModule| be |moduleObject|.\[[ImportedStringModule]].
1. Let |builtinOrStringImports| be the result of [=instantiate the builtin and string imports=] of |module| with |builtinSetNames| and |importedStringModule|.
1. Let |imports| be « ».
1. [=list/iterate|For each=] (|importedModuleName|, |name|, |importtype|) of [=module_imports=](|module|),
1. If |importedStringModule| is not null and |importedModuleName| equals |importedStringModule|,
1. Assert: |importtype| is of the form [=global=] [=const=] |valtype|.
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
1. Let |value| be [=?=] [=ToWebAssemblyValue=](|name|, |valtype|).
1. Let (|store|, |globaladdr|) be [=global_alloc=](|store|, [=const=] |valtype|, |value|).
1. Set the [=surrounding agent=]'s [=associated store=] to |store|.
1. Let |externglobal| be [=external value|global=] |globaladdr|.
1. [=list/Append=] |externglobal| to |imports|.
1. [=iteration/continue=].
1. If |builtinSetNames| is not null,
1. Let |maybeBuiltin| be the result of [=find a builtin|finding a builtin=] for (|importedModuleName|, |name|, |importtype|) and |builtinSetNames|.
1. If |maybeBuiltin| is not null,
1. Let |funcType| be |maybeBuiltin|[1][1].
1. Let |steps| be |maybeBuiltin|[1][2].
1. Let |funcaddr| be the result of [=create a builtin function=] with |funcType| and |steps|.
1. Let |externfunc| be the [=external value=] [=external value|func=] |funcaddr|.
1. [=list/Append=] |externfunc| to |imports|.
1. If |builtinOrStringImports| [=map/exist|contains=] |importedModuleName|,
1. Let |o| be |builtinOrStringImports|[|importedModuleName|].
1. If [$HasProperty$](|o|, |name|) is true,
1. Let |v| be [=!=] [$Get$](|o|, |name|).
1. [=Read an import value=] |v| of type |importtype| into |imports|.
Comment thread
guybedford marked this conversation as resolved.
1. [=iteration/continue=].
1. Let |importedModule| be [$GetImportedModule$](|record|, |importedModuleName|).
1. Let |resolution| be |importedModule|.ResolveExport(|name|).
Expand All @@ -2457,38 +2458,7 @@ WebAssembly Module Records have the following methods:
1. Otherwise,
1. Let |env| be |resolvedModule|.\[[Environment]].
1. Let |v| be [=?=] |env|.GetBindingValue(|resolvedName|, true).
1. If |importtype| is of the form [=func=] |functype|,
1. If [$IsCallable$](|v|) is false, throw a {{LinkError}} exception.
1. If |v| has a \[[FunctionAddress]] internal slot, and therefore is an [=Exported Function=],
1. Let |funcaddr| be the value of |v|'s \[[FunctionAddress]] internal slot.
1. Otherwise,
1. [=Create a host function=] from |v| and |functype|, and let |funcaddr| be the result.
1. Let <var ignore>index</var> be the number of external functions in |imports|, defining the [=index of the host function=] |funcaddr|.
1. Let |externfunc| be the [=external value=] [=external value|func=] |funcaddr|.
1. [=list/Append=] |externfunc| to |imports|.
1. If |importtype| is of the form [=global=] |mut| |valtype|,
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
1. If |v| [=implements=] {{Global}},
1. Let |globaladdr| be |v|.\[[Global]].
1. Let |targetmut| <var ignore>valuetype</var> be [=global_type=](|store|, |globaladdr|).
1. If |mut| is [=const=] and |targetmut| is [=var=], throw a {{LinkError}} exception.
1. Otherwise,
1. If |valtype| is [=v128=], throw a {{LinkError}} exception.
1. If |mut| is [=var=], throw a {{LinkError}} exception.
1. Let |value| be [=?=] [=ToWebAssemblyValue=](|v|, |valtype|).
1. Let (|store|, |globaladdr|) be [=global_alloc=](|store|, |mut| |valtype|, |value|).
1. Set the [=surrounding agent=]'s [=associated store=] to |store|.
1. Let |externglobal| be [=external value|global=] |globaladdr|.
1. [=list/Append=] |externglobal| to |imports|.
1. If |importtype| is of the form [=mem=] <var ignore>memtype</var>,
1. If |v| does not [=implement=] {{Memory}}, throw a {{LinkError}} exception.
1. Let |externmem| be the [=external value=] [=external value|mem=] |v|.\[[Memory]].
1. [=list/Append=] |externmem| to |imports|.
1. If |importtype| is of the form [=table=] <var ignore>tabletype</var>,
1. If |v| does not [=implement=] {{Table}}, throw a {{LinkError}} exception.
1. Let |tableaddr| be |v|.\[[Table]].
1. Let |externtable| be the [=external value=] [=external value|table=] |tableaddr|.
1. [=list/Append=] |externtable| to |imports|.
1. [=Read an import value=] |v| of type |importtype| into |imports|.
1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |coreInstance| be the result.
1. Let |instanceObject| be a [=/new=] {{Instance}}.
1. [=initialize an instance object|Initialize=] |instanceObject| from |module| and |coreInstance|.
Expand Down
Loading