@@ -6,18 +6,45 @@ import {
66 pointer ,
77 TypedArray ,
88 ImportedFunctions ,
9+ MAIN_THREAD_TID ,
910} from "./types.js" ;
1011import * as JSValue from "./js-value.js" ;
1112import { Memory } from "./memory.js" ;
1213
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+
1340type MainToWorkerMessage = {
1441 type : "wake" ;
15- } ;
42+ } | RequestTransferMessage | TransferMessage | TransferErrorMessage ;
1643
1744type WorkerToMainMessage = {
1845 type : "job" ;
1946 data : number ;
20- } ;
47+ } | RequestTransferMessage | TransferMessage | TransferErrorMessage ;
2148
2249/**
2350 * A thread channel is a set of functions that are used to communicate between
@@ -60,8 +87,9 @@ export type SwiftRuntimeThreadChannel =
6087 * This function is used to send messages from the worker thread to the main thread.
6188 * The message submitted by this function is expected to be listened by `listenMessageFromWorkerThread`.
6289 * @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.
6391 */
64- postMessageToMainThread : ( message : WorkerToMainMessage ) => void ;
92+ postMessageToMainThread : ( message : WorkerToMainMessage , transfer : any [ ] ) => void ;
6593 /**
6694 * This function is expected to be set in the worker thread and should listen
6795 * to messages from the main thread sent by `postMessageToWorkerThread`.
@@ -75,8 +103,9 @@ export type SwiftRuntimeThreadChannel =
75103 * The message submitted by this function is expected to be listened by `listenMessageFromMainThread`.
76104 * @param tid The thread ID of the worker thread.
77105 * @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.
78107 */
79- postMessageToWorkerThread : ( tid : number , message : MainToWorkerMessage ) => void ;
108+ postMessageToWorkerThread : ( tid : number , message : MainToWorkerMessage , transfer : any [ ] ) => void ;
80109 /**
81110 * This function is expected to be set in the main thread and should listen
82111 * to messages sent by `postMessageToMainThread` from the worker thread.
@@ -610,8 +639,37 @@ export class SwiftRuntime {
610639 case "wake" :
611640 this . exports . swjs_wake_worker_thread ( ) ;
612641 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+ }
613671 default :
614- const unknownMessage : never = message . type ;
672+ const unknownMessage : never = message ;
615673 throw new Error ( `Unknown message type: ${ unknownMessage } ` ) ;
616674 }
617675 } ) ;
@@ -632,8 +690,57 @@ export class SwiftRuntime {
632690 case "job" :
633691 this . exports . swjs_enqueue_main_job_from_worker ( message . data ) ;
634692 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+ }
635742 default :
636- const unknownMessage : never = message . type ;
743+ const unknownMessage : never = message ;
637744 throw new Error ( `Unknown message type: ${ unknownMessage } ` ) ;
638745 }
639746 } ,
@@ -649,27 +756,47 @@ export class SwiftRuntime {
649756 // Main thread's tid is always -1
650757 return this . tid || - 1 ;
651758 } ,
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+ } ,
652779 } ;
653780 }
654781
655- private postMessageToMainThread ( message : WorkerToMainMessage ) {
782+ private postMessageToMainThread ( message : WorkerToMainMessage , transfer : any [ ] = [ ] ) {
656783 const threadChannel = this . options . threadChannel ;
657784 if ( ! ( threadChannel && "postMessageToMainThread" in threadChannel ) ) {
658785 throw new Error (
659786 "postMessageToMainThread is not set in options given to SwiftRuntime. Please set it to send messages to the main thread."
660787 ) ;
661788 }
662- threadChannel . postMessageToMainThread ( message ) ;
789+ threadChannel . postMessageToMainThread ( message , transfer ) ;
663790 }
664791
665- private postMessageToWorkerThread ( tid : number , message : MainToWorkerMessage ) {
792+ private postMessageToWorkerThread ( tid : number , message : MainToWorkerMessage , transfer : any [ ] = [ ] ) {
666793 const threadChannel = this . options . threadChannel ;
667794 if ( ! ( threadChannel && "postMessageToWorkerThread" in threadChannel ) ) {
668795 throw new Error (
669796 "postMessageToWorkerThread is not set in options given to SwiftRuntime. Please set it to send messages to worker threads."
670797 ) ;
671798 }
672- threadChannel . postMessageToWorkerThread ( tid , message ) ;
799+ threadChannel . postMessageToWorkerThread ( tid , message , transfer ) ;
673800 }
674801}
675802
0 commit comments