@@ -649,6 +649,17 @@ pub(crate) fn record_tls_handshake(
649649/// ABI — see `NA_F64` lowering in perry-codegen.
650650#[ no_mangle]
651651pub unsafe extern "C" fn js_tls_connect ( arg1 : f64 , arg2 : f64 , arg3 : f64 , arg4 : f64 ) -> i64 {
652+ // `js_tls_prepare_connect` may invoke a user-replaced createSecureContext
653+ // before overload resolution. Keep every incoming value in the runtime's
654+ // moving-GC root stack, and re-read the selected options/callback values
655+ // after every later callback-capable runtime call.
656+ let root_scope = perry_ffi:: TransientRootScope :: enter ( ) ;
657+ let rooted_args = [
658+ root_scope. root_nanbox ( arg1) ,
659+ root_scope. root_nanbox ( arg2) ,
660+ root_scope. root_nanbox ( arg3) ,
661+ root_scope. root_nanbox ( arg4) ,
662+ ] ;
652663 extern "C" {
653664 fn js_tls_prepare_connect ( ) ;
654665 }
@@ -685,87 +696,89 @@ pub unsafe extern "C" fn js_tls_connect(arg1: f64, arg2: f64, arg3: f64, arg4: f
685696 ( j. is_bool ( ) && !j. to_bool ( ) ) || ( j. is_number ( ) && j. to_number ( ) == 0.0 )
686697 } ;
687698
688- let ( host, port, servername, verify, cb_f64 , metadata_options ) ;
689- if let Some ( h) = as_string ( arg1 ) {
699+ let ( host, port, servername, verify, callback_arg , metadata_options_arg ) ;
700+ if let Some ( h) = as_string ( rooted_args [ 0 ] . get ( ) ) {
690701 // Legacy Perry positional: (host, port, servername?, verify?).
691- let p = JsValue :: from_bits ( arg2 . to_bits ( ) ) ;
702+ let p = JsValue :: from_bits ( rooted_args [ 1 ] . get ( ) . to_bits ( ) ) ;
692703 if !p. is_number ( ) && !p. is_int32 ( ) {
693704 return 0 ;
694705 }
695706 port = p. to_number ( ) as u16 ;
696- servername = as_string ( arg3 ) . unwrap_or_else ( || h. clone ( ) ) ;
707+ servername = as_string ( rooted_args [ 2 ] . get ( ) ) . unwrap_or_else ( || h. clone ( ) ) ;
697708 host = h;
698- verify = !explicitly_off ( arg4 ) ;
699- cb_f64 = None ;
700- metadata_options = f64 :: from_bits ( 0x7FFC_0000_0000_0001 ) ;
701- } else if JsValue :: from_bits ( arg1 . to_bits ( ) ) . is_number ( )
702- || JsValue :: from_bits ( arg1 . to_bits ( ) ) . is_int32 ( )
709+ verify = !explicitly_off ( rooted_args [ 3 ] . get ( ) ) ;
710+ callback_arg = None ;
711+ metadata_options_arg = None ;
712+ } else if JsValue :: from_bits ( rooted_args [ 0 ] . get ( ) . to_bits ( ) ) . is_number ( )
713+ || JsValue :: from_bits ( rooted_args [ 0 ] . get ( ) . to_bits ( ) ) . is_int32 ( )
703714 {
704715 // Node positional form: tls.connect(port[, host][, options][, cb]).
705- js_net_validate_connect_port ( arg1 ) ;
706- port = JsValue :: from_bits ( arg1 . to_bits ( ) ) . to_number ( ) as u16 ;
716+ js_net_validate_connect_port ( rooted_args [ 0 ] . get ( ) ) ;
717+ port = JsValue :: from_bits ( rooted_args [ 0 ] . get ( ) . to_bits ( ) ) . to_number ( ) as u16 ;
707718 let mut opt_host: Option < String > = None ;
708- let mut opts: Option < f64 > = None ;
709- let mut cb: Option < f64 > = None ;
710- for v in [ arg2, arg3, arg4] {
719+ let mut opts_arg: Option < usize > = None ;
720+ let mut cb_arg: Option < usize > = None ;
721+ for index in [ 1 , 2 , 3 ] {
722+ let v = rooted_args[ index] . get ( ) ;
711723 if opt_host. is_none ( ) {
712724 if let Some ( h) = as_string ( v) {
713725 opt_host = Some ( h) ;
714726 continue ;
715727 }
716728 }
717729 if is_closure ( v) {
718- cb = cb . or ( Some ( v ) ) ;
730+ cb_arg = cb_arg . or ( Some ( index ) ) ;
719731 } else if is_nanboxed_pointer ( v) {
720- opts = opts . or ( Some ( v ) ) ;
732+ opts_arg = opts_arg . or ( Some ( index ) ) ;
721733 }
722734 }
723- if let Some ( options ) = opts {
735+ if let Some ( index ) = opts_arg {
724736 extern "C" {
725737 fn js_tls_validate_positional_connect_options ( options : f64 ) ;
726738 }
727- js_tls_validate_positional_connect_options ( options ) ;
739+ js_tls_validate_positional_connect_options ( rooted_args [ index ] . get ( ) ) ;
728740 }
729741 host = opt_host
730742 . or_else ( || {
731- opts. and_then ( |o| {
732- get_object_string_field ( o, "host" )
733- . or_else ( || get_object_string_field ( o, "hostname" ) )
743+ opts_arg. and_then ( |index| {
744+ let options = rooted_args[ index] . get ( ) ;
745+ get_object_string_field ( options, "host" )
746+ . or_else ( || get_object_string_field ( rooted_args[ index] . get ( ) , "hostname" ) )
734747 } )
735748 } )
736749 . filter ( |h| !h. is_empty ( ) )
737750 . unwrap_or_else ( || "localhost" . to_string ( ) ) ;
738- servername = opts
739- . and_then ( |o | get_object_string_field ( o , "servername" ) )
751+ servername = opts_arg
752+ . and_then ( |index | get_object_string_field ( rooted_args [ index ] . get ( ) , "servername" ) )
740753 . unwrap_or_else ( || host. clone ( ) ) ;
741- verify = opts
742- . and_then ( |o | get_object_bool_field ( o , "rejectUnauthorized" ) )
754+ verify = opts_arg
755+ . and_then ( |index | get_object_bool_field ( rooted_args [ index ] . get ( ) , "rejectUnauthorized" ) )
743756 . unwrap_or ( true ) ;
744- cb_f64 = cb ;
745- metadata_options = opts . unwrap_or_else ( || f64 :: from_bits ( 0x7FFC_0000_0000_0001 ) ) ;
746- } else if is_nanboxed_pointer ( arg1 ) && !is_closure ( arg1 ) {
757+ callback_arg = cb_arg ;
758+ metadata_options_arg = opts_arg ;
759+ } else if is_nanboxed_pointer ( rooted_args [ 0 ] . get ( ) ) && !is_closure ( rooted_args [ 0 ] . get ( ) ) {
747760 // Node options form: tls.connect(options[, callback]).
748761 extern "C" {
749762 fn js_tls_validate_connect_options ( options : f64 ) ;
750763 }
751- js_tls_validate_connect_options ( arg1 ) ;
752- if let Some ( socket_value) = crate :: get_object_value_field ( arg1 , "socket" ) {
764+ js_tls_validate_connect_options ( rooted_args [ 0 ] . get ( ) ) ;
765+ if let Some ( socket_value) = crate :: get_object_value_field ( rooted_args [ 0 ] . get ( ) , "socket" ) {
753766 let socket_js = JsValue :: from_bits ( socket_value. to_bits ( ) ) ;
754767 let handle = if socket_js. is_pointer ( ) {
755768 crate :: unbox_pointer ( socket_value) as i64
756769 } else {
757770 0
758771 } ;
759772 if handle != 0 {
760- host = get_object_string_field ( arg1 , "host" )
761- . or_else ( || get_object_string_field ( arg1 , "hostname" ) )
773+ host = get_object_string_field ( rooted_args [ 0 ] . get ( ) , "host" )
774+ . or_else ( || get_object_string_field ( rooted_args [ 0 ] . get ( ) , "hostname" ) )
762775 . unwrap_or_else ( || "localhost" . to_string ( ) ) ;
763- servername =
764- get_object_string_field ( arg1 , "servername" ) . unwrap_or_else ( || host. clone ( ) ) ;
765- verify = get_object_bool_field ( arg1 , "rejectUnauthorized" ) . unwrap_or ( true ) ;
766- cb_f64 = is_closure ( arg2 ) . then_some ( arg2 ) ;
767- metadata_options = arg1 ;
768- let config = tls_client_config_data ( metadata_options ) ;
776+ servername = get_object_string_field ( rooted_args [ 0 ] . get ( ) , "servername" )
777+ . unwrap_or_else ( || host. clone ( ) ) ;
778+ verify = get_object_bool_field ( rooted_args [ 0 ] . get ( ) , "rejectUnauthorized" )
779+ . unwrap_or ( true ) ;
780+ callback_arg = is_closure ( rooted_args [ 1 ] . get ( ) ) . then_some ( 1 ) ;
781+ let config = tls_client_config_data ( rooted_args [ 0 ] . get ( ) ) ;
769782 extern "C" {
770783 fn js_tls_client_record_start (
771784 handle : i64 ,
@@ -776,12 +789,12 @@ pub unsafe extern "C" fn js_tls_connect(arg1: f64, arg2: f64, arg3: f64, arg4: f
776789 }
777790 js_tls_client_record_start (
778791 handle,
779- metadata_options ,
792+ rooted_args [ 0 ] . get ( ) ,
780793 servername. as_ptr ( ) ,
781794 servername. len ( ) ,
782795 ) ;
783- if let Some ( cb ) = cb_f64 {
784- let cb_ptr = unbox_pointer ( cb ) as i64 ;
796+ if let Some ( index ) = callback_arg {
797+ let cb_ptr = unbox_pointer ( rooted_args [ index ] . get ( ) ) as i64 ;
785798 if cb_ptr != 0 {
786799 statics:: listeners ( )
787800 . lock ( )
@@ -793,7 +806,7 @@ pub unsafe extern "C" fn js_tls_connect(arg1: f64, arg2: f64, arg3: f64, arg4: f
793806 . push ( cb_ptr) ;
794807 }
795808 }
796- let preflight = tls_preflight ( 0 , & servername, metadata_options ) ;
809+ let preflight = tls_preflight ( 0 , & servername, rooted_args [ 0 ] . get ( ) ) ;
797810 if preflight != 0 {
798811 crate :: push_event ( crate :: PendingNetEvent :: Error (
799812 handle,
@@ -807,29 +820,35 @@ pub unsafe extern "C" fn js_tls_connect(arg1: f64, arg2: f64, arg3: f64, arg4: f
807820 return handle;
808821 }
809822 }
810- port = match get_object_number_field ( arg1 , "port" ) {
823+ port = match get_object_number_field ( rooted_args [ 0 ] . get ( ) , "port" ) {
811824 Some ( p) => {
812825 js_net_validate_connect_port ( p) ;
813826 p as u16
814827 }
815828 None => return 0 ,
816829 } ;
817- host = match get_object_string_field ( arg1 , "host" )
818- . or_else ( || get_object_string_field ( arg1 , "hostname" ) )
830+ host = match get_object_string_field ( rooted_args [ 0 ] . get ( ) , "host" )
831+ . or_else ( || get_object_string_field ( rooted_args [ 0 ] . get ( ) , "hostname" ) )
819832 {
820833 Some ( h) if !h. is_empty ( ) => h,
821834 _ => "localhost" . to_string ( ) ,
822835 } ;
823- servername = get_object_string_field ( arg1, "servername" ) . unwrap_or_else ( || host. clone ( ) ) ;
824- verify = get_object_bool_field ( arg1, "rejectUnauthorized" ) . unwrap_or ( true ) ;
825- cb_f64 = is_closure ( arg2) . then_some ( arg2) ;
826- metadata_options = arg1;
836+ servername = get_object_string_field ( rooted_args[ 0 ] . get ( ) , "servername" )
837+ . unwrap_or_else ( || host. clone ( ) ) ;
838+ verify = get_object_bool_field ( rooted_args[ 0 ] . get ( ) , "rejectUnauthorized" ) . unwrap_or ( true ) ;
839+ callback_arg = is_closure ( rooted_args[ 1 ] . get ( ) ) . then_some ( 1 ) ;
840+ metadata_options_arg = Some ( 0 ) ;
827841 } else {
828842 return 0 ;
829843 }
830844
831- let config = tls_client_config_data ( metadata_options) ;
832- if signal_is_pre_aborted ( metadata_options) {
845+ let metadata_options = || {
846+ metadata_options_arg
847+ . map ( |index| rooted_args[ index] . get ( ) )
848+ . unwrap_or_else ( || f64:: from_bits ( 0x7FFC_0000_0000_0001 ) )
849+ } ;
850+ let config = tls_client_config_data ( metadata_options ( ) ) ;
851+ if signal_is_pre_aborted ( metadata_options ( ) ) {
833852 let handle = crate :: js_net_socket_alloc ( ) ;
834853 extern "C" {
835854 fn js_tls_client_record_start (
@@ -841,14 +860,14 @@ pub unsafe extern "C" fn js_tls_connect(arg1: f64, arg2: f64, arg3: f64, arg4: f
841860 }
842861 js_tls_client_record_start (
843862 handle,
844- metadata_options,
863+ metadata_options ( ) ,
845864 servername. as_ptr ( ) ,
846865 servername. len ( ) ,
847866 ) ;
848867 schedule_tls_abort ( handle) ;
849868 return handle;
850869 }
851- let preflight = tls_preflight ( port, & servername, metadata_options) ;
870+ let preflight = tls_preflight ( port, & servername, metadata_options ( ) ) ;
852871 if preflight != 0 {
853872 let handle = crate :: js_net_socket_alloc ( ) ;
854873 extern "C" {
@@ -861,7 +880,7 @@ pub unsafe extern "C" fn js_tls_connect(arg1: f64, arg2: f64, arg3: f64, arg4: f
861880 }
862881 js_tls_client_record_start (
863882 handle,
864- metadata_options,
883+ metadata_options ( ) ,
865884 servername. as_ptr ( ) ,
866885 servername. len ( ) ,
867886 ) ;
@@ -885,14 +904,14 @@ pub unsafe extern "C" fn js_tls_connect(arg1: f64, arg2: f64, arg3: f64, arg4: f
885904 }
886905 js_tls_client_record_start (
887906 handle,
888- metadata_options,
907+ metadata_options ( ) ,
889908 metadata_servername. as_ptr ( ) ,
890909 metadata_servername. len ( ) ,
891910 ) ;
892911 } ) ;
893- if let Some ( cb ) = cb_f64 {
912+ if let Some ( index ) = callback_arg {
894913 if handle != 0 {
895- let cb_ptr = unbox_pointer ( cb ) as i64 ;
914+ let cb_ptr = unbox_pointer ( rooted_args [ index ] . get ( ) ) as i64 ;
896915 if cb_ptr != 0 {
897916 statics:: listeners ( )
898917 . lock ( )
0 commit comments