@@ -32,15 +32,16 @@ public struct ClosureCodegen {
3232 func renderClosureHelpers ( _ signature : ClosureSignature ) throws -> [ DeclSyntax ] {
3333 let mangledName = signature . mangleName
3434 let helperName = " _BJS_Closure_ \( mangledName ) "
35- let boxClassName = " _BJS_ClosureBox_ \( mangledName ) "
3635
3736 let closureParams = signature . parameters . enumerated ( ) . map { _ , type in
3837 " \( type . swiftType ) "
3938 } . joined ( separator : " , " )
4039
4140 let swiftEffects = ( signature . isAsync ? " async " : " " ) + ( signature . isThrows ? " throws " : " " )
4241 let swiftReturnType = signature . returnType . swiftType
43- let closureType = " ( \( closureParams ) ) \( swiftEffects ) -> \( swiftReturnType ) "
42+ let swiftClosureType = " ( \( closureParams ) ) \( swiftEffects ) -> \( swiftReturnType ) "
43+ let typedClosureType = " JSTypedClosure< \( swiftClosureType ) > "
44+ let boxType = " _BridgeJSTypedClosureBox< \( swiftClosureType ) > "
4445
4546 let externName = " invoke_js_callback_ \( signature . moduleName ) _ \( mangledName ) "
4647
@@ -65,17 +66,25 @@ public struct ClosureCodegen {
6566
6667 // Get the body code
6768 let bodyCode = builder . getBody ( )
69+ let wasmBody = SwiftCodePattern . buildWasmConditionalCompilation ( wasmBody : bodyCode . statements )
70+ . formatted ( using : BasicFormat ( ) ) . description
71+ let closureParamsList = signature . parameters . enumerated ( ) . map { " param \( $0 . offset ) " } . joined ( separator : " , " )
72+ let wrapperParamClause = closureParamsList . isEmpty ? " " : " \( closureParamsList ) "
73+ let wrapperParamIn = closureParamsList . isEmpty ? " " : " in "
74+ let wrapperCallArguments = closureParamsList . isEmpty ? " " : " \( closureParamsList ) "
6875
6976 // Generate extern declaration using CallJSEmission
7077 let externDecl = builder . renderImportDecl ( )
7178
72- let boxClassDecl : DeclSyntax = """
73- private final class \( raw : boxClassName ) : _BridgedSwiftClosureBox {
74- let closure: \( raw : closureType )
75- init(_ closure: @escaping \( raw : closureType ) ) {
76- self.closure = closure
77- }
79+ let makeClosureExternDecl : DeclSyntax = """
80+ #if arch(wasm32)
81+ @_extern(wasm, module: " bjs " , name: " make_swift_closure_ \( raw : signature . moduleName ) _ \( raw : signature . mangleName ) " )
82+ fileprivate func make_swift_closure_ \( raw : signature . moduleName ) _ \( raw : signature . mangleName ) (_ boxPtr: UnsafeMutableRawPointer) -> Int32
83+ #else
84+ fileprivate func make_swift_closure_ \( raw : signature . moduleName ) _ \( raw : signature . mangleName ) (_ boxPtr: UnsafeMutableRawPointer) -> Int32 {
85+ fatalError( " Only available on WebAssembly " )
7886 }
87+ #endif
7988 """
8089
8190 let helperEnumDecl = EnumDeclSyntax (
@@ -84,33 +93,6 @@ public struct ClosureCodegen {
8493 } ,
8594 name : . identifier ( helperName ) ,
8695 memberBlockBuilder : {
87- DeclSyntax (
88- FunctionDeclSyntax (
89- modifiers : DeclModifierListSyntax {
90- DeclModifierSyntax ( name : . keyword ( . static ) )
91- } ,
92- name : . identifier ( " bridgeJSLower " ) ,
93- signature : FunctionSignatureSyntax (
94- parameterClause : FunctionParameterClauseSyntax {
95- FunctionParameterSyntax (
96- firstName : . wildcardToken ( ) ,
97- secondName : . identifier ( " closure " ) ,
98- colon : . colonToken ( ) ,
99- type : TypeSyntax ( " @escaping \( raw : closureType ) " )
100- )
101- } ,
102- returnClause : ReturnClauseSyntax (
103- arrow : . arrowToken ( ) ,
104- type : IdentifierTypeSyntax ( name : . identifier ( " UnsafeMutableRawPointer " ) )
105- )
106- ) ,
107- body : CodeBlockSyntax {
108- " let box = \( raw : boxClassName ) (closure) "
109- " return Unmanaged.passRetained(box).toOpaque() "
110- }
111- )
112- )
113-
11496 DeclSyntax (
11597 FunctionDeclSyntax (
11698 modifiers : DeclModifierListSyntax {
@@ -128,61 +110,60 @@ public struct ClosureCodegen {
128110 } ,
129111 returnClause : ReturnClauseSyntax (
130112 arrow : . arrowToken ( ) ,
131- type : IdentifierTypeSyntax ( name : . identifier ( closureType ) )
113+ type : IdentifierTypeSyntax ( name : . identifier ( swiftClosureType ) )
132114 )
133115 ) ,
134116 body : CodeBlockSyntax {
135117 " let callback = JSObject.bridgeJSLiftParameter(callbackId) "
136- ReturnStmtSyntax (
137- expression : ClosureExprSyntax (
138- leftBrace : . leftBraceToken ( ) ,
139- signature : ClosureSignatureSyntax (
140- capture : ClosureCaptureClauseSyntax (
141- leftSquare : . leftSquareToken ( ) ,
142- items : ClosureCaptureListSyntax {
143- #if canImport( SwiftSyntax602 )
144- ClosureCaptureSyntax (
145- name : . identifier ( " " , presence : . missing ) ,
146- initializer : InitializerClauseSyntax (
147- equal : . equalToken ( presence : . missing ) ,
148- nil ,
149- value : ExprSyntax ( " callback " )
150- ) ,
151- trailingTrivia : nil
152- )
153- #else
154- ClosureCaptureSyntax (
155- expression : ExprSyntax ( " callback " )
156- )
157- #endif
158- } ,
159- rightSquare : . rightSquareToken ( )
160- ) ,
161- parameterClause : . simpleInput (
162- ClosureShorthandParameterListSyntax {
163- for ( index , _) in signature . parameters . enumerated ( ) {
164- ClosureShorthandParameterSyntax ( name : . identifier ( " param \( index ) " ) )
165- }
166- }
167- ) ,
168- inKeyword : . keyword ( . in )
169- ) ,
170- statements : CodeBlockItemListSyntax {
171- SwiftCodePattern . buildWasmConditionalCompilation ( wasmBody : bodyCode . statements )
172- } ,
173- rightBrace : . rightBraceToken ( )
174- )
175- )
118+ """
119+ let callable: \( raw : swiftClosureType ) = { [callback] \( raw : closureParamsList ) in
120+ \( raw : wasmBody )
121+ }
122+ """
123+ " return callable "
176124 }
177125 )
178126 )
179127 }
180128 )
181- return [ externDecl , boxClassDecl , DeclSyntax ( helperEnumDecl ) ]
129+ let typedClosureExtension : DeclSyntax = """
130+ extension JSTypedClosure where Signature == \( raw : swiftClosureType ) {
131+ init(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping \( raw : swiftClosureType ) ) {
132+ let box = \( raw : boxType ) (body, fileID: fileID, line: line)
133+ let pointer = Unmanaged.passRetained(box).toOpaque()
134+ let funcRefValue = make_swift_closure_ \( raw : signature . moduleName ) _ \( raw : signature . mangleName ) (pointer)
135+ let jsObject = JSObject(id: UInt32(bitPattern: funcRefValue))
136+ self.init(
137+ _boxPointer: pointer,
138+ jsObject: jsObject
139+ )
140+ }
141+
142+ static func oneshot(fileID: StaticString = #fileID, line: UInt32 = #line, _ body: @escaping \( raw : swiftClosureType ) ) -> JSTypedClosure<Signature> {
143+ var typedClosure: JSTypedClosure<Signature>!
144+ let wrapper: Signature = { \( raw : wrapperParamClause ) \( raw : wrapperParamIn )
145+ defer { typedClosure.release() }
146+ return body( \( raw : wrapperCallArguments ) )
147+ }
148+ typedClosure = JSTypedClosure(fileID: fileID, line: line, wrapper)
149+ return typedClosure
150+ }
151+ }
152+ """
153+
154+ return [
155+ externDecl , makeClosureExternDecl , DeclSyntax ( helperEnumDecl ) , typedClosureExtension ,
156+ ]
182157 }
183158
184159 func renderClosureInvokeHandler ( _ signature : ClosureSignature ) throws -> DeclSyntax {
185- let boxClassName = " _BJS_ClosureBox_ \( signature . mangleName ) "
160+ let closureParams = signature . parameters . enumerated ( ) . map { _ , type in
161+ " \( type . swiftType ) "
162+ } . joined ( separator : " , " )
163+ let swiftEffects = ( signature . isAsync ? " async " : " " ) + ( signature . isThrows ? " throws " : " " )
164+ let swiftReturnType = signature . returnType . swiftType
165+ let swiftClosureType = " ( \( closureParams ) ) \( swiftEffects ) -> \( swiftReturnType ) "
166+ let boxType = " _BridgeJSTypedClosureBox< \( swiftClosureType ) > "
186167 let abiName = " invoke_swift_closure_ \( signature . moduleName ) _ \( signature . mangleName ) "
187168
188169 // Build ABI parameters directly with WasmCoreType (no string conversion needed)
@@ -205,7 +186,7 @@ public struct ClosureCodegen {
205186 liftedParams . append ( " \( paramType . swiftType ) .bridgeJSLiftParameter( \( argNames . joined ( separator : " , " ) ) ) " )
206187 }
207188
208- let closureCallExpr = ExprSyntax ( " box. closure(\( raw : liftedParams . joined ( separator : " , " ) ) ) " )
189+ let closureCallExpr = ExprSyntax ( " closure( \( raw : liftedParams . joined ( separator : " , " ) ) ) " )
209190
210191 // Determine return type
211192 let abiReturnWasmType : WasmCoreType ?
@@ -217,6 +198,19 @@ public struct ClosureCodegen {
217198 abiReturnWasmType = nil
218199 }
219200
201+ let throwReturn : String
202+ if let abiReturnWasmType {
203+ switch abiReturnWasmType {
204+ case . i32 : throwReturn = " return 0 "
205+ case . i64 : throwReturn = " return 0 "
206+ case . f32 : throwReturn = " return 0 "
207+ case . f64 : throwReturn = " return 0 "
208+ case . pointer : throwReturn = " return UnsafeMutableRawPointer(bitPattern: 0)! "
209+ }
210+ } else {
211+ throwReturn = " return "
212+ }
213+
220214 // Build signature using SwiftSignatureBuilder
221215 let funcSignature = SwiftSignatureBuilder . buildABIFunctionSignature (
222216 abiParameters : abiParams ,
@@ -225,7 +219,11 @@ public struct ClosureCodegen {
225219
226220 // Build body
227221 let body = CodeBlockItemListSyntax {
228- " let box = Unmanaged< \( raw : boxClassName ) >.fromOpaque(boxPtr).takeUnretainedValue() "
222+ " let box = Unmanaged< \( raw : boxType ) >.fromOpaque(boxPtr).takeUnretainedValue() "
223+ " guard let closure = box.closure else { "
224+ " box._bridgeJSThrowReleasedClosure() "
225+ " \( raw : throwReturn ) "
226+ " } "
229227 if signature . returnType == . void {
230228 closureCallExpr
231229 } else {
0 commit comments