@@ -31,6 +31,14 @@ public class ExportSwift {
3131 self . skeleton = skeleton
3232 }
3333
34+ /// Whether a class should use identity caching based on its annotation and the config default.
35+ private func shouldUseIdentityCache ( for klass : ExportedClass ) -> Bool {
36+ if let classOverride = klass . identityMode {
37+ return classOverride
38+ }
39+ return skeleton . identityMode == " pointer "
40+ }
41+
3442 /// Finalizes the export process and generates the bridge code
3543 ///
3644 /// - Parameters:
@@ -103,6 +111,9 @@ public class ExportSwift {
103111 var abiReturnType : WasmCoreType ?
104112 var externDecls : [ DeclSyntax ] = [ ]
105113 let effects : Effects
114+ /// When set, heap object returns use the per-class identity Set pattern
115+ /// instead of the default `bridgeJSLowerReturn()`.
116+ var identityClassName : String ?
106117
107118 init ( effects : Effects ) {
108119 self . effects = effects
@@ -323,6 +334,26 @@ public class ExportSwift {
323334 }
324335 """
325336 )
337+ case . swiftHeapObject ( let className ) :
338+ if let identityClass = identityClassName , identityClass == className {
339+ append (
340+ """
341+ return withExtendedLifetime(ret) {
342+ let pointer = Unmanaged.passUnretained(ret).toOpaque()
343+ if _ \( raw : identityClass ) _identityExported.contains(pointer) {
344+ _bridgeJSIdentityFlag = 1
345+ return pointer
346+ }
347+ _ \( raw : identityClass ) _identityExported.insert(pointer)
348+ _ = Unmanaged.passRetained(ret)
349+ _bridgeJSIdentityFlag = 0
350+ return pointer
351+ }
352+ """
353+ )
354+ } else {
355+ append ( " return ret.bridgeJSLowerReturn() " )
356+ }
326357 default :
327358 append ( " return ret.bridgeJSLowerReturn() " )
328359 }
@@ -534,9 +565,11 @@ public class ExportSwift {
534565 private func renderSingleExportedConstructor (
535566 constructor : ExportedConstructor ,
536567 callName : String ,
537- returnType : BridgeType
568+ returnType : BridgeType ,
569+ identityClassName : String ? = nil
538570 ) throws -> DeclSyntax {
539571 let builder = ExportedThunkBuilder ( effects : constructor . effects )
572+ builder . identityClassName = identityClassName
540573 for param in constructor . parameters {
541574 try builder . liftParameter ( param : param )
542575 }
@@ -548,9 +581,11 @@ public class ExportSwift {
548581 private func renderSingleExportedMethod (
549582 method : ExportedFunction ,
550583 ownerTypeName : String ,
551- instanceSelfType : BridgeType
584+ instanceSelfType : BridgeType ,
585+ identityClassName : String ? = nil
552586 ) throws -> DeclSyntax {
553587 let builder = ExportedThunkBuilder ( effects : method . effects )
588+ builder . identityClassName = identityClassName
554589 if ! method . effects . isStatic {
555590 try builder . liftParameter ( param : Parameter ( label : nil , name : " _self " , type : instanceSelfType ) )
556591 }
@@ -652,21 +687,31 @@ public class ExportSwift {
652687 func renderSingleExportedClass ( klass : ExportedClass ) throws -> [ DeclSyntax ] {
653688 var decls : [ DeclSyntax ] = [ ]
654689
655- if let constructor = klass . constructor {
690+ let useIdentity = shouldUseIdentityCache ( for : klass )
691+
692+ // For identity-mode classes, emit the per-class Set
693+ if useIdentity {
656694 decls . append (
657- try renderSingleExportedConstructor (
658- constructor : constructor ,
659- callName : klass . swiftCallName ,
660- returnType : . swiftHeapObject ( klass . name )
661- )
695+ " nonisolated(unsafe) var _ \( raw : klass . name ) _identityExported: Set<UnsafeMutableRawPointer> = [] "
662696 )
663697 }
698+
699+ if let constructor = klass . constructor {
700+ let constructorDecl = try renderSingleExportedConstructor (
701+ constructor : constructor ,
702+ callName : klass . swiftCallName ,
703+ returnType : . swiftHeapObject ( klass . name ) ,
704+ identityClassName : useIdentity ? klass . name : nil
705+ )
706+ decls . append ( constructorDecl )
707+ }
664708 for method in klass . methods {
665709 decls . append (
666710 try renderSingleExportedMethod (
667711 method : method ,
668712 ownerTypeName : klass . swiftCallName ,
669- instanceSelfType : . swiftHeapObject ( klass . swiftCallName )
713+ instanceSelfType : . swiftHeapObject ( klass . swiftCallName ) ,
714+ identityClassName : useIdentity ? klass . name : nil
670715 )
671716 )
672717 }
@@ -686,6 +731,9 @@ public class ExportSwift {
686731 returnType : nil
687732 )
688733 ) { printer in
734+ if useIdentity {
735+ printer . write ( " _ \( klass . name ) _identityExported.remove(pointer) " )
736+ }
689737 printer . write ( " Unmanaged< \( klass . swiftCallName ) >.fromOpaque(pointer).release() " )
690738 }
691739 decls . append ( DeclSyntax ( funcDecl ) )
0 commit comments