◐ Shell
clean mode source ↗

BridgeJS: Always provide swift_js_closure_unregister intrinsic in generated bridge-js.js by krodak · Pull Request #599 · swiftwasm/JavaScriptKit

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