From 34f71bec29e15fcb92e5c1885c66375caff9ed14 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Tue, 9 Jul 2024 14:24:32 -0700 Subject: [PATCH] A handful of little tweaks for GC types (#8925) * A handful of little tweaks for GC types Splitting this out from a larger PR so that it is easier to review and everything can land quicker. * Don't use `Cow`, just use references --- crates/wasmtime/src/runtime/types.rs | 129 +++++++++++++++++++++++---- 1 file changed, 113 insertions(+), 16 deletions(-) diff --git a/crates/wasmtime/src/runtime/types.rs b/crates/wasmtime/src/runtime/types.rs index 029aecfc9c..d4f43c9e22 100644 --- a/crates/wasmtime/src/runtime/types.rs +++ b/crates/wasmtime/src/runtime/types.rs @@ -127,6 +127,9 @@ impl ValType { /// The `externref` type, aka `(ref null extern)`. pub const EXTERNREF: Self = ValType::Ref(RefType::EXTERNREF); + /// The `nullexternref` type, aka `(ref null noextern)`. + pub const NULLEXTERNREF: Self = ValType::Ref(RefType::NULLEXTERNREF); + /// The `funcref` type, aka `(ref null func)`. pub const FUNCREF: Self = ValType::Ref(RefType::FUNCREF); @@ -139,6 +142,9 @@ impl ValType { /// The `i31ref` type, aka `(ref null i31)`. pub const I31REF: Self = ValType::Ref(RefType::I31REF); + /// The `structref` type, aka `(ref null struct)`. + pub const STRUCTREF: Self = ValType::Ref(RefType::STRUCTREF); + /// The `nullref` type, aka `(ref null none)`. pub const NULLREF: Self = ValType::Ref(RefType::NULLREF); @@ -371,6 +377,12 @@ impl RefType { heap_type: HeapType::Extern, }; + /// The `nullexternref` type, aka `(ref null noextern)`. + pub const NULLEXTERNREF: Self = RefType { + is_nullable: true, + heap_type: HeapType::NoExtern, + }; + /// The `funcref` type, aka `(ref null func)`. pub const FUNCREF: Self = RefType { is_nullable: true, @@ -395,6 +407,12 @@ impl RefType { heap_type: HeapType::I31, }; + /// The `structref` type, aka `(ref null struct)`. + pub const STRUCTREF: Self = RefType { + is_nullable: true, + heap_type: HeapType::Struct, + }; + /// The `nullref` type, aka `(ref null none)`. pub const NULLREF: Self = RefType { is_nullable: true, @@ -752,7 +770,10 @@ impl HeapType { /// Types that are not concrete, user-defined types are abstract types. #[inline] pub fn is_concrete(&self) -> bool { - matches!(self, HeapType::ConcreteFunc(_) | HeapType::ConcreteArray(_)) + matches!( + self, + HeapType::ConcreteFunc(_) | HeapType::ConcreteArray(_) | HeapType::ConcreteStruct(_) + ) } /// Is this a concrete, user-defined function type? @@ -797,6 +818,27 @@ impl HeapType { self.as_concrete_array().unwrap() } + /// Is this a concrete, user-defined struct type? + pub fn is_concrete_struct(&self) -> bool { + matches!(self, HeapType::ConcreteStruct(_)) + } + + /// Get the underlying concrete, user-defined struct type, if any. + /// + /// Returns `None` for if this is not a concrete struct type. + pub fn as_concrete_struct(&self) -> Option<&StructType> { + match self { + HeapType::ConcreteStruct(f) => Some(f), + _ => None, + } + } + + /// Get the underlying concrete, user-defined type, panicking if this is not + /// a concrete struct type. + pub fn unwrap_concrete_struct(&self) -> &StructType { + self.as_concrete_struct().unwrap() + } + /// Get the top type of this heap type's type hierarchy. /// /// The returned heap type is a supertype of all types in this heap type's @@ -1198,6 +1240,16 @@ pub enum StorageType { ValType(ValType), } +impl fmt::Display for StorageType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + StorageType::I8 => write!(f, "i8"), + StorageType::I16 => write!(f, "i16"), + StorageType::ValType(ty) => fmt::Display::fmt(ty, f), + } + } +} + impl From for StorageType { #[inline] fn from(v: ValType) -> Self { @@ -1241,6 +1293,20 @@ impl StorageType { self.as_val_type().unwrap() } + /// Unpack this (possibly packed) storage type into a full `ValType`. + /// + /// If this is a `StorageType::ValType`, then the inner `ValType` is + /// returned as-is. + /// + /// If this is a packed `StorageType::I8` or `StorageType::I16, then a + /// `ValType::I32` is returned. + pub fn unpack(&self) -> &ValType { + match self { + StorageType::I8 | StorageType::I16 => &ValType::I32, + StorageType::ValType(ty) => ty, + } + } + /// Does this field type match the other field type? /// /// That is, is this field type a subtype of the other field type? @@ -1307,6 +1373,16 @@ pub struct FieldType { element_type: StorageType, } +impl fmt::Display for FieldType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.mutability.is_var() { + write!(f, "(mut {})", self.element_type) + } else { + fmt::Display::fmt(&self.element_type, f) + } + } +} + impl FieldType { /// Construct a new field type from the given parts. #[inline] @@ -1401,6 +1477,17 @@ pub struct StructType { registered_type: RegisteredType, } +impl fmt::Display for StructType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(struct")?; + for field in self.fields() { + write!(f, " (field {field})")?; + } + write!(f, ")")?; + Ok(()) + } +} + impl StructType { /// Construct a new `StructType` with the given field types. /// @@ -1576,15 +1663,19 @@ impl StructType { } pub(crate) fn comes_from_same_engine(&self, engine: &Engine) -> bool { - Engine::same(self.registered_type.engine(), engine) + Engine::same(self.registered_type().engine(), engine) } pub(crate) fn type_index(&self) -> VMSharedTypeIndex { - self.registered_type.index() + self.registered_type().index() } pub(crate) fn as_wasm_struct_type(&self) -> &WasmStructType { - self.registered_type.unwrap_struct() + self.registered_type().unwrap_struct() + } + + pub(crate) fn registered_type(&self) -> &RegisteredType { + &self.registered_type } /// Construct a `StructType` from a `WasmStructType`. @@ -1630,10 +1721,12 @@ impl StructType { "VMSharedTypeIndex is not registered in the Engine! Wrong \ engine? Didn't root the index somewhere?", ); - assert!(ty.is_struct()); - Self { - registered_type: ty, - } + Self::from_registered_type(ty) + } + + pub(crate) fn from_registered_type(registered_type: RegisteredType) -> Self { + debug_assert!(registered_type.is_struct()); + Self { registered_type } } } @@ -1860,10 +1953,12 @@ impl ArrayType { "VMSharedTypeIndex is not registered in the Engine! Wrong \ engine? Didn't root the index somewhere?", ); - assert!(ty.is_array()); - Self { - registered_type: ty, - } + Self::from_registered_type(ty) + } + + pub(crate) fn from_registered_type(registered_type: RegisteredType) -> Self { + debug_assert!(registered_type.is_array()); + Self { registered_type } } } @@ -2214,10 +2309,12 @@ impl FuncType { "VMSharedTypeIndex is not registered in the Engine! Wrong \ engine? Didn't root the index somewhere?", ); - assert!(ty.is_func()); - Self { - registered_type: ty, - } + Self::from_registered_type(ty) + } + + pub(crate) fn from_registered_type(registered_type: RegisteredType) -> Self { + debug_assert!(registered_type.is_func()); + Self { registered_type } } }