Skip to content

Commit 3ce7fdb

Browse files
authored
Refactor internals of PassiveElementSegment (#13187)
In looking over #13179 I found it a bit brittle to access `anyref` fields unconditionally where the determination that the type of the segment was a GC reference was made much further away. I also found it somewhat confusing to have methods like `clone_gc_ref` and `drop_gc_ref` applied to all values which happened to be noops for non-gc-ref types. I've refactored things a bit internally here to plumb a `WasmRefType` around and have additionally added comments to why `anyref` accessors are used despite the value possibly having an `exnref` or `externref` type.
1 parent d207ae1 commit 3ce7fdb

4 files changed

Lines changed: 39 additions & 64 deletions

File tree

crates/environ/src/compile/module_environ.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::module::{
33
FuncRefIndex, Initializer, MemoryInitialization, MemoryInitializer, Module, TableSegment,
44
TableSegmentElements,
55
};
6+
use crate::prelude::*;
67
use crate::{
78
ConstExpr, ConstOp, DataIndex, DefinedFuncIndex, ElemIndex, EngineOrModuleTypeIndex,
89
EntityIndex, EntityType, FuncIndex, FuncKey, GlobalIndex, IndexType, InitMemory, MemoryIndex,
@@ -11,7 +12,6 @@ use crate::{
1112
Tunables, TypeConvert, TypeIndex, WasmError, WasmHeapTopType, WasmHeapType, WasmResult,
1213
WasmValType, WasmparserTypeConverter,
1314
};
14-
use crate::{NeedsGcRooting, prelude::*};
1515
use cranelift_entity::SecondaryMap;
1616
use cranelift_entity::packed_option::ReservedValue;
1717
use std::borrow::Cow;
@@ -543,11 +543,7 @@ impl<'a, 'data> ModuleEnvironment<'a, 'data> {
543543
}
544544
}
545545
TableSegmentElements::Expressions {
546-
needs_gc_rooting: if ty.is_vmgcref_type_and_not_i31() {
547-
NeedsGcRooting::Yes
548-
} else {
549-
NeedsGcRooting::No
550-
},
546+
ty,
551547
exprs: exprs.into(),
552548
}
553549
}

crates/environ/src/module.rs

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -266,15 +266,6 @@ pub struct TableSegment {
266266
pub elements: TableSegmentElements,
267267
}
268268

