diff --git a/Cargo.toml b/Cargo.toml index bb3c7d78..501df342 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,8 +29,8 @@ leb128 = "0.2.4" log = "0.4.8" rayon = { version = "1.1.0", optional = true } walrus-macro = { path = './crates/macro', version = '=0.19.0' } -wasm-encoder = "0.41.0" -wasmparser = "0.80.2" +wasm-encoder = "0.211.0" +wasmparser = "0.211.0" gimli = "0.26.0" [features] diff --git a/src/init_expr.rs b/src/init_expr.rs index 5c9f9bc8..391db297 100644 --- a/src/init_expr.rs +++ b/src/init_expr.rs @@ -22,7 +22,7 @@ pub enum InitExpr { } impl InitExpr { - pub(crate) fn eval(init: &wasmparser::InitExpr, ids: &IndicesToIds) -> Result { + pub(crate) fn eval(init: &wasmparser::ConstExpr, ids: &IndicesToIds) -> Result { use wasmparser::Operator::*; let mut reader = init.get_operators_reader(); let val = match reader.read()? { @@ -32,7 +32,8 @@ impl InitExpr { F64Const { value } => InitExpr::Value(Value::F64(f64::from_bits(value.bits()))), V128Const { value } => InitExpr::Value(Value::V128(v128_to_u128(&value))), GlobalGet { global_index } => InitExpr::Global(ids.get_global(global_index)?), - RefNull { ty } => InitExpr::RefNull(ValType::parse(&ty)?), + // TODO: handle RefNull + // RefNull { hty } => InitExpr::RefNull(ValType::parse(&hty)?), RefFunc { function_index } => InitExpr::RefFunc(ids.get_func(function_index)?), _ => bail!("invalid constant expression"), }; @@ -57,8 +58,8 @@ impl InitExpr { wasm_encoder::ConstExpr::global_get(cx.indices.get_global_index(*g)) } InitExpr::RefNull(ty) => wasm_encoder::ConstExpr::ref_null(match ty { - ValType::Externref => wasm_encoder::HeapType::Extern, - ValType::Funcref => wasm_encoder::HeapType::Func, + ValType::Externref => wasm_encoder::HeapType::Abstract { shared: false, ty: wasm_encoder::AbstractHeapType::Extern }, + ValType::Funcref => wasm_encoder::HeapType::Abstract { shared: false, ty: wasm_encoder::AbstractHeapType::Func }, _ => unreachable!(), }), InitExpr::RefFunc(f) => { diff --git a/src/ir/mod.rs b/src/ir/mod.rs index e02ef54f..c4dfc251 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -830,8 +830,8 @@ pub enum BinaryOp { I8x16NarrowI16x8U, I16x8NarrowI32x4S, I16x8NarrowI32x4U, - I8x16RoundingAverageU, - I16x8RoundingAverageU, + I8x16AvgrU, + I16x8AvgrU, I8x16MinS, I8x16MinU, diff --git a/src/module/data.rs b/src/module/data.rs index 57139227..d4fc10c9 100644 --- a/src/module/data.rs +++ b/src/module/data.rs @@ -222,7 +222,7 @@ impl Module { } wasmparser::DataKind::Active { memory_index, - init_expr, + offset_expr, } => { data.value = segment.data.to_vec(); @@ -230,7 +230,7 @@ impl Module { let memory = self.memories.get_mut(memory_id); memory.data_segments.insert(data.id); - let offset = InitExpr::eval(&init_expr, ids) + let offset = InitExpr::eval(&offset_expr, ids) .with_context(|| format!("in segment {}", i))?; data.kind = DataKind::Active(ActiveData { memory: memory_id, diff --git a/src/module/debug/expression.rs b/src/module/debug/expression.rs index 3c95bbd8..582ff828 100644 --- a/src/module/debug/expression.rs +++ b/src/module/debug/expression.rs @@ -1,6 +1,6 @@ use crate::{CodeTransform, Function, InstrLocId, ModuleFunctions}; use id_arena::Id; -use std::cmp::Ordering; +use std::{cmp::Ordering, ops::Range}; use super::dwarf::AddressSearchPreference; @@ -22,7 +22,7 @@ pub(crate) enum CodeAddress { /// Converts original code address to CodeAddress pub(crate) struct CodeAddressGenerator { /// Function range based convert table - address_convert_table: Vec<(wasmparser::Range, Id)>, + address_convert_table: Vec<(Range, Id)>, /// Instrument based convert table instrument_address_convert_table: Vec<(usize, InstrLocId)>, } @@ -31,7 +31,7 @@ impl CodeAddressGenerator { pub(crate) fn new(funcs: &ModuleFunctions) -> Self { let mut address_convert_table = funcs .iter_local() - .filter_map(|(func_id, func)| func.original_range.map(|range| (range, func_id))) + .filter_map(|(func_id, func)| func.original_range.clone().map(|range| (range, func_id))) .collect::>(); let mut instrument_address_convert_table = funcs @@ -75,7 +75,7 @@ impl CodeAddressGenerator { }; // If the address is not mapped to any instruction, falling back to function-range-based comparison. - let inclusive_range_comparor = |range: &(wasmparser::Range, Id)| { + let inclusive_range_comparor = |range: &(Range, Id)| { // range.start < address <= range.end if range.0.end < address { Ordering::Less @@ -85,7 +85,7 @@ impl CodeAddressGenerator { Ordering::Equal } }; - let exclusive_range_comparor = |range: &(wasmparser::Range, Id)| { + let exclusive_range_comparor = |range: &(Range, Id)| { // normal comparison: range.start <= address < range.end if range.0.end <= address { Ordering::Less @@ -189,7 +189,7 @@ mod tests { crate::FunctionBuilder::new(&mut module.types, &[], &[]), ); - func1.original_range = Some(wasmparser::Range { start: 20, end: 30 }); + func1.original_range = Some(Range { start: 20, end: 30 }); let id1 = module.funcs.add_local(func1); @@ -198,7 +198,7 @@ mod tests { crate::FunctionBuilder::new(&mut module.types, &[], &[]), ); - func2.original_range = Some(wasmparser::Range { start: 30, end: 50 }); + func2.original_range = Some(Range { start: 30, end: 50 }); let id2 = module.funcs.add_local(func2); @@ -262,7 +262,7 @@ mod tests { { code_transform .function_ranges - .push((id1, wasmparser::Range { start: 50, end: 80 })); + .push((id1, Range { start: 50, end: 80 })); code_transform.instruction_map.push((instr_id1, 60)); code_transform.instruction_map.push((instr_id2, 65)); } diff --git a/src/module/elements.rs b/src/module/elements.rs index e5e8750d..6b444f65 100644 --- a/src/module/elements.rs +++ b/src/module/elements.rs @@ -110,36 +110,35 @@ impl Module { ) -> Result<()> { log::debug!("parse element section"); for (i, segment) in section.into_iter().enumerate() { - let segment = segment?; - let ty = ValType::parse(&segment.ty)?; - match ty { - ValType::Funcref => {} - _ => bail!("only funcref type allowed in element segments"), - } - let members = segment - .items - .get_items_reader()? - .into_iter() - .map(|e| -> Result<_> { - Ok(match e? { - wasmparser::ElementItem::Func(f) => Some(ids.get_func(f)?), - wasmparser::ElementItem::Null(_) => None, + let element = segment?; + + let members = match element.items { + wasmparser::ElementItems::Functions(f) => f + .into_iter() + .map(|f| -> Result<_> { + match ids.get_func(f?) { + Ok(f) => Ok(Some(f)), + Err(_) => Ok(None), + } }) - }) - .collect::>()?; + .collect::>()?, + wasmparser::ElementItems::Expressions(_, _) => todo!(), + }; + let id = self.elements.arena.next_id(); - let kind = match segment.kind { + let kind = match element.kind { wasmparser::ElementKind::Passive => ElementKind::Passive, wasmparser::ElementKind::Declared => ElementKind::Declared, wasmparser::ElementKind::Active { table_index, - init_expr, + offset_expr, } => { - let table = ids.get_table(table_index)?; + // TODO: check if this is correct + let table = ids.get_table(table_index.unwrap_or_default())?; self.tables.get_mut(table).elem_segments.insert(id); - let offset = InitExpr::eval(&init_expr, ids) + let offset = InitExpr::eval(&offset_expr, ids) .with_context(|| format!("in segment {}", i))?; match offset { InitExpr::Value(Value::I32(_)) => {} @@ -152,7 +151,7 @@ impl Module { }; self.elements.arena.alloc(Element { id, - ty, + ty: ValType::Funcref, kind, members, name: None, @@ -182,7 +181,12 @@ impl Emit for ModuleElements { Some(func) => { wasm_encoder::ConstExpr::ref_func(cx.indices.get_func_index(*func)) } - None => wasm_encoder::ConstExpr::ref_null(wasm_encoder::HeapType::Func), + None => { + wasm_encoder::ConstExpr::ref_null(wasm_encoder::HeapType::Abstract { + shared: false, + ty: wasm_encoder::AbstractHeapType::Func, + }) + } }) .collect(); let els = wasm_encoder::Elements::Expressions( diff --git a/src/module/exports.rs b/src/module/exports.rs index f51042f9..1416facc 100644 --- a/src/module/exports.rs +++ b/src/module/exports.rs @@ -164,20 +164,17 @@ impl Module { for entry in section { let entry = entry?; let item = match entry.kind { - Function => ExportItem::Function(ids.get_func(entry.index)?), + Func => ExportItem::Function(ids.get_func(entry.index)?), Table => ExportItem::Table(ids.get_table(entry.index)?), Memory => ExportItem::Memory(ids.get_memory(entry.index)?), Global => ExportItem::Global(ids.get_global(entry.index)?), - Type | Module | Instance => { - unimplemented!("module linking not supported"); - } Tag => { unimplemented!("exception handling not supported"); } }; self.exports.arena.alloc_with_id(|id| Export { id, - name: entry.field.to_string(), + name: entry.name.to_string(), item, }); } diff --git a/src/module/functions/local_function/emit.rs b/src/module/functions/local_function/emit.rs index 226f5a46..be3127df 100644 --- a/src/module/functions/local_function/emit.rs +++ b/src/module/functions/local_function/emit.rs @@ -356,7 +356,7 @@ impl<'instr> Visitor<'instr> for Emit<'_> { I8x16MinU => Instruction::I8x16MinU, I8x16MaxS => Instruction::I8x16MaxS, I8x16MaxU => Instruction::I8x16MaxU, - I8x16RoundingAverageU => Instruction::I8x16AvgrU, + I8x16AvgrU => Instruction::I8x16AvgrU, I16x8NarrowI32x4S => Instruction::I16x8NarrowI32x4S, I16x8NarrowI32x4U => Instruction::I16x8NarrowI32x4U, @@ -374,7 +374,7 @@ impl<'instr> Visitor<'instr> for Emit<'_> { I16x8MinU => Instruction::I16x8MinU, I16x8MaxS => Instruction::I16x8MaxS, I16x8MaxU => Instruction::I16x8MaxU, - I16x8RoundingAverageU => Instruction::I16x8AvgrU, + I16x8AvgrU => Instruction::I16x8AvgrU, I32x4Shl => Instruction::I32x4Shl, I32x4ShrS => Instruction::I32x4ShrS, @@ -772,8 +772,14 @@ impl<'instr> Visitor<'instr> for Emit<'_> { TableSize(e) => Instruction::TableSize(self.indices.get_table_index(e.table)), TableFill(e) => Instruction::TableFill(self.indices.get_table_index(e.table)), RefNull(e) => Instruction::RefNull(match &e.ty { - crate::ValType::Externref => wasm_encoder::HeapType::Extern, - crate::ValType::Funcref => wasm_encoder::HeapType::Func, + crate::ValType::Externref => wasm_encoder::HeapType::Abstract { + shared: false, + ty: wasm_encoder::AbstractHeapType::Extern, + }, + crate::ValType::Funcref => wasm_encoder::HeapType::Abstract { + shared: false, + ty: wasm_encoder::AbstractHeapType::Func, + }, _ => unreachable!(), }), RefIsNull(_) => Instruction::RefIsNull, diff --git a/src/module/functions/local_function/mod.rs b/src/module/functions/local_function/mod.rs index 19931cfc..38d7592c 100644 --- a/src/module/functions/local_function/mod.rs +++ b/src/module/functions/local_function/mod.rs @@ -10,7 +10,8 @@ use crate::map::{IdHashMap, IdHashSet}; use crate::parse::IndicesToIds; use crate::{Data, DataId, FunctionBuilder, FunctionId, MemoryId, Module, Result, TypeId, ValType}; use std::collections::BTreeMap; -use wasmparser::{FuncValidator, Operator, Range, ValidatorResources}; +use std::ops::Range; +use wasmparser::{FuncValidator, Operator, ValidatorResources}; /// A function defined locally within the wasm module. #[derive(Debug)] @@ -25,7 +26,7 @@ pub struct LocalFunction { pub instruction_mapping: Vec<(usize, InstrLocId)>, /// Original function binary range. - pub original_range: Option, + pub original_range: Option>, } impl LocalFunction { @@ -62,7 +63,7 @@ impl LocalFunction { builder: FunctionBuilder::without_entry(ty), args, instruction_mapping: Vec::new(), - original_range: Some(wasmparser::Range { + original_range: Some(Range:: { start: body.range().start - code_address_offset - (function_body_size_bit as usize), end: body.range().end - code_address_offset, }), @@ -276,29 +277,25 @@ impl LocalFunction { } } -fn block_result_tys( - ctx: &ValidationContext, - ty: wasmparser::TypeOrFuncType, -) -> Result> { +fn block_result_tys(ctx: &ValidationContext, ty: wasmparser::BlockType) -> Result> { match ty { - wasmparser::TypeOrFuncType::Type(ty) => ValType::from_wasmparser_type(ty).map(Into::into), - wasmparser::TypeOrFuncType::FuncType(idx) => { + wasmparser::BlockType::Type(ty) => ValType::from_wasmparser_type(ty).map(Into::into), + wasmparser::BlockType::FuncType(idx) => { let ty = ctx.indices.get_type(idx)?; Ok(ctx.module.types.results(ty).into()) } + wasmparser::BlockType::Empty => Ok(Box::new([])), } } -fn block_param_tys( - ctx: &ValidationContext, - ty: wasmparser::TypeOrFuncType, -) -> Result> { +fn block_param_tys(ctx: &ValidationContext, ty: wasmparser::BlockType) -> Result> { match ty { - wasmparser::TypeOrFuncType::Type(_) => Ok([][..].into()), - wasmparser::TypeOrFuncType::FuncType(idx) => { + wasmparser::BlockType::Type(_) => Ok([][..].into()), + wasmparser::BlockType::FuncType(idx) => { let ty = ctx.indices.get_type(idx)?; Ok(ctx.module.types.params(ty).into()) } + wasmparser::BlockType::Empty => Ok(Box::new([])), } } @@ -325,16 +322,15 @@ fn append_instruction<'context>( ctx.alloc_instr(Binop { op }, loc); }; - let mem_arg = - |ctx: &mut ValidationContext, arg: &wasmparser::MemoryImmediate| -> (MemoryId, MemArg) { - ( - ctx.indices.get_memory(arg.memory).unwrap(), - MemArg { - align: 1 << (arg.align as i32), - offset: arg.offset as u32, - }, - ) - }; + let mem_arg = |ctx: &mut ValidationContext, arg: &wasmparser::MemArg| -> (MemoryId, MemArg) { + ( + ctx.indices.get_memory(arg.memory).unwrap(), + MemArg { + align: 1 << (arg.align as i32), + offset: arg.offset as u32, + }, + ) + }; let load = |ctx: &mut ValidationContext, arg, kind| { let (memory, arg) = mem_arg(ctx, &arg); @@ -373,8 +369,11 @@ fn append_instruction<'context>( let func = ctx.indices.get_func(function_index).unwrap(); ctx.alloc_instr(Call { func }, loc); } - Operator::CallIndirect { index, table_index } => { - let type_id = ctx.indices.get_type(index).unwrap(); + Operator::CallIndirect { + type_index, + table_index, + } => { + let type_id = ctx.indices.get_type(type_index).unwrap(); let table = ctx.indices.get_table(table_index).unwrap(); ctx.alloc_instr(CallIndirect { table, ty: type_id }, loc); } @@ -562,25 +561,25 @@ fn append_instruction<'context>( ctx.alloc_instr(Unreachable {}, loc); ctx.unreachable(); } - Operator::Block { ty } => { - let param_tys = block_param_tys(ctx, ty).unwrap(); - let result_tys = block_result_tys(ctx, ty).unwrap(); + Operator::Block { blockty } => { + let param_tys = block_param_tys(ctx, blockty).unwrap(); + let result_tys = block_result_tys(ctx, blockty).unwrap(); let seq = ctx .push_control(BlockKind::Block, param_tys, result_tys) .unwrap(); ctx.alloc_instr_in_control(1, Block { seq }, loc).unwrap(); } - Operator::Loop { ty } => { - let result_tys = block_result_tys(ctx, ty).unwrap(); - let param_tys = block_param_tys(ctx, ty).unwrap(); + Operator::Loop { blockty } => { + let result_tys = block_result_tys(ctx, blockty).unwrap(); + let param_tys = block_param_tys(ctx, blockty).unwrap(); let seq = ctx .push_control(BlockKind::Loop, param_tys, result_tys) .unwrap(); ctx.alloc_instr_in_control(1, Loop { seq }, loc).unwrap(); } - Operator::If { ty } => { - let result_tys = block_result_tys(ctx, ty).unwrap(); - let param_tys = block_param_tys(ctx, ty).unwrap(); + Operator::If { blockty } => { + let result_tys = block_result_tys(ctx, blockty).unwrap(); + let param_tys = block_param_tys(ctx, blockty).unwrap(); let consequent = ctx .push_control(BlockKind::If, param_tys, result_tys) @@ -672,22 +671,19 @@ fn append_instruction<'context>( ctx.alloc_instr(BrIf { block }, loc); } - Operator::BrTable { table } => { - let mut blocks = Vec::with_capacity(table.len()); - let mut default = None; - for pair in table.targets() { - let (target, is_default) = pair.unwrap(); + Operator::BrTable { targets } => { + let mut blocks = Vec::with_capacity(targets.len() as usize); + let default = ctx.control(targets.default() as usize).unwrap().block; + for target in targets.targets() { + let target = target.unwrap(); let control = ctx.control(target as usize).unwrap(); - if is_default { - default = Some(control.block); - } else { - blocks.push(control.block); - } + + blocks.push(control.block); } ctx.alloc_instr( BrTable { blocks: blocks.into(), - default: default.unwrap(), + default, }, loc, ); @@ -702,18 +698,18 @@ fn append_instruction<'context>( let memory = ctx.indices.get_memory(mem).unwrap(); ctx.alloc_instr(MemoryGrow { memory }, loc); } - Operator::MemoryInit { segment, mem } => { + Operator::MemoryInit { data_index, mem } => { let memory = ctx.indices.get_memory(mem).unwrap(); - let data = ctx.indices.get_data(segment).unwrap(); + let data = ctx.indices.get_data(data_index).unwrap(); ctx.alloc_instr(MemoryInit { memory, data }, loc); } - Operator::DataDrop { segment } => { - let data = ctx.indices.get_data(segment).unwrap(); + Operator::DataDrop { data_index } => { + let data = ctx.indices.get_data(data_index).unwrap(); ctx.alloc_instr(DataDrop { data }, loc); } - Operator::MemoryCopy { src, dst } => { - let src = ctx.indices.get_memory(src).unwrap(); - let dst = ctx.indices.get_memory(dst).unwrap(); + Operator::MemoryCopy { dst_mem, src_mem } => { + let src = ctx.indices.get_memory(src_mem).unwrap(); + let dst = ctx.indices.get_memory(dst_mem).unwrap(); ctx.alloc_instr(MemoryCopy { src, dst }, loc); } Operator::MemoryFill { mem } => { @@ -750,7 +746,7 @@ fn append_instruction<'context>( Operator::I64Store16 { memarg } => store(ctx, memarg, StoreKind::I64_16 { atomic: false }), Operator::I64Store32 { memarg } => store(ctx, memarg, StoreKind::I64_32 { atomic: false }), - Operator::AtomicFence { flags: _ } => ctx.alloc_instr(AtomicFence {}, loc), + Operator::AtomicFence => ctx.alloc_instr(AtomicFence {}, loc), Operator::I32AtomicLoad { memarg } => load(ctx, memarg, LoadKind::I32 { atomic: true }), Operator::I64AtomicLoad { memarg } => load(ctx, memarg, LoadKind::I64 { atomic: true }), @@ -1002,9 +998,13 @@ fn append_instruction<'context>( let table = ctx.indices.get_table(table).unwrap(); ctx.alloc_instr(TableFill { table }, loc); } - Operator::RefNull { ty } => { - let ty = ValType::parse(&ty).unwrap(); - ctx.alloc_instr(RefNull { ty }, loc); + Operator::RefNull { hty: _ } => { + // TODO: + // RefNull definition has changed in wasmparser. + // Should we update accordingly? + + // let ty = ValType::parse(&hty).unwrap(); + // ctx.alloc_instr(RefNull { ty }, loc); } Operator::RefIsNull => { ctx.alloc_instr(RefIsNull {}, loc); @@ -1273,8 +1273,8 @@ fn append_instruction<'context>( Operator::V128Load16x4U { memarg } => load_simd(ctx, memarg, LoadSimdKind::V128Load16x4U), Operator::V128Load32x2S { memarg } => load_simd(ctx, memarg, LoadSimdKind::V128Load32x2S), Operator::V128Load32x2U { memarg } => load_simd(ctx, memarg, LoadSimdKind::V128Load32x2U), - Operator::I8x16RoundingAverageU => binop(ctx, BinaryOp::I8x16RoundingAverageU), - Operator::I16x8RoundingAverageU => binop(ctx, BinaryOp::I16x8RoundingAverageU), + Operator::I8x16AvgrU => binop(ctx, BinaryOp::I8x16AvgrU), + Operator::I16x8AvgrU => binop(ctx, BinaryOp::I16x8AvgrU), Operator::I8x16MinS => binop(ctx, BinaryOp::I8x16MinS), Operator::I8x16MinU => binop(ctx, BinaryOp::I8x16MinU), @@ -1305,26 +1305,28 @@ fn append_instruction<'context>( ctx.alloc_instr(TableCopy { src, dst }, loc); } - Operator::TableInit { segment, table } => { - let elem = ctx.indices.get_element(segment).unwrap(); + Operator::TableInit { elem_index, table } => { + let elem = ctx.indices.get_element(elem_index).unwrap(); let table = ctx.indices.get_table(table).unwrap(); ctx.alloc_instr(TableInit { elem, table }, loc); } - Operator::ElemDrop { segment } => { - let elem = ctx.indices.get_element(segment).unwrap(); + Operator::ElemDrop { elem_index } => { + let elem = ctx.indices.get_element(elem_index).unwrap(); ctx.alloc_instr(ElemDrop { elem }, loc); } Operator::ReturnCall { .. } | Operator::ReturnCallIndirect { .. } - | Operator::Try { ty: _ } - | Operator::Catch { index: _ } - | Operator::Throw { index: _ } + | Operator::Try { blockty: _ } + | Operator::Catch { tag_index: _ } + | Operator::Throw { tag_index: _ } | Operator::Rethrow { relative_depth: _ } | Operator::Delegate { relative_depth: _ } | Operator::CatchAll => { unimplemented!("not supported") } + + _ => todo!("Many operators are not yet implemented"), } } diff --git a/src/module/functions/mod.rs b/src/module/functions/mod.rs index 530ce720..4d4d4625 100644 --- a/src/module/functions/mod.rs +++ b/src/module/functions/mod.rs @@ -2,10 +2,11 @@ use std::cmp; use std::collections::BTreeMap; +use std::ops::Range; use anyhow::{bail, Context}; use wasm_encoder::Encode; -use wasmparser::{FuncValidator, FunctionBody, Range, ValidatorResources}; +use wasmparser::{FuncValidator, FunctionBody, ValidatorResources}; #[cfg(feature = "parallel")] use rayon::prelude::*; @@ -383,7 +384,7 @@ impl Module { for _ in 0..reader.read_var_u32()? { let pos = reader.original_position(); let count = reader.read_var_u32()?; - let ty = reader.read_type()?; + let ty = reader.read()?; validator.define_locals(pos, count, ty)?; let ty = ValType::parse(&ty)?; for _ in 0..count { @@ -689,7 +690,7 @@ mod tests { #[test] fn get_memory_id() { let mut module = Module::default(); - let expected_id = module.memories.add_local(false, 0, None); + let expected_id = module.memories.add_local(false, false, 0, None); assert!(module.get_memory_id().is_ok_and(|id| id == expected_id)); } diff --git a/src/module/globals.rs b/src/module/globals.rs index 399f04e7..ed3de487 100644 --- a/src/module/globals.rs +++ b/src/module/globals.rs @@ -17,6 +17,8 @@ pub struct Global { pub ty: ValType, /// Whether this global is mutable or not. pub mutable: bool, + /// Whether this global is shared or not. + pub shared: bool, /// The kind of global this is pub kind: GlobalKind, /// The name of this data, used for debugging purposes in the `name` @@ -51,11 +53,18 @@ pub struct ModuleGlobals { impl ModuleGlobals { /// Adds a new imported global to this list. - pub fn add_import(&mut self, ty: ValType, mutable: bool, import_id: ImportId) -> GlobalId { + pub fn add_import( + &mut self, + ty: ValType, + mutable: bool, + shared: bool, + import_id: ImportId, + ) -> GlobalId { self.arena.alloc_with_id(|id| Global { id, ty, mutable, + shared, kind: GlobalKind::Import(import_id), name: None, }) @@ -63,11 +72,18 @@ impl ModuleGlobals { /// Construct a new global, that does not originate from any of the input /// wasm globals. - pub fn add_local(&mut self, ty: ValType, mutable: bool, init: InitExpr) -> GlobalId { + pub fn add_local( + &mut self, + ty: ValType, + mutable: bool, + shared: bool, + init: InitExpr, + ) -> GlobalId { self.arena.alloc_with_id(|id| Global { id, ty, mutable, + shared, kind: GlobalKind::Local(init), name: None, }) @@ -110,6 +126,7 @@ impl Module { let id = self.globals.add_local( ValType::parse(&g.ty.content_type)?, g.ty.mutable, + g.ty.shared, InitExpr::eval(&g.init_expr, ids)?, ); ids.push_global(id); @@ -144,6 +161,7 @@ impl Emit for ModuleGlobals { wasm_encoder::GlobalType { val_type: global.ty.to_wasmencoder_type(), mutable: global.mutable, + shared: global.shared, }, &local.to_wasmencoder_type(cx), ); diff --git a/src/module/imports.rs b/src/module/imports.rs index e7e02289..3ff6c1bf 100644 --- a/src/module/imports.rs +++ b/src/module/imports.rs @@ -153,53 +153,48 @@ impl Module { for entry in section { let entry = entry?; match entry.ty { - wasmparser::ImportSectionEntryType::Function(idx) => { + wasmparser::TypeRef::Func(idx) => { let ty = ids.get_type(idx)?; - let id = self.add_import_func( - entry.module, - entry.field.expect("module linking not supported"), - ty, - ); + let id = self.add_import_func(entry.module, entry.name, ty); ids.push_func(id.0); } - wasmparser::ImportSectionEntryType::Table(t) => { - let ty = ValType::parse(&t.element_type)?; + wasmparser::TypeRef::Table(t) => { + let ty = ValType::parse(&wasmparser::ValType::Ref(t.element_type))?; let id = self.add_import_table( entry.module, - entry.field.expect("module linking not supported"), + entry.name, + t.table64, t.initial, t.maximum, ty, ); ids.push_table(id.0); } - wasmparser::ImportSectionEntryType::Memory(m) => { + wasmparser::TypeRef::Memory(m) => { if m.memory64 { bail!("64-bit memories not supported") }; let id = self.add_import_memory( entry.module, - entry.field.expect("module linking not supported"), + entry.name, m.shared, - m.initial as u32, - m.maximum.map(|m| m as u32), + m.memory64, + m.initial, + m.maximum, ); ids.push_memory(id.0); } - wasmparser::ImportSectionEntryType::Global(g) => { + wasmparser::TypeRef::Global(g) => { let id = self.add_import_global( entry.module, - entry.field.expect("module linking not supported"), + entry.name, ValType::parse(&g.content_type)?, g.mutable, + g.shared, ); ids.push_global(id.0); } - wasmparser::ImportSectionEntryType::Module(_) - | wasmparser::ImportSectionEntryType::Instance(_) => { - unimplemented!("component model not implemented"); - } - wasmparser::ImportSectionEntryType::Tag(_) => { + wasmparser::TypeRef::Tag(_) => { unimplemented!("exception handling not implemented"); } } @@ -227,11 +222,14 @@ impl Module { module: &str, name: &str, shared: bool, - initial: u32, - maximum: Option, + memory64: bool, + initial: u64, + maximum: Option, ) -> (MemoryId, ImportId) { let import = self.imports.arena.next_id(); - let mem = self.memories.add_import(shared, initial, maximum, import); + let mem = self + .memories + .add_import(shared, memory64, initial, maximum, import); self.imports.add(module, name, mem); (mem, import) } @@ -241,12 +239,15 @@ impl Module { &mut self, module: &str, name: &str, - initial: u32, - max: Option, + table64: bool, + initial: u64, + maximum: Option, ty: ValType, ) -> (TableId, ImportId) { let import = self.imports.arena.next_id(); - let table = self.tables.add_import(initial, max, ty, import); + let table = self + .tables + .add_import(table64, initial, maximum, ty, import); self.imports.add(module, name, table); (table, import) } @@ -258,9 +259,10 @@ impl Module { name: &str, ty: ValType, mutable: bool, + shared: bool, ) -> (GlobalId, ImportId) { let import = self.imports.arena.next_id(); - let global = self.globals.add_import(ty, mutable, import); + let global = self.globals.add_import(ty, mutable, shared, import); self.imports.add(module, name, global); (global, import) } @@ -297,6 +299,7 @@ impl Emit for ModuleImports { ValType::Funcref => wasm_encoder::RefType::FUNCREF, _ => panic!("Unexpected table type"), }, + table64: table.table64, minimum: table.initial, maximum: table.maximum, }) @@ -309,6 +312,7 @@ impl Emit for ModuleImports { maximum: mem.maximum.map(|v| v as u64), memory64: false, shared: mem.shared, + page_size_log2: None, }) } ImportKind::Global(id) => { @@ -317,6 +321,7 @@ impl Emit for ModuleImports { wasm_encoder::EntityType::Global(wasm_encoder::GlobalType { val_type: g.ty.to_wasmencoder_type(), mutable: g.mutable, + shared: g.shared, }) } }, diff --git a/src/module/memories.rs b/src/module/memories.rs index 48acc339..eb6d2761 100644 --- a/src/module/memories.rs +++ b/src/module/memories.rs @@ -16,10 +16,12 @@ pub struct Memory { id: MemoryId, /// Is this memory shared? pub shared: bool, + /// Whether or not this is a 64-bit memory. + pub memory64: bool, /// The initial page size for this memory. - pub initial: u32, + pub initial: u64, /// The maximum page size for this memory. - pub maximum: Option, + pub maximum: Option, /// Whether or not this memory is imported, and if so from where. pub import: Option, /// Active data segments that will be used to initialize this memory. @@ -53,14 +55,16 @@ impl ModuleMemories { pub fn add_import( &mut self, shared: bool, - initial: u32, - maximum: Option, + memory64: bool, + initial: u64, + maximum: Option, import: ImportId, ) -> MemoryId { let id = self.arena.next_id(); let id2 = self.arena.alloc(Memory { id, shared, + memory64, initial, maximum, import: Some(import), @@ -73,11 +77,18 @@ impl ModuleMemories { /// Construct a new memory, that does not originate from any of the input /// wasm memories. - pub fn add_local(&mut self, shared: bool, initial: u32, maximum: Option) -> MemoryId { + pub fn add_local( + &mut self, + shared: bool, + memory64: bool, + initial: u64, + maximum: Option, + ) -> MemoryId { let id = self.arena.next_id(); let id2 = self.arena.alloc(Memory { id, shared, + memory64, initial, maximum, import: None, @@ -135,9 +146,9 @@ impl Module { if m.memory64 { bail!("64-bit memories not supported") }; - let id = - self.memories - .add_local(m.shared, m.initial as u32, m.maximum.map(|m| m as u32)); + let id = self + .memories + .add_local(m.shared, m.memory64, m.initial, m.maximum); ids.push_memory(id); } Ok(()) @@ -164,6 +175,7 @@ impl Emit for ModuleMemories { maximum: memory.maximum.map(|v| v as u64), memory64: false, shared: memory.shared, + page_size_log2: None, // No support for the custom-page-sizes proposal }); } @@ -180,10 +192,10 @@ mod tests { let mut module = Module::default(); assert_eq!(module.memories.len(), 0); - module.memories.add_local(false, 0, Some(1024)); + module.memories.add_local(false, false, 0, Some(1024)); assert_eq!(module.memories.len(), 1); - module.memories.add_local(true, 1024, Some(2048)); + module.memories.add_local(true, true, 1024, Some(2048)); assert_eq!(module.memories.len(), 2); } } diff --git a/src/module/mod.rs b/src/module/mod.rs index 881b30f9..625b040e 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -43,8 +43,9 @@ use id_arena::Id; use log::warn; use std::fs; use std::mem; +use std::ops::Range; use std::path::Path; -use wasmparser::{Parser, Payload, Validator, WasmFeatures}; +use wasmparser::{BinaryReader, Parser, Payload, Validator, WasmFeatures}; pub use self::config::ModuleConfig; @@ -93,7 +94,7 @@ pub struct CodeTransform { pub code_section_start: usize, /// Emitted binary ranges of functions - pub function_ranges: Vec<(Id, wasmparser::Range)>, + pub function_ranges: Vec<(Id, Range)>, } impl Module { @@ -132,24 +133,23 @@ impl Module { let mut ret = Module::default(); ret.config = config.clone(); let mut indices = IndicesToIds::default(); - let mut validator = Validator::new(); - validator.wasm_features(WasmFeatures { - reference_types: !config.only_stable_features, - multi_value: true, - bulk_memory: !config.only_stable_features, - simd: !config.only_stable_features, - threads: !config.only_stable_features, - multi_memory: !config.only_stable_features, - ..WasmFeatures::default() - }); + let wasm_features = match config.only_stable_features { + true => WasmFeatures::default(), + false => WasmFeatures::all(), + }; + let mut validator = Validator::new_with_features(wasm_features); let mut local_functions = Vec::new(); let mut debug_sections = Vec::new(); for payload in Parser::new(0).parse_all(wasm) { match payload? { - Payload::Version { num, range } => { - validator.version(num, &range)?; + Payload::Version { + num, + encoding, + range, + } => { + validator.version(num, encoding, &range)?; } Payload::DataSection(s) => { validator @@ -218,40 +218,43 @@ impl Module { ret.funcs.code_section_offset = range.start; } Payload::CodeSectionEntry(body) => { - let validator = validator.code_section_entry()?; + let validator = validator + .code_section_entry(&body)? + .into_validator(Default::default()); local_functions.push((body, validator)); } - Payload::CustomSection { - name, - data, - data_offset, - range: _range, - } => { - let result = match name { - "producers" => wasmparser::ProducersSectionReader::new(data, data_offset) + Payload::CustomSection(s) => { + let result = + match s.name() { + "producers" => wasmparser::ProducersSectionReader::new( + BinaryReader::new(s.data(), s.data_offset(), wasm_features), + ) .map_err(anyhow::Error::from) .and_then(|s| ret.parse_producers_section(s)), - "name" => wasmparser::NameSectionReader::new(data, data_offset) - .map_err(anyhow::Error::from) - .and_then(|r| ret.parse_name_section(r, &indices)), - _ => { - log::debug!("parsing custom section `{}`", name); - if name.starts_with(".debug") { - debug_sections.push(RawCustomSection { - name: name.to_string(), - data: data.to_vec(), - }); - } else { - ret.customs.add(RawCustomSection { - name: name.to_string(), - data: data.to_vec(), - }); + "name" => { + let name_section_reader = wasmparser::NameSectionReader::new( + BinaryReader::new(s.data(), s.data_offset(), wasm_features), + ); + ret.parse_name_section(name_section_reader, &indices) } - continue; - } - }; + name => { + log::debug!("parsing custom section `{}`", name); + if name.starts_with(".debug") { + debug_sections.push(RawCustomSection { + name: name.to_string(), + data: s.data().to_vec(), + }); + } else { + ret.customs.add(RawCustomSection { + name: name.to_string(), + data: s.data().to_vec(), + }); + } + continue; + } + }; if let Err(e) = result { - log::warn!("failed to parse `{}` custom section {}", name, e); + log::warn!("failed to parse `{}` custom section {}", s.name(), e); } } Payload::UnknownSection { id, range, .. } => { @@ -259,32 +262,26 @@ impl Module { unreachable!() } - Payload::End => validator.end()?, - - // the module linking proposal is not implemented yet. - Payload::AliasSection(s) => { - validator.alias_section(&s)?; - bail!("not supported yet"); + Payload::End(offset) => { + validator.end(offset)?; + continue; } - Payload::InstanceSection(s) => { - validator.instance_section(&s)?; - bail!("not supported yet"); - } - Payload::ModuleSectionEntry { - parser: _, - range: _, - } => { - validator.module_section_entry(); - bail!("not supported yet"); - } - Payload::ModuleSectionStart { - count, - range, - size: _, - } => { - validator.module_section_start(count, &range)?; + + // component module proposal is not implemented yet. + Payload::ModuleSection { .. } + | Payload::InstanceSection(..) + | Payload::CoreTypeSection(..) + | Payload::ComponentSection { .. } + | Payload::ComponentInstanceSection(..) + | Payload::ComponentAliasSection(..) + | Payload::ComponentTypeSection(..) + | Payload::ComponentCanonicalSection(..) + | Payload::ComponentStartSection { .. } + | Payload::ComponentImportSection(..) + | Payload::ComponentExportSection(..) => { bail!("not supported yet"); } + // exception handling is not implemented yet. Payload::TagSection(s) => { validator.tag_section(&s)?; @@ -413,38 +410,35 @@ impl Module { indices: &IndicesToIds, ) -> Result<()> { log::debug!("parse name section"); - for name in names { - match name? { - wasmparser::Name::Module(m) => { - self.name = Some(m.get_name()?.to_string()); + for subsection in names { + match subsection? { + wasmparser::Name::Module { + name, + name_range: _, + } => { + self.name = Some(name.to_string()); } - wasmparser::Name::Function(f) => { - let mut map = f.get_map()?; - for _ in 0..map.get_count() { - let naming = map.read()?; + wasmparser::Name::Function(names) => { + for name in names { + let naming = name?; match indices.get_func(naming.index) { Ok(id) => self.funcs.get_mut(id).name = Some(naming.name.to_string()), - // If some tool fails to GC function names properly, - // it doesn't really hurt anything to ignore the - // broken references and keep going. Err(e) => warn!("in name section: {}", e), } } } - wasmparser::Name::Type(t) => { - let mut map = t.get_map()?; - for _ in 0..map.get_count() { - let naming = map.read()?; + wasmparser::Name::Type(names) => { + for name in names { + let naming = name?; match indices.get_type(naming.index) { Ok(id) => self.types.get_mut(id).name = Some(naming.name.to_string()), Err(e) => warn!("in name section: {}", e), } } } - wasmparser::Name::Memory(m) => { - let mut map = m.get_map()?; - for _ in 0..map.get_count() { - let naming = map.read()?; + wasmparser::Name::Memory(names) => { + for name in names { + let naming = name?; match indices.get_memory(naming.index) { Ok(id) => { self.memories.get_mut(id).name = Some(naming.name.to_string()) @@ -453,30 +447,27 @@ impl Module { } } } - wasmparser::Name::Table(t) => { - let mut map = t.get_map()?; - for _ in 0..map.get_count() { - let naming = map.read()?; + wasmparser::Name::Table(names) => { + for name in names { + let naming = name?; match indices.get_table(naming.index) { Ok(id) => self.tables.get_mut(id).name = Some(naming.name.to_string()), Err(e) => warn!("in name section: {}", e), } } } - wasmparser::Name::Data(d) => { - let mut map = d.get_map()?; - for _ in 0..map.get_count() { - let naming = map.read()?; + wasmparser::Name::Data(names) => { + for name in names { + let naming = name?; match indices.get_data(naming.index) { Ok(id) => self.data.get_mut(id).name = Some(naming.name.to_string()), Err(e) => warn!("in name section: {}", e), } } } - wasmparser::Name::Element(e) => { - let mut map = e.get_map()?; - for _ in 0..map.get_count() { - let naming = map.read()?; + wasmparser::Name::Element(names) => { + for name in names { + let naming = name?; match indices.get_element(naming.index) { Ok(id) => { self.elements.get_mut(id).name = Some(naming.name.to_string()) @@ -485,10 +476,9 @@ impl Module { } } } - wasmparser::Name::Global(e) => { - let mut map = e.get_map()?; - for _ in 0..map.get_count() { - let naming = map.read()?; + wasmparser::Name::Global(names) => { + for name in names { + let naming = name?; match indices.get_global(naming.index) { Ok(id) => self.globals.get_mut(id).name = Some(naming.name.to_string()), Err(e) => warn!("in name section: {}", e), @@ -496,13 +486,11 @@ impl Module { } } wasmparser::Name::Local(l) => { - let mut reader = l.get_indirect_map()?; - for _ in 0..reader.get_indirect_count() { - let name = reader.read()?; - let func_id = indices.get_func(name.indirect_index)?; - let mut map = name.get_map()?; - for _ in 0..map.get_count() { - let naming = map.read()?; + for f in l { + let f = f?; + let func_id = indices.get_func(f.index)?; + for name in f.names { + let naming = name?; // Looks like tools like `wat2wasm` generate empty // names for locals if they aren't specified, so // just ignore empty names which would in theory @@ -526,6 +514,8 @@ impl Module { } wasmparser::Name::Unknown { ty, .. } => warn!("unknown name subsection {}", ty), wasmparser::Name::Label(_) => warn!("labels name subsection ignored"), + wasmparser::Name::Field(_) => warn!("fields name subsection ignored"), + wasmparser::Name::Tag(_) => warn!("tags name subsection ignored"), } } Ok(()) diff --git a/src/module/producers.rs b/src/module/producers.rs index d6570bfd..8dae0c96 100644 --- a/src/module/producers.rs +++ b/src/module/producers.rs @@ -83,7 +83,7 @@ impl Module { for field in data { let field = field?; let mut values = Vec::new(); - for value in field.get_producer_field_values_reader()? { + for value in field.values { let value = value?; values.push(Value { name: value.name.to_string(), diff --git a/src/module/tables.rs b/src/module/tables.rs index fbeb2b3c..835aba6d 100644 --- a/src/module/tables.rs +++ b/src/module/tables.rs @@ -14,10 +14,12 @@ pub type TableId = Id; #[derive(Debug)] pub struct Table { id: TableId, + /// Whether or not this is a 64-bit table. + pub table64: bool, /// The initial size of this table - pub initial: u32, + pub initial: u64, /// The maximum size of this table - pub maximum: Option, + pub maximum: Option, /// The type of the elements in this table pub element_ty: ValType, /// Whether or not this table is imported, and if so what imports it. @@ -49,16 +51,18 @@ impl ModuleTables { /// Adds a new imported table to this list of tables pub fn add_import( &mut self, - initial: u32, - max: Option, + table64: bool, + initial: u64, + maximum: Option, element_ty: ValType, import: ImportId, ) -> TableId { let id = self.arena.next_id(); self.arena.alloc(Table { id, + table64, initial, - maximum: max, + maximum, element_ty, import: Some(import), elem_segments: Default::default(), @@ -68,12 +72,19 @@ impl ModuleTables { /// Construct a new table, that does not originate from any of the input /// wasm tables. - pub fn add_local(&mut self, initial: u32, max: Option, element_ty: ValType) -> TableId { + pub fn add_local( + &mut self, + table64: bool, + initial: u64, + maximum: Option, + element_ty: ValType, + ) -> TableId { let id = self.arena.next_id(); let id2 = self.arena.alloc(Table { id, + table64, initial, - maximum: max, + maximum, element_ty, import: None, elem_segments: Default::default(), @@ -144,9 +155,12 @@ impl Module { log::debug!("parse table section"); for t in section { let t = t?; - let id = self - .tables - .add_local(t.initial, t.maximum, ValType::parse(&t.element_type)?); + let id = self.tables.add_local( + t.ty.table64, + t.ty.initial, + t.ty.maximum, + ValType::parse(&wasmparser::ValType::Ref(t.ty.element_type))?, + ); ids.push_table(id); } Ok(()) @@ -169,6 +183,7 @@ impl Emit for ModuleTables { cx.indices.push_table(table.id()); wasm_table_section.table(wasm_encoder::TableType { + table64: table.table64, minimum: table.initial, maximum: table.maximum, element_type: match table.element_ty { diff --git a/src/module/types.rs b/src/module/types.rs index f48fcaae..23aec534 100644 --- a/src/module/types.rs +++ b/src/module/types.rs @@ -118,20 +118,17 @@ impl Module { ids: &mut IndicesToIds, ) -> Result<()> { log::debug!("parsing type section"); - for ty in section { - let fun_ty = match ty? { - wasmparser::TypeDef::Func(ty) => ty, - _ => unimplemented!("module linking not supported"), - }; + for ty in section.into_iter_err_on_gc_types() { + let fun_ty = ty?; let id = self.types.arena.next_id(); let params = fun_ty - .params + .params() .iter() .map(ValType::parse) .collect::>>()? .into_boxed_slice(); let results = fun_ty - .returns + .results() .iter() .map(ValType::parse) .collect::>>()? diff --git a/src/ty.rs b/src/ty.rs index bcbede96..73d59813 100644 --- a/src/ty.rs +++ b/src/ty.rs @@ -142,11 +142,8 @@ pub enum ValType { } impl ValType { - pub(crate) fn from_wasmparser_type(ty: wasmparser::Type) -> Result> { - let v = match ty { - wasmparser::Type::EmptyBlockType => Vec::new(), - _ => vec![ValType::parse(&ty)?], - }; + pub(crate) fn from_wasmparser_type(ty: wasmparser::ValType) -> Result> { + let v = vec![ValType::parse(&ty)?]; Ok(v.into_boxed_slice()) } @@ -162,16 +159,18 @@ impl ValType { } } - pub(crate) fn parse(input: &wasmparser::Type) -> Result { + pub(crate) fn parse(input: &wasmparser::ValType) -> Result { match input { - wasmparser::Type::I32 => Ok(ValType::I32), - wasmparser::Type::I64 => Ok(ValType::I64), - wasmparser::Type::F32 => Ok(ValType::F32), - wasmparser::Type::F64 => Ok(ValType::F64), - wasmparser::Type::V128 => Ok(ValType::V128), - wasmparser::Type::ExternRef => Ok(ValType::Externref), - wasmparser::Type::FuncRef => Ok(ValType::Funcref), - _ => bail!("not a value type"), + 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::Ref(ref_type) => match *ref_type { + wasmparser::RefType::EXTERNREF => Ok(ValType::Externref), + wasmparser::RefType::FUNCREF => Ok(ValType::Funcref), + _ => bail!("unsupported ref type {:?}", ref_type), + }, } } }