@@ -13,25 +13,39 @@ extension JSObject {
1313 /// intended to be shared across threads.
1414 public struct Transferring : @unchecked Sendable {
1515 fileprivate struct CriticalState {
16- var continuation : CheckedContinuation < JSObject , Error > ?
16+ var continuation : CheckedContinuation < JavaScriptObjectRef , Error > ?
1717 }
1818 fileprivate class Storage {
19- let sourceTid : Int32
20- let idInSource : JavaScriptObjectRef
19+ /// The original ``JSObject`` that is transferred.
20+ ///
21+ /// Retain it here to prevent it from being released before the transfer is complete.
22+ let sourceObject : JSObject
2123 #if compiler(>=6.1) && _runtime(_multithreaded)
2224 let criticalState : Mutex < CriticalState > = . init( CriticalState ( ) )
2325 #endif
2426
25- init ( sourceTid: Int32 , id: JavaScriptObjectRef ) {
26- self . sourceTid = sourceTid
27- self . idInSource = id
27+ var idInSource : JavaScriptObjectRef {
28+ sourceObject. id
29+ }
30+
31+ var sourceTid : Int32 {
32+ #if compiler(>=6.1) && _runtime(_multithreaded)
33+ sourceObject. ownerTid
34+ #else
35+ // On single-threaded runtime, source and destination threads are always the main thread (TID = -1).
36+ - 1
37+ #endif
38+ }
39+
40+ init ( sourceObject: JSObject ) {
41+ self . sourceObject = sourceObject
2842 }
2943 }
3044
3145 private let storage : Storage
3246
33- fileprivate init ( sourceTid : Int32 , id : JavaScriptObjectRef ) {
34- self . init ( storage: Storage ( sourceTid : sourceTid , id : id ) )
47+ fileprivate init ( sourceObject : JSObject ) {
48+ self . init ( storage: Storage ( sourceObject : sourceObject ) )
3549 }
3650
3751 fileprivate init ( storage: Storage ) {
@@ -63,7 +77,7 @@ extension JSObject {
6377 self . storage. sourceTid,
6478 Unmanaged . passRetained ( self . storage) . toOpaque ( )
6579 )
66- return try await withCheckedThrowingContinuation { continuation in
80+ let idInDestination = try await withCheckedThrowingContinuation { continuation in
6781 self . storage. criticalState. withLock { criticalState in
6882 guard criticalState. continuation == nil else {
6983 // This is a programming error, `receive` should be called only once.
@@ -72,6 +86,7 @@ extension JSObject {
7286 criticalState. continuation = continuation
7387 }
7488 }
89+ return JSObject ( id: idInDestination)
7590 #else
7691 return JSObject ( id: storage. idInSource)
7792 #endif
@@ -85,12 +100,7 @@ extension JSObject {
85100 /// - Parameter object: The ``JSObject`` to be transferred.
86101 /// - Returns: A ``Transferring`` instance that can be shared across threads.
87102 public static func transfer( _ object: JSObject ) -> Transferring {
88- #if compiler(>=6.1) && _runtime(_multithreaded)
89- Transferring ( sourceTid: object. ownerTid, id: object. id)
90- #else
91- // On single-threaded runtime, source and destination threads are always the main thread (TID = -1).
92- Transferring ( sourceTid: - 1 , id: object. id)
93- #endif
103+ return Transferring ( sourceObject: object)
94104 }
95105}
96106
@@ -110,7 +120,7 @@ func _swjs_receive_object(_ object: JavaScriptObjectRef, _ transferring: UnsafeR
110120 let storage = Unmanaged < JSObject . Transferring . Storage > . fromOpaque ( transferring) . takeRetainedValue ( )
111121 storage. criticalState. withLock { criticalState in
112122 assert ( criticalState. continuation != nil , " JSObject.Transferring object is not yet received!? " )
113- criticalState. continuation? . resume ( returning: JSObject ( id : object) )
123+ criticalState. continuation? . resume ( returning: object)
114124 }
115125 #endif
116126}
0 commit comments