@@ -13,7 +13,7 @@ use crate::runtime::vm::vmcontext::{
1313 VMTableDefinition , VMTableImport , VMTagDefinition , VMTagImport ,
1414} ;
1515use crate :: runtime:: vm:: {
16- GcStore , HostResult , Imports , ModuleRuntimeInfo , SendSyncPtr , VMGlobalKind , VMStore ,
16+ GcStore , HostResult , Imports , ModuleRuntimeInfo , SendSyncPtr , VMGcRef , VMGlobalKind , VMStore ,
1717 VMStoreRawPtr , VmPtr , VmSafe , WasmFault , catch_unwind_and_record_trap,
1818} ;
1919use crate :: store:: {
@@ -133,7 +133,7 @@ pub struct Instance {
133133 //
134134 // TODO(#12621): This should be a `TrySecondaryMap<PassiveElemIndex, _>`
135135 // but that type is currently footgun-y / isn't actually OOM-safe yet.
136- passive_elements : TryVec < Option < ( NeedsGcRooting , TryVec < ValRaw > ) > > ,
136+ passive_elements : TryVec < PassiveElementSegment > ,
137137
138138 /// Stores the dropped passive data segments in this instantiation by index.
139139 /// If the index is present in the set, the segment has been dropped.
@@ -225,8 +225,8 @@ impl Instance {
225225 gc_roots : & mut crate :: vm:: GcRootsList ,
226226 ) {
227227 for segment in self . passive_elements_mut ( ) . iter_mut ( ) {
228- if let Some ( ( wasmtime_environ :: NeedsGcRooting :: Yes , elems ) ) = segment {
229- for e in elems {
228+ if segment . needs_gc_rooting ( ) == NeedsGcRooting :: Yes {
229+ for e in segment . elements ( ) {
230230 let Some ( root) = e. as_vmgc_ref_ptr ( ) else {
231231 continue ;
232232 } ;
@@ -912,16 +912,12 @@ impl Instance {
912912 return & [ ] ;
913913 } ;
914914
915- let Some ( ( _, seg) ) = & self . passive_elements [ passive. index ( ) ] else {
916- return & [ ] ;
917- } ;
918-
919- & * * seg
915+ self . passive_elements [ passive. index ( ) ] . elements ( )
920916 }
921917
922918 pub ( crate ) fn passive_elements_mut (
923919 self : Pin < & mut Self > ,
924- ) -> Pin < & mut TryVec < Option < ( NeedsGcRooting , TryVec < ValRaw > ) > > > {
920+ ) -> Pin < & mut TryVec < PassiveElementSegment > > {
925921 // SAFETY: Not moving data out of `self`.
926922 Pin :: new ( & mut unsafe { self . get_unchecked_mut ( ) } . passive_elements )
927923 }
@@ -996,6 +992,7 @@ impl Instance {
996992 /// Drop an element.
997993 pub ( crate ) fn elem_drop (
998994 self : Pin < & mut Self > ,
995+ gc_store : Option < & mut GcStore > ,
999996 elem_index : ElemIndex ,
1000997 ) -> Result < ( ) , OutOfMemory > {
1001998 // https://webassembly.github.io/reference-types/core/exec/instructions.html#exec-elem-drop
@@ -1010,7 +1007,7 @@ impl Instance {
10101007 return Ok ( ( ) ) ;
10111008 } ;
10121009
1013- self . passive_elements_mut ( ) [ passive_index. index ( ) ] = None ;
1010+ self . passive_elements_mut ( ) [ passive_index. index ( ) ] . clear ( gc_store ) ;
10141011 Ok ( ( ) )
10151012 }
10161013
@@ -1922,3 +1919,77 @@ impl<T: InstanceLayout> Drop for OwnedInstance<T> {
19221919 }
19231920 }
19241921}
1922+
1923+ #[ derive( Debug ) ]
1924+ pub ( crate ) struct PassiveElementSegment {
1925+ needs_gc_rooting : NeedsGcRooting ,
1926+ elements : TryVec < ValRaw > ,
1927+ }
1928+
1929+ impl PassiveElementSegment {
1930+ /// Create a new passive element segment with the given capacity.
1931+ pub ( crate ) fn new (
1932+ needs_gc_rooting : NeedsGcRooting ,
1933+ capacity : usize ,
1934+ ) -> Result < Self , OutOfMemory > {
1935+ Ok ( Self {
1936+ needs_gc_rooting,
1937+ elements : TryVec :: with_capacity ( capacity) ?,
1938+ } )
1939+ }
1940+
1941+ /// Push a value onto this passive element segment.
1942+ ///
1943+ /// NB: Does not type check the value, relies on callers to ensure the value
1944+ /// is of the correct type (generally, due to validation).
1945+ pub ( crate ) fn push ( & mut self , store : & mut StoreOpaque , val : Val ) -> Result < ( ) > {
1946+ let val = {
1947+ let mut store = AutoAssertNoGc :: new ( store) ;
1948+ val. to_raw_ ( & mut store) ?
1949+ } ;
1950+ let val = self . clone_gc_ref ( store, val) ;
1951+ self . elements . push ( val) ?;
1952+ Ok ( ( ) )
1953+ }
1954+
1955+ fn clone_gc_ref ( & mut self , store : & mut StoreOpaque , val : ValRaw ) -> ValRaw {
1956+ if let NeedsGcRooting :: Yes = self . needs_gc_rooting {
1957+ let gc_ref = val. get_anyref ( ) ;
1958+ if let Some ( gc_ref) = VMGcRef :: from_raw_u32 ( gc_ref) {
1959+ if let Some ( gc_store) = store. optional_gc_store_mut ( ) {
1960+ return ValRaw :: anyref ( gc_store. clone_gc_ref ( & gc_ref) . as_raw_u32 ( ) ) ;
1961+ }
1962+ }
1963+ }
1964+ val
1965+ }
1966+
1967+ /// Clear this segment's elements.
1968+ pub ( crate ) fn clear ( & mut self , mut gc_store : Option < & mut GcStore > ) {
1969+ for val in mem:: take ( & mut self . elements ) {
1970+ self . drop_gc_ref ( & mut gc_store, val) ;
1971+ }
1972+ }
1973+
1974+ fn drop_gc_ref ( & mut self , gc_store : & mut Option < & mut GcStore > , val : ValRaw ) {
1975+ if let NeedsGcRooting :: Yes = self . needs_gc_rooting {
1976+ let gc_ref = val. get_anyref ( ) ;
1977+ if let Some ( gc_ref) = VMGcRef :: from_raw_u32 ( gc_ref) {
1978+ if let Some ( gc_store) = gc_store. as_deref_mut ( ) {
1979+ let _ = gc_store. drop_gc_ref ( gc_ref) ;
1980+ }
1981+ }
1982+ }
1983+ }
1984+
1985+ /// Whether this segment needs GC rooting and tracing.
1986+ #[ cfg( feature = "gc" ) ]
1987+ pub ( crate ) fn needs_gc_rooting ( & self ) -> NeedsGcRooting {
1988+ self . needs_gc_rooting
1989+ }
1990+
1991+ /// The elements of this segment.
1992+ pub ( crate ) fn elements ( & self ) -> & [ ValRaw ] {
1993+ & self . elements
1994+ }
1995+ }
0 commit comments