From 4ea78279265fa072a673d356e41a5833438245a0 Mon Sep 17 00:00:00 2001 From: Christoph Herzog Date: Wed, 31 Jan 2024 15:20:31 +0100 Subject: [PATCH] deps: Upgrade wasmparser to 0.121.0 --- Cargo.lock | 13 +- Cargo.toml | 1 + .../wasm_c_api/unstable/parser/operator.rs | 19 +- lib/compiler-cranelift/src/func_environ.rs | 8 +- .../src/translator/code_translator.rs | 104 ++++++--- .../src/translator/func_environ.rs | 4 +- .../src/translator/func_translator.rs | 11 +- .../src/translator/translation_utils.rs | 17 +- lib/compiler-llvm/src/translator/code.rs | 16 +- lib/compiler-singlepass/src/codegen.rs | 17 +- lib/compiler/Cargo.toml | 2 +- lib/compiler/src/compiler.rs | 9 +- lib/compiler/src/lib.rs | 7 +- lib/compiler/src/translator/middleware.rs | 2 +- lib/compiler/src/translator/mod.rs | 2 +- lib/compiler/src/translator/module.rs | 3 +- lib/compiler/src/translator/sections.rs | 209 ++++++++++-------- lib/compiler/src/translator/state.rs | 112 ++++++++-- 18 files changed, 376 insertions(+), 180 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5591b4a9edb..3abbf40c748 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6518,7 +6518,7 @@ dependencies = [ "wasmer-object", "wasmer-types", "wasmer-vm", - "wasmparser 0.95.0", + "wasmparser 0.121.0", "winapi 0.3.9", ] @@ -7070,6 +7070,17 @@ dependencies = [ "semver 1.0.20", ] +[[package]] +name = "wasmparser" +version = "0.121.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953cf6a7606ab31382cb1caa5ae403e77ba70c7f8e12eeda167e7040d42bfda8" +dependencies = [ + "bitflags 2.4.1", + "indexmap 2.1.0", + "semver 1.0.20", +] + [[package]] name = "wasmprinter" version = "0.2.75" diff --git a/Cargo.toml b/Cargo.toml index 85c024b7074..6d419061714 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,6 +88,7 @@ version = "4.2.5" enumset = "1.1.0" memoffset = "0.9.0" wasmer-toml = "0.9.2" +wasmparser = { version = "0.121.0", default-features = false } webc = { version = "5.8.0", default-features = false, features = ["package"] } shared-buffer = "0.1.4" diff --git a/lib/c-api/src/wasm_c_api/unstable/parser/operator.rs b/lib/c-api/src/wasm_c_api/unstable/parser/operator.rs index db6424c5d96..8a503179a9f 100644 --- a/lib/c-api/src/wasm_c_api/unstable/parser/operator.rs +++ b/lib/c-api/src/wasm_c_api/unstable/parser/operator.rs @@ -1058,14 +1058,11 @@ impl<'a> From<&Operator<'a>> for wasmer_parser_operator_t { O::I32x4TruncSatF64x2SZero => Self::I32x4TruncSatF64x2SZero, O::I32x4TruncSatF64x2UZero => Self::I32x4TruncSatF64x2UZero, O::I8x16RelaxedSwizzle => Self::I8x16RelaxedSwizzle, - O::I32x4RelaxedTruncSatF32x4S => Self::I32x4RelaxedTruncSatF32x4S, - O::I32x4RelaxedTruncSatF32x4U => Self::I32x4RelaxedTruncSatF32x4U, - O::I32x4RelaxedTruncSatF64x2SZero => Self::I32x4RelaxedTruncSatF64x2SZero, - O::I32x4RelaxedTruncSatF64x2UZero => Self::I32x4RelaxedTruncSatF64x2UZero, - O::F32x4RelaxedFma => Self::F32x4Fma, - O::F32x4RelaxedFnma => Self::F32x4Fms, - O::F64x2RelaxedFma => Self::F64x2Fma, - O::F64x2RelaxedFnma => Self::F64x2Fms, + O::I32x4RelaxedTruncF32x4S => Self::I32x4RelaxedTruncSatF32x4S, + O::I32x4RelaxedTruncF32x4U => Self::I32x4RelaxedTruncSatF32x4U, + O::I32x4RelaxedTruncF64x2SZero => Self::I32x4RelaxedTruncSatF64x2SZero, + O::I32x4RelaxedTruncF64x2UZero => Self::I32x4RelaxedTruncSatF64x2UZero, + O::F32x4RelaxedMadd => Self::F32x4Fma, O::I8x16RelaxedLaneselect => Self::I8x16LaneSelect, O::I16x8RelaxedLaneselect => Self::I16x8LaneSelect, O::I32x4RelaxedLaneselect => Self::I32x4LaneSelect, @@ -1075,9 +1072,9 @@ impl<'a> From<&Operator<'a>> for wasmer_parser_operator_t { O::F64x2RelaxedMin => Self::F64x2RelaxedMin, O::F64x2RelaxedMax => Self::F64x2RelaxedMax, O::I16x8RelaxedQ15mulrS => Self::I16x8RelaxedQ15mulrS, - O::I16x8DotI8x16I7x16S => Self::I16x8DotI8x16I7x16S, - O::I32x4DotI8x16I7x16AddS => Self::I32x4DotI8x16I7x16AddS, - O::F32x4RelaxedDotBf16x8AddF32x4 => Self::F32x4RelaxedDotBf16x8AddF32x4, + _ => { + panic!("unimplemented operator {operator:?}"); + } } } } diff --git a/lib/compiler-cranelift/src/func_environ.rs b/lib/compiler-cranelift/src/func_environ.rs index 98f371cca3c..4a664b50fe3 100644 --- a/lib/compiler-cranelift/src/func_environ.rs +++ b/lib/compiler-cranelift/src/func_environ.rs @@ -13,7 +13,7 @@ use cranelift_codegen::ir::{AbiParam, ArgumentPurpose, Function, InstBuilder, Si use cranelift_codegen::isa::TargetFrontendConfig; use cranelift_frontend::FunctionBuilder; use std::convert::TryFrom; -use wasmer_compiler::wasmparser::ValType; +use wasmer_compiler::wasmparser::HeapType; use wasmer_types::entity::EntityRef; use wasmer_types::entity::PrimaryMap; use wasmer_types::VMBuiltinFunctionIndex; @@ -999,11 +999,11 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro fn translate_ref_null( &mut self, mut pos: cranelift_codegen::cursor::FuncCursor, - ty: ValType, + ty: HeapType, ) -> WasmResult { Ok(match ty { - ValType::FuncRef => pos.ins().null(self.reference_type()), - ValType::ExternRef => pos.ins().null(self.reference_type()), + HeapType::Func => pos.ins().null(self.reference_type()), + HeapType::Extern => pos.ins().null(self.reference_type()), _ => { return Err(WasmError::Unsupported( "`ref.null T` that is not a `funcref` or an `externref`".into(), diff --git a/lib/compiler-cranelift/src/translator/code_translator.rs b/lib/compiler-cranelift/src/translator/code_translator.rs index 293283e2b77..d68d3ced6e7 100644 --- a/lib/compiler-cranelift/src/translator/code_translator.rs +++ b/lib/compiler-cranelift/src/translator/code_translator.rs @@ -236,14 +236,14 @@ pub fn translate_operator( * possible `Block`'s arguments values. ***********************************************************************************/ Operator::Block { blockty } => { - let (params, results) = module_translation_state.blocktype_params_results(*blockty)?; - let next = block_with_params(builder, results, environ)?; + let (params, results) = module_translation_state.blocktype_params_results(blockty)?; + let next = block_with_params(builder, results.iter(), environ)?; state.push_block(next, params.len(), results.len()); } Operator::Loop { blockty } => { - let (params, results) = module_translation_state.blocktype_params_results(*blockty)?; - let loop_body = block_with_params(builder, params, environ)?; - let next = block_with_params(builder, results, environ)?; + let (params, results) = module_translation_state.blocktype_params_results(blockty)?; + let loop_body = block_with_params(builder, params.iter(), environ)?; + let next = block_with_params(builder, results.iter(), environ)?; canonicalise_then_jump(builder, loop_body, state.peekn(params.len())); state.push_loop(loop_body, next, params.len(), results.len()); @@ -260,7 +260,7 @@ pub fn translate_operator( Operator::If { blockty } => { let val = state.pop1(); - let (params, results) = module_translation_state.blocktype_params_results(*blockty)?; + let (params, results) = module_translation_state.blocktype_params_results(blockty)?; let (destination, else_data) = if params == results { // It is possible there is no `else` block, so we will only // allocate a block for it if/when we find the `else`. For now, @@ -268,15 +268,15 @@ pub fn translate_operator( // destination block following the whole `if...end`. If we do end // up discovering an `else`, then we will allocate a block for it // and go back and patch the jump. - let destination = block_with_params(builder, results, environ)?; + let destination = block_with_params(builder, results.iter(), environ)?; let branch_inst = canonicalise_then_brz(builder, val, destination, state.peekn(params.len())); (destination, ElseData::NoElse { branch_inst }) } else { // The `if` type signature is not valid without an `else` block, // so we eagerly allocate the `else` block here. - let destination = block_with_params(builder, results, environ)?; - let else_block = block_with_params(builder, params, environ)?; + let destination = block_with_params(builder, results.iter(), environ)?; + let else_block = block_with_params(builder, params.iter(), environ)?; canonicalise_then_brz(builder, val, else_block, state.peekn(params.len())); builder.seal_block(else_block); (destination, ElseData::WithElse { else_block }) @@ -326,10 +326,11 @@ pub fn translate_operator( // already been pre-allocated, see `ElseData` for details). let else_block = match *else_data { ElseData::NoElse { branch_inst } => { - let (params, _results) = - module_translation_state.blocktype_params_results(blocktype)?; + let (params, _results) = module_translation_state + .blocktype_params_results(&blocktype)?; debug_assert_eq!(params.len(), num_return_values); - let else_block = block_with_params(builder, params, environ)?; + let else_block = + block_with_params(builder, params.iter(), environ)?; canonicalise_then_jump( builder, destination, @@ -1039,7 +1040,9 @@ pub fn translate_operator( Operator::F32Le | Operator::F64Le => { translate_fcmp(FloatCC::LessThanOrEqual, builder, state) } - Operator::RefNull { ty } => state.push1(environ.translate_ref_null(builder.cursor(), *ty)?), + Operator::RefNull { hty } => { + state.push1(environ.translate_ref_null(builder.cursor(), *hty)?) + } Operator::RefIsNull => { let value = state.pop1(); state.push1(environ.translate_ref_is_null(builder.cursor(), value)?); @@ -2032,14 +2035,12 @@ pub fn translate_operator( return Err(wasm_unsupported!("proposed tail-call operator {:?}", op)); } Operator::I8x16RelaxedSwizzle - | Operator::I32x4RelaxedTruncSatF32x4S - | Operator::I32x4RelaxedTruncSatF32x4U - | Operator::I32x4RelaxedTruncSatF64x2SZero - | Operator::I32x4RelaxedTruncSatF64x2UZero - | Operator::F32x4RelaxedFma - | Operator::F32x4RelaxedFnma - | Operator::F64x2RelaxedFma - | Operator::F64x2RelaxedFnma + | Operator::I32x4RelaxedTruncF32x4S + | Operator::I32x4RelaxedTruncF32x4U + | Operator::I32x4RelaxedTruncF64x2SZero + | Operator::I32x4RelaxedTruncF64x2UZero + | Operator::F32x4RelaxedNmadd + | Operator::F32x4RelaxedMadd | Operator::I8x16RelaxedLaneselect | Operator::I16x8RelaxedLaneselect | Operator::I32x4RelaxedLaneselect @@ -2048,12 +2049,58 @@ pub fn translate_operator( | Operator::F32x4RelaxedMax | Operator::F64x2RelaxedMin | Operator::F64x2RelaxedMax - | Operator::F32x4RelaxedDotBf16x8AddF32x4 - | Operator::I16x8RelaxedQ15mulrS - | Operator::I16x8DotI8x16I7x16S - | Operator::I32x4DotI8x16I7x16AddS => { + | Operator::F64x2RelaxedMadd + | Operator::F64x2RelaxedNmadd + | Operator::I16x8RelaxedDotI8x16I7x16S + | Operator::I32x4RelaxedDotI8x16I7x16AddS + | Operator::I16x8RelaxedQ15mulrS => { return Err(wasm_unsupported!("proposed relaxed-simd operator {:?}", op)); } + Operator::TryTable { .. } | Operator::ThrowRef => { + return Err(wasm_unsupported!( + "exceptions are not supported (operator: {op:?})" + )); + } + Operator::RefEq + | Operator::StructNew { .. } + | Operator::StructNewDefault { .. } + | Operator::StructGet { .. } + | Operator::StructGetS { .. } + | Operator::StructGetU { .. } + | Operator::StructSet { .. } + | Operator::ArrayNew { .. } + | Operator::ArrayNewDefault { .. } + | Operator::ArrayNewFixed { .. } + | Operator::ArrayNewData { .. } + | Operator::ArrayNewElem { .. } + | Operator::ArrayGet { .. } + | Operator::ArrayGetS { .. } + | Operator::ArrayGetU { .. } + | Operator::ArraySet { .. } + | Operator::ArrayLen + | Operator::ArrayFill { .. } + | Operator::ArrayCopy { .. } + | Operator::ArrayInitData { .. } + | Operator::ArrayInitElem { .. } + | Operator::RefTestNonNull { .. } => {} + Operator::RefTestNullable { .. } + | Operator::RefCastNonNull { .. } + | Operator::RefCastNullable { .. } + | Operator::BrOnCast { .. } + | Operator::BrOnCastFail { .. } + | Operator::AnyConvertExtern + | Operator::ExternConvertAny + | Operator::RefI31 + | Operator::I31GetS + | Operator::I31GetU + | Operator::MemoryDiscard { .. } + | Operator::CallRef { .. } + | Operator::ReturnCallRef { .. } + | Operator::RefAsNonNull + | Operator::BrOnNull { .. } + | Operator::BrOnNonNull { .. } => { + return Err(wasm_unsupported!("GC proposal not (operator: {:?})", op)); + } }; Ok(()) } @@ -2107,9 +2154,10 @@ fn translate_unreachable_operator( let else_block = match *else_data { ElseData::NoElse { branch_inst } => { - let (params, _results) = - module_translation_state.blocktype_params_results(blocktype)?; - let else_block = block_with_params(builder, params, environ)?; + let (params, _results) = module_translation_state + .blocktype_params_results(&blocktype)?; + let else_block = + block_with_params(builder, params.iter(), environ)?; let frame = state.control_stack.last().unwrap(); frame.truncate_value_stack_to_else_params(&mut state.stack); diff --git a/lib/compiler-cranelift/src/translator/func_environ.rs b/lib/compiler-cranelift/src/translator/func_environ.rs index dc0967ef854..d863fa6baf3 100644 --- a/lib/compiler-cranelift/src/translator/func_environ.rs +++ b/lib/compiler-cranelift/src/translator/func_environ.rs @@ -12,7 +12,7 @@ use cranelift_codegen::ir::immediates::Offset32; use cranelift_codegen::ir::{self, InstBuilder}; use cranelift_codegen::isa::TargetFrontendConfig; use cranelift_frontend::FunctionBuilder; -use wasmer_compiler::wasmparser::{Operator, ValType}; +use wasmer_compiler::wasmparser::{HeapType, Operator}; use wasmer_types::{ FunctionIndex, FunctionType, GlobalIndex, LocalFunctionIndex, MemoryIndex, SignatureIndex, TableIndex, Type as WasmerType, WasmResult, @@ -359,7 +359,7 @@ pub trait FuncEnvironment: TargetEnvironment { /// null sentinel is not a null reference type pointer for your type. If you /// override this method, then you should also override /// `translate_ref_is_null` as well. - fn translate_ref_null(&mut self, pos: FuncCursor, ty: ValType) -> WasmResult; + fn translate_ref_null(&mut self, pos: FuncCursor, ty: HeapType) -> WasmResult; // { // let _ = ty; // Ok(pos.ins().null(self.reference_type(ty))) diff --git a/lib/compiler-cranelift/src/translator/func_translator.rs b/lib/compiler-cranelift/src/translator/func_translator.rs index e3263ce5760..8c6fa89950c 100644 --- a/lib/compiler-cranelift/src/translator/func_translator.rs +++ b/lib/compiler-cranelift/src/translator/func_translator.rs @@ -15,7 +15,7 @@ use cranelift_codegen::entity::EntityRef; use cranelift_codegen::ir::{self, Block, InstBuilder, ValueLabel}; use cranelift_codegen::timing; use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; -use wasmer_compiler::wasmparser; +use wasmer_compiler::{wasm_unsupported, wasmparser}; use wasmer_compiler::{wptype_to_type, FunctionBinaryReader, ModuleTranslationState}; use wasmer_types::{LocalFunctionIndex, WasmResult}; @@ -194,8 +194,13 @@ fn declare_locals( let constant_handle = builder.func.dfg.constants.insert([0; 16].to_vec().into()); builder.ins().vconst(ir::types::I8X16, constant_handle) } - ExternRef => builder.ins().null(environ.reference_type()), - FuncRef => builder.ins().null(environ.reference_type()), + Ref(ty) => { + if ty.is_func_ref() || ty.is_extern_ref() { + builder.ins().null(environ.reference_type()) + } else { + return Err(wasm_unsupported!("unsupported reference type: {:?}", ty)); + } + } }; let wasmer_ty = wptype_to_type(wasm_type).unwrap(); diff --git a/lib/compiler-cranelift/src/translator/translation_utils.rs b/lib/compiler-cranelift/src/translator/translation_utils.rs index bd1a8a13339..eb33af54126 100644 --- a/lib/compiler-cranelift/src/translator/translation_utils.rs +++ b/lib/compiler-cranelift/src/translator/translation_utils.rs @@ -90,13 +90,13 @@ pub fn irreloc_to_relocationkind(reloc: Reloc) -> RelocationKind { } /// Create a `Block` with the given Wasm parameters. -pub fn block_with_params( +pub fn block_with_params<'a, PE: TargetEnvironment + ?Sized>( builder: &mut FunctionBuilder, - params: &[wasmparser::ValType], + params: impl Iterator, environ: &PE, ) -> WasmResult { let block = builder.create_block(); - for ty in params.iter() { + for ty in params.into_iter() { match ty { wasmparser::ValType::I32 => { builder.append_block_param(block, ir::types::I32); @@ -110,8 +110,15 @@ pub fn block_with_params( wasmparser::ValType::F64 => { builder.append_block_param(block, ir::types::F64); } - wasmparser::ValType::ExternRef | wasmparser::ValType::FuncRef => { - builder.append_block_param(block, environ.reference_type()); + wasmparser::ValType::Ref(ty) => { + if ty.is_extern_ref() || ty.is_func_ref() { + builder.append_block_param(block, environ.reference_type()); + } else { + return Err(WasmError::Unsupported(format!( + "unsupported reference type: {:?}", + ty + ))); + } } wasmparser::ValType::V128 => { builder.append_block_param(block, ir::types::I8X16); diff --git a/lib/compiler-llvm/src/translator/code.rs b/lib/compiler-llvm/src/translator/code.rs index 4084558e386..e4d00ee271f 100644 --- a/lib/compiler-llvm/src/translator/code.rs +++ b/lib/compiler-llvm/src/translator/code.rs @@ -26,8 +26,8 @@ use crate::config::{CompiledKind, LLVM}; use crate::object_file::{load_object_file, CompiledFunction}; use wasmer_compiler::wasmparser::{MemArg, Operator}; use wasmer_compiler::{ - from_binaryreadererror_wasmerror, wptype_to_type, FunctionBinaryReader, FunctionBodyData, - MiddlewareBinaryReader, ModuleMiddlewareChain, ModuleTranslationState, + from_binaryreadererror_wasmerror, wpheaptype_to_type, wptype_to_type, FunctionBinaryReader, + FunctionBodyData, MiddlewareBinaryReader, ModuleMiddlewareChain, ModuleTranslationState, }; use wasmer_types::entity::PrimaryMap; use wasmer_types::{ @@ -1439,7 +1439,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let phis: SmallVec<[PhiValue<'ctx>; 1]> = self .module_translation - .blocktype_params_results(blockty)? + .blocktype_params_results(&blockty)? .1 .iter() .map(|&wp_ty| { @@ -1463,7 +1463,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.builder.build_unconditional_branch(loop_body); self.builder.position_at_end(loop_next); - let blocktypes = self.module_translation.blocktype_params_results(blockty)?; + let blocktypes = self.module_translation.blocktype_params_results(&blockty)?; let phis = blocktypes .1 .iter() @@ -1671,7 +1671,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let phis = self .module_translation - .blocktype_params_results(blockty)? + .blocktype_params_results(&blockty)? .1 .iter() .map(|&wp_ty| { @@ -1702,7 +1702,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.builder.position_at_end(if_else_block); let block_param_types = self .module_translation - .blocktype_params_results(blockty)? + .blocktype_params_results(&blockty)? .0 .iter() .map(|&wp_ty| { @@ -11146,8 +11146,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { * Reference types. * https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md ***************************/ - Operator::RefNull { ty } => { - let ty = wptype_to_type(ty).map_err(to_compile_error)?; + Operator::RefNull { hty } => { + let ty = wpheaptype_to_type(hty).map_err(to_compile_error)?; let ty = type_to_llvm(self.intrinsics, ty)?; self.state.push1(ty.const_zero()); } diff --git a/lib/compiler-singlepass/src/codegen.rs b/lib/compiler-singlepass/src/codegen.rs index 56744557d06..0ed8a773cf3 100644 --- a/lib/compiler-singlepass/src/codegen.rs +++ b/lib/compiler-singlepass/src/codegen.rs @@ -11,7 +11,10 @@ use gimli::write::Address; use smallvec::{smallvec, SmallVec}; use std::cmp; use std::iter; -use wasmer_compiler::wasmparser::{BlockType as WpTypeOrFuncType, Operator, ValType as WpType}; +use wasmer_compiler::wasmparser::{ + BlockType as WpTypeOrFuncType, HeapType as WpHeapType, Operator, RefType as WpRefType, + ValType as WpType, +}; use wasmer_compiler::FunctionBodyData; #[cfg(feature = "unwind")] use wasmer_types::CompiledFunctionUnwindInfo; @@ -235,8 +238,8 @@ fn type_to_wp_type(ty: Type) -> WpType { Type::F32 => WpType::F32, Type::F64 => WpType::F64, Type::V128 => WpType::V128, - Type::ExternRef => WpType::ExternRef, - Type::FuncRef => WpType::FuncRef, // TODO: FuncRef or Func? + Type::ExternRef => WpType::Ref(WpRefType::new(true, WpHeapType::Extern).unwrap()), + Type::FuncRef => WpType::Ref(WpRefType::new(true, WpHeapType::Func).unwrap()), } } @@ -270,7 +273,9 @@ impl<'a, M: Machine> FuncGen<'a, M> { let loc = match *ty { WpType::F32 | WpType::F64 => self.machine.pick_simd().map(Location::SIMD), WpType::I32 | WpType::I64 => self.machine.pick_gpr().map(Location::GPR), - WpType::FuncRef | WpType::ExternRef => self.machine.pick_gpr().map(Location::GPR), + WpType::Ref(ty) if ty.is_extern_ref() || ty.is_func_ref() => { + self.machine.pick_gpr().map(Location::GPR) + } _ => codegen_error!("can't acquire location for type {:?}", ty), }; @@ -6067,7 +6072,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { let ret = self.acquire_locations( &[( - WpType::FuncRef, + WpType::Ref(WpRefType::new(true, WpHeapType::Func).unwrap()), MachineValue::WasmStack(self.value_stack.len()), )], false, @@ -6163,7 +6168,7 @@ impl<'a, M: Machine> FuncGen<'a, M> { let ret = self.acquire_locations( &[( - WpType::FuncRef, + WpType::Ref(WpRefType::new(true, WpHeapType::Func).unwrap()), MachineValue::WasmStack(self.value_stack.len()), )], false, diff --git a/lib/compiler/Cargo.toml b/lib/compiler/Cargo.toml index 1adedf80f17..12abb2c33cf 100644 --- a/lib/compiler/Cargo.toml +++ b/lib/compiler/Cargo.toml @@ -15,7 +15,7 @@ version.workspace = true [dependencies] wasmer-types = { path = "../types", version = "=4.2.5", default-features = false } wasmer-object = { path = "../object", version = "=4.2.5", optional = true } -wasmparser = { version = "0.95", optional = true, default-features = false } +wasmparser = { workspace = true, optional = true, default-features = false } enumset.workspace = true hashbrown = { version = "0.11", optional = true } serde = { version = "1.0", features = ["derive"], optional = true } diff --git a/lib/compiler/src/compiler.rs b/lib/compiler/src/compiler.rs index 56f87fbbe12..e65494822ed 100644 --- a/lib/compiler/src/compiler.rs +++ b/lib/compiler/src/compiler.rs @@ -88,13 +88,20 @@ pub trait Compiler: Send { multi_memory: features.multi_memory, memory64: features.memory64, exceptions: features.exceptions, - deterministic_only: false, extended_const: features.extended_const, relaxed_simd: features.relaxed_simd, mutable_global: true, saturating_float_to_int: true, + floats: true, sign_extension: true, + + // Not supported component_model: false, + function_references: false, + memory_control: false, + gc: false, + component_model_values: false, + component_model_nested_names: false, }; let mut validator = Validator::new_with_features(wasm_features); validator diff --git a/lib/compiler/src/lib.rs b/lib/compiler/src/lib.rs index 212cf5057f7..ba4624bd457 100644 --- a/lib/compiler/src/lib.rs +++ b/lib/compiler/src/lib.rs @@ -73,9 +73,10 @@ mod translator; pub use crate::compiler::{Compiler, CompilerConfig}; #[cfg(feature = "translator")] pub use crate::translator::{ - from_binaryreadererror_wasmerror, translate_module, wptype_to_type, FunctionBinaryReader, - FunctionBodyData, FunctionMiddleware, MiddlewareBinaryReader, MiddlewareReaderState, - ModuleEnvironment, ModuleMiddleware, ModuleMiddlewareChain, ModuleTranslationState, + from_binaryreadererror_wasmerror, translate_module, wpheaptype_to_type, wptype_to_type, + FunctionBinaryReader, FunctionBodyData, FunctionMiddleware, MiddlewareBinaryReader, + MiddlewareReaderState, ModuleEnvironment, ModuleMiddleware, ModuleMiddlewareChain, + ModuleTranslationState, }; pub use wasmer_types::{Addend, CodeOffset, Features}; diff --git a/lib/compiler/src/translator/middleware.rs b/lib/compiler/src/translator/middleware.rs index f853df826b0..c6dea96abfd 100644 --- a/lib/compiler/src/translator/middleware.rs +++ b/lib/compiler/src/translator/middleware.rs @@ -146,7 +146,7 @@ impl<'a> FunctionBinaryReader<'a> for MiddlewareBinaryReader<'a> { let ty: ValType = self .state .inner - .read_val_type() + .read::() .map_err(from_binaryreadererror_wasmerror)?; Ok((count, ty)) } diff --git a/lib/compiler/src/translator/mod.rs b/lib/compiler/src/translator/mod.rs index eaa2425ce4c..bcad78797b6 100644 --- a/lib/compiler/src/translator/mod.rs +++ b/lib/compiler/src/translator/mod.rs @@ -19,6 +19,6 @@ pub use self::middleware::{ ModuleMiddlewareChain, }; pub use self::module::translate_module; -pub use self::sections::wptype_to_type; +pub use self::sections::{wpheaptype_to_type, wptype_to_type}; pub use self::state::ModuleTranslationState; pub use error::from_binaryreadererror_wasmerror; diff --git a/lib/compiler/src/translator/module.rs b/lib/compiler/src/translator/module.rs index 763dbfd5b0b..97034a9aa5a 100644 --- a/lib/compiler/src/translator/module.rs +++ b/lib/compiler/src/translator/module.rs @@ -107,8 +107,7 @@ pub fn translate_module<'data>( environ.custom_section(name, sectionreader.data())?; if name == "name" { parse_name_section( - NameSectionReader::new(sectionreader.data(), sectionreader.data_offset()) - .map_err(from_binaryreadererror_wasmerror)?, + NameSectionReader::new(sectionreader.data(), sectionreader.data_offset()), environ, )?; } diff --git a/lib/compiler/src/translator/sections.rs b/lib/compiler/src/translator/sections.rs index 9848a2ff4ad..55aea49405a 100644 --- a/lib/compiler/src/translator/sections.rs +++ b/lib/compiler/src/translator/sections.rs @@ -10,11 +10,11 @@ //! The special case of the initialize expressions for table elements offsets or global variables //! is handled, according to the semantics of WebAssembly, to only specific expressions that are //! interpreted on the fly. + use super::environ::ModuleEnvironment; use super::error::from_binaryreadererror_wasmerror; use super::state::ModuleTranslationState; use crate::wasm_unsupported; -use core::convert::TryFrom; use std::boxed::Box; use std::vec::Vec; use wasmer_types::entity::packed_option::ReservedValue; @@ -25,7 +25,7 @@ use wasmer_types::{ }; use wasmer_types::{WasmError, WasmResult}; use wasmparser::{ - self, Data, DataKind, DataSectionReader, Element, ElementItem, ElementItems, ElementKind, + self, Data, DataKind, DataSectionReader, Element, ElementItems, ElementKind, ElementSectionReader, Export, ExportSectionReader, ExternalKind, FunctionSectionReader, GlobalSectionReader, GlobalType as WPGlobalType, ImportSectionReader, MemorySectionReader, MemoryType as WPMemoryType, NameSectionReader, Operator, TableSectionReader, TypeRef, @@ -40,8 +40,27 @@ pub fn wptype_to_type(ty: wasmparser::ValType) -> WasmResult { wasmparser::ValType::F32 => Ok(Type::F32), wasmparser::ValType::F64 => Ok(Type::F64), wasmparser::ValType::V128 => Ok(Type::V128), - wasmparser::ValType::ExternRef => Ok(Type::ExternRef), - wasmparser::ValType::FuncRef => Ok(Type::FuncRef), + wasmparser::ValType::Ref(ty) => wpreftype_to_type(ty), + } +} + +/// Converts a wasmparser ref type to a Wasm Type. +pub fn wpreftype_to_type(ty: wasmparser::RefType) -> WasmResult { + if ty.is_extern_ref() { + Ok(Type::ExternRef) + } else if ty.is_func_ref() { + Ok(Type::FuncRef) + } else { + Err(wasm_unsupported!("unsupported reference type: {:?}", ty)) + } +} + +/// Converts a wasmparser heap type to a Wasm Type. +pub fn wpheaptype_to_type(ty: wasmparser::HeapType) -> WasmResult { + match ty { + wasmparser::HeapType::Func => Ok(Type::FuncRef), + wasmparser::HeapType::Extern => Ok(Type::ExternRef), + other => Err(wasm_unsupported!("unsupported reference type: {other:?}")), } } @@ -51,35 +70,33 @@ pub fn parse_type_section( module_translation_state: &mut ModuleTranslationState, environ: &mut ModuleEnvironment, ) -> WasmResult<()> { - let count = types.get_count(); + let count = types.count(); environ.reserve_signatures(count)?; - for entry in types { - if let Ok(wasmparser::Type::Func(functype)) = entry { - let params = functype.params(); - let returns = functype.results(); - let sig_params: Box<[Type]> = params - .iter() - .map(|ty| { - wptype_to_type(*ty) - .expect("only numeric types are supported in function signatures") - }) - .collect(); - let sig_returns: Box<[Type]> = returns - .iter() - .map(|ty| { - wptype_to_type(*ty) - .expect("only numeric types are supported in function signatures") - }) - .collect(); - let sig = FunctionType::new(sig_params, sig_returns); - environ.declare_signature(sig)?; - module_translation_state - .wasm_types - .push((params.to_vec().into(), returns.to_vec().into())); - } else { - unimplemented!("module linking not implemented yet") - } + for res in types.into_iter_err_on_gc_types() { + let functype = res.map_err(from_binaryreadererror_wasmerror)?; + + let params = functype.params(); + let returns = functype.results(); + let sig_params: Box<[Type]> = params + .iter() + .map(|ty| { + wptype_to_type(*ty) + .expect("only numeric types are supported in function signatures") + }) + .collect(); + let sig_returns: Box<[Type]> = returns + .iter() + .map(|ty| { + wptype_to_type(*ty) + .expect("only numeric types are supported in function signatures") + }) + .collect(); + let sig = FunctionType::new(sig_params, sig_returns); + environ.declare_signature(sig)?; + module_translation_state + .wasm_types + .push((params.to_vec().into(), returns.to_vec().into())); } Ok(()) @@ -90,7 +107,7 @@ pub fn parse_import_section<'data>( imports: ImportSectionReader<'data>, environ: &mut ModuleEnvironment<'data>, ) -> WasmResult<()> { - environ.reserve_imports(imports.get_count())?; + environ.reserve_imports(imports.count())?; for entry in imports { let import = entry.map_err(from_binaryreadererror_wasmerror)?; @@ -130,7 +147,7 @@ pub fn parse_import_section<'data>( TypeRef::Global(ref ty) => { environ.declare_global_import( GlobalType { - ty: wptype_to_type(ty.content_type).unwrap(), + ty: wptype_to_type(ty.content_type)?, mutability: ty.mutable.into(), }, module_name, @@ -140,7 +157,7 @@ pub fn parse_import_section<'data>( TypeRef::Table(ref tab) => { environ.declare_table_import( TableType { - ty: wptype_to_type(tab.element_type).unwrap(), + ty: wpreftype_to_type(tab.element_type)?, minimum: tab.initial, maximum: tab.maximum, }, @@ -160,7 +177,7 @@ pub fn parse_function_section( functions: FunctionSectionReader, environ: &mut ModuleEnvironment, ) -> WasmResult<()> { - let num_functions = functions.get_count(); + let num_functions = functions.count(); if num_functions == std::u32::MAX { // We reserve `u32::MAX` for our own use. return Err(WasmError::ImplLimitExceeded); @@ -181,14 +198,14 @@ pub fn parse_table_section( tables: TableSectionReader, environ: &mut ModuleEnvironment, ) -> WasmResult<()> { - environ.reserve_tables(tables.get_count())?; + environ.reserve_tables(tables.count())?; for entry in tables { let table = entry.map_err(from_binaryreadererror_wasmerror)?; environ.declare_table(TableType { - ty: wptype_to_type(table.element_type).unwrap(), - minimum: table.initial, - maximum: table.maximum, + ty: wpreftype_to_type(table.ty.element_type).unwrap(), + minimum: table.ty.initial, + maximum: table.ty.maximum, })?; } @@ -200,7 +217,7 @@ pub fn parse_memory_section( memories: MemorySectionReader, environ: &mut ModuleEnvironment, ) -> WasmResult<()> { - environ.reserve_memories(memories.get_count())?; + environ.reserve_memories(memories.count())?; for entry in memories { let WPMemoryType { @@ -227,7 +244,7 @@ pub fn parse_global_section( globals: GlobalSectionReader, environ: &mut ModuleEnvironment, ) -> WasmResult<()> { - environ.reserve_globals(globals.get_count())?; + environ.reserve_globals(globals.count())?; for entry in globals { let wasmparser::Global { @@ -247,7 +264,10 @@ pub fn parse_global_section( Operator::F32Const { value } => GlobalInit::F32Const(f32::from_bits(value.bits())), Operator::F64Const { value } => GlobalInit::F64Const(f64::from_bits(value.bits())), Operator::V128Const { value } => GlobalInit::V128Const(V128::from(*value.bytes())), - Operator::RefNull { ty: _ } => GlobalInit::RefNullConst, + Operator::RefNull { hty: _ } => { + // TODO: Do we need to handle different heap types here? + GlobalInit::RefNullConst + } Operator::RefFunc { function_index } => { GlobalInit::RefFunc(FunctionIndex::from_u32(function_index)) } @@ -276,7 +296,7 @@ pub fn parse_export_section<'data>( exports: ExportSectionReader<'data>, environ: &mut ModuleEnvironment<'data>, ) -> WasmResult<()> { - environ.reserve_exports(exports.get_count())?; + environ.reserve_exports(exports.count())?; for entry in exports { let Export { @@ -315,31 +335,47 @@ pub fn parse_start_section(index: u32, environ: &mut ModuleEnvironment) -> WasmR } fn read_elems(items: &ElementItems) -> WasmResult> { - let items_reader = items - .get_items_reader() - .map_err(from_binaryreadererror_wasmerror)?; - let mut elems = Vec::with_capacity(usize::try_from(items_reader.get_count()).unwrap()); - for item in items_reader { - let elem = match item.map_err(from_binaryreadererror_wasmerror)? { - ElementItem::Expr(init) => match init - .get_binary_reader() - .read_operator() - .map_err(from_binaryreadererror_wasmerror)? - { - Operator::RefNull { .. } => FunctionIndex::reserved_value(), - Operator::RefFunc { function_index } => FunctionIndex::from_u32(function_index), - s => { - return Err(WasmError::Unsupported(format!( - "unsupported init expr in element section: {:?}", - s - ))); + let mut out = Vec::new(); + + match items { + ElementItems::Functions(funcs) => { + for res in funcs.clone().into_iter() { + let func_index = res.map_err(from_binaryreadererror_wasmerror)?; + out.push(FunctionIndex::from_u32(func_index)); + } + } + ElementItems::Expressions(ty, section) => { + // TODO: check type is supported + if !(ty.is_extern_ref() || ty.is_func_ref()) { + return Err(wasm_unsupported!( + "unsupported element type in element section: {:?}", + ty + )); + } + + for res in section.clone().into_iter() { + let expr = res.map_err(from_binaryreadererror_wasmerror)?; + + let op = expr + .get_binary_reader() + .read_operator() + .map_err(from_binaryreadererror_wasmerror)?; + match op { + Operator::RefNull { .. } => out.push(FunctionIndex::reserved_value()), + Operator::RefFunc { function_index } => { + out.push(FunctionIndex::from_u32(function_index)) + } + other => { + return Err(WasmError::Unsupported(format!( + "unsupported init expr in element section: {other:?}", + ))); + } } - }, - ElementItem::Func(index) => FunctionIndex::from_u32(index), - }; - elems.push(elem); + } + } } - Ok(elems.into_boxed_slice()) + + Ok(out.into_boxed_slice()) } /// Parses the Element section of the wasm module. @@ -347,27 +383,23 @@ pub fn parse_element_section( elements: ElementSectionReader<'_>, environ: &mut ModuleEnvironment, ) -> WasmResult<()> { - environ.reserve_table_initializers(elements.get_count())?; + environ.reserve_table_initializers(elements.count())?; - for (index, entry) in elements.into_iter().enumerate() { + for (index, elem) in elements.into_iter().enumerate() { let Element { kind, items, - ty, range: _, - } = entry.map_err(from_binaryreadererror_wasmerror)?; - if ty != wasmparser::ValType::FuncRef { - return Err(wasm_unsupported!( - "unsupported table element type: {:?}", - ty - )); - } + } = elem.map_err(from_binaryreadererror_wasmerror)?; + let segments = read_elems(&items)?; match kind { ElementKind::Active { table_index, offset_expr, } => { + let table_index = TableIndex::from_u32(table_index.unwrap_or(0)); + let mut init_expr_reader = offset_expr.get_binary_reader(); let (base, offset) = match init_expr_reader .read_operator() @@ -384,12 +416,7 @@ pub fn parse_element_section( )); } }; - environ.declare_table_initializers( - TableIndex::from_u32(table_index), - base, - offset, - segments, - )? + environ.declare_table_initializers(table_index, base, offset, segments)? } ElementKind::Passive => { let index = ElemIndex::from_u32(index as u32); @@ -406,7 +433,7 @@ pub fn parse_data_section<'data>( data: DataSectionReader<'data>, environ: &mut ModuleEnvironment<'data>, ) -> WasmResult<()> { - environ.reserve_data_initializers(data.get_count())?; + environ.reserve_data_initializers(data.count())?; for (index, entry) in data.into_iter().enumerate() { let Data { @@ -454,10 +481,16 @@ pub fn parse_data_section<'data>( /// Parses the Name section of the wasm module. pub fn parse_name_section<'data>( - mut names: NameSectionReader<'data>, + names: NameSectionReader<'data>, environ: &mut ModuleEnvironment<'data>, ) -> WasmResult<()> { - while let Ok(subsection) = names.read() { + for res in names { + let subsection = if let Ok(subsection) = res { + subsection + } else { + // Should we log / warn here? + continue; + }; match subsection { wasmparser::Name::Function(function_subsection) => { for naming in function_subsection.into_iter().flatten() { @@ -483,8 +516,10 @@ pub fn parse_name_section<'data>( | wasmparser::Name::Global(_) | wasmparser::Name::Element(_) | wasmparser::Name::Data(_) - | wasmparser::Name::Unknown { .. } => {} - }; + | wasmparser::Name::Unknown { .. } + | wasmparser::Name::Tag(..) => {} + } } + Ok(()) } diff --git a/lib/compiler/src/translator/state.rs b/lib/compiler/src/translator/state.rs index b86e8d55940..4182b06e535 100644 --- a/lib/compiler/src/translator/state.rs +++ b/lib/compiler/src/translator/state.rs @@ -33,26 +33,106 @@ impl ModuleTranslationState { } /// Get the parameter and result types for the given Wasm blocktype. - pub fn blocktype_params_results( - &self, - ty_or_ft: wasmparser::BlockType, - ) -> WasmResult<(&[wasmparser::ValType], &[wasmparser::ValType])> { + pub fn blocktype_params_results<'a>( + &'a self, + ty_or_ft: &'a wasmparser::BlockType, + ) -> WasmResult<(&'a [wasmparser::ValType], SingleOrMultiValue<'a>)> { Ok(match ty_or_ft { - wasmparser::BlockType::Type(ty) => match ty { - wasmparser::ValType::I32 => (&[], &[wasmparser::ValType::I32]), - wasmparser::ValType::I64 => (&[], &[wasmparser::ValType::I64]), - wasmparser::ValType::F32 => (&[], &[wasmparser::ValType::F32]), - wasmparser::ValType::F64 => (&[], &[wasmparser::ValType::F64]), - wasmparser::ValType::V128 => (&[], &[wasmparser::ValType::V128]), - wasmparser::ValType::ExternRef => (&[], &[wasmparser::ValType::ExternRef]), - wasmparser::ValType::FuncRef => (&[], &[wasmparser::ValType::FuncRef]), - }, + wasmparser::BlockType::Type(ty) => (&[], SingleOrMultiValue::Single(ty)), wasmparser::BlockType::FuncType(ty_index) => { - let sig_idx = SignatureIndex::from_u32(ty_index); + let sig_idx = SignatureIndex::from_u32(*ty_index); let (ref params, ref results) = self.wasm_types[sig_idx]; - (params, results) + (params, SingleOrMultiValue::Multi(results.as_ref())) } - wasmparser::BlockType::Empty => (&[], &[]), + wasmparser::BlockType::Empty => (&[], SingleOrMultiValue::Multi(&[])), }) } } + +/// A helper enum for representing either a single or multiple values. +pub enum SingleOrMultiValue<'a> { + /// A single value. + Single(&'a wasmparser::ValType), + /// Multiple values. + Multi(&'a [wasmparser::ValType]), +} + +impl<'a> SingleOrMultiValue<'a> { + /// True if empty. + pub fn is_empty(&self) -> bool { + match self { + SingleOrMultiValue::Single(_) => false, + SingleOrMultiValue::Multi(values) => values.is_empty(), + } + } + + /// Count of values. + pub fn len(&self) -> usize { + match self { + SingleOrMultiValue::Single(_) => 1, + SingleOrMultiValue::Multi(values) => values.len(), + } + } + + /// Iterate ofer the value types. + pub fn iter(&self) -> SingleOrMultiValueIterator<'_> { + match self { + SingleOrMultiValue::Single(v) => SingleOrMultiValueIterator::Single(v), + SingleOrMultiValue::Multi(items) => SingleOrMultiValueIterator::Multi { + index: 0, + values: items, + }, + } + } +} + +pub enum SingleOrMultiValueIterator<'a> { + Done, + Single(&'a wasmparser::ValType), + Multi { + index: usize, + values: &'a [wasmparser::ValType], + }, +} + +impl<'a> Iterator for SingleOrMultiValueIterator<'a> { + type Item = &'a wasmparser::ValType; + + fn next(&mut self) -> Option { + match self { + SingleOrMultiValueIterator::Done => None, + SingleOrMultiValueIterator::Single(v) => { + let v = *v; + *self = SingleOrMultiValueIterator::Done; + Some(v) + } + SingleOrMultiValueIterator::Multi { index, values } => { + if let Some(x) = values.get(*index) { + *index += 1; + Some(x) + } else { + *self = SingleOrMultiValueIterator::Done; + None + } + } + } + } +} + +impl<'a> PartialEq<[wasmparser::ValType]> for SingleOrMultiValue<'a> { + fn eq(&self, other: &[wasmparser::ValType]) -> bool { + match self { + SingleOrMultiValue::Single(ty) => other.len() == 1 && &other[0] == *ty, + SingleOrMultiValue::Multi(tys) => *tys == other, + } + } +} + +impl<'a> PartialEq> for &'a [wasmparser::ValType] { + fn eq(&self, other: &SingleOrMultiValue<'a>) -> bool { + match other { + SingleOrMultiValue::Single(ty) => self.len() == 1 && &self[0] == *ty, + SingleOrMultiValue::Multi(tys) => tys == self, + } + } +}