@@ -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 ;
@@ -878,7 +879,7 @@ impl Isolate {
878879
879880 // Isolate data slots used internally by rusty_v8.
880881 const ANNEX_SLOT : u32 = 0 ;
881- const INTERNAL_DATA_SLOT_COUNT : u32 = 2 ;
882+ const INTERNAL_DATA_SLOT_COUNT : u32 = 1 ;
882883
883884 #[ inline( always) ]
884885 fn assert_embedder_data_slot_count_and_offset_correct ( & self ) {
@@ -943,7 +944,7 @@ impl Isolate {
943944
944945 #[ inline( always) ]
945946 pub fn thread_safe_handle ( & self ) -> IsolateHandle {
946- IsolateHandle :: new ( self )
947+ self . get_annex ( ) . isolate_handle . clone ( )
947948 }
948949
949950 /// See [`IsolateHandle::terminate_execution`]
@@ -968,25 +969,23 @@ impl Isolate {
968969 & mut self ,
969970 create_param_allocations : Box < dyn Any > ,
970971 ) {
971- let annex_arc = Arc :: new ( IsolateAnnex :: new ( self , create_param_allocations) ) ;
972- let annex_ptr = Arc :: into_raw ( annex_arc ) ;
972+ let annex_box = Box :: new ( IsolateAnnex :: new ( self , create_param_allocations) ) ;
973+ let annex_ptr = Box :: into_raw ( annex_box ) ;
973974 assert ! ( self . get_data_internal( Self :: ANNEX_SLOT ) . is_null( ) ) ;
974975 self . set_data_internal ( Self :: ANNEX_SLOT , annex_ptr as * mut _ ) ;
975976 }
976977
977978 unsafe fn dispose_annex ( & mut self ) -> Box < dyn Any > {
979+ // SAFETY: `dispose_annex()` is only called once, when the `Isolate` is dropped.
980+ let mut annex = unsafe { self . take_annex ( ) } ;
981+
978982 // Set the `isolate` pointer inside the annex struct to null, so any
979983 // IsolateHandle that outlives the isolate will know that it can't call
980984 // methods on the isolate.
981- let annex = self . get_annex_mut ( ) ;
982- {
983- let _lock = annex. isolate_mutex . lock ( ) . unwrap ( ) ;
984- annex. isolate = null_mut ( ) ;
985- }
985+ annex. isolate_handle . dispose ( ) ;
986986
987987 // Clear slots and drop owned objects that were taken out of `CreateParams`.
988- let create_param_allocations =
989- std:: mem:: replace ( & mut annex. create_param_allocations , Box :: new ( ( ) ) ) ;
988+ let create_param_allocations = annex. create_param_allocations ;
990989 annex. slots . clear ( ) ;
991990
992991 // Run through any remaining guaranteed finalizers.
@@ -996,10 +995,6 @@ impl Isolate {
996995 }
997996 }
998997
999- // Subtract one from the Arc<IsolateAnnex> reference count.
1000- unsafe { Arc :: from_raw ( annex) } ;
1001- self . set_data ( 0 , null_mut ( ) ) ;
1002-
1003998 create_param_allocations
1004999 }
10051000
@@ -1019,6 +1014,15 @@ impl Isolate {
10191014 unsafe { & mut * annex_ptr }
10201015 }
10211016
1017+ /// # Safety
1018+ /// This must only be called once.
1019+ #[ inline( always) ]
1020+ unsafe fn take_annex ( & mut self ) -> Box < IsolateAnnex > {
1021+ let annex_ptr =
1022+ self . take_data_internal ( Self :: ANNEX_SLOT ) as * mut IsolateAnnex ;
1023+ unsafe { Box :: from_raw ( annex_ptr) }
1024+ }
1025+
10221026 pub ( crate ) fn set_snapshot_creator (
10231027 & mut self ,
10241028 snapshot_creator : SnapshotCreator ,
@@ -1038,13 +1042,6 @@ impl Isolate {
10381042 & mut self . get_annex_mut ( ) . finalizer_map
10391043 }
10401044
1041- fn get_annex_arc ( & self ) -> Arc < IsolateAnnex > {
1042- let annex_ptr = self . get_annex ( ) ;
1043- let annex_arc = unsafe { Arc :: from_raw ( annex_ptr) } ;
1044- let _ = Arc :: into_raw ( annex_arc. clone ( ) ) ;
1045- annex_arc
1046- }
1047-
10481045 /// Retrieve embedder-specific data from the isolate.
10491046 /// Returns NULL if SetData has never been called for the given `slot`.
10501047 pub fn get_data ( & self , slot : u32 ) -> * mut c_void {
@@ -1075,6 +1072,14 @@ impl Isolate {
10751072 unsafe { v8__Isolate__SetData ( self . as_real_ptr ( ) , slot, data) }
10761073 }
10771074
1075+ /// Get the value of the slot and replace it with a null pointer.
1076+ #[ inline( always) ]
1077+ fn take_data_internal ( & mut self , slot : u32 ) -> * mut c_void {
1078+ let ptr = self . get_data_internal ( slot) ;
1079+ self . set_data_internal ( slot, null_mut ( ) ) ;
1080+ ptr
1081+ }
1082+
10781083 // pub(crate) fn init_scope_root(&mut self) {
10791084 // ScopeData::new_root(self);
10801085 // }
@@ -1864,65 +1869,111 @@ pub(crate) struct IsolateAnnex {
18641869 slots : HashMap < TypeId , RawSlot , BuildTypeIdHasher > ,
18651870 finalizer_map : FinalizerMap ,
18661871 maybe_snapshot_creator : Option < SnapshotCreator > ,
1867- // The `isolate` and `isolate_mutex` fields are there so an `IsolateHandle`
1868- // (which may outlive the isolate itself) can determine whether the isolate
1869- // is still alive, and if so, get a reference to it. Safety rules:
1870- // - The 'main thread' must lock the mutex and reset `isolate` to null just
1871- // before the isolate is disposed.
1872- // - Any other thread must lock the mutex while it's reading/using the
1873- // `isolate` pointer.
1874- isolate : * mut RealIsolate ,
1875- isolate_mutex : Mutex < ( ) > ,
1872+ isolate_handle : IsolateHandle ,
18761873}
18771874
1878- unsafe impl Send for IsolateAnnex { }
1879- unsafe impl Sync for IsolateAnnex { }
1880-
18811875impl IsolateAnnex {
1882- fn new (
1883- isolate : & mut Isolate ,
1884- create_param_allocations : Box < dyn Any > ,
1885- ) -> Self {
1876+ fn new ( isolate : & Isolate , create_param_allocations : Box < dyn Any > ) -> Self {
18861877 Self {
18871878 create_param_allocations,
18881879 slots : HashMap :: default ( ) ,
18891880 finalizer_map : FinalizerMap :: default ( ) ,
18901881 maybe_snapshot_creator : None ,
1891- isolate : isolate. as_real_ptr ( ) ,
1892- isolate_mutex : Mutex :: new ( ( ) ) ,
1882+ isolate_handle : IsolateHandle :: new ( isolate) ,
18931883 }
18941884 }
18951885}
18961886
18971887impl Debug for IsolateAnnex {
18981888 fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
18991889 f. debug_struct ( "IsolateAnnex" )
1900- . field ( "isolate" , & self . isolate )
1901- . field ( "isolate_mutex" , & self . isolate_mutex )
1890+ . field ( "isolate_handle" , & self . isolate_handle )
19021891 . finish ( )
19031892 }
19041893}
19051894
1906- /// IsolateHandle is a thread-safe reference to an Isolate. It's main use is to
1895+ pub ( crate ) struct IsolateHandleInner {
1896+ /// Safety invariants:
1897+ /// - The 'main thread' must lock the mutex and reset `isolate` to null just
1898+ /// before the isolate is disposed.
1899+ /// - Any other thread must lock the mutex while it's reading/using the
1900+ /// `isolate` pointer.
1901+ // These two fields can be replaced with a `Mutex<*mut RealIsolate>` once
1902+ // `Mutex::data_ptr()` is stabilized.
1903+ isolate : UnsafeCell < * mut RealIsolate > ,
1904+ isolate_mutex : Mutex < ( ) > ,
1905+ }
1906+
1907+ unsafe impl Send for IsolateHandleInner { }
1908+ unsafe impl Sync for IsolateHandleInner { }
1909+
1910+ /// IsolateHandle is a thread-safe reference to an Isolate. Its main use is to
19071911/// terminate execution of a running isolate from another thread.
19081912///
1909- /// It is created with Isolate::thread_safe_handle().
1913+ /// It is created with [` Isolate::thread_safe_handle()`] .
19101914///
19111915/// IsolateHandle is Cloneable, Send, and Sync.
1912- #[ derive( Clone , Debug ) ]
1913- pub struct IsolateHandle ( Arc < IsolateAnnex > ) ;
1916+ #[ derive( Clone ) ]
1917+ pub struct IsolateHandle ( Arc < IsolateHandleInner > ) ;
19141918
1915- impl IsolateHandle {
1916- // This function is marked unsafe because it must be called only with either
1917- // IsolateAnnex::mutex locked, or from the main thread associated with the V8
1918- // isolate.
1919- pub ( crate ) unsafe fn get_isolate_ptr ( & self ) -> * mut RealIsolate {
1920- self . 0 . isolate
1919+ impl fmt:: Debug for IsolateHandle {
1920+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
1921+ if let Ok ( _lock) = self . 0 . isolate_mutex . try_lock ( ) {
1922+ // SAFETY: mutex lock is held
1923+ let ptr = unsafe { * self . 0 . isolate . get ( ) } ;
1924+ f. debug_struct ( "IsolateHandle" )
1925+ . field ( "isolate_ptr" , & ptr)
1926+ . finish ( )
1927+ } else {
1928+ f. debug_struct ( "IsolateHandle" ) . finish_non_exhaustive ( )
1929+ }
19211930 }
1931+ }
19221932
1933+ impl IsolateHandle {
19231934 #[ inline( always) ]
19241935 fn new ( isolate : & Isolate ) -> Self {
1925- Self ( isolate. get_annex_arc ( ) )
1936+ let inner = Arc :: new ( IsolateHandleInner {
1937+ isolate : UnsafeCell :: new ( isolate. as_real_ptr ( ) ) ,
1938+ isolate_mutex : Mutex :: new ( ( ) ) ,
1939+ } ) ;
1940+ Self ( inner)
1941+ }
1942+
1943+ /// Set the inner isolate pointer to null.
1944+ fn dispose ( self ) {
1945+ let _lock = self . 0 . isolate_mutex . lock ( ) . unwrap ( ) ;
1946+ // SAFETY: mutex lock is held
1947+ unsafe { * self . 0 . isolate . get ( ) = null_mut ( ) }
1948+ }
1949+
1950+ /// Access the isolate, if it hasn't yet been disposed of.
1951+ ///
1952+ /// A lock is taken on the pointer and held for the scope of `f`, which
1953+ /// means the isolate can't be dropped until after `f` returns. If you
1954+ /// do something with the isolate afterwards, that needs to be verified
1955+ /// to be safe separately.
1956+ pub ( crate ) fn with_isolate_ptr < R > (
1957+ & self ,
1958+ f : impl FnOnce ( NonNull < RealIsolate > ) -> R ,
1959+ ) -> Option < R > {
1960+ let _lock = self . 0 . isolate_mutex . lock ( ) . unwrap ( ) ;
1961+ // SAFETY: mutex lock is held
1962+ let ptr = unsafe { * self . 0 . isolate . get ( ) } ;
1963+ NonNull :: new ( ptr) . map ( f)
1964+ }
1965+
1966+ /// Access the pointer for this isolate - it may be null.
1967+ ///
1968+ /// # Safety
1969+ /// This function must only be called from the main thread associated with
1970+ /// the V8 isolate.
1971+ // TODO: have this return an `Option<NonNull<RealIsolate>>`
1972+ pub ( crate ) unsafe fn get_isolate_ptr ( & self ) -> * mut RealIsolate {
1973+ // SAFETY: this function must only be called from the main thread of the
1974+ // isolate, which means that `Isolate::dispose_annex` can't concurrently
1975+ // be setting this to null.
1976+ unsafe { * self . 0 . isolate . get ( ) }
19261977 }
19271978
19281979 /// Forcefully terminate the current thread of JavaScript execution
@@ -1934,13 +1985,11 @@ impl IsolateHandle {
19341985 /// Returns false if Isolate was already destroyed.
19351986 #[ inline( always) ]
19361987 pub fn terminate_execution ( & self ) -> bool {
1937- let _lock = self . 0 . isolate_mutex . lock ( ) . unwrap ( ) ;
1938- if self . 0 . isolate . is_null ( ) {
1939- false
1940- } else {
1941- unsafe { v8__Isolate__TerminateExecution ( self . 0 . isolate ) } ;
1942- true
1943- }
1988+ self
1989+ . with_isolate_ptr ( |isolate| unsafe {
1990+ v8__Isolate__TerminateExecution ( isolate. as_ptr ( ) )
1991+ } )
1992+ . is_some ( )
19441993 }
19451994
19461995 /// Resume execution capability in the given isolate, whose execution
@@ -1959,13 +2008,11 @@ impl IsolateHandle {
19592008 /// Returns false if Isolate was already destroyed.
19602009 #[ inline( always) ]
19612010 pub fn cancel_terminate_execution ( & self ) -> bool {
1962- let _lock = self . 0 . isolate_mutex . lock ( ) . unwrap ( ) ;
1963- if self . 0 . isolate . is_null ( ) {
1964- false
1965- } else {
1966- unsafe { v8__Isolate__CancelTerminateExecution ( self . 0 . isolate ) } ;
1967- true
1968- }
2011+ self
2012+ . with_isolate_ptr ( |isolate| unsafe {
2013+ v8__Isolate__CancelTerminateExecution ( isolate. as_ptr ( ) )
2014+ } )
2015+ . is_some ( )
19692016 }
19702017
19712018 /// Is V8 terminating JavaScript execution.
@@ -1978,12 +2025,11 @@ impl IsolateHandle {
19782025 /// Returns false if Isolate was already destroyed.
19792026 #[ inline( always) ]
19802027 pub fn is_execution_terminating ( & self ) -> bool {
1981- let _lock = self . 0 . isolate_mutex . lock ( ) . unwrap ( ) ;
1982- if self . 0 . isolate . is_null ( ) {
1983- false
1984- } else {
1985- unsafe { v8__Isolate__IsExecutionTerminating ( self . 0 . isolate ) }
1986- }
2028+ self
2029+ . with_isolate_ptr ( |isolate| unsafe {
2030+ v8__Isolate__IsExecutionTerminating ( isolate. as_ptr ( ) )
2031+ } )
2032+ . unwrap_or ( false )
19872033 }
19882034
19892035 /// Request V8 to interrupt long running JavaScript code and invoke
@@ -2003,13 +2049,11 @@ impl IsolateHandle {
20032049 callback : InterruptCallback ,
20042050 data : * mut c_void ,
20052051 ) -> bool {
2006- let _lock = self . 0 . isolate_mutex . lock ( ) . unwrap ( ) ;
2007- if self . 0 . isolate . is_null ( ) {
2008- false
2009- } else {
2010- unsafe { v8__Isolate__RequestInterrupt ( self . 0 . isolate , callback, data) } ;
2011- true
2012- }
2052+ self
2053+ . with_isolate_ptr ( |isolate| unsafe {
2054+ v8__Isolate__RequestInterrupt ( isolate. as_ptr ( ) , callback, data)
2055+ } )
2056+ . is_some ( )
20132057 }
20142058}
20152059
0 commit comments