@@ -43,6 +43,7 @@ use crate::support::int;
4343use crate :: support:: size_t;
4444use crate :: wasm:: WasmStreaming ;
4545use crate :: wasm:: trampoline;
46+ use std:: cell:: UnsafeCell ;
4647use std:: ffi:: CStr ;
4748
4849use std:: any:: Any ;
@@ -583,12 +584,6 @@ pub type PrepareStackTraceCallback<'s> =
583584 Local < ' s , Array > ,
584585 ) -> * mut * const Value ;
585586
586- // System V ABI: MaybeLocal<Value> returned in a register.
587- // System V i386 ABI: Local<Value> returned in hidden pointer (struct).
588- #[ cfg( not( target_os = "windows" ) ) ]
589- #[ repr( C ) ]
590- pub struct PrepareStackTraceCallbackRet ( * const Value ) ;
591-
592587#[ cfg( not( target_os = "windows" ) ) ]
593588pub type PrepareStackTraceCallback < ' s > =
594589 unsafe extern "C" fn (
@@ -597,6 +592,12 @@ pub type PrepareStackTraceCallback<'s> =
597592 Local < ' s , Array > ,
598593 ) -> PrepareStackTraceCallbackRet ;
599594
595+ // System V ABI: MaybeLocal<Value> returned in a register.
596+ // System V i386 ABI: Local<Value> returned in hidden pointer (struct).
597+ #[ cfg( not( target_os = "windows" ) ) ]
598+ #[ repr( C ) ]
599+ pub struct PrepareStackTraceCallbackRet ( * const Value ) ;
600+
600601pub type UseCounterFeature = v8__Isolate__UseCounterFeature ;
601602pub type UseCounterCallback =
602603 unsafe extern "C" fn ( & mut Isolate , UseCounterFeature ) ;
@@ -890,7 +891,7 @@ impl Isolate {
890891
891892 // Isolate data slots used internally by rusty_v8.
892893 const ANNEX_SLOT : u32 = 0 ;
893- const INTERNAL_DATA_SLOT_COUNT : u32 = 2 ;
894+ const INTERNAL_DATA_SLOT_COUNT : u32 = 1 ;
894895
895896 #[ inline( always) ]
896897 fn assert_embedder_data_slot_count_and_offset_correct ( & self ) {
@@ -955,7 +956,7 @@ impl Isolate {
955956
956957 #[ inline( always) ]
957958 pub fn thread_safe_handle ( & self ) -> IsolateHandle {
958- IsolateHandle :: new ( self )
959+ self . get_annex ( ) . isolate_handle . clone ( )
959960 }
960961
961962 /// See [`IsolateHandle::terminate_execution`]
@@ -980,25 +981,23 @@ impl Isolate {
980981 & mut self ,
981982 create_param_allocations : Box < dyn Any > ,
982983 ) {
983- let annex_arc = Arc :: new ( IsolateAnnex :: new ( self , create_param_allocations) ) ;
984- let annex_ptr = Arc :: into_raw ( annex_arc ) ;
984+ let annex_box = Box :: new ( IsolateAnnex :: new ( self , create_param_allocations) ) ;
985+ let annex_ptr = Box :: into_raw ( annex_box ) ;
985986 assert ! ( self . get_data_internal( Self :: ANNEX_SLOT ) . is_null( ) ) ;
986987 self . set_data_internal ( Self :: ANNEX_SLOT , annex_ptr as * mut _ ) ;
987988 }
988989
989990 unsafe fn dispose_annex ( & mut self ) -> Box < dyn Any > {
991+ // SAFETY: `dispose_annex()` is only called once, when the `Isolate` is dropped.
992+ let mut annex = unsafe { self . take_annex ( ) } ;
993+
990994 // Set the `isolate` pointer inside the annex struct to null, so any
991995 // IsolateHandle that outlives the isolate will know that it can't call
992996 // methods on the isolate.
993- let annex = self . get_annex_mut ( ) ;
994- {
995- let _lock = annex. isolate_mutex . lock ( ) . unwrap ( ) ;
996- annex. isolate = null_mut ( ) ;
997- }
997+ annex. isolate_handle . dispose ( ) ;
998998
999999 // Clear slots and drop owned objects that were taken out of `CreateParams`.
1000- let create_param_allocations =
1001- std:: mem:: replace ( & mut annex. create_param_allocations , Box :: new ( ( ) ) ) ;
1000+ let create_param_allocations = annex. create_param_allocations ;
10021001 annex. slots . clear ( ) ;
10031002
10041003 // Run through any remaining guaranteed finalizers.
@@ -1008,10 +1007,6 @@ impl Isolate {
10081007 }
10091008 }
10101009
1011- // Subtract one from the Arc<IsolateAnnex> reference count.
1012- unsafe { Arc :: from_raw ( annex) } ;
1013- self . set_data ( 0 , null_mut ( ) ) ;
1014-
10151010 create_param_allocations
10161011 }
10171012
@@ -1031,6 +1026,15 @@ impl Isolate {
10311026 unsafe { & mut * annex_ptr }
10321027 }
10331028
1029+ /// # Safety
1030+ /// This must only be called once.
1031+ #[ inline( always) ]
1032+ unsafe fn take_annex ( & mut self ) -> Box < IsolateAnnex > {
1033+ let annex_ptr =
1034+ self . take_data_internal ( Self :: ANNEX_SLOT ) as * mut IsolateAnnex ;
1035+ unsafe { Box :: from_raw ( annex_ptr) }
1036+ }
1037+
10341038 pub ( crate ) fn set_snapshot_creator (
10351039 & mut self ,
10361040 snapshot_creator : SnapshotCreator ,
@@ -1050,13 +1054,6 @@ impl Isolate {
10501054 & mut self . get_annex_mut ( ) . finalizer_map
10511055 }
10521056
1053- fn get_annex_arc ( & self ) -> Arc < IsolateAnnex > {
1054- let annex_ptr = self . get_annex ( ) ;
1055- let annex_arc = unsafe { Arc :: from_raw ( annex_ptr) } ;
1056- let _ = Arc :: into_raw ( annex_arc. clone ( ) ) ;
1057- annex_arc
1058- }
1059-
10601057 /// Retrieve embedder-specific data from the isolate.
10611058 /// Returns NULL if SetData has never been called for the given `slot`.
10621059 pub fn get_data ( & self , slot : u32 ) -> * mut c_void {
@@ -1087,6 +1084,14 @@ impl Isolate {
10871084 unsafe { v8__Isolate__SetData ( self . as_real_ptr ( ) , slot, data) }
10881085 }
10891086
1087+ /// Get the value of the slot and replace it with a null pointer.
1088+ #[ inline( always) ]
1089+ fn take_data_internal ( & mut self , slot : u32 ) -> * mut c_void {
1090+ let ptr = self . get_data_internal ( slot) ;
1091+ self . set_data_internal ( slot, null_mut ( ) ) ;
1092+ ptr
1093+ }
1094+
10901095 // pub(crate) fn init_scope_root(&mut self) {
10911096 // ScopeData::new_root(self);
10921097 // }
@@ -1876,65 +1881,111 @@ pub(crate) struct IsolateAnnex {
18761881 slots : HashMap < TypeId , RawSlot , BuildTypeIdHasher > ,
18771882 finalizer_map : FinalizerMap ,
18781883 maybe_snapshot_creator : Option < SnapshotCreator > ,
1879- // The `isolate` and `isolate_mutex` fields are there so an `IsolateHandle`
1880- // (which may outlive the isolate itself) can determine whether the isolate
1881- // is still alive, and if so, get a reference to it. Safety rules:
1882- // - The 'main thread' must lock the mutex and reset `isolate` to null just
1883- // before the isolate is disposed.
1884- // - Any other thread must lock the mutex while it's reading/using the
1885- // `isolate` pointer.
1886- isolate : * mut RealIsolate ,
1887- isolate_mutex : Mutex < ( ) > ,
1884+ isolate_handle : IsolateHandle ,
18881885}
18891886
1890- unsafe impl Send for IsolateAnnex { }
1891- unsafe impl Sync for IsolateAnnex { }
1892-
18931887impl IsolateAnnex {
1894- fn new (
1895- isolate : & mut Isolate ,
1896- create_param_allocations : Box < dyn Any > ,
1897- ) -> Self {
1888+ fn new ( isolate : & Isolate , create_param_allocations : Box < dyn Any > ) -> Self {
18981889 Self {
18991890 create_param_allocations,
19001891 slots : HashMap :: default ( ) ,
19011892 finalizer_map : FinalizerMap :: default ( ) ,
19021893 maybe_snapshot_creator : None ,
1903- isolate : isolate. as_real_ptr ( ) ,
1904- isolate_mutex : Mutex :: new ( ( ) ) ,
1894+ isolate_handle : IsolateHandle :: new ( isolate) ,
19051895 }
19061896 }
19071897}
19081898
19091899impl Debug for IsolateAnnex {
19101900 fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
19111901 f. debug_struct ( "IsolateAnnex" )
1912- . field ( "isolate" , & self . isolate )
1913- . field ( "isolate_mutex" , & self . isolate_mutex )
1902+ . field ( "isolate_handle" , & self . isolate_handle )
19141903 . finish ( )
19151904 }
19161905}
19171906
1918- /// IsolateHandle is a thread-safe reference to an Isolate. It's main use is to
1907+ pub ( crate ) struct IsolateHandleInner {
1908+ /// Safety invariants:
1909+ /// - The 'main thread' must lock the mutex and reset `isolate` to null just
1910+ /// before the isolate is disposed.
1911+ /// - Any other thread must lock the mutex while it's reading/using the
1912+ /// `isolate` pointer.
1913+ // These two fields can be replaced with a `Mutex<*mut RealIsolate>` once
1914+ // `Mutex::data_ptr()` is stabilized.
1915+ isolate : UnsafeCell < * mut RealIsolate > ,
1916+ isolate_mutex : Mutex < ( ) > ,
1917+ }
1918+
1919+ unsafe impl Send for IsolateHandleInner { }
1920+ unsafe impl Sync for IsolateHandleInner { }
1921+
1922+ /// IsolateHandle is a thread-safe reference to an Isolate. Its main use is to
19191923/// terminate execution of a running isolate from another thread.
19201924///
1921- /// It is created with Isolate::thread_safe_handle().
1925+ /// It is created with [` Isolate::thread_safe_handle()`] .
19221926///
19231927/// IsolateHandle is Cloneable, Send, and Sync.
1924- #[ derive( Clone , Debug ) ]
1925- pub struct IsolateHandle ( Arc < IsolateAnnex > ) ;
1928+ #[ derive( Clone ) ]
1929+ pub struct IsolateHandle ( Arc < IsolateHandleInner > ) ;
19261930
1927- impl IsolateHandle {
1928- // This function is marked unsafe because it must be called only with either
1929- // IsolateAnnex::mutex locked, or from the main thread associated with the V8
1930- // isolate.
1931- pub ( crate ) unsafe fn get_isolate_ptr ( & self ) -> * mut RealIsolate {
1932- self . 0 . isolate
1931+ impl fmt:: Debug for IsolateHandle {
1932+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
1933+ if let Ok ( _lock) = self . 0 . isolate_mutex . try_lock ( ) {
1934+ // SAFETY: mutex lock is held
1935+ let ptr = unsafe { * self . 0 . isolate . get ( ) } ;
1936+ f. debug_struct ( "IsolateHandle" )
1937+ . field ( "isolate_ptr" , & ptr)
1938+ . finish ( )
1939+ } else {
1940+ f. debug_struct ( "IsolateHandle" ) . finish_non_exhaustive ( )
1941+ }
19331942 }
1943+ }
19341944
1945+ impl IsolateHandle {
19351946 #[ inline( always) ]
19361947 fn new ( isolate : & Isolate ) -> Self {
1937- Self ( isolate. get_annex_arc ( ) )
1948+ let inner = Arc :: new ( IsolateHandleInner {
1949+ isolate : UnsafeCell :: new ( isolate. as_real_ptr ( ) ) ,
1950+ isolate_mutex : Mutex :: new ( ( ) ) ,
1951+ } ) ;
1952+ Self ( inner)
1953+ }
1954+
1955+ /// Set the inner isolate pointer to null.
1956+ fn dispose ( self ) {
1957+ let _lock = self . 0 . isolate_mutex . lock ( ) . unwrap ( ) ;
1958+ // SAFETY: mutex lock is held
1959+ unsafe { * self . 0 . isolate . get ( ) = null_mut ( ) }
1960+ }
1961+
1962+ /// Access the isolate, if it hasn't yet been disposed of.
1963+ ///
1964+ /// A lock is taken on the pointer and held for the scope of `f`, which
1965+ /// means the isolate can't be dropped until after `f` returns. If you
1966+ /// do something with the isolate afterwards, that needs to be verified
1967+ /// to be safe separately.
1968+ pub ( crate ) fn with_isolate_ptr < R > (
1969+ & self ,
1970+ f : impl FnOnce ( NonNull < RealIsolate > ) -> R ,
1971+ ) -> Option < R > {
1972+ let _lock = self . 0 . isolate_mutex . lock ( ) . unwrap ( ) ;
1973+ // SAFETY: mutex lock is held
1974+ let ptr = unsafe { * self . 0 . isolate . get ( ) } ;
1975+ NonNull :: new ( ptr) . map ( f)
1976+ }
1977+
1978+ /// Access the pointer for this isolate - it may be null.
1979+ ///
1980+ /// # Safety
1981+ /// This function must only be called from the main thread associated with
1982+ /// the V8 isolate.
1983+ // TODO: have this return an `Option<NonNull<RealIsolate>>`
1984+ pub ( crate ) unsafe fn get_isolate_ptr ( & self ) -> * mut RealIsolate {
1985+ // SAFETY: this function must only be called from the main thread of the
1986+ // isolate, which means that `Isolate::dispose_annex` can't concurrently
1987+ // be setting this to null.
1988+ unsafe { * self . 0 . isolate . get ( ) }
19381989 }
19391990
19401991 /// Forcefully terminate the current thread of JavaScript execution
@@ -1946,13 +1997,11 @@ impl IsolateHandle {
19461997 /// Returns false if Isolate was already destroyed.
19471998 #[ inline( always) ]
19481999 pub fn terminate_execution ( & self ) -> bool {
1949- let _lock = self . 0 . isolate_mutex . lock ( ) . unwrap ( ) ;
1950- if self . 0 . isolate . is_null ( ) {
1951- false
1952- } else {
1953- unsafe { v8__Isolate__TerminateExecution ( self . 0 . isolate ) } ;
1954- true
1955- }
2000+ self
2001+ . with_isolate_ptr ( |isolate| unsafe {
2002+ v8__Isolate__TerminateExecution ( isolate. as_ptr ( ) )
2003+ } )
2004+ . is_some ( )
19562005 }
19572006
19582007 /// Resume execution capability in the given isolate, whose execution
@@ -1971,13 +2020,11 @@ impl IsolateHandle {
19712020 /// Returns false if Isolate was already destroyed.
19722021 #[ inline( always) ]
19732022 pub fn cancel_terminate_execution ( & self ) -> bool {
1974- let _lock = self . 0 . isolate_mutex . lock ( ) . unwrap ( ) ;
1975- if self . 0 . isolate . is_null ( ) {
1976- false
1977- } else {
1978- unsafe { v8__Isolate__CancelTerminateExecution ( self . 0 . isolate ) } ;
1979- true
1980- }
2023+ self
2024+ . with_isolate_ptr ( |isolate| unsafe {
2025+ v8__Isolate__CancelTerminateExecution ( isolate. as_ptr ( ) )
2026+ } )
2027+ . is_some ( )
19812028 }
19822029
19832030 /// Is V8 terminating JavaScript execution.
@@ -1990,12 +2037,11 @@ impl IsolateHandle {
19902037 /// Returns false if Isolate was already destroyed.
19912038 #[ inline( always) ]
19922039 pub fn is_execution_terminating ( & self ) -> bool {
1993- let _lock = self . 0 . isolate_mutex . lock ( ) . unwrap ( ) ;
1994- if self . 0 . isolate . is_null ( ) {
1995- false
1996- } else {
1997- unsafe { v8__Isolate__IsExecutionTerminating ( self . 0 . isolate ) }
1998- }
2040+ self
2041+ . with_isolate_ptr ( |isolate| unsafe {
2042+ v8__Isolate__IsExecutionTerminating ( isolate. as_ptr ( ) )
2043+ } )
2044+ . unwrap_or ( false )
19992045 }
20002046
20012047 /// Request V8 to interrupt long running JavaScript code and invoke
@@ -2015,13 +2061,11 @@ impl IsolateHandle {
20152061 callback : InterruptCallback ,
20162062 data : * mut c_void ,
20172063 ) -> bool {
2018- let _lock = self . 0 . isolate_mutex . lock ( ) . unwrap ( ) ;
2019- if self . 0 . isolate . is_null ( ) {
2020- false
2021- } else {
2022- unsafe { v8__Isolate__RequestInterrupt ( self . 0 . isolate , callback, data) } ;
2023- true
2024- }
2064+ self
2065+ . with_isolate_ptr ( |isolate| unsafe {
2066+ v8__Isolate__RequestInterrupt ( isolate. as_ptr ( ) , callback, data)
2067+ } )
2068+ . is_some ( )
20252069 }
20262070}
20272071
0 commit comments