269-
/// Does something need GC rooting?
270-
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
271-
pub enum NeedsGcRooting {
272-
/// GC rooting is needed.
273-
Yes,
274-
/// GC rooting is not needed.
275-
No,
276-
}
277-
278269
/// Elements of a table segment, either a list of functions or list of arbitrary
279270
/// expressions.
280271
#[derive(Clone, Debug, Serialize, Deserialize)]
@@ -284,9 +275,8 @@ pub enum TableSegmentElements {
284275
Functions(Box<[FuncIndex]>),
285276
/// Arbitrary expressions, aka either functions, null or a load of a global.
286277
Expressions {
287-
/// Is this expression's result of a type that needs GC rooting and
288-
/// tracing?
289-
needs_gc_rooting: NeedsGcRooting,
278+
/// The type of each element in `exprs`.
279+
ty: WasmRefType,
290280
/// The const expressions for this segment's elements.
291281
exprs: Box<[ConstExpr]>,
292282
},

crates/wasmtime/src/runtime/vm/instance.rs

Lines changed: 29 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ use wasmtime_environ::ModuleInternedTypeIndex;
3636
use wasmtime_environ::error::OutOfMemory;
3737
use wasmtime_environ::{
3838
DataIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, DefinedTagIndex,
39-
ElemIndex, EntityIndex, EntityRef, FuncIndex, GlobalIndex, HostPtr, MemoryIndex,
40-
NeedsGcRooting, PtrSize, TableIndex, TableInitialValue, TagIndex, Trap, VMCONTEXT_MAGIC,
41-
VMOffsets, VMSharedTypeIndex, packed_option::ReservedValue,
39+
ElemIndex, EntityIndex, EntityRef, FuncIndex, GlobalIndex, HostPtr, MemoryIndex, PtrSize,
40+
TableIndex, TableInitialValue, TagIndex, Trap, VMCONTEXT_MAGIC, VMOffsets, VMSharedTypeIndex,
41+
WasmRefType, packed_option::ReservedValue,
4242
};
4343
#[cfg(feature = "wmemcheck")]
4444
use wasmtime_wmemcheck::Wmemcheck;
@@ -225,7 +225,7 @@ impl Instance {
225225
gc_roots: &mut crate::vm::GcRootsList,
226226
) {
227227
for segment in self.passive_elements_mut().iter_mut() {
228-
if segment.needs_gc_rooting() == NeedsGcRooting::Yes {
228+
if segment.needs_gc_rooting {
229229
for e in segment.elements() {
230230
let Some(root) = e.as_vmgc_ref_ptr() else {
231231
continue;
@@ -1922,58 +1922,59 @@ impl<T: InstanceLayout> Drop for OwnedInstance<T> {
19221922

19231923
#[derive(Debug)]
19241924
pub(crate) struct PassiveElementSegment {
1925-
needs_gc_rooting: NeedsGcRooting,
1925+
needs_gc_rooting: bool,
19261926
elements: TryVec<ValRaw>,
19271927
}
19281928

19291929
impl PassiveElementSegment {
19301930
/// 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> {
1931+
pub(crate) fn new(ty: WasmRefType, capacity: usize) -> Result<Self, OutOfMemory> {
19351932
Ok(Self {
1936-
needs_gc_rooting,
1933+
needs_gc_rooting: ty.is_vmgcref_type_and_not_i31(),
19371934
elements: TryVec::with_capacity(capacity)?,
19381935
})
19391936
}
19401937

19411938
/// Push a value onto this passive element segment.
19421939
///
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).
1940+
/// NB: Does not type check the value, relies on callers to ensure the
1941+
/// value is of the correct type (generally, due to validation).
19451942
pub(crate) fn push(&mut self, store: &mut StoreOpaque, val: Val) -> Result<()> {
1946-
let val = {
1943+
let mut val = {
19471944
let mut store = AutoAssertNoGc::new(store);
19481945
val.to_raw_(&mut store)?
19491946
};
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 {
1947+
if self.needs_gc_rooting {
1948+
// Note that `anyref` accessors and constructors are used here
1949+
// without actually checking the type of this segment or value. The
1950+
// representation and handling of all three is the same which means
1951+
// that this should work out.
19571952
let gc_ref = val.get_anyref();
1953+
debug_assert_eq!(gc_ref, val.get_exnref());
1954+
debug_assert_eq!(gc_ref, val.get_externref());
19581955
if let Some(gc_ref) = VMGcRef::from_raw_u32(gc_ref) {
19591956
if let Some(gc_store) = store.optional_gc_store_mut() {
1960-
return ValRaw::anyref(gc_store.clone_gc_ref(&gc_ref).as_raw_u32());
1957+
val = ValRaw::anyref(gc_store.clone_gc_ref(&gc_ref).as_raw_u32());
19611958
}
19621959
}
19631960
}
1964-
val
1961+
self.elements.push(val)?;
1962+
Ok(())
19651963
}
19661964

19671965
/// Clear this segment's elements.
19681966
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);
1967+
let elements = mem::take(&mut self.elements);
1968+
if !self.needs_gc_rooting {
1969+
return;
19711970
}
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 {
1971+
for val in elements {
1972+
// Like above, `anyref` accessors are used here even if this
1973+
// element segment has a different type because all of the vmgcref
1974+
// types are treated the same way.
19761975
let gc_ref = val.get_anyref();
1976+
debug_assert_eq!(gc_ref, val.get_exnref());
1977+
debug_assert_eq!(gc_ref, val.get_externref());
19771978
if let Some(gc_ref) = VMGcRef::from_raw_u32(gc_ref) {
19781979
if let Some(gc_store) = gc_store.as_deref_mut() {
19791980
let _ = gc_store.drop_gc_ref(gc_ref);
@@ -1982,12 +1983,6 @@ impl PassiveElementSegment {
19821983
}
19831984
}
19841985

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-
19911986
/// The elements of this segment.
19921987
pub(crate) fn elements(&self) -> &[ValRaw] {
19931988
&self.elements

crates/wasmtime/src/runtime/vm/instance/allocator.rs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ use core::pin::Pin;
1414
use core::{mem, ptr};
1515
use wasmtime_environ::{
1616
DefinedMemoryIndex, DefinedTableIndex, EntityRef, HostPtr, InitMemory, MemoryInitialization,
17-
MemoryInitializer, Module, NeedsGcRooting, SizeOverflow, TableInitialValue,
18-
TableSegmentElements, Trap, VMOffsets,
17+
MemoryInitializer, Module, SizeOverflow, TableInitialValue, TableSegmentElements, Trap,
18+
VMOffsets, WasmRefType,
1919
};
2020

2121
#[cfg(feature = "gc")]
@@ -597,10 +597,7 @@ async fn initialize_tables(
597597
table.set_(&mut store, i, func.into())?;
598598
}
599599
}
600-
TableSegmentElements::Expressions {
601-
exprs,
602-
needs_gc_rooting: _,
603-
} => {
600+
TableSegmentElements::Expressions { exprs, ty: _ } => {
604601
for (i, expr) in positions.zip(exprs) {
605602
let val = const_evaluator
606603
.eval(&mut store, limiter.as_deref_mut(), context, expr)
@@ -861,7 +858,7 @@ async fn initialize_passive_elements(
861858
match segment {
862859
TableSegmentElements::Functions(func_indices) => {
863860
let mut segment =
864-
PassiveElementSegment::new(NeedsGcRooting::No, func_indices.len())?;
861+
PassiveElementSegment::new(WasmRefType::FUNCREF, func_indices.len())?;
865862
for func_idx in func_indices {
866863
let (instance, registry) =
867864
store.instance_and_module_registry_mut(context.instance);
@@ -873,11 +870,8 @@ async fn initialize_passive_elements(
873870
debug_assert_eq!(instance.passive_elements.len(), idx.index());
874871
instance.passive_elements_mut().push(segment)?;
875872
}
876-
TableSegmentElements::Expressions {
877-
needs_gc_rooting,
878-
exprs,
879-
} => {
880-
let mut segment = PassiveElementSegment::new(*needs_gc_rooting, exprs.len())?;
873+
TableSegmentElements::Expressions { ty, exprs } => {
874+
let mut segment = PassiveElementSegment::new(*ty, exprs.len())?;
881875
for expr in exprs {
882876
let mut store = OpaqueRootScope::new(&mut *store);
883877
let val = const_evaluator

0 commit comments

Comments
 (0)