diff --git a/crates/wasmparser/src/binary_reader.rs b/crates/wasmparser/src/binary_reader.rs index 50dd3fb801..167783d16c 100644 --- a/crates/wasmparser/src/binary_reader.rs +++ b/crates/wasmparser/src/binary_reader.rs @@ -1001,11 +1001,24 @@ impl<'a> BinaryReader<'a> { { let code = self.read_var_u32()?; Ok(match code { + 0x01 => { + let type_index = self.read_var_u32()?; + visitor.visit_struct_new_default(type_index) + } + + 0x07 => { + let type_index = self.read_var_u32()?; + visitor.visit_array_new_default(type_index) + } + 0x14 => visitor.visit_ref_test_non_null(self.read()?), 0x15 => visitor.visit_ref_test_nullable(self.read()?), 0x16 => visitor.visit_ref_cast_non_null(self.read()?), 0x17 => visitor.visit_ref_cast_nullable(self.read()?), + 0x1a => visitor.visit_any_convert_extern(), + 0x1b => visitor.visit_extern_convert_any(), + 0x1c => visitor.visit_ref_i31(), 0x1d => visitor.visit_i31_get_s(), 0x1e => visitor.visit_i31_get_u(), diff --git a/crates/wasmparser/src/lib.rs b/crates/wasmparser/src/lib.rs index 9e8fd9ed5a..269bb580b8 100644 --- a/crates/wasmparser/src/lib.rs +++ b/crates/wasmparser/src/lib.rs @@ -316,13 +316,17 @@ macro_rules! for_each_operator { // 0xFB prefixed operators // Garbage Collection // http://github.com/WebAssembly/gc - @gc RefI31 => visit_ref_i31 - @gc I31GetS => visit_i31_get_s - @gc I31GetU => visit_i31_get_u + @gc StructNewDefault { type_index: u32 } => visit_struct_new_default + @gc ArrayNewDefault { type_index: u32 } => visit_array_new_default @gc RefTestNonNull { hty: $crate::HeapType } => visit_ref_test_non_null @gc RefTestNullable { hty: $crate::HeapType } => visit_ref_test_nullable @gc RefCastNonNull { hty: $crate::HeapType } => visit_ref_cast_non_null @gc RefCastNullable { hty: $crate::HeapType } => visit_ref_cast_nullable + @gc AnyConvertExtern => visit_any_convert_extern + @gc ExternConvertAny => visit_extern_convert_any + @gc RefI31 => visit_ref_i31 + @gc I31GetS => visit_i31_get_s + @gc I31GetU => visit_i31_get_u // 0xFC operators // Non-trapping Float-to-int Conversions diff --git a/crates/wasmparser/src/readers/core/types.rs b/crates/wasmparser/src/readers/core/types.rs index 6ebe3d485d..f1c42c6ace 100644 --- a/crates/wasmparser/src/readers/core/types.rs +++ b/crates/wasmparser/src/readers/core/types.rs @@ -409,6 +409,24 @@ pub struct SubType { pub composite_type: CompositeType, } +impl std::fmt::Display for SubType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.is_final && self.supertype_idx.is_none() { + std::fmt::Display::fmt(&self.composite_type, f) + } else { + write!(f, "(sub ")?; + if self.is_final { + write!(f, "final ")?; + } + if let Some(idx) = self.supertype_idx { + write!(f, "{idx} ")?; + } + std::fmt::Display::fmt(&self.composite_type, f)?; + write!(f, ")") + } + } +} + impl SubType { /// Unwrap an `ArrayType` or panic. /// @@ -472,6 +490,16 @@ pub enum CompositeType { Struct(StructType), } +impl std::fmt::Display for CompositeType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Self::Array(_) => write!(f, "(array ...)"), + Self::Func(_) => write!(f, "(func ...)"), + Self::Struct(_) => write!(f, "(struct ...)"), + } + } +} + impl CompositeType { /// Unwrap a `FuncType` or panic. pub fn unwrap_func(&self) -> &FuncType { @@ -629,6 +657,17 @@ pub enum StorageType { Val(ValType), } +impl StorageType { + /// Unpack this storage type into the valtype that it is represented as on + /// the operand stack. + pub fn unpack(&self) -> ValType { + match *self { + Self::Val(ty) => ty, + Self::I8 | Self::I16 => ValType::I32, + } + } +} + /// Represents a type of a struct in a WebAssembly module. #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct StructType { diff --git a/crates/wasmparser/src/resources.rs b/crates/wasmparser/src/resources.rs index 136dce05f6..4fc7e7550d 100644 --- a/crates/wasmparser/src/resources.rs +++ b/crates/wasmparser/src/resources.rs @@ -13,13 +13,39 @@ * limitations under the License. */ -use crate::types::CoreTypeId; use crate::{ - BinaryReaderError, FuncType, GlobalType, HeapType, MemoryType, RefType, TableType, ValType, - WasmFeatures, + types::CoreTypeId, ArrayType, BinaryReaderError, CompositeType, FuncType, GlobalType, HeapType, + MemoryType, RefType, StructType, SubType, TableType, ValType, WasmFeatures, }; use std::ops::Range; +/// Types that qualify as Wasm sub types for validation purposes. +pub trait WasmSubType: Clone + std::fmt::Display { + /// The associated array type. + type ArrayType: WasmArrayType; + + /// The associated function type. + type FuncType: WasmFuncType; + + /// The associated struct type. + type StructType: WasmStructType; + + /// Get the underlying array type, if any. + fn as_array_type(&self) -> Option<&Self::ArrayType>; + + /// Get the underlying func type, if any. + fn as_func_type(&self) -> Option<&Self::FuncType>; + + /// Get the underlying struct type, if any. + fn as_struct_type(&self) -> Option<&Self::StructType>; +} + +/// Types that qualify as Wasm array types for validation purposes. +pub trait WasmArrayType: Clone { + /// Get the array's field type. + fn field_type(&self) -> crate::FieldType; +} + /// Types that qualify as Wasm function types for validation purposes. pub trait WasmFuncType: Clone { /// Returns the number of input types. @@ -73,6 +99,15 @@ pub trait WasmFuncType: Clone { } } +/// Types that qualify as Wasm struct types for validation purposes. +pub trait WasmStructType: Clone { + /// Get the number of fields in this struct. + fn len_fields(&self) -> usize; + + /// Get the field at the given index. + fn field_at(&self, at: u32) -> Option; +} + impl WasmFuncType for &'_ T where T: ?Sized + WasmFuncType, @@ -192,6 +227,9 @@ where /// structure while parsing and also validate at the same time without /// the need of an additional parsing or validation step or copying data around. pub trait WasmModuleResources { + /// The sub type used for validation. + type SubType: WasmSubType; + /// The function type used for validation. type FuncType: WasmFuncType; @@ -213,10 +251,10 @@ pub trait WasmModuleResources { /// The global's value type must be canonicalized. fn global_at(&self, at: u32) -> Option; - /// Returns the `FuncType` associated with the given type index. + /// Returns the `SubType` associated with the given type index. /// - /// The function type must be canonicalized. - fn func_type_at(&self, type_idx: u32) -> Option<&Self::FuncType>; + /// The sub type must be canonicalized. + fn sub_type_at(&self, type_index: u32) -> Option<&Self::SubType>; /// Returns the type id associated with the given function /// index. @@ -289,6 +327,7 @@ impl WasmModuleResources for &'_ T where T: ?Sized + WasmModuleResources, { + type SubType = T::SubType; type FuncType = T::FuncType; fn table_at(&self, at: u32) -> Option { @@ -303,8 +342,8 @@ where fn global_at(&self, at: u32) -> Option { T::global_at(self, at) } - fn func_type_at(&self, at: u32) -> Option<&Self::FuncType> { - T::func_type_at(self, at) + fn sub_type_at(&self, at: u32) -> Option<&Self::SubType> { + T::sub_type_at(self, at) } fn type_id_of_function(&self, func_idx: u32) -> Option { T::type_id_of_function(self, func_idx) @@ -340,6 +379,7 @@ impl WasmModuleResources for std::sync::Arc where T: WasmModuleResources, { + type SubType = T::SubType; type FuncType = T::FuncType; fn table_at(&self, at: u32) -> Option { @@ -358,8 +398,8 @@ where T::global_at(self, at) } - fn func_type_at(&self, type_idx: u32) -> Option<&Self::FuncType> { - T::func_type_at(self, type_idx) + fn sub_type_at(&self, type_idx: u32) -> Option<&Self::SubType> { + T::sub_type_at(self, type_idx) } fn type_id_of_function(&self, func_idx: u32) -> Option { @@ -399,6 +439,39 @@ where } } +impl WasmSubType for SubType { + type ArrayType = ArrayType; + type FuncType = FuncType; + type StructType = StructType; + + fn as_array_type(&self) -> Option<&Self::ArrayType> { + match &self.composite_type { + CompositeType::Array(a) => Some(a), + _ => None, + } + } + + fn as_func_type(&self) -> Option<&Self::FuncType> { + match &self.composite_type { + CompositeType::Func(f) => Some(f), + _ => None, + } + } + + fn as_struct_type(&self) -> Option<&Self::StructType> { + match &self.composite_type { + CompositeType::Struct(s) => Some(s), + _ => None, + } + } +} + +impl WasmArrayType for ArrayType { + fn field_type(&self) -> crate::FieldType { + self.0 + } +} + impl WasmFuncType for FuncType { fn len_inputs(&self) -> usize { self.params().len() @@ -416,3 +489,13 @@ impl WasmFuncType for FuncType { self.results().get(at as usize).copied() } } + +impl WasmStructType for StructType { + fn len_fields(&self) -> usize { + self.fields.len() + } + + fn field_at(&self, at: u32) -> Option { + self.fields.get(usize::try_from(at).unwrap()).copied() + } +} diff --git a/crates/wasmparser/src/validator/core.rs b/crates/wasmparser/src/validator/core.rs index 25fb16282f..23945364ae 100644 --- a/crates/wasmparser/src/validator/core.rs +++ b/crates/wasmparser/src/validator/core.rs @@ -9,12 +9,12 @@ use super::{ operators::{ty_to_str, OperatorValidator, OperatorValidatorAllocations}, types::{CoreTypeId, EntityType, RecGroupId, TypeAlloc, TypeList}, }; -use crate::validator::types::TypeIdentifier; use crate::{ - limits::*, BinaryReaderError, CompositeType, ConstExpr, Data, DataKind, Element, ElementKind, - ExternalKind, FuncType, Global, GlobalType, HeapType, MemoryType, PackedIndex, RecGroup, - RefType, Result, StorageType, SubType, Table, TableInit, TableType, TagType, TypeRef, - UnpackedIndex, ValType, VisitOperator, WasmFeatures, WasmModuleResources, + limits::*, validator::types::TypeIdentifier, BinaryReaderError, CompositeType, ConstExpr, Data, + DataKind, Element, ElementKind, ExternalKind, FuncType, Global, GlobalType, HeapType, + MemoryType, PackedIndex, RecGroup, RefType, Result, StorageType, SubType, Table, TableInit, + TableType, TagType, TypeRef, UnpackedIndex, ValType, VisitOperator, WasmFeatures, + WasmModuleResources, WasmSubType, }; use indexmap::IndexMap; use std::mem; @@ -1155,6 +1155,7 @@ struct OperatorValidatorResources<'a> { } impl WasmModuleResources for OperatorValidatorResources<'_> { + type SubType = crate::SubType; type FuncType = crate::FuncType; fn table_at(&self, at: u32) -> Option { @@ -1174,12 +1175,9 @@ impl WasmModuleResources for OperatorValidatorResources<'_> { self.module.globals.get(at as usize).cloned() } - fn func_type_at(&self, at: u32) -> Option<&Self::FuncType> { + fn sub_type_at(&self, at: u32) -> Option<&Self::SubType> { let id = *self.module.types.get(at as usize)?; - match &self.types[id].composite_type { - CompositeType::Func(f) => Some(f), - _ => None, - } + Some(&self.types[id]) } fn type_id_of_function(&self, at: u32) -> Option { @@ -1189,7 +1187,7 @@ impl WasmModuleResources for OperatorValidatorResources<'_> { fn type_of_function(&self, at: u32) -> Option<&Self::FuncType> { let type_index = self.module.functions.get(at as usize)?; - self.func_type_at(*type_index) + self.sub_type_at(*type_index)?.as_func_type() } fn check_heap_type(&self, t: &mut HeapType, offset: usize) -> Result<()> { @@ -1226,6 +1224,7 @@ impl WasmModuleResources for OperatorValidatorResources<'_> { pub struct ValidatorResources(pub(crate) Arc); impl WasmModuleResources for ValidatorResources { + type SubType = crate::SubType; type FuncType = crate::FuncType; fn table_at(&self, at: u32) -> Option { @@ -1249,13 +1248,10 @@ impl WasmModuleResources for ValidatorResources { self.0.globals.get(at as usize).cloned() } - fn func_type_at(&self, at: u32) -> Option<&Self::FuncType> { + fn sub_type_at(&self, at: u32) -> Option<&Self::SubType> { let id = *self.0.types.get(at as usize)?; let types = self.0.snapshot.as_ref().unwrap(); - match &types[id].composite_type { - CompositeType::Func(f) => Some(f), - _ => None, - } + Some(&types[id]) } fn type_id_of_function(&self, at: u32) -> Option { @@ -1265,7 +1261,7 @@ impl WasmModuleResources for ValidatorResources { fn type_of_function(&self, at: u32) -> Option<&Self::FuncType> { let type_index = *self.0.functions.get(at as usize)?; - self.func_type_at(type_index) + self.sub_type_at(type_index)?.as_func_type() } fn check_heap_type(&self, t: &mut HeapType, offset: usize) -> Result<()> { diff --git a/crates/wasmparser/src/validator/func.rs b/crates/wasmparser/src/validator/func.rs index f003323c7a..5655752ddf 100644 --- a/crates/wasmparser/src/validator/func.rs +++ b/crates/wasmparser/src/validator/func.rs @@ -249,12 +249,13 @@ impl FuncValidator { mod tests { use super::*; use crate::types::CoreTypeId; - use crate::{HeapType, WasmFuncType}; + use crate::{HeapType, WasmFuncType, WasmSubType, WasmArrayType, WasmStructType}; struct EmptyResources; impl WasmModuleResources for EmptyResources { - type FuncType = EmptyFuncType; + type SubType = EmptySubType; + type FuncType = EmptySubType; fn table_at(&self, _at: u32) -> Option { todo!() @@ -268,8 +269,8 @@ mod tests { fn global_at(&self, _at: u32) -> Option { todo!() } - fn func_type_at(&self, _type_idx: u32) -> Option<&Self::FuncType> { - Some(&EmptyFuncType) + fn sub_type_at(&self, _type_idx: u32) -> Option<&Self::FuncType> { + Some(&EmptySubType) } fn type_id_of_function(&self, _at: u32) -> Option { todo!() @@ -300,10 +301,38 @@ mod tests { } } - #[derive(Clone)] - struct EmptyFuncType; + #[derive(Clone, Debug)] + struct EmptySubType; - impl WasmFuncType for EmptyFuncType { + impl std::fmt::Display for EmptySubType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Debug::fmt(self, f) + } + } + + impl WasmSubType for EmptySubType { + type ArrayType = Self; + type FuncType = Self; + type StructType = Self; + + fn as_array_type(&self) -> Option<&Self::ArrayType> { + Some(self) + } + fn as_func_type(&self) -> Option<&Self::FuncType> { + Some(self) + } + fn as_struct_type(&self) -> Option<&Self::StructType> { + Some(self) + } + } + + impl WasmArrayType for EmptySubType { + fn field_type(&self) -> crate::FieldType { + todo!() + } + } + + impl WasmFuncType for EmptySubType { fn len_inputs(&self) -> usize { 0 } @@ -318,6 +347,15 @@ mod tests { } } + impl WasmStructType for EmptySubType { + fn len_fields(&self) -> usize { + 0 + } + fn field_at(&self, _at: u32) -> Option { + todo!() + } + } + #[test] fn operand_stack_height() { let mut v = FuncToValidate::new(0, 0, EmptyResources, &Default::default()) diff --git a/crates/wasmparser/src/validator/operators.rs b/crates/wasmparser/src/validator/operators.rs index 9f6a73697d..06ae90c049 100644 --- a/crates/wasmparser/src/validator/operators.rs +++ b/crates/wasmparser/src/validator/operators.rs @@ -24,8 +24,8 @@ use crate::{ limits::MAX_WASM_FUNCTION_LOCALS, BinaryReaderError, BlockType, BrTable, HeapType, Ieee32, - Ieee64, MemArg, RefType, Result, UnpackedIndex, ValType, VisitOperator, WasmFeatures, - WasmFuncType, WasmModuleResources, V128, + Ieee64, MemArg, RefType, Result, UnpackedIndex, ValType, VisitOperator, WasmArrayType, + WasmFeatures, WasmFuncType, WasmModuleResources, WasmStructType, WasmSubType, V128, }; use std::ops::{Deref, DerefMut}; @@ -745,15 +745,7 @@ where } fn check_call_type_index(&mut self, type_index: u32) -> Result<()> { - let ty = match self.resources.func_type_at(type_index) { - Some(i) => i, - None => { - bail!( - self.offset, - "unknown type {type_index}: type index out of bounds", - ); - } - }; + let ty = self.func_type_at(type_index)?; self.check_call_ty(ty) } @@ -1025,12 +1017,51 @@ where self.push_operand(sub_ty) } - fn func_type_at(&self, at: u32) -> Result<&'resources R::FuncType> { + fn sub_type_at(&self, at: u32) -> Result<&'resources R::SubType> { self.resources - .func_type_at(at) + .sub_type_at(at) .ok_or_else(|| format_err!(self.offset, "unknown type: type index out of bounds")) } + fn struct_type_at( + &self, + at: u32, + ) -> Result<&'resources ::StructType> { + let sub_ty = self.sub_type_at(at)?; + if let Some(struct_ty) = sub_ty.as_struct_type() { + Ok(struct_ty) + } else { + bail!( + self.offset, + "expected struct type at index {at}, found {sub_ty}" + ) + } + } + + fn array_type_at(&self, at: u32) -> Result<&'resources ::ArrayType> { + let sub_ty = self.sub_type_at(at)?; + if let Some(array_ty) = sub_ty.as_array_type() { + Ok(array_ty) + } else { + bail!( + self.offset, + "expected array type at index {at}, found {sub_ty}" + ) + } + } + + fn func_type_at(&self, at: u32) -> Result<&'resources R::FuncType> { + let sub_ty = self.sub_type_at(at)?; + if let Some(func_ty) = sub_ty.as_func_type() { + Ok(func_ty) + } else { + bail!( + self.offset, + "expected func type at index {at}, found {sub_ty}" + ) + } + } + fn tag_at(&self, at: u32) -> Result<&'resources R::FuncType> { self.resources .tag_at(at) @@ -3442,6 +3473,79 @@ where self.pop_operand(Some(ValType::I32))?; Ok(()) } + fn visit_struct_new_default(&mut self, type_index: u32) -> Self::Output { + let ty = self.struct_type_at(type_index)?; + for i in 0..u32::try_from(ty.len_fields()).unwrap() { + let field = ty.field_at(i).unwrap(); + let val_ty = field.element_type.unpack(); + if !val_ty.is_defaultable() { + bail!( + self.offset, + "invalid `struct.new_default`: {val_ty} field is not defaultable" + ); + } + } + + let mut heap_ty = HeapType::Concrete(UnpackedIndex::Module(type_index)); + self.resources.check_heap_type(&mut heap_ty, self.offset)?; + + let ref_ty = RefType::new(false, heap_ty).ok_or_else(|| { + format_err!(self.offset, "implementation limit: type index too large") + })?; + + self.push_operand(ref_ty) + } + fn visit_array_new_default(&mut self, type_index: u32) -> Self::Output { + let ty = self.array_type_at(type_index)?; + let field = ty.field_type(); + let val_ty = field.element_type.unpack(); + if !val_ty.is_defaultable() { + bail!( + self.offset, + "invalid `array.new_default`: {val_ty} field is not defaultable" + ); + } + + let mut heap_ty = HeapType::Concrete(UnpackedIndex::Module(type_index)); + self.resources.check_heap_type(&mut heap_ty, self.offset)?; + + let ref_ty = RefType::new(false, heap_ty).ok_or_else(|| { + format_err!(self.offset, "implementation limit: type index too large") + })?; + + self.pop_operand(Some(ValType::I32))?; + self.push_operand(ref_ty) + } + fn visit_any_convert_extern(&mut self) -> Self::Output { + let extern_ref = match self.pop_ref()? { + Some(r) if self.resources.top_type(&r.heap_type()) == HeapType::Extern => r, + Some(r) => bail!( + self.offset, + "type mismatch: expected (ref null? extern), found {r}" + ), + None => bail!( + self.offset, + "type mismatch: expected (ref null? extern), found bottom" + ), + }; + let any_ref = RefType::new(extern_ref.is_nullable(), HeapType::Any).unwrap(); + self.push_operand(any_ref) + } + fn visit_extern_convert_any(&mut self) -> Self::Output { + let any_ref = match self.pop_ref()? { + Some(r) if self.resources.top_type(&r.heap_type()) == HeapType::Any => r, + Some(r) => bail!( + self.offset, + "type mismatch: expected (ref null? any), found {r}" + ), + None => bail!( + self.offset, + "type mismatch: expected (ref null? any), found bottom" + ), + }; + let extern_ref = RefType::new(any_ref.is_nullable(), HeapType::Extern).unwrap(); + self.push_operand(extern_ref) + } fn visit_ref_test_non_null(&mut self, heap_type: HeapType) -> Self::Output { self.check_ref_test(false, heap_type) } diff --git a/crates/wasmprinter/src/operator.rs b/crates/wasmprinter/src/operator.rs index 30559b17e9..ad38d4ba78 100644 --- a/crates/wasmprinter/src/operator.rs +++ b/crates/wasmprinter/src/operator.rs @@ -120,6 +120,12 @@ impl<'a, 'b> PrintOperator<'a, 'b> { self.printer.print_core_type_ref(self.state, idx) } + /// Like `self.type_index` but without the `(type ..)` wrapper. + fn type_index_no_type(&mut self, idx: u32) -> Result<()> { + self.push_str(" "); + self.printer.print_idx(&self.state.core.type_names, idx) + } + fn data_index(&mut self, idx: u32) -> Result<()> { self.printer.print_idx(&self.state.core.data_names, idx) } @@ -316,6 +322,12 @@ macro_rules! define_visit { )?; } ); + (payload $self:ident StructNewDefault $type_index: ident) => ( + $self.type_index_no_type($type_index)?; + ); + (payload $self:ident ArrayNewDefault $type_index: ident) => ( + $self.type_index_no_type($type_index)?; + ); (payload $self:ident RefTestNonNull $hty:ident) => ( $self.push_str(" "); let rty = RefType::new(false, $hty) @@ -885,6 +897,10 @@ macro_rules! define_visit { (name I16x8RelaxedQ15mulrS) => ("i16x8.relaxed_q15mulr_s"); (name I16x8RelaxedDotI8x16I7x16S) => ("i16x8.relaxed_dot_i8x16_i7x16_s"); (name I32x4RelaxedDotI8x16I7x16AddS) => ("i32x4.relaxed_dot_i8x16_i7x16_add_s"); + (name StructNewDefault) => ("struct.new_default"); + (name ArrayNewDefault) => ("array.new_default"); + (name AnyConvertExtern) => ("any.convert_extern"); + (name ExternConvertAny) => ("extern.convert_any"); (name RefTestNonNull) => ("ref.test"); (name RefTestNullable) => ("ref.test"); (name RefCastNonNull) => ("ref.cast"); diff --git a/tests/roundtrip.rs b/tests/roundtrip.rs index a22f37f806..f3adde04ae 100644 --- a/tests/roundtrip.rs +++ b/tests/roundtrip.rs @@ -153,9 +153,7 @@ fn skip_validation(test: &Path) -> bool { "proposals/gc/br_on_cast.wast", "proposals/gc/br_on_cast_fail.wast", "proposals/gc/extern.wast", - "proposals/gc/ref_cast.wast", "proposals/gc/ref_eq.wast", - "proposals/gc/ref_test.wast", "proposals/gc/struct.wast", "exnref/exnref.wast", "exnref/throw_ref.wast", diff --git a/tests/snapshots/testsuite/proposals/gc/ref_cast.wast/0.print b/tests/snapshots/testsuite/proposals/gc/ref_cast.wast/0.print new file mode 100644 index 0000000000..670af6f641 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/ref_cast.wast/0.print @@ -0,0 +1,107 @@ +(module + (type $ft (;0;) (func)) + (type $st (;1;) (struct)) + (type $at (;2;) (array i8)) + (type (;3;) (func (param externref))) + (type (;4;) (func (param i32))) + (func $f (;0;) (type $ft)) + (func (;1;) (type 3) (param $x externref) + i32.const 0 + ref.null any + table.set 0 + i32.const 1 + i32.const 7 + ref.i31 + table.set 0 + i32.const 2 + struct.new_default $st + table.set 0 + i32.const 3 + i32.const 0 + array.new_default $at + table.set 0 + i32.const 4 + local.get $x + any.convert_extern + table.set 0 + i32.const 5 + ref.null i31 + table.set 0 + i32.const 6 + ref.null struct + table.set 0 + i32.const 7 + ref.null none + table.set 0 + ) + (func (;2;) (type 4) (param $i i32) + local.get $i + table.get 0 + ref.as_non_null + drop + local.get $i + table.get 0 + ref.cast anyref + drop + ) + (func (;3;) (type 4) (param $i i32) + local.get $i + table.get 0 + ref.cast anyref + drop + local.get $i + table.get 0 + ref.cast structref + drop + local.get $i + table.get 0 + ref.cast arrayref + drop + local.get $i + table.get 0 + ref.cast i31ref + drop + local.get $i + table.get 0 + ref.cast nullref + drop + ) + (func (;4;) (type 4) (param $i i32) + local.get $i + table.get 0 + ref.cast (ref i31) + drop + local.get $i + table.get 0 + ref.cast i31ref + drop + ) + (func (;5;) (type 4) (param $i i32) + local.get $i + table.get 0 + ref.cast (ref struct) + drop + local.get $i + table.get 0 + ref.cast structref + drop + ) + (func (;6;) (type 4) (param $i i32) + local.get $i + table.get 0 + ref.cast (ref array) + drop + local.get $i + table.get 0 + ref.cast arrayref + drop + ) + (table (;0;) 10 anyref) + (export "init" (func 1)) + (export "ref_cast_non_null" (func 2)) + (export "ref_cast_null" (func 3)) + (export "ref_cast_i31" (func 4)) + (export "ref_cast_struct" (func 5)) + (export "ref_cast_array" (func 6)) + (elem (;0;) declare func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/ref_cast.wast/42.print b/tests/snapshots/testsuite/proposals/gc/ref_cast.wast/42.print new file mode 100644 index 0000000000..73cd7aa679 --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/ref_cast.wast/42.print @@ -0,0 +1,194 @@ +(module + (type $t0 (;0;) (sub (struct))) + (type $t1 (;1;) (sub $t0 (;0;) (struct (field i32)))) + (type $t1' (;2;) (sub $t0 (;0;) (struct (field i32)))) + (type $t2 (;3;) (sub $t1 (;1;) (struct (field i32) (field i32)))) + (type $t2' (;4;) (sub $t1' (;2;) (struct (field i32) (field i32)))) + (type $t3 (;5;) (sub $t0 (;0;) (struct (field i32) (field i32)))) + (type $t0' (;6;) (sub $t0 (;0;) (struct))) + (type $t4 (;7;) (sub $t0' (;6;) (struct (field i32) (field i32)))) + (type (;8;) (func)) + (func $init (;0;) (type 8) + i32.const 0 + struct.new_default $t0 + table.set 0 + i32.const 10 + struct.new_default $t0 + table.set 0 + i32.const 1 + struct.new_default $t1 + table.set 0 + i32.const 11 + struct.new_default $t1' + table.set 0 + i32.const 2 + struct.new_default $t2 + table.set 0 + i32.const 12 + struct.new_default $t2' + table.set 0 + i32.const 3 + struct.new_default $t3 + table.set 0 + i32.const 4 + struct.new_default $t4 + table.set 0 + ) + (func (;1;) (type 8) + call $init + ref.null struct + ref.cast (ref null 0) + drop + i32.const 0 + table.get 0 + ref.cast (ref null 0) + drop + i32.const 1 + table.get 0 + ref.cast (ref null 0) + drop + i32.const 2 + table.get 0 + ref.cast (ref null 0) + drop + i32.const 3 + table.get 0 + ref.cast (ref null 0) + drop + i32.const 4 + table.get 0 + ref.cast (ref null 0) + drop + ref.null struct + ref.cast (ref null 0) + drop + i32.const 1 + table.get 0 + ref.cast (ref null 1) + drop + i32.const 2 + table.get 0 + ref.cast (ref null 1) + drop + ref.null struct + ref.cast (ref null 0) + drop + i32.const 2 + table.get 0 + ref.cast (ref null 3) + drop + ref.null struct + ref.cast (ref null 0) + drop + i32.const 3 + table.get 0 + ref.cast (ref null 5) + drop + i32.const 4 + table.get 0 + ref.cast (ref null 7) + drop + i32.const 0 + table.get 0 + ref.cast (ref 0) + drop + i32.const 1 + table.get 0 + ref.cast (ref 0) + drop + i32.const 2 + table.get 0 + ref.cast (ref 0) + drop + i32.const 3 + table.get 0 + ref.cast (ref 0) + drop + i32.const 4 + table.get 0 + ref.cast (ref 0) + drop + i32.const 1 + table.get 0 + ref.cast (ref 1) + drop + i32.const 2 + table.get 0 + ref.cast (ref 1) + drop + i32.const 2 + table.get 0 + ref.cast (ref 3) + drop + i32.const 3 + table.get 0 + ref.cast (ref 5) + drop + i32.const 4 + table.get 0 + ref.cast (ref 7) + drop + ) + (func (;2;) (type 8) + call $init + i32.const 0 + table.get 0 + ref.cast (ref 0) + drop + i32.const 1 + table.get 0 + ref.cast (ref 0) + drop + i32.const 2 + table.get 0 + ref.cast (ref 0) + drop + i32.const 3 + table.get 0 + ref.cast (ref 0) + drop + i32.const 4 + table.get 0 + ref.cast (ref 0) + drop + i32.const 10 + table.get 0 + ref.cast (ref 0) + drop + i32.const 11 + table.get 0 + ref.cast (ref 0) + drop + i32.const 12 + table.get 0 + ref.cast (ref 0) + drop + i32.const 1 + table.get 0 + ref.cast (ref 2) + drop + i32.const 2 + table.get 0 + ref.cast (ref 2) + drop + i32.const 11 + table.get 0 + ref.cast (ref 1) + drop + i32.const 12 + table.get 0 + ref.cast (ref 1) + drop + i32.const 2 + table.get 0 + ref.cast (ref 4) + drop + i32.const 12 + table.get 0 + ref.cast (ref 3) + drop + ) + (table (;0;) 20 structref) + (export "test-sub" (func 1)) + (export "test-canon" (func 2)) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/ref_test.wast/0.print b/tests/snapshots/testsuite/proposals/gc/ref_test.wast/0.print new file mode 100644 index 0000000000..10f1f89f7a --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/ref_test.wast/0.print @@ -0,0 +1,174 @@ +(module + (type $ft (;0;) (func)) + (type $st (;1;) (struct)) + (type $at (;2;) (array i8)) + (type (;3;) (func (param externref))) + (type (;4;) (func (param i32) (result i32))) + (func $f (;0;) (type $ft)) + (func (;1;) (type 3) (param $x externref) + i32.const 0 + ref.null any + table.set $ta + i32.const 1 + ref.null struct + table.set $ta + i32.const 2 + ref.null none + table.set $ta + i32.const 3 + i32.const 7 + ref.i31 + table.set $ta + i32.const 4 + struct.new_default $st + table.set $ta + i32.const 5 + i32.const 0 + array.new_default $at + table.set $ta + i32.const 6 + local.get $x + any.convert_extern + table.set $ta + i32.const 7 + ref.null extern + any.convert_extern + table.set $ta + i32.const 0 + ref.null nofunc + table.set $tf + i32.const 1 + ref.null func + table.set $tf + i32.const 2 + ref.func $f + table.set $tf + i32.const 0 + ref.null noextern + table.set $te + i32.const 1 + ref.null extern + table.set $te + i32.const 2 + local.get $x + table.set $te + i32.const 3 + i32.const 8 + ref.i31 + extern.convert_any + table.set $te + i32.const 4 + struct.new_default $st + extern.convert_any + table.set $te + i32.const 5 + ref.null any + extern.convert_any + table.set $te + ) + (func (;2;) (type 4) (param $i i32) (result i32) + local.get $i + table.get $ta + ref.is_null + local.get $i + table.get $ta + ref.test nullref + i32.add + ) + (func (;3;) (type 4) (param $i i32) (result i32) + local.get $i + table.get $ta + ref.test (ref any) + local.get $i + table.get $ta + ref.test anyref + i32.add + ) + (func (;4;) (type 4) (param $i i32) (result i32) + local.get $i + table.get $ta + ref.test (ref eq) + local.get $i + table.get $ta + ref.test eqref + i32.add + ) + (func (;5;) (type 4) (param $i i32) (result i32) + local.get $i + table.get $ta + ref.test (ref i31) + local.get $i + table.get $ta + ref.test i31ref + i32.add + ) + (func (;6;) (type 4) (param $i i32) (result i32) + local.get $i + table.get $ta + ref.test (ref struct) + local.get $i + table.get $ta + ref.test structref + i32.add + ) + (func (;7;) (type 4) (param $i i32) (result i32) + local.get $i + table.get $ta + ref.test (ref array) + local.get $i + table.get $ta + ref.test arrayref + i32.add + ) + (func (;8;) (type 4) (param $i i32) (result i32) + local.get $i + table.get $tf + ref.is_null + local.get $i + table.get $tf + ref.test nullfuncref + i32.add + ) + (func (;9;) (type 4) (param $i i32) (result i32) + local.get $i + table.get $tf + ref.test (ref func) + local.get $i + table.get $tf + ref.test funcref + i32.add + ) + (func (;10;) (type 4) (param $i i32) (result i32) + local.get $i + table.get $te + ref.is_null + local.get $i + table.get $te + ref.test nullexternref + i32.add + ) + (func (;11;) (type 4) (param $i i32) (result i32) + local.get $i + table.get $te + ref.test (ref extern) + local.get $i + table.get $te + ref.test externref + i32.add + ) + (table $ta (;0;) 10 anyref) + (table $tf (;1;) 10 funcref) + (table $te (;2;) 10 externref) + (export "init" (func 1)) + (export "ref_test_null_data" (func 2)) + (export "ref_test_any" (func 3)) + (export "ref_test_eq" (func 4)) + (export "ref_test_i31" (func 5)) + (export "ref_test_struct" (func 6)) + (export "ref_test_array" (func 7)) + (export "ref_test_null_func" (func 8)) + (export "ref_test_func" (func 9)) + (export "ref_test_null_extern" (func 10)) + (export "ref_test_extern" (func 11)) + (elem (;0;) declare func $f) +) \ No newline at end of file diff --git a/tests/snapshots/testsuite/proposals/gc/ref_test.wast/68.print b/tests/snapshots/testsuite/proposals/gc/ref_test.wast/68.print new file mode 100644 index 0000000000..e6161a096d --- /dev/null +++ b/tests/snapshots/testsuite/proposals/gc/ref_test.wast/68.print @@ -0,0 +1,419 @@ +(module + (type $t0 (;0;) (sub (struct))) + (type $t1 (;1;) (sub $t0 (;0;) (struct (field i32)))) + (type $t1' (;2;) (sub $t0 (;0;) (struct (field i32)))) + (type $t2 (;3;) (sub $t1 (;1;) (struct (field i32) (field i32)))) + (type $t2' (;4;) (sub $t1' (;2;) (struct (field i32) (field i32)))) + (type $t3 (;5;) (sub $t0 (;0;) (struct (field i32) (field i32)))) + (type $t0' (;6;) (sub $t0 (;0;) (struct))) + (type $t4 (;7;) (sub $t0' (;6;) (struct (field i32) (field i32)))) + (type (;8;) (func)) + (func $init (;0;) (type 8) + i32.const 0 + struct.new_default $t0 + table.set 0 + i32.const 10 + struct.new_default $t0 + table.set 0 + i32.const 1 + struct.new_default $t1 + table.set 0 + i32.const 11 + struct.new_default $t1' + table.set 0 + i32.const 2 + struct.new_default $t2 + table.set 0 + i32.const 12 + struct.new_default $t2' + table.set 0 + i32.const 3 + struct.new_default $t3 + table.set 0 + i32.const 4 + struct.new_default $t4 + table.set 0 + ) + (func (;1;) (type 8) + call $init + block $l ;; label = @1 + ref.null struct + ref.test (ref null 0) + i32.eqz + br_if 0 (;@1;) + ref.null 0 + ref.test (ref null 0) + i32.eqz + br_if 0 (;@1;) + ref.null 1 + ref.test (ref null 0) + i32.eqz + br_if 0 (;@1;) + ref.null 3 + ref.test (ref null 0) + i32.eqz + br_if 0 (;@1;) + ref.null 5 + ref.test (ref null 0) + i32.eqz + br_if 0 (;@1;) + ref.null 7 + ref.test (ref null 0) + i32.eqz + br_if 0 (;@1;) + i32.const 0 + table.get 0 + ref.test (ref null 0) + i32.eqz + br_if 0 (;@1;) + i32.const 1 + table.get 0 + ref.test (ref null 0) + i32.eqz + br_if 0 (;@1;) + i32.const 2 + table.get 0 + ref.test (ref null 0) + i32.eqz + br_if 0 (;@1;) + i32.const 3 + table.get 0 + ref.test (ref null 0) + i32.eqz + br_if 0 (;@1;) + i32.const 4 + table.get 0 + ref.test (ref null 0) + i32.eqz + br_if 0 (;@1;) + ref.null struct + ref.test (ref null 1) + i32.eqz + br_if 0 (;@1;) + ref.null 0 + ref.test (ref null 1) + i32.eqz + br_if 0 (;@1;) + ref.null 1 + ref.test (ref null 1) + i32.eqz + br_if 0 (;@1;) + ref.null 3 + ref.test (ref null 1) + i32.eqz + br_if 0 (;@1;) + ref.null 5 + ref.test (ref null 1) + i32.eqz + br_if 0 (;@1;) + ref.null 7 + ref.test (ref null 1) + i32.eqz + br_if 0 (;@1;) + i32.const 1 + table.get 0 + ref.test (ref null 1) + i32.eqz + br_if 0 (;@1;) + i32.const 2 + table.get 0 + ref.test (ref null 1) + i32.eqz + br_if 0 (;@1;) + ref.null struct + ref.test (ref null 3) + i32.eqz + br_if 0 (;@1;) + ref.null 0 + ref.test (ref null 3) + i32.eqz + br_if 0 (;@1;) + ref.null 1 + ref.test (ref null 3) + i32.eqz + br_if 0 (;@1;) + ref.null 3 + ref.test (ref null 3) + i32.eqz + br_if 0 (;@1;) + ref.null 5 + ref.test (ref null 3) + i32.eqz + br_if 0 (;@1;) + ref.null 7 + ref.test (ref null 3) + i32.eqz + br_if 0 (;@1;) + i32.const 2 + table.get 0 + ref.test (ref null 3) + i32.eqz + br_if 0 (;@1;) + ref.null struct + ref.test (ref null 5) + i32.eqz + br_if 0 (;@1;) + ref.null 0 + ref.test (ref null 5) + i32.eqz + br_if 0 (;@1;) + ref.null 1 + ref.test (ref null 5) + i32.eqz + br_if 0 (;@1;) + ref.null 3 + ref.test (ref null 5) + i32.eqz + br_if 0 (;@1;) + ref.null 5 + ref.test (ref null 5) + i32.eqz + br_if 0 (;@1;) + ref.null 7 + ref.test (ref null 5) + i32.eqz + br_if 0 (;@1;) + i32.const 3 + table.get 0 + ref.test (ref null 5) + i32.eqz + br_if 0 (;@1;) + ref.null struct + ref.test (ref null 7) + i32.eqz + br_if 0 (;@1;) + ref.null 0 + ref.test (ref null 7) + i32.eqz + br_if 0 (;@1;) + ref.null 1 + ref.test (ref null 7) + i32.eqz + br_if 0 (;@1;) + ref.null 3 + ref.test (ref null 7) + i32.eqz + br_if 0 (;@1;) + ref.null 5 + ref.test (ref null 7) + i32.eqz + br_if 0 (;@1;) + ref.null 7 + ref.test (ref null 7) + i32.eqz + br_if 0 (;@1;) + i32.const 4 + table.get 0 + ref.test (ref null 7) + i32.eqz + br_if 0 (;@1;) + i32.const 0 + table.get 0 + ref.test (ref 0) + i32.eqz + br_if 0 (;@1;) + i32.const 1 + table.get 0 + ref.test (ref 0) + i32.eqz + br_if 0 (;@1;) + i32.const 2 + table.get 0 + ref.test (ref 0) + i32.eqz + br_if 0 (;@1;) + i32.const 3 + table.get 0 + ref.test (ref 0) + i32.eqz + br_if 0 (;@1;) + i32.const 4 + table.get 0 + ref.test (ref 0) + i32.eqz + br_if 0 (;@1;) + i32.const 1 + table.get 0 + ref.test (ref 1) + i32.eqz + br_if 0 (;@1;) + i32.const 2 + table.get 0 + ref.test (ref 1) + i32.eqz + br_if 0 (;@1;) + i32.const 2 + table.get 0 + ref.test (ref 3) + i32.eqz + br_if 0 (;@1;) + i32.const 3 + table.get 0 + ref.test (ref 5) + i32.eqz + br_if 0 (;@1;) + i32.const 4 + table.get 0 + ref.test (ref 7) + i32.eqz + br_if 0 (;@1;) + ref.null struct + ref.test (ref 0) + br_if 0 (;@1;) + ref.null struct + ref.test (ref 1) + br_if 0 (;@1;) + ref.null struct + ref.test (ref 3) + br_if 0 (;@1;) + ref.null struct + ref.test (ref 5) + br_if 0 (;@1;) + ref.null struct + ref.test (ref 7) + br_if 0 (;@1;) + i32.const 0 + table.get 0 + ref.test (ref 1) + br_if 0 (;@1;) + i32.const 3 + table.get 0 + ref.test (ref 1) + br_if 0 (;@1;) + i32.const 4 + table.get 0 + ref.test (ref 1) + br_if 0 (;@1;) + i32.const 0 + table.get 0 + ref.test (ref 3) + br_if 0 (;@1;) + i32.const 1 + table.get 0 + ref.test (ref 3) + br_if 0 (;@1;) + i32.const 3 + table.get 0 + ref.test (ref 3) + br_if 0 (;@1;) + i32.const 4 + table.get 0 + ref.test (ref 3) + br_if 0 (;@1;) + i32.const 0 + table.get 0 + ref.test (ref 5) + br_if 0 (;@1;) + i32.const 1 + table.get 0 + ref.test (ref 5) + br_if 0 (;@1;) + i32.const 2 + table.get 0 + ref.test (ref 5) + br_if 0 (;@1;) + i32.const 4 + table.get 0 + ref.test (ref 5) + br_if 0 (;@1;) + i32.const 0 + table.get 0 + ref.test (ref 7) + br_if 0 (;@1;) + i32.const 1 + table.get 0 + ref.test (ref 7) + br_if 0 (;@1;) + i32.const 2 + table.get 0 + ref.test (ref 7) + br_if 0 (;@1;) + i32.const 3 + table.get 0 + ref.test (ref 7) + br_if 0 (;@1;) + return + end + unreachable + ) + (func (;2;) (type 8) + call $init + block $l ;; label = @1 + i32.const 0 + table.get 0 + ref.test (ref 0) + i32.eqz + br_if 0 (;@1;) + i32.const 1 + table.get 0 + ref.test (ref 0) + i32.eqz + br_if 0 (;@1;) + i32.const 2 + table.get 0 + ref.test (ref 0) + i32.eqz + br_if 0 (;@1;) + i32.const 3 + table.get 0 + ref.test (ref 0) + i32.eqz + br_if 0 (;@1;) + i32.const 4 + table.get 0 + ref.test (ref 0) + i32.eqz + br_if 0 (;@1;) + i32.const 10 + table.get 0 + ref.test (ref 0) + i32.eqz + br_if 0 (;@1;) + i32.const 11 + table.get 0 + ref.test (ref 0) + i32.eqz + br_if 0 (;@1;) + i32.const 12 + table.get 0 + ref.test (ref 0) + i32.eqz + br_if 0 (;@1;) + i32.const 1 + table.get 0 + ref.test (ref 2) + i32.eqz + br_if 0 (;@1;) + i32.const 2 + table.get 0 + ref.test (ref 2) + i32.eqz + br_if 0 (;@1;) + i32.const 11 + table.get 0 + ref.test (ref 1) + i32.eqz + br_if 0 (;@1;) + i32.const 12 + table.get 0 + ref.test (ref 1) + i32.eqz + br_if 0 (;@1;) + i32.const 2 + table.get 0 + ref.test (ref 4) + i32.eqz + br_if 0 (;@1;) + i32.const 12 + table.get 0 + ref.test (ref 3) + i32.eqz + br_if 0 (;@1;) + return + end + unreachable + ) + (table (;0;) 20 structref) + (export "test-sub" (func 1)) + (export "test-canon" (func 2)) +) \ No newline at end of file