Skip to content

BridgeJS: Always provide swift_js_closure_unregister intrinsic in generated bridge-js.js#599

Merged
krodak merged 1 commit intoswiftwasm:mainfrom
PassiveLogic:krodak/js-closure-intrinsic-fix
Feb 6, 2026
Merged

BridgeJS: Always provide swift_js_closure_unregister intrinsic in generated bridge-js.js#599
krodak merged 1 commit intoswiftwasm:mainfrom
PassiveLogic:krodak/js-closure-intrinsic-fix

Conversation

@krodak
Copy link
Member

@krodak krodak commented Feb 6, 2026

Overview

PR #578 added JSTypedClosure API which introduced a new swift_js_closure_unregister BridgeJS intrinsic. The @_extern(wasm) declaration in BridgeJSIntrinsics.swift is unconditional, so the WASM binary always imports this symbol from the bjs module. However, the generated bridge-js.js only provides it when closure signatures are detected in the API surface.

Issue

When a project uses BridgeJS but does not use any closure types, the generated bridge-js.js omits swift_js_closure_unregister. Since the WASM binary unconditionally imports it, instantiation fails with:

LinkError: WebAssembly.instantiate(): Import #36 module="bjs" function="swift_js_closure_unregister": function import requires a callable

The instantiate.js template has unexpectedBjsCall stubs for all intrinsics (including swift_js_closure_unregister), but these stubs are only used when HAS_BRIDGE is false. When BridgeJS IS active, the template imports from bridge-js.js instead — which may not include the intrinsic.

Fix

  • Added an unconditional no-op default for swift_js_closure_unregister in BridgeJSLink.swift, alongside other always-present intrinsics like swift_js_throw, swift_js_retain, swift_js_release
  • When closures ARE used, the real implementation overrides the no-op later in the generation
  • Updated all BridgeJSLinkTests snapshots to include the new unconditional intrinsic

@krodak krodak self-assigned this Feb 6, 2026
Copy link
Member

@kateinoigakukun kateinoigakukun left a comment

Choose a reason for hiding this comment

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

🙏

@krodak krodak merged commit 60b9444 into swiftwasm:main Feb 6, 2026
11 checks passed
printer.write("}")
// Always provide swift_js_closure_unregister as a no-op by default.
// The @_extern(wasm) declaration in BridgeJSIntrinsics.swift is unconditional,
// so the WASM binary always imports this symbol. When closures ARE used,
Copy link
Member

Choose a reason for hiding this comment

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

nit

Suggested change
// so the WASM binary always imports this symbol. When closures ARE used,
// so the Wasm binary always imports this symbol. When closures ARE used,

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.

3 participants