From 1cf60d8837a675310214eeda610dd540adebbdcf Mon Sep 17 00:00:00 2001 From: Francisco Javier Trujillo Mata Date: Fri, 13 Feb 2026 11:43:55 +0100 Subject: [PATCH] Prevent cross-module inlining of remaining @_extern(wasm) functions Extends the fix from b3ddd88f (which addressed f32/f64) to all remaining public @_extern(wasm) BridgeJS intrinsics: i32, string, pointer, throw, init_memory, and struct_cleanup. Without @inline(never) wrappers, the Swift compiler can inline these functions across module boundaries, causing the wasm import module attribute to change from "bjs" to "env". This results in a wasm-ld linker error when a downstream module (e.g. via BridgeJS codegen) references the same symbol with a different import module. Co-Authored-By: Claude Opus 4.6 --- .../JavaScriptKit/BridgeJSIntrinsics.swift | 61 ++++++++++++++----- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift index 52a8d829..edb41b9f 100644 --- a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift +++ b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift @@ -15,8 +15,13 @@ import _CJavaScriptKit #if arch(wasm32) @_extern(wasm, module: "bjs", name: "swift_js_throw") -@_spi(BridgeJS) public func _swift_js_throw(_ id: Int32) +private func _swift_js_throw_extern(_ id: Int32) #else +private func _swift_js_throw_extern(_ id: Int32) { + _onlyAvailableOnWasm() +} +#endif + /// Throws a JavaScript exception from Swift code. /// /// This function is called by the BridgeJS code generator when a Swift function throws @@ -24,10 +29,9 @@ import _CJavaScriptKit /// JavaScript-side runtime code. /// /// - Parameter id: The ID of the JavaScript exception object to throw -@_spi(BridgeJS) public func _swift_js_throw(_ id: Int32) { - _onlyAvailableOnWasm() +@_spi(BridgeJS) @inline(never) public func _swift_js_throw(_ id: Int32) { + _swift_js_throw_extern(id) } -#endif /// Retrieves and clears any pending JavaScript exception. /// @@ -702,31 +706,44 @@ where Self: RawRepresentable, RawValue: _BridgedSwiftTypeLoweredIntoSingleWasmCo #if arch(wasm32) @_extern(wasm, module: "bjs", name: "swift_js_init_memory") -@_spi(BridgeJS) public func _swift_js_init_memory(_ sourceId: Int32, _ ptr: UnsafeMutablePointer) +private func _swift_js_init_memory_extern(_ sourceId: Int32, _ ptr: UnsafeMutablePointer) #else -@_spi(BridgeJS) public func _swift_js_init_memory(_ sourceId: Int32, _ ptr: UnsafeMutablePointer) { +private func _swift_js_init_memory_extern(_ sourceId: Int32, _ ptr: UnsafeMutablePointer) { _onlyAvailableOnWasm() } #endif +@_spi(BridgeJS) @inline(never) public func _swift_js_init_memory(_ sourceId: Int32, _ ptr: UnsafeMutablePointer) +{ + _swift_js_init_memory_extern(sourceId, ptr) +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "swift_js_push_string") -@_spi(BridgeJS) public func _swift_js_push_string(_ ptr: UnsafePointer?, _ len: Int32) +private func _swift_js_push_string_extern(_ ptr: UnsafePointer?, _ len: Int32) #else -@_spi(BridgeJS) public func _swift_js_push_string(_ ptr: UnsafePointer?, _ len: Int32) { +private func _swift_js_push_string_extern(_ ptr: UnsafePointer?, _ len: Int32) { _onlyAvailableOnWasm() } #endif +@_spi(BridgeJS) @inline(never) public func _swift_js_push_string(_ ptr: UnsafePointer?, _ len: Int32) { + _swift_js_push_string_extern(ptr, len) +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "swift_js_push_i32") -@_spi(BridgeJS) public func _swift_js_push_i32(_ value: Int32) +private func _swift_js_push_i32_extern(_ value: Int32) #else -@_spi(BridgeJS) public func _swift_js_push_i32(_ value: Int32) { +private func _swift_js_push_i32_extern(_ value: Int32) { _onlyAvailableOnWasm() } #endif +@_spi(BridgeJS) @inline(never) public func _swift_js_push_i32(_ value: Int32) { + _swift_js_push_i32_extern(value) +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "swift_js_push_f32") private func _swift_js_push_f32_extern(_ value: Float32) @@ -755,13 +772,17 @@ private func _swift_js_push_f64_extern(_ value: Float64) { #if arch(wasm32) @_extern(wasm, module: "bjs", name: "swift_js_pop_i32") -@_spi(BridgeJS) public func _swift_js_pop_i32() -> Int32 +private func _swift_js_pop_i32_extern() -> Int32 #else -@_spi(BridgeJS) public func _swift_js_pop_i32() -> Int32 { +private func _swift_js_pop_i32_extern() -> Int32 { _onlyAvailableOnWasm() } #endif +@_spi(BridgeJS) @inline(never) public func _swift_js_pop_i32() -> Int32 { + _swift_js_pop_i32_extern() +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "swift_js_pop_f32") private func _swift_js_pop_f32_extern() -> Float32 @@ -792,13 +813,17 @@ private func _swift_js_pop_f64_extern() -> Float64 { #if arch(wasm32) @_extern(wasm, module: "bjs", name: "swift_js_struct_cleanup") -@_spi(BridgeJS) public func _swift_js_struct_cleanup(_ cleanupId: Int32) +private func _swift_js_struct_cleanup_extern(_ cleanupId: Int32) #else -@_spi(BridgeJS) public func _swift_js_struct_cleanup(_ cleanupId: Int32) { +private func _swift_js_struct_cleanup_extern(_ cleanupId: Int32) { _onlyAvailableOnWasm() } #endif +@_spi(BridgeJS) @inline(never) public func _swift_js_struct_cleanup(_ cleanupId: Int32) { + _swift_js_struct_cleanup_extern(cleanupId) +} + // MARK: Wasm externs used by type lowering/lifting #if arch(wasm32) @@ -986,13 +1011,17 @@ func _swift_js_return_optional_double(_ isSome: Int32, _ value: Float64) { #if arch(wasm32) @_extern(wasm, module: "bjs", name: "swift_js_push_pointer") -@_spi(BridgeJS) public func _swift_js_push_pointer(_ pointer: UnsafeMutableRawPointer) +private func _swift_js_push_pointer_extern(_ pointer: UnsafeMutableRawPointer) #else -@_spi(BridgeJS) public func _swift_js_push_pointer(_ pointer: UnsafeMutableRawPointer) { +private func _swift_js_push_pointer_extern(_ pointer: UnsafeMutableRawPointer) { _onlyAvailableOnWasm() } #endif +@_spi(BridgeJS) @inline(never) public func _swift_js_push_pointer(_ pointer: UnsafeMutableRawPointer) { + _swift_js_push_pointer_extern(pointer) +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "swift_js_pop_pointer") private func _swift_js_pop_pointer_extern() -> UnsafeMutableRawPointer