@@ -6,18 +6,45 @@ import {
6
6
pointer ,
7
7
TypedArray ,
8
8
ImportedFunctions ,
9
+ MAIN_THREAD_TID ,
9
10
} from "./types.js" ;
10
11
import * as JSValue from "./js-value.js" ;
11
12
import { Memory } from "./memory.js" ;
12
13
14
+ type TransferMessage = {
15
+ type : "transfer" ;
16
+ data : {
17
+ object : any ;
18
+ transferring : pointer ;
19
+ destinationTid : number ;
20
+ } ;
21
+ } ;
22
+
23
+ type RequestTransferMessage = {
24
+ type : "requestTransfer" ;
25
+ data : {
26
+ objectRef : ref ;
27
+ objectSourceTid : number ;
28
+ transferring : pointer ;
29
+ destinationTid : number ;
30
+ } ;
31
+ } ;
32
+
33
+ type TransferErrorMessage = {
34
+ type : "transferError" ;
35
+ data : {
36
+ error : string ;
37
+ } ;
38
+ } ;
39
+
13
40
type MainToWorkerMessage = {
14
41
type : "wake" ;
15
- } ;
42
+ } | RequestTransferMessage | TransferMessage | TransferErrorMessage ;
16
43
17
44
type WorkerToMainMessage = {
18
45
type : "job" ;
19
46
data : number ;
20
- } ;
47
+ } | RequestTransferMessage | TransferMessage | TransferErrorMessage ;
21
48
22
49
/**
23
50
* A thread channel is a set of functions that are used to communicate between
@@ -60,8 +87,9 @@ export type SwiftRuntimeThreadChannel =
60
87
* This function is used to send messages from the worker thread to the main thread.
61
88
* The message submitted by this function is expected to be listened by `listenMessageFromWorkerThread`.
62
89
* @param message The message to be sent to the main thread.
90
+ * @param transfer The array of objects to be transferred to the main thread.
63
91
*/
64
- postMessageToMainThread : ( message : WorkerToMainMessage ) => void ;
92
+ postMessageToMainThread : ( message : WorkerToMainMessage , transfer : any [ ] ) => void ;
65
93
/**
66
94
* This function is expected to be set in the worker thread and should listen
67
95
* to messages from the main thread sent by `postMessageToWorkerThread`.
@@ -75,8 +103,9 @@ export type SwiftRuntimeThreadChannel =
75
103
* The message submitted by this function is expected to be listened by `listenMessageFromMainThread`.
76
104
* @param tid The thread ID of the worker thread.
77
105
* @param message The message to be sent to the worker thread.
106
+ * @param transfer The array of objects to be transferred to the worker thread.
78
107
*/
79
- postMessageToWorkerThread : ( tid : number , message : MainToWorkerMessage ) => void ;
108
+ postMessageToWorkerThread : ( tid : number , message : MainToWorkerMessage , transfer : any [ ] ) => void ;
80
109
/**
81
110
* This function is expected to be set in the main thread and should listen
82
111
* to messages sent by `postMessageToMainThread` from the worker thread.
@@ -610,8 +639,37 @@ export class SwiftRuntime {
610
639
case "wake" :
611
640
this . exports . swjs_wake_worker_thread ( ) ;
612
641
break ;
642
+ case "requestTransfer" : {
643
+ const object = this . memory . getObject ( message . data . objectRef ) ;
644
+ const messageToMainThread : TransferMessage = {
645
+ type : "transfer" ,
646
+ data : {
647
+ object,
648
+ destinationTid : message . data . destinationTid ,
649
+ transferring : message . data . transferring ,
650
+ } ,
651
+ } ;
652
+ try {
653
+ this . postMessageToMainThread ( messageToMainThread , [ object ] ) ;
654
+ } catch ( error ) {
655
+ this . postMessageToMainThread ( {
656
+ type : "transferError" ,
657
+ data : { error : String ( error ) } ,
658
+ } ) ;
659
+ }
660
+ break ;
661
+ }
662
+ case "transfer" : {
663
+ const objectRef = this . memory . retain ( message . data . object ) ;
664
+ this . exports . swjs_receive_object ( objectRef , message . data . transferring ) ;
665
+ break ;
666
+ }
667
+ case "transferError" : {
668
+ console . error ( message . data . error ) ; // TODO: Handle the error
669
+ break ;
670
+ }
613
671
default :
614
- const unknownMessage : never = message . type ;
672
+ const unknownMessage : never = message ;
615
673
throw new Error ( `Unknown message type: ${ unknownMessage } ` ) ;
616
674
}
617
675
} ) ;
@@ -632,8 +690,57 @@ export class SwiftRuntime {
632
690
case "job" :
633
691
this . exports . swjs_enqueue_main_job_from_worker ( message . data ) ;
634
692
break ;
693
+ case "requestTransfer" : {
694
+ if ( message . data . objectSourceTid == MAIN_THREAD_TID ) {
695
+ const object = this . memory . getObject ( message . data . objectRef ) ;
696
+ if ( message . data . destinationTid != tid ) {
697
+ throw new Error ( "Invariant violation: The destination tid of the transfer request must be the same as the tid of the worker thread that received the request." ) ;
698
+ }
699
+ this . postMessageToWorkerThread ( message . data . destinationTid , {
700
+ type : "transfer" ,
701
+ data : {
702
+ object,
703
+ transferring : message . data . transferring ,
704
+ destinationTid : message . data . destinationTid ,
705
+ } ,
706
+ } , [ object ] ) ;
707
+ } else {
708
+ // Proxy the transfer request to the worker thread that owns the object
709
+ this . postMessageToWorkerThread ( message . data . objectSourceTid , {
710
+ type : "requestTransfer" ,
711
+ data : {
712
+ objectRef : message . data . objectRef ,
713
+ objectSourceTid : tid ,
714
+ transferring : message . data . transferring ,
715
+ destinationTid : message . data . destinationTid ,
716
+ } ,
717
+ } ) ;
718
+ }
719
+ break ;
720
+ }
721
+ case "transfer" : {
722
+ if ( message . data . destinationTid == MAIN_THREAD_TID ) {
723
+ const objectRef = this . memory . retain ( message . data . object ) ;
724
+ this . exports . swjs_receive_object ( objectRef , message . data . transferring ) ;
725
+ } else {
726
+ // Proxy the transfer response to the destination worker thread
727
+ this . postMessageToWorkerThread ( message . data . destinationTid , {
728
+ type : "transfer" ,
729
+ data : {
730
+ object : message . data . object ,
731
+ transferring : message . data . transferring ,
732
+ destinationTid : message . data . destinationTid ,
733
+ } ,
734
+ } , [ message . data . object ] ) ;
735
+ }
736
+ break ;
737
+ }
738
+ case "transferError" : {
739
+ console . error ( message . data . error ) ; // TODO: Handle the error
740
+ break ;
741
+ }
635
742
default :
636
- const unknownMessage : never = message . type ;
743
+ const unknownMessage : never = message ;
637
744
throw new Error ( `Unknown message type: ${ unknownMessage } ` ) ;
638
745
}
639
746
} ,
@@ -649,27 +756,47 @@ export class SwiftRuntime {
649
756
// Main thread's tid is always -1
650
757
return this . tid || - 1 ;
651
758
} ,
759
+ swjs_request_transferring_object : (
760
+ object_ref : ref ,
761
+ object_source_tid : number ,
762
+ transferring : pointer ,
763
+ ) => {
764
+ if ( this . tid == object_source_tid ) {
765
+ // Fast path: The object is already in the same thread
766
+ this . exports . swjs_receive_object ( object_ref , transferring ) ;
767
+ return ;
768
+ }
769
+ this . postMessageToMainThread ( {
770
+ type : "requestTransfer" ,
771
+ data : {
772
+ objectRef : object_ref ,
773
+ objectSourceTid : object_source_tid ,
774
+ transferring,
775
+ destinationTid : this . tid ?? MAIN_THREAD_TID ,
776
+ } ,
777
+ } ) ;
778
+ } ,
652
779
} ;
653
780
}
654
781
655
- private postMessageToMainThread ( message : WorkerToMainMessage ) {
782
+ private postMessageToMainThread ( message : WorkerToMainMessage , transfer : any [ ] = [ ] ) {
656
783
const threadChannel = this . options . threadChannel ;
657
784
if ( ! ( threadChannel && "postMessageToMainThread" in threadChannel ) ) {
658
785
throw new Error (
659
786
"postMessageToMainThread is not set in options given to SwiftRuntime. Please set it to send messages to the main thread."
660
787
) ;
661
788
}
662
- threadChannel . postMessageToMainThread ( message ) ;
789
+ threadChannel . postMessageToMainThread ( message , transfer ) ;
663
790
}
664
791
665
- private postMessageToWorkerThread ( tid : number , message : MainToWorkerMessage ) {
792
+ private postMessageToWorkerThread ( tid : number , message : MainToWorkerMessage , transfer : any [ ] = [ ] ) {
666
793
const threadChannel = this . options . threadChannel ;
667
794
if ( ! ( threadChannel && "postMessageToWorkerThread" in threadChannel ) ) {
668
795
throw new Error (
669
796
"postMessageToWorkerThread is not set in options given to SwiftRuntime. Please set it to send messages to worker threads."
670
797
) ;
671
798
}
672
- threadChannel . postMessageToWorkerThread ( tid , message ) ;
799
+ threadChannel . postMessageToWorkerThread ( tid , message , transfer ) ;
673
800
}
674
801
}
675
802
0 commit comments