From fcbd32e6b45bffcd6edff1b448c160013c655f3d Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Thu, 28 Mar 2024 13:38:34 -0700 Subject: [PATCH] Upgrade to latest wasmparser and wasm_encoder. --- Cargo.toml | 14 +++---- src/backend/mod.rs | 5 +-- src/frontend.rs | 94 +++++++++++++++++++++++----------------------- src/ir.rs | 54 ++++++++++++++++++++------ 4 files changed, 99 insertions(+), 68 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 459a7c6..bad5591 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,22 +7,22 @@ license = "Apache-2.0 WITH LLVM-exception" edition = "2018" [dependencies] -wasmparser = "0.95" -wasm-encoder = "0.20" +wasmparser = "0.202" +wasm-encoder = "0.202" anyhow = "1.0" structopt = "0.3" log = "0.4" -env_logger = "0.9" +env_logger = "0.11" fxhash = "0.2" -smallvec = "1.7" -rayon = "1.5" +smallvec = "1.13" +rayon = "1.10" lazy_static = "1.4" libc = "0.2" -addr2line = "0.19" +addr2line = "0.21" # For fuzzing only. Versions must match those in fuzz/Cargo.toml. libfuzzer-sys = { version = "0.4", optional = true } -wasm-smith = { version = "0.8", optional = true } +wasm-smith = { version = "0.202", optional = true } [features] default = [] diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 088a424..8535d76 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -950,7 +950,7 @@ pub fn compile(module: &Module<'_>) -> anyhow::Result> { num_table_imports += 1; let table = &module.tables[table]; wasm_encoder::EntityType::Table(wasm_encoder::TableType { - element_type: wasm_encoder::ValType::from(table.ty), + element_type: wasm_encoder::RefType::from(table.ty), minimum: table .func_elements .as_ref() @@ -1000,7 +1000,7 @@ pub fn compile(module: &Module<'_>) -> anyhow::Result> { let mut tables = wasm_encoder::TableSection::new(); for table_data in module.tables.values().skip(num_table_imports) { tables.table(wasm_encoder::TableType { - element_type: wasm_encoder::ValType::from(table_data.ty), + element_type: wasm_encoder::RefType::from(table_data.ty), minimum: table_data .func_elements .as_ref() @@ -1084,7 +1084,6 @@ pub fn compile(module: &Module<'_>) -> anyhow::Result> { elem.active( Some(table.index() as u32), &wasm_encoder::ConstExpr::i32_const(i as i32), - wasm_encoder::ValType::FuncRef, wasm_encoder::Elements::Functions(&[elt.index() as u32]), ); } diff --git a/src/frontend.rs b/src/frontend.rs index 1fef966..5bae767 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -96,10 +96,17 @@ fn handle_payload<'a>( trace!("Wasm parser item: {:?}", payload); match payload { Payload::TypeSection(reader) => { - for ty in reader { - let ty = ty?; - let wasmparser::Type::Func(fty) = ty; - module.signatures.push(fty.into()); + for rec_group in reader { + for ty in rec_group?.into_types() { + match &ty.composite_type { + wasmparser::CompositeType::Func(fty) => { + module.signatures.push(fty.into()); + } + _ => bail!(FrontendError::UnsupportedFeature( + "non-function type in type section".into() + )), + } + } } } Payload::ImportSection(reader) => { @@ -167,7 +174,7 @@ fn handle_payload<'a>( Payload::TableSection(reader) => { for table in reader { let table = table?; - module.frontend_add_table(table.element_type.into(), table.maximum); + module.frontend_add_table(table.ty.element_type.into(), table.ty.maximum); } } Payload::FunctionSection(reader) => { @@ -237,7 +244,7 @@ fn handle_payload<'a>( } } Payload::CustomSection(reader) if reader.name() == "name" => { - let name_reader = NameSectionReader::new(reader.data(), reader.data_offset())?; + let name_reader = NameSectionReader::new(reader.data(), reader.data_offset()); for subsection in name_reader { let subsection = subsection?; match subsection { @@ -302,12 +309,6 @@ fn handle_payload<'a>( Payload::ElementSection(reader) => { for element in reader { let element = element?; - if element.ty != wasmparser::ValType::FuncRef { - bail!(FrontendError::UnsupportedFeature(format!( - "Unsupported table type: {:?}", - element.ty - ))); - } match &element.kind { wasmparser::ElementKind::Passive => {} wasmparser::ElementKind::Declared => {} @@ -315,44 +316,45 @@ fn handle_payload<'a>( table_index, offset_expr, } => { - let table = Table::from(*table_index); + let table = Table::from(table_index.unwrap_or(0)); let offset = parse_init_expr(&offset_expr)?.unwrap_or(0) as usize; - let items = element - .items - .get_items_reader()? - .into_iter() - .collect::, _>>()?; - let mut funcs = vec![]; - for item in items { - let func = match item { - wasmparser::ElementItem::Func(func_idx) => Func::from(func_idx), - _ => bail!(FrontendError::UnsupportedFeature(format!( - "Unsupported element item: {:?}", - item - ))), - }; - funcs.push(func); - } + match element.items { + wasmparser::ElementItems::Functions(items) => { + let mut funcs = vec![]; + for item in items { + let item = item?; + let func = Func::from(item); + funcs.push(func); + } - let table_items = module.tables[table].func_elements.as_mut().unwrap(); - let new_size = offset.checked_add(funcs.len()).ok_or_else(|| { - FrontendError::TooLarge(format!( - "Overflowing element offset + length: {} + {}", - offset, - funcs.len() - )) - })?; - if new_size > table_items.len() { - static MAX_TABLE: usize = 100_000; - if new_size > MAX_TABLE { - bail!(FrontendError::TooLarge(format!( - "Too many table elements: {:?}", - new_size - ))); + let table_items = + module.tables[table].func_elements.as_mut().unwrap(); + let new_size = + offset.checked_add(funcs.len()).ok_or_else(|| { + FrontendError::TooLarge(format!( + "Overflowing element offset + length: {} + {}", + offset, + funcs.len() + )) + })?; + if new_size > table_items.len() { + static MAX_TABLE: usize = 100_000; + if new_size > MAX_TABLE { + bail!(FrontendError::TooLarge(format!( + "Too many table elements: {:?}", + new_size + ))); + } + table_items.resize(new_size, Func::invalid()); + } + table_items[offset..new_size].copy_from_slice(&funcs[..]); + } + wasmparser::ElementItems::Expressions(..) => { + bail!(FrontendError::UnsupportedFeature( + "Expression element items".into() + )) } - table_items.resize(new_size, Func::invalid()); } - table_items[offset..new_size].copy_from_slice(&funcs[..]); } } } diff --git a/src/ir.rs b/src/ir.rs index c7d10ad..71b14d6 100644 --- a/src/ir.rs +++ b/src/ir.rs @@ -10,6 +10,7 @@ pub enum Type { F64, V128, FuncRef, + TypedFuncRef(bool, u32), } impl From for Type { fn from(ty: wasmparser::ValType) -> Self { @@ -19,23 +20,39 @@ impl From for Type { wasmparser::ValType::F32 => Type::F32, wasmparser::ValType::F64 => Type::F64, wasmparser::ValType::V128 => Type::V128, - wasmparser::ValType::FuncRef => Type::FuncRef, - _ => panic!("Unsupported type: {:?}", ty), + wasmparser::ValType::Ref(r) => r.into(), + } + } +} +impl From for Type { + fn from(ty: wasmparser::RefType) -> Self { + assert!(ty.is_func_ref(), "only funcrefs are supported right now"); + match ty.type_index() { + Some(idx) => { + let nullable = ty.is_nullable(); + Type::TypedFuncRef(nullable, idx.as_module_index().unwrap()) + } + None => Type::FuncRef, } } } impl std::fmt::Display for Type { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - let s = match self { - Type::I32 => "i32", - Type::I64 => "i64", - Type::F32 => "f32", - Type::F64 => "f64", - Type::V128 => "v128", - Type::FuncRef => "funcref", - }; - write!(f, "{}", s) + match self { + Type::I32 => write!(f, "i32"), + Type::I64 => write!(f, "i64"), + Type::F32 => write!(f, "f32"), + Type::F64 => write!(f, "f64"), + Type::V128 => write!(f, "v128"), + Type::FuncRef => write!(f, "funcref"), + Type::TypedFuncRef(nullable, idx) => write!( + f, + "funcref({}, {})", + if *nullable { "null" } else { "not_null" }, + idx + ), + } } } @@ -47,7 +64,20 @@ impl From for wasm_encoder::ValType { Type::F32 => wasm_encoder::ValType::F32, Type::F64 => wasm_encoder::ValType::F64, Type::V128 => wasm_encoder::ValType::V128, - Type::FuncRef => wasm_encoder::ValType::FuncRef, + Type::FuncRef | Type::TypedFuncRef(..) => wasm_encoder::ValType::Ref(ty.into()), + } + } +} + +impl From for wasm_encoder::RefType { + fn from(ty: Type) -> wasm_encoder::RefType { + match ty { + Type::FuncRef => wasm_encoder::RefType::FUNCREF, + Type::TypedFuncRef(nullable, idx) => wasm_encoder::RefType { + nullable, + heap_type: wasm_encoder::HeapType::Concrete(idx), + }, + _ => panic!("Cannot convert {:?} into reftype", ty), } } }