@@ -135,7 +135,6 @@ public struct BridgeJSLink {
135135 var importObjectBuilders : [ ImportObjectBuilder ] = [ ]
136136 var enumStaticAssignments : [ String ] = [ ]
137137 var needsImportsObject : Bool = false
138- var hasAsyncImports : Bool = false
139138 }
140139
141140 private func collectLinkData( ) throws -> LinkData {
@@ -238,19 +237,12 @@ public struct BridgeJSLink {
238237 if function. from == nil {
239238 data. needsImportsObject = true
240239 }
241- if function. effects. isAsync {
242- data. hasAsyncImports = true
243- }
244240 try renderImportedFunction ( importObjectBuilder: importObjectBuilder, function: function)
245241 }
246242 for type in fileSkeleton. types {
247243 if type. constructor != nil , type. from == nil {
248244 data. needsImportsObject = true
249245 }
250- // Check for async methods in imported types
251- for method in type. methods where method. effects. isAsync {
252- data. hasAsyncImports = true
253- }
254246 try renderImportedType ( importObjectBuilder: importObjectBuilder, type: type)
255247 }
256248 }
@@ -322,85 +314,6 @@ public struct BridgeJSLink {
322314 ]
323315 }
324316
325- /// Generates helper functions for the continuation-pointer pattern used by async imports.
326- ///
327- /// These encode a JS value as `(kind, payload1, payload2)` matching the `RawJSValue`
328- /// encoding from `_CJavaScriptKit.h`, then call the appropriate Wasm export to resume
329- /// the Swift continuation.
330- private func generatePromiseContinuationHelpers( ) -> [ String ] {
331- let printer = CodeFragmentPrinter ( )
332- // Helper to encode a JS value into (kind, payload1, payload2) and call the resolve export
333- printer. write ( " function bjs_resolvePromiseContinuation(ptr, value) { " )
334- printer. indent {
335- printer. write ( lines: generateJSValueEncoding ( variableName: " value " ) )
336- printer. write (
337- " \( JSGlueVariableScope . reservedInstance) .exports.bjs_resolve_promise_continuation(ptr, kind, payload1, payload2); "
338- )
339- }
340- printer. write ( " } " )
341- // Helper to encode a JS value into (kind, payload1, payload2) and call the reject export
342- printer. write ( " function bjs_rejectPromiseContinuation(ptr, error) { " )
343- printer. indent {
344- printer. write ( lines: generateJSValueEncoding ( variableName: " error " ) )
345- printer. write (
346- " \( JSGlueVariableScope . reservedInstance) .exports.bjs_reject_promise_continuation(ptr, kind, payload1, payload2); "
347- )
348- }
349- printer. write ( " } " )
350- return printer. lines
351- }
352-
353- /// Generates JS code that encodes a variable into `(kind, payload1, payload2)`.
354- ///
355- /// The encoding matches `JavaScriptValueKind` from `_CJavaScriptKit.h`:
356- /// - Boolean(0): payload1 = 1 or 0
357- /// - String(1): payload1 = retained object ID
358- /// - Number(2): payload2 = the number
359- /// - Object(3): payload1 = retained object ID
360- /// - Null(4): no payload
361- /// - Undefined(5): no payload
362- /// - Symbol(7): payload1 = retained object ID
363- /// - BigInt(8): payload1 = retained object ID
364- private func generateJSValueEncoding( variableName: String ) -> [ String ] {
365- let s = JSGlueVariableScope . reservedSwift
366- return [
367- " let kind, payload1 = 0, payload2 = 0; " ,
368- " if ( \( variableName) === null) { " ,
369- " kind = 4; " ,
370- " } else if ( \( variableName) === undefined) { " ,
371- " kind = 5; " ,
372- " } else { " ,
373- " const type = typeof \( variableName) ; " ,
374- " switch (type) { " ,
375- " case \" boolean \" : " ,
376- " kind = 0; " ,
377- " payload1 = \( variableName) ? 1 : 0; " ,
378- " break; " ,
379- " case \" number \" : " ,
380- " kind = 2; " ,
381- " payload2 = \( variableName) ; " ,
382- " break; " ,
383- " case \" string \" : " ,
384- " kind = 1; " ,
385- " payload1 = \( s) .memory.retain( \( variableName) ); " ,
386- " break; " ,
387- " case \" symbol \" : " ,
388- " kind = 7; " ,
389- " payload1 = \( s) .memory.retain( \( variableName) ); " ,
390- " break; " ,
391- " case \" bigint \" : " ,
392- " kind = 8; " ,
393- " payload1 = \( s) .memory.retain( \( variableName) ); " ,
394- " break; " ,
395- " default: " ,
396- " kind = 3; " ,
397- " payload1 = \( s) .memory.retain( \( variableName) ); " ,
398- " break; " ,
399- " } " ,
400- " } " ,
401- ]
402- }
403-
404317 private func generateAddImports( needsImportsObject: Bool ) throws -> CodeFragmentPrinter {
405318 let printer = CodeFragmentPrinter ( )
406319 let allStructs = skeletons. compactMap { $0. exported? . structs } . flatMap { $0 }
@@ -726,7 +639,26 @@ public struct BridgeJSLink {
726639 let collector = ClosureSignatureCollectorVisitor ( )
727640 var walker = BridgeTypeWalker ( visitor: collector)
728641 walker. walk ( unified)
729- let closureSignatures = walker. visitor. signatures
642+ var closureSignatures = walker. visitor. signatures
643+
644+ // Inject (JSValue) -> Void closure signature when async imports exist
645+ if let imported = unified. imported {
646+ let hasAsyncImport = imported. children. contains { file in
647+ file. functions. contains ( where: { $0. effects. isAsync } )
648+ || file. types. contains ( where: { type in
649+ type. methods. contains ( where: { $0. effects. isAsync } )
650+ } )
651+ }
652+ if hasAsyncImport {
653+ closureSignatures. insert (
654+ ClosureSignature (
655+ parameters: [ . jsValue] ,
656+ returnType: . void,
657+ moduleName: moduleName
658+ )
659+ )
660+ }
661+ }
730662
731663 guard !closureSignatures. isEmpty else { continue }
732664
@@ -1057,11 +989,6 @@ public struct BridgeJSLink {
1057989 try printer. indent {
1058990 printer. write ( lines: generateVariableDeclarations ( ) )
1059991
1060- // Generate Promise continuation helpers when async imports exist
1061- if data. hasAsyncImports {
1062- printer. write ( lines: generatePromiseContinuationHelpers ( ) )
1063- }
1064-
1065992 let bodyPrinter = CodeFragmentPrinter ( )
1066993 let allStructs = exportedSkeletons. flatMap { $0. structs }
1067994 for structDef in allStructs {
@@ -2327,36 +2254,34 @@ extension BridgeJSLink {
23272254 /// Generates the call expression for an async import.
23282255 ///
23292256 /// Instead of lowering the return value, this assigns the result to `promise`
2330- /// and attaches `.then`/`.catch` handlers that call the resolve/reject continuations .
2257+ /// and passes the resolve/reject closure refs to `.then` .
23312258 func callAsync( name: String , fromObjectExpr: String ) {
23322259 let calleeExpr = Self . propertyAccessExpr ( objectExpr: fromObjectExpr, propertyName: name)
23332260 let callExpr = " \( calleeExpr) ( \( parameterForwardings. joined ( separator: " , " ) ) ) "
23342261 body. write ( " const promise = \( callExpr) ; " )
2335- body. write ( " promise.then( " )
2336- body. indent {
2337- body. write ( " (value) => { bjs_resolvePromiseContinuation(continuationPtr, value); }, " )
2338- body. write ( " (error) => { bjs_rejectPromiseContinuation(continuationPtr, error); } " )
2339- }
2340- body. write ( " ); " )
2262+ body. write ( " promise.then(resolve, reject); " )
23412263 }
23422264
2343- /// Renders an async import function with continuation-pointer pattern .
2265+ /// Renders an async import function with resolve/reject closure refs .
23442266 ///
2345- /// The generated function takes `continuationPtr` as the first parameter ,
2267+ /// The generated function takes `resolveRef` and `rejectRef` as the first parameters ,
23462268 /// wraps the import call in try/catch, attaches Promise handlers, and
2347- /// calls reject continuation on synchronous errors.
2269+ /// calls reject on synchronous errors.
23482270 func renderAsyncFunction( name: String ? ) -> [ String ] {
23492271 let printer = CodeFragmentPrinter ( )
2350- let allParams = [ " continuationPtr " ] + parameterNames
2272+ let allParams = [ " resolveRef " , " rejectRef " ] + parameterNames
23512273 printer. write ( " function \( name. map { " \( $0) " } ?? " " ) ( \( allParams. joined ( separator: " , " ) ) ) { " )
23522274 printer. indent {
2275+ let s = JSGlueVariableScope . reservedSwift
2276+ printer. write ( " const resolve = \( s) .memory.getObject(resolveRef); " )
2277+ printer. write ( " const reject = \( s) .memory.getObject(rejectRef); " )
23532278 printer. write ( " try { " )
23542279 printer. indent {
23552280 printer. write ( contentsOf: body)
23562281 }
23572282 printer. write ( " } catch (error) { " )
23582283 printer. indent {
2359- printer. write ( " bjs_rejectPromiseContinuation(continuationPtr, error);" )
2284+ printer. write ( " reject( error);" )
23602285 }
23612286 printer. write ( " } " )
23622287 }
@@ -2417,18 +2342,13 @@ extension BridgeJSLink {
24172342 )
24182343 }
24192344
2420- /// Generates an async method call with continuation-pointer pattern .
2345+ /// Generates an async method call with resolve/reject closure refs .
24212346 func callAsyncMethod( name: String ) {
24222347 let objectExpr = " \( JSGlueVariableScope . reservedSwift) .memory.getObject(self) "
24232348 let calleeExpr = Self . propertyAccessExpr ( objectExpr: objectExpr, propertyName: name)
24242349 let callExpr = " \( calleeExpr) ( \( parameterForwardings. joined ( separator: " , " ) ) ) "
24252350 body. write ( " const promise = \( callExpr) ; " )
2426- body. write ( " promise.then( " )
2427- body. indent {
2428- body. write ( " (value) => { bjs_resolvePromiseContinuation(continuationPtr, value); }, " )
2429- body. write ( " (error) => { bjs_rejectPromiseContinuation(continuationPtr, error); } " )
2430- }
2431- body. write ( " ); " )
2351+ body. write ( " promise.then(resolve, reject); " )
24322352 }
24332353
24342354 func callStaticMethod( on objectExpr: String , name: String , returnType: BridgeType ) throws -> String ? {
0 commit comments