diff --git a/crates/wasm-compose/src/encoding.rs b/crates/wasm-compose/src/encoding.rs index 2ef5a2b0ac..02cf64f318 100644 --- a/crates/wasm-compose/src/encoding.rs +++ b/crates/wasm-compose/src/encoding.rs @@ -159,14 +159,22 @@ impl<'a> TypeEncoder<'a> { wasmparser::ValType::F32 => ValType::F32, wasmparser::ValType::F64 => ValType::F64, wasmparser::ValType::V128 => ValType::V128, - wasmparser::ValType::FuncRef => ValType::FuncRef, - wasmparser::ValType::ExternRef => ValType::ExternRef, + wasmparser::ValType::Ref(ty) => Self::ref_type(ty), + wasmparser::ValType::Bot => unimplemented!(), + } + } + + fn ref_type(ty: wasmparser::RefType) -> ValType { + match ty { + wasmparser::FUNC_REF => ValType::FuncRef, + wasmparser::EXTERN_REF => ValType::ExternRef, + _ => unimplemented!(), } } fn table_type(ty: wasmparser::TableType) -> TableType { TableType { - element_type: Self::val_type(ty.element_type), + element_type: Self::ref_type(ty.element_type), minimum: ty.initial, maximum: ty.maximum, } diff --git a/crates/wasm-encoder/src/core/code.rs b/crates/wasm-encoder/src/core/code.rs index 9759cf6603..15ab54e690 100644 --- a/crates/wasm-encoder/src/core/code.rs +++ b/crates/wasm-encoder/src/core/code.rs @@ -322,9 +322,9 @@ pub enum Instruction<'a> { BrOnNonNull(u32), Return, Call(u32), - CallRef, + CallRef(ValType), CallIndirect { ty: u32, table: u32 }, - ReturnCallRef, + ReturnCallRef(ValType), Throw(u32), Rethrow(u32), @@ -916,13 +916,19 @@ impl Encode for Instruction<'_> { sink.push(0x10); f.encode(sink); } - Instruction::CallRef => sink.push(0x14), + Instruction::CallRef(ty) => { + sink.push(0x14); + ty.encode(sink); + } Instruction::CallIndirect { ty, table } => { sink.push(0x11); ty.encode(sink); table.encode(sink); } - Instruction::ReturnCallRef => sink.push(0x15), + Instruction::ReturnCallRef(ty) => { + sink.push(0x15); + ty.encode(sink); + } Instruction::Delegate(l) => { sink.push(0x18); l.encode(sink); diff --git a/crates/wasm-mutate/src/module.rs b/crates/wasm-mutate/src/module.rs index 024cb6c1f6..cb5f42c083 100644 --- a/crates/wasm-mutate/src/module.rs +++ b/crates/wasm-mutate/src/module.rs @@ -34,8 +34,18 @@ impl From for PrimitiveTypeInfo { wasmparser::ValType::F32 => PrimitiveTypeInfo::F32, wasmparser::ValType::F64 => PrimitiveTypeInfo::F64, wasmparser::ValType::V128 => PrimitiveTypeInfo::V128, - wasmparser::ValType::FuncRef => PrimitiveTypeInfo::FuncRef, - wasmparser::ValType::ExternRef => PrimitiveTypeInfo::ExternRef, + wasmparser::ValType::Ref(t) => t.into(), + wasmparser::ValType::Bot => unreachable!(), + } + } +} + +impl From for PrimitiveTypeInfo { + fn from(value: wasmparser::RefType) -> Self { + match value { + wasmparser::FUNC_REF => PrimitiveTypeInfo::FuncRef, + wasmparser::EXTERN_REF => PrimitiveTypeInfo::ExternRef, + _ => unimplemented!(), } } } @@ -57,6 +67,7 @@ impl TryFrom for TypeInfo { .map(|&t| PrimitiveTypeInfo::from(t)) .collect(), })), + wasmparser::Type::Cont(_) => unimplemented!(), } } } @@ -68,8 +79,16 @@ pub fn map_type(tpe: wasmparser::ValType) -> Result { wasmparser::ValType::F32 => Ok(ValType::F32), wasmparser::ValType::F64 => Ok(ValType::F64), wasmparser::ValType::V128 => Ok(ValType::V128), - wasmparser::ValType::FuncRef => Ok(ValType::FuncRef), - wasmparser::ValType::ExternRef => Ok(ValType::ExternRef), + wasmparser::ValType::Ref(t) => map_ref_type(t), + wasmparser::ValType::Bot => unimplemented!(), + } +} + +pub fn map_ref_type(tpe: wasmparser::RefType) -> Result { + match tpe { + wasmparser::FUNC_REF => Ok(ValType::FuncRef), + wasmparser::EXTERN_REF => Ok(ValType::ExternRef), + _ => unimplemented!(), } } diff --git a/crates/wasm-mutate/src/mutators/add_type.rs b/crates/wasm-mutate/src/mutators/add_type.rs index 67e6ea59d0..0181c96404 100644 --- a/crates/wasm-mutate/src/mutators/add_type.rs +++ b/crates/wasm-mutate/src/mutators/add_type.rs @@ -70,6 +70,7 @@ impl Mutator for AddTypeMutator { .collect::, _>>()?; types.function(params, results); } + wasmparser::Type::Cont(_) => unimplemented!(), } } // And then add our new type. @@ -94,8 +95,16 @@ fn translate_type(ty: &wasmparser::ValType) -> Result { wasmparser::ValType::F32 => wasm_encoder::ValType::F32, wasmparser::ValType::F64 => wasm_encoder::ValType::F64, wasmparser::ValType::V128 => wasm_encoder::ValType::V128, - wasmparser::ValType::FuncRef => wasm_encoder::ValType::FuncRef, - wasmparser::ValType::ExternRef => wasm_encoder::ValType::ExternRef, + wasmparser::ValType::Ref(rt) => translate_ref_type(rt)?, + wasmparser::ValType::Bot => unreachable!(), + }) +} + +fn translate_ref_type(rt: &wasmparser::RefType) -> Result { + Ok(match *rt { + wasmparser::FUNC_REF => wasm_encoder::ValType::FuncRef, + wasmparser::EXTERN_REF => wasm_encoder::ValType::ExternRef, + _ => unimplemented!(), }) } diff --git a/crates/wasm-mutate/src/mutators/modify_const_exprs.rs b/crates/wasm-mutate/src/mutators/modify_const_exprs.rs index e5bad0a4b0..95e2e129c6 100644 --- a/crates/wasm-mutate/src/mutators/modify_const_exprs.rs +++ b/crates/wasm-mutate/src/mutators/modify_const_exprs.rs @@ -122,8 +122,10 @@ impl<'cfg, 'wasm> Translator for InitTranslator<'cfg, 'wasm> { } else { f64::from_bits(self.config.rng().gen()) }), - T::FuncRef => CE::ref_null(wasm_encoder::ValType::FuncRef), - T::ExternRef => CE::ref_null(wasm_encoder::ValType::ExternRef), + T::Ref(wasmparser::FUNC_REF) => CE::ref_null(wasm_encoder::ValType::FuncRef), + T::Ref(wasmparser::EXTERN_REF) => CE::ref_null(wasm_encoder::ValType::ExternRef), + T::Ref(_) => unimplemented!(), + T::Bot => unreachable!(), } } else { // FIXME: implement non-reducing mutations for constant expressions. diff --git a/crates/wasm-mutate/src/mutators/peephole/dfg.rs b/crates/wasm-mutate/src/mutators/peephole/dfg.rs index 69b991f488..94e21fd416 100644 --- a/crates/wasm-mutate/src/mutators/peephole/dfg.rs +++ b/crates/wasm-mutate/src/mutators/peephole/dfg.rs @@ -762,12 +762,12 @@ impl<'a> DFGBuilder { } Operator::RefNull { - ty: wasmparser::ValType::ExternRef, + ty: wasmparser::HeapType::Extern, } => { self.push_node(Lang::RefNull(RefType::Extern), idx); } Operator::RefNull { - ty: wasmparser::ValType::FuncRef, + ty: wasmparser::HeapType::Func, } => { self.push_node(Lang::RefNull(RefType::Func), idx); } diff --git a/crates/wasm-mutate/src/mutators/translate.rs b/crates/wasm-mutate/src/mutators/translate.rs index 2adfe116b5..ed2de50b21 100644 --- a/crates/wasm-mutate/src/mutators/translate.rs +++ b/crates/wasm-mutate/src/mutators/translate.rs @@ -60,6 +60,14 @@ pub trait Translator { ty(self.as_obj(), t) } + fn translate_refty(&mut self, t: &wasmparser::RefType) -> Result { + refty(self.as_obj(), t) + } + + fn translate_heapty(&mut self, t: &wasmparser::HeapType) -> Result { + heapty(self.as_obj(), t) + } + fn translate_global(&mut self, g: Global, s: &mut GlobalSection) -> Result<()> { global(self.as_obj(), g, s) } @@ -130,6 +138,7 @@ pub fn type_def(t: &mut dyn Translator, ty: Type, s: &mut TypeSection) -> Result ); Ok(()) } + Type::Cont(_) => unimplemented!(), } } @@ -138,7 +147,7 @@ pub fn table_type( ty: &wasmparser::TableType, ) -> Result { Ok(wasm_encoder::TableType { - element_type: t.translate_ty(&ty.element_type)?, + element_type: t.translate_refty(&ty.element_type)?, minimum: ty.initial, maximum: ty.maximum, }) @@ -174,14 +183,18 @@ pub fn tag_type(t: &mut dyn Translator, ty: &wasmparser::TagType) -> Result Result { + crate::module::map_type(*ty) +} + +pub fn refty(_t: &mut dyn Translator, ty: &wasmparser::RefType) -> Result { + crate::module::map_ref_type(*ty) +} + +pub fn heapty(_t: &mut dyn Translator, ty: &wasmparser::HeapType) -> Result { match ty { - wasmparser::ValType::I32 => Ok(ValType::I32), - wasmparser::ValType::I64 => Ok(ValType::I64), - wasmparser::ValType::F32 => Ok(ValType::F32), - wasmparser::ValType::F64 => Ok(ValType::F64), - wasmparser::ValType::V128 => Ok(ValType::V128), - wasmparser::ValType::FuncRef => Ok(ValType::FuncRef), - wasmparser::ValType::ExternRef => Ok(ValType::ExternRef), + wasmparser::HeapType::Func => Ok(ValType::FuncRef), + wasmparser::HeapType::Extern => Ok(ValType::ExternRef), + _ => unimplemented!(), } } @@ -208,7 +221,7 @@ pub fn const_expr( match op { Operator::RefFunc { .. } | Operator::RefNull { - ty: wasmparser::ValType::FuncRef, + ty: wasmparser::HeapType::Func, .. } | Operator::GlobalGet { .. } => {} @@ -247,7 +260,7 @@ pub fn element( ElementKind::Passive => ElementMode::Passive, ElementKind::Declared => ElementMode::Declared, }; - let element_type = t.translate_ty(&element.ty)?; + let element_type = t.translate_refty(&element.ty)?; let mut functions = Vec::new(); let mut exprs = Vec::new(); let mut reader = element.items.get_items_reader()?; @@ -259,7 +272,7 @@ pub fn element( ElementItem::Expr(expr) => { exprs.push(t.translate_const_expr( &expr, - &element.ty, + &wasmparser::ValType::Ref(element.ty), ConstExprKind::ElementFunction, )?); } @@ -312,7 +325,7 @@ pub fn op(t: &mut dyn Translator, op: &Operator<'_>) -> Result I::Return, O::Call { function_index } => I::Call(t.remap(Item::Function, *function_index)?), - O::CallRef => I::CallRef, + O::CallRef { ty } => I::CallRef(t.translate_heapty(ty)?), O::CallIndirect { index, table_index, @@ -321,7 +334,7 @@ pub fn op(t: &mut dyn Translator, op: &Operator<'_>) -> Result I::ReturnCallRef, + O::ReturnCallRef { ty } => I::ReturnCallRef(t.translate_heapty(ty)?), O::Delegate { relative_depth } => I::Delegate(*relative_depth), O::CatchAll => I::CatchAll, O::Drop => I::Drop, @@ -367,7 +380,7 @@ pub fn op(t: &mut dyn Translator, op: &Operator<'_>) -> Result I::F32Const(f32::from_bits(value.bits())), O::F64Const { value } => I::F64Const(f64::from_bits(value.bits())), - O::RefNull { ty } => I::RefNull(t.translate_ty(ty)?), + O::RefNull { ty } => I::RefNull(t.translate_heapty(ty)?), O::RefIsNull => I::RefIsNull, O::RefFunc { function_index } => I::RefFunc(t.remap(Item::Function, *function_index)?), O::RefAsNonNull => I::RefAsNonNull, @@ -933,6 +946,9 @@ pub fn op(t: &mut dyn Translator, op: &Operator<'_>) -> Result return Err(Error::no_mutations_applicable()), + + // Typed continuations + | O::ContNew { .. } | O::ContBind { .. } | O::Suspend { .. } | O::Resume { .. } | O::ResumeThrow { .. } | O::Barrier { .. } => unimplemented!(), }) } diff --git a/crates/wasm-shrink/src/lib.rs b/crates/wasm-shrink/src/lib.rs index 09a8b0b264..6c9bc8174c 100755 --- a/crates/wasm-shrink/src/lib.rs +++ b/crates/wasm-shrink/src/lib.rs @@ -233,6 +233,8 @@ impl ShrinkRun { saturating_float_to_int: true, sign_extension: true, component_model: false, + function_references: false, + typed_continuations: false, // We'll never enable this here. deterministic_only: false, diff --git a/crates/wasm-smith/src/component.rs b/crates/wasm-smith/src/component.rs index ea3186ed03..b433217b1e 100644 --- a/crates/wasm-smith/src/component.rs +++ b/crates/wasm-smith/src/component.rs @@ -1799,9 +1799,9 @@ fn inverse_scalar_canonical_abi_for( .cloned(), ValType::F32 => Ok(ComponentValType::Primitive(PrimitiveValType::Float32)), ValType::F64 => Ok(ComponentValType::Primitive(PrimitiveValType::Float64)), - ValType::V128 | ValType::FuncRef | ValType::ExternRef => { + ValType::V128 | ValType::FuncRef | ValType::ExternRef | ValType::Ref(_) => { unreachable!("not used in canonical ABI") - } + }, }; let mut param_names = HashSet::default(); diff --git a/crates/wasm-smith/src/core.rs b/crates/wasm-smith/src/core.rs index acc94885b8..6fe9e22f99 100644 --- a/crates/wasm-smith/src/core.rs +++ b/crates/wasm-smith/src/core.rs @@ -602,6 +602,7 @@ impl Module { new_types.push(Type::Func(Rc::clone(&func_type))); new_index } + Some((wasmparser::Type::Cont(_), _)) => unimplemented!(), }; match &new_types[serialized_sig_idx - first_type_index] { Type::Func(f) => Some((serialized_sig_idx as u32, Rc::clone(f))), @@ -648,7 +649,7 @@ impl Module { wasmparser::TypeRef::Table(table_ty) => { let table_ty = TableType { - element_type: convert_type(table_ty.element_type), + element_type: convert_reftype(table_ty.element_type), minimum: table_ty.initial, maximum: table_ty.maximum, }; @@ -880,7 +881,8 @@ impl Module { } else { ConstExpr::ref_null(ValType::FuncRef) } - } + }, + ValType::Ref(_) => unimplemented!(), })) })); @@ -1567,6 +1569,15 @@ fn convert_type(parsed_type: wasmparser::ValType) -> ValType { } } +/// Convert a wasmparser's `ValType` to a `wasm_encoder::ValType`. +fn convert_reftype(parsed_type: wasmparser::RefType) -> ValType { + match parsed_type { + wasmparser::FUNC_REF => ValType::FuncRef, + wasmparser::EXTERN_REF => ValType::ExternRef, + _ => unimplemented!(), + } +} + impl EntityType { fn size(&self) -> u32 { match self { diff --git a/crates/wasm-smith/src/core/code_builder.rs b/crates/wasm-smith/src/core/code_builder.rs index e11a753592..fc0241d117 100644 --- a/crates/wasm-smith/src/core/code_builder.rs +++ b/crates/wasm-smith/src/core/code_builder.rs @@ -1096,6 +1096,7 @@ fn arbitrary_val(ty: ValType, u: &mut Unstructured<'_>) -> Instruction { ValType::V128 => Instruction::V128Const(u.arbitrary().unwrap_or(0)), ValType::ExternRef => Instruction::RefNull(ValType::ExternRef), ValType::FuncRef => Instruction::RefNull(ValType::FuncRef), + ValType::Ref(_) => unimplemented!(), } } @@ -1562,6 +1563,7 @@ fn select(_: &mut Unstructured, _: &Module, builder: &mut CodeBuilder) -> Result } Some(ValType::I32) | Some(ValType::I64) | Some(ValType::F32) | Some(ValType::F64) | Some(ValType::V128) | None => Ok(Instruction::Select), + Some(ValType::Ref(_)) => unimplemented!(), } } diff --git a/crates/wasm-smith/src/core/notrap.rs b/crates/wasm-smith/src/core/notrap.rs index 3557f29761..df26d57fd4 100755 --- a/crates/wasm-smith/src/core/notrap.rs +++ b/crates/wasm-smith/src/core/notrap.rs @@ -634,6 +634,7 @@ fn dummy_value_inst<'a>(ty: ValType) -> Instruction<'a> { ValType::F64 => Instruction::F64Const(0.0), ValType::V128 => Instruction::V128Const(0), ValType::FuncRef | ValType::ExternRef => Instruction::RefNull(ty), + ValType::Ref(_) => unimplemented!(), } } @@ -808,6 +809,6 @@ fn size_of_type_in_memory(ty: ValType) -> u64 { ValType::F32 => 4, ValType::F64 => 8, ValType::V128 => 16, - ValType::FuncRef | ValType::ExternRef => panic!("not a memory type"), + ValType::Ref(_) | ValType::FuncRef | ValType::ExternRef => panic!("not a memory type"), } } diff --git a/crates/wasmparser/src/binary_reader.rs b/crates/wasmparser/src/binary_reader.rs index 3800c610a4..d4107082cc 100644 --- a/crates/wasmparser/src/binary_reader.rs +++ b/crates/wasmparser/src/binary_reader.rs @@ -1689,8 +1689,12 @@ impl<'a> BinaryReader<'a> { index: self.read_var_u32()?, table_index: self.read_var_u32()?, }, - 0x14 => Operator::CallRef, - 0x15 => Operator::ReturnCallRef, + 0x14 => Operator::CallRef { + ty: self.read_heap_type()?, + }, + 0x15 => Operator::ReturnCallRef { + ty: self.read_heap_type()?, + }, 0x18 => Operator::Delegate { relative_depth: self.read_var_u32()?, }, diff --git a/crates/wasmparser/src/readers/core/operators.rs b/crates/wasmparser/src/readers/core/operators.rs index 17a94665ee..0158c01015 100644 --- a/crates/wasmparser/src/readers/core/operators.rs +++ b/crates/wasmparser/src/readers/core/operators.rs @@ -160,7 +160,7 @@ pub enum Operator<'a> { Call { function_index: u32, }, - CallRef, + CallRef { ty: HeapType }, CallIndirect { index: u32, table_index: u32, @@ -169,7 +169,7 @@ pub enum Operator<'a> { ReturnCall { function_index: u32, }, - ReturnCallRef, + ReturnCallRef { ty: HeapType }, ReturnCallIndirect { index: u32, table_index: u32, diff --git a/crates/wasmparser/src/readers/core/types.rs b/crates/wasmparser/src/readers/core/types.rs index 6bee747802..ff169dc3f6 100644 --- a/crates/wasmparser/src/readers/core/types.rs +++ b/crates/wasmparser/src/readers/core/types.rs @@ -66,13 +66,13 @@ pub enum HeapType { /// funcref, in both reference types and function references, represented /// using the general ref syntax -pub(crate) const FUNC_REF: RefType = RefType { +pub const FUNC_REF: RefType = RefType { nullable: true, heap_type: HeapType::Func, }; /// externref, in both reference types and function references, represented /// using the general ref syntax -pub(crate) const EXTERN_REF: RefType = RefType { +pub const EXTERN_REF: RefType = RefType { nullable: true, heap_type: HeapType::Extern, }; diff --git a/crates/wasmparser/src/validator/operators.rs b/crates/wasmparser/src/validator/operators.rs index e6c7288c62..aca2d7957e 100644 --- a/crates/wasmparser/src/validator/operators.rs +++ b/crates/wasmparser/src/validator/operators.rs @@ -876,25 +876,25 @@ impl OperatorValidator { } self.check_call_indirect(index, table_index, resources)? } - Operator::CallRef => { + Operator::CallRef { ty } => { self.check_function_references_enabled()?; let rt = self.pop_ref(resources)?; + let expected = RefType { + nullable: true, + heap_type: ty, + }; + if !resources.matches(ValType::Ref(rt), ValType::Ref(expected)) { + bail_op_err!( + "type mismatch: funcref on stack does not match specified type", + ); + } match rt.heap_type { - HeapType::Index(type_index) => - { - let ft = func_type_at(resources, type_index)?; - for ty in ft.inputs().rev() { - self.pop_operand(Some(ty), resources)?; - } - for ty in ft.outputs() { - self.push_operand(ty, resources)?; - } - }, + HeapType::Index(type_index) => self.check_call(type_index, resources)?, HeapType::Bot => (), _ => bail_op_err!("type mismatch: instruction requires function reference type but stack has {}", ty_to_str(ValType::Ref(rt))) } } - Operator::ReturnCallRef => { + Operator::ReturnCallRef { ty }=> { self.check_function_references_enabled()?; if !self.features.tail_call { return Err(OperatorValidatorError::new( @@ -902,16 +902,17 @@ impl OperatorValidator { )); } let rt = self.pop_ref(resources)?; + let expected = RefType { + nullable: true, + heap_type: ty, + }; + if !resources.matches(ValType::Ref(rt), ValType::Ref(expected)) { + bail_op_err!( + "type mismatch: funcref on stack does not match specified type", + ); + } match rt.heap_type { - HeapType::Index(type_index) => { - let ft = func_type_at(resources, type_index)?; - for ty in ft.inputs().rev() { - self.pop_operand(Some(ty), resources)?; - } - for ty in ft.outputs() { - self.push_operand(ty, resources)?; - } - }, + HeapType::Index(type_index) => self.check_call(type_index, resources)?, HeapType::Bot => (), _ => bail_op_err!("type mismatch: instruction requires function reference type but stack has {}", ty_to_str(ValType::Ref(rt))) } diff --git a/crates/wasmprinter/src/lib.rs b/crates/wasmprinter/src/lib.rs index 0ba68981f0..637c6ab381 100644 --- a/crates/wasmprinter/src/lib.rs +++ b/crates/wasmprinter/src/lib.rs @@ -1031,7 +1031,10 @@ impl Printer { self.result.push_str("call "); self.print_idx(&state.core.func_names, *function_index)?; } - CallRef => self.result.push_str("call_ref"), + CallRef { ty } => { + self.result.push_str("call_ref "); + self.print_heaptype(*ty)?; + } CallIndirect { table_index, index, @@ -1048,7 +1051,10 @@ impl Printer { self.result.push_str("return_call "); self.print_idx(&state.core.func_names, *function_index)?; } - ReturnCallRef => self.result.push_str("return_call_ref"), + ReturnCallRef { ty } => { + self.result.push_str("return_call_ref"); + self.print_heaptype(*ty)?; + } ReturnCallIndirect { table_index, index } => { self.result.push_str("return_call_indirect"); if *table_index != 0 {