Skip to content

[js-api] Share import reading between the JS API and ESM integration - #126

Open
guybedford wants to merge 3 commits into
mainfrom
esm-shared-import-reading
Open

guybedford wants to merge 3 commits into
mainfrom
esm-shared-import-reading

Conversation

@guybedford

Copy link
Copy Markdown
Collaborator

This refactors read the imports so that ExecuteModule can share it.

Two helpers are extracted from read the imports, keeping the internal implementation identical:

  • instantiate the builtin and string imports returns the moduleName -> exportsObject map
  • read an import value coerces a JS value of a given extern type and appends the externval

In the process this resolves some drift between the two paths including:

  • ToWebAssemblyValue failures propagated as TypeError rather than being converted to LinkError
  • the i64 / BigInt and numeric kind checks were missing
  • there was no tag case, so a JS module exporting a WebAssembly.Tag to a Wasm import appended nothing and misaligned the externval list
  • builtins were created with a fresh function address per import, whereas read the imports instantiates each builtin set once, so importing the same builtin twice gave distinct Exported Function identities under ESM only

//cc @chicoxyzzy for review

ExecuteModule duplicated the per-import value coercion of read the
imports and had drifted from it: TypeError from ToWebAssemblyValue was
not converted to LinkError, the i64 / number kind checks were missing,
and there was no tag case at all. It also created a fresh builtin
function address per import, whereas read the imports instantiates each
builtin set once, so importing the same builtin twice gave distinct
Exported Function identities under ESM only.

Factor read the imports into two helpers, instantiate the builtin and
string imports and read an import value, and use them from
ExecuteModule so both instantiation paths share the same semantics.
Only the Wasm to Wasm instance_export linking remains ESM specific.
Comment thread document/js-api/index.bs
Comment on lines +560 to +572
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|).

@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.

Comment thread document/js-api/index.bs
parse a WebAssembly module constructed the Module object without running
validate builtins and imported string, unlike compile, validate and the
Module constructor, so a string constant import with a non extern type
or a builtin import with the wrong signature was accepted at parse time
and only failed during execution.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants