From c2499d9fb0f90d8c332d89e12207c88c025e91c1 Mon Sep 17 00:00:00 2001 From: Henry Date: Sun, 12 Apr 2026 15:29:20 +0200 Subject: fix: fix remaining issues with extended-const Signed-off-by: Henry --- crates/parser/src/conversion.rs | 46 +++-- crates/parser/src/lib.rs | 1 + crates/tinywasm/Cargo.toml | 1 - crates/tinywasm/src/instance.rs | 3 +- crates/tinywasm/src/module.rs | 77 ++++---- crates/tinywasm/src/store/mod.rs | 194 ++++++++++++++------- crates/tinywasm/tests/generated/wasm-3.csv | 2 +- .../tests/generated/wasm-extended-const.csv | 2 +- crates/tinywasm/tests/generated/wasm-latest.csv | 2 +- crates/types/src/instructions.rs | 6 + crates/types/src/lib.rs | 12 +- crates/types/src/value.rs | 6 +- 12 files changed, 213 insertions(+), 139 deletions(-) (limited to 'crates') diff --git a/crates/parser/src/conversion.rs b/crates/parser/src/conversion.rs index 570d0a1..dfd5415 100644 --- a/crates/parser/src/conversion.rs +++ b/crates/parser/src/conversion.rs @@ -235,7 +235,7 @@ pub(crate) fn convert_valtype(valtype: &wasmparser::ValType) -> ValType { } } -pub(crate) fn process_const_operators(ops: OperatorsReader<'_>) -> Result { +pub(crate) fn process_const_operators(ops: OperatorsReader<'_>) -> Result> { let ops = ops.into_iter().collect::>>()?; // In practice, the len can never be something other than 2, // but we'll keep this here since it's part of the spec @@ -243,21 +243,37 @@ pub(crate) fn process_const_operators(ops: OperatorsReader<'_>) -> Result= 2); assert!(matches!(ops[ops.len() - 1], wasmparser::Operator::End)); - match &ops[ops.len() - 2] { - wasmparser::Operator::RefNull { hty } => match convert_heaptype(*hty) { - ValType::RefFunc => Ok(ConstInstruction::RefFunc(None)), - ValType::RefExtern => Ok(ConstInstruction::RefExtern(None)), - _ => unimplemented!("Unsupported heap type: {:?}", hty), - }, - wasmparser::Operator::RefFunc { function_index } => Ok(ConstInstruction::RefFunc(Some(*function_index))), - wasmparser::Operator::I32Const { value } => Ok(ConstInstruction::I32Const(*value)), - wasmparser::Operator::I64Const { value } => Ok(ConstInstruction::I64Const(*value)), - wasmparser::Operator::F32Const { value } => Ok(ConstInstruction::F32Const(f32::from_bits(value.bits()))), - wasmparser::Operator::F64Const { value } => Ok(ConstInstruction::F64Const(f64::from_bits(value.bits()))), - wasmparser::Operator::V128Const { value } => Ok(ConstInstruction::V128Const(value.i128())), - wasmparser::Operator::GlobalGet { global_index } => Ok(ConstInstruction::GlobalGet(*global_index)), - op => Err(crate::ParseError::UnsupportedOperator(format!("Unsupported const instruction: {op:?}"))), + let mut out = Vec::with_capacity(ops.len().saturating_sub(1)); + for op in ops.iter().take(ops.len() - 1) { + let instr = match op { + wasmparser::Operator::RefNull { hty } => match convert_heaptype(*hty) { + ValType::RefFunc => ConstInstruction::RefFunc(None), + ValType::RefExtern => ConstInstruction::RefExtern(None), + _ => unimplemented!("Unsupported heap type: {:?}", hty), + }, + wasmparser::Operator::RefFunc { function_index } => ConstInstruction::RefFunc(Some(*function_index)), + wasmparser::Operator::I32Const { value } => ConstInstruction::I32Const(*value), + wasmparser::Operator::I64Const { value } => ConstInstruction::I64Const(*value), + wasmparser::Operator::F32Const { value } => ConstInstruction::F32Const(f32::from_bits(value.bits())), + wasmparser::Operator::F64Const { value } => ConstInstruction::F64Const(f64::from_bits(value.bits())), + wasmparser::Operator::V128Const { value } => ConstInstruction::V128Const(value.i128()), + wasmparser::Operator::GlobalGet { global_index } => ConstInstruction::GlobalGet(*global_index), + wasmparser::Operator::I32Add => ConstInstruction::I32Add, + wasmparser::Operator::I32Sub => ConstInstruction::I32Sub, + wasmparser::Operator::I32Mul => ConstInstruction::I32Mul, + wasmparser::Operator::I64Add => ConstInstruction::I64Add, + wasmparser::Operator::I64Sub => ConstInstruction::I64Sub, + wasmparser::Operator::I64Mul => ConstInstruction::I64Mul, + other => { + return Err(crate::ParseError::UnsupportedOperator(format!( + "Unsupported const instruction: {other:?}" + ))); + } + }; + out.push(instr); } + + Ok(out.into_boxed_slice()) } pub(crate) fn convert_heaptype(heap: wasmparser::HeapType) -> ValType { diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index a0c0c7e..850042c 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -90,6 +90,7 @@ impl Parser { | WasmFeatures::BULK_MEMORY | WasmFeatures::SATURATING_FLOAT_TO_INT | WasmFeatures::SIGN_EXTENSION + | WasmFeatures::EXTENDED_CONST | WasmFeatures::FUNCTION_REFERENCES | WasmFeatures::TAIL_CALL | WasmFeatures::MULTI_MEMORY diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index 62b592b..1a89033 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -98,7 +98,6 @@ harness=false [[test]] name="test-wasm-extended-const" harness=false -test=false [[test]] name="test-wasm-relaxed-simd" diff --git a/crates/tinywasm/src/instance.rs b/crates/tinywasm/src/instance.rs index a23213b..2537a87 100644 --- a/crates/tinywasm/src/instance.rs +++ b/crates/tinywasm/src/instance.rs @@ -152,7 +152,8 @@ impl ModuleInstance { let global_addrs = store.init_globals(addrs.globals, &module.0.globals, &addrs.funcs, idx)?; let (elem_addrs, elem_trapped) = store.init_elements(&addrs.tables, &addrs.funcs, &global_addrs, &module.0.elements, idx)?; - let (data_addrs, data_trapped) = store.init_data(&addrs.memories, &module.0.data, idx)?; + let (data_addrs, data_trapped) = + store.init_data(&addrs.memories, &global_addrs, &addrs.funcs, &module.0.data, idx)?; let instance = ModuleInstanceInner { store_id: store.id(), diff --git a/crates/tinywasm/src/module.rs b/crates/tinywasm/src/module.rs index df8b0ac..f725054 100644 --- a/crates/tinywasm/src/module.rs +++ b/crates/tinywasm/src/module.rs @@ -1,32 +1,6 @@ use crate::{Imports, ModuleInstance, Result, Store}; use tinywasm_types::{ExternalKind, FuncType, TinyWasmModule}; -fn imported_func_type(module: &TinyWasmModule, function_index: usize) -> Option<&FuncType> { - let mut seen = 0usize; - for import in module.imports.iter() { - if let tinywasm_types::ImportKind::Function(type_idx) = import.kind { - if seen == function_index { - return module.func_types.get(type_idx as usize); - } - seen += 1; - } - } - None -} - -fn imported_global_type(module: &TinyWasmModule, global_index: usize) -> Option<&tinywasm_types::GlobalType> { - let mut seen = 0usize; - for import in module.imports.iter() { - if let tinywasm_types::ImportKind::Global(global_ty) = &import.kind { - if seen == global_index { - return Some(global_ty); - } - seen += 1; - } - } - None -} - /// A module import descriptor. pub struct ModuleImport<'a> { /// Importing module name. @@ -146,16 +120,12 @@ impl Module { /// The returned data mirrors the module's export section and preserves order. pub fn exports(&self) -> impl Iterator> { self.0.exports.iter().filter_map(|export| { + let imports = self.0.imports.iter(); + let idx = export.index as usize; let ty = match export.kind { ExternalKind::Func => { - let idx = export.index as usize; - let imported_funcs = self - .0 - .imports - .iter() - .filter(|import| matches!(import.kind, tinywasm_types::ImportKind::Function(_))) - .count(); - + let imported_funcs = + imports.filter(|import| matches!(import.kind, tinywasm_types::ImportKind::Function(_))).count(); if idx < imported_funcs { ExportType::Func(imported_func_type(&self.0, idx)?) } else { @@ -163,16 +133,11 @@ impl Module { ExportType::Func(&self.0.funcs.get(local_idx)?.ty) } } - ExternalKind::Table => ExportType::Table(self.0.table_types.get(export.index as usize)?), - ExternalKind::Memory => ExportType::Memory(self.0.memory_types.get(export.index as usize)?), + ExternalKind::Table => ExportType::Table(self.0.table_types.get(idx)?), + ExternalKind::Memory => ExportType::Memory(self.0.memory_types.get(idx)?), ExternalKind::Global => { - let idx = export.index as usize; - let imported_globals = self - .0 - .imports - .iter() - .filter(|import| matches!(import.kind, tinywasm_types::ImportKind::Global(_))) - .count(); + let imported_globals = + imports.filter(|import| matches!(import.kind, tinywasm_types::ImportKind::Global(_))).count(); if idx < imported_globals { ExportType::Global(imported_global_type(&self.0, idx)?) } else { @@ -186,3 +151,29 @@ impl Module { }) } } + +fn imported_func_type(module: &TinyWasmModule, function_index: usize) -> Option<&FuncType> { + let mut seen = 0usize; + for import in module.imports.iter() { + if let tinywasm_types::ImportKind::Function(type_idx) = import.kind { + if seen == function_index { + return module.func_types.get(type_idx as usize); + } + seen += 1; + } + } + None +} + +fn imported_global_type(module: &TinyWasmModule, global_index: usize) -> Option<&tinywasm_types::GlobalType> { + let mut seen = 0usize; + for import in module.imports.iter() { + if let tinywasm_types::ImportKind::Global(global_ty) = &import.kind { + if seen == global_index { + return Some(global_ty); + } + seen += 1; + } + } + None +} diff --git a/crates/tinywasm/src/store/mod.rs b/crates/tinywasm/src/store/mod.rs index 648efaa..9301e9b 100644 --- a/crates/tinywasm/src/store/mod.rs +++ b/crates/tinywasm/src/store/mod.rs @@ -318,27 +318,10 @@ impl Store { fn elem_addr(&self, item: &ElementItem, globals: &[Addr], funcs: &[FuncAddr]) -> Result> { let res = match item { - ElementItem::Func(addr) | ElementItem::Expr(ConstInstruction::RefFunc(Some(addr))) => { - Some(funcs.get(*addr as usize).copied().ok_or_else(|| { - Error::Other(format!("function {addr} not found. This should have been caught by the validator")) - })?) - } - ElementItem::Expr(ConstInstruction::RefFunc(None)) => None, - ElementItem::Expr(ConstInstruction::RefExtern(None)) => None, - ElementItem::Expr(ConstInstruction::GlobalGet(addr)) => { - let addr = globals.get(*addr as usize).copied().ok_or_else(|| { - Error::Other(format!("global {addr} not found. This should have been caught by the validator")) - })?; - self.state.globals[addr as usize].value.get().unwrap_ref() - } - #[cfg(feature = "debug")] - ElementItem::Expr(item) => { - return Err(Error::UnsupportedFeature(format!("const expression other than ref: {item:?}"))); - } - #[cfg(not(feature = "debug"))] - ElementItem::Expr(_) => { - return Err(Error::UnsupportedFeature("const expression other than ref".to_string())); - } + ElementItem::Func(addr) => Some(funcs.get(*addr as usize).copied().ok_or_else(|| { + Error::Other(format!("function {addr} not found. This should have been caught by the validator")) + })?), + ElementItem::Expr(expr) => self.eval_ref_const(expr, globals, funcs)?, }; Ok(res) @@ -363,7 +346,7 @@ impl Store { .map(|item| Ok(TableElement::from(self.elem_addr(item, global_addrs, func_addrs)?))) .collect::>>()?; - let items = match element.kind { + let items = match &element.kind { // doesn't need to be initialized, can be initialized lazily using the `table.init` instruction ElementKind::Passive => Some(init), @@ -372,9 +355,9 @@ impl Store { // this one is active, so we need to initialize it (essentially a `table.init` instruction) ElementKind::Active { offset, table } => { - let offset = self.eval_size_const(offset)?; + let offset = self.eval_size_const(offset, global_addrs, func_addrs)?; let table_addr = table_addrs - .get(table as usize) + .get(*table as usize) .copied() .ok_or_else(|| Error::Other(format!("table {table} not found for element {i}")))?; @@ -396,7 +379,7 @@ impl Store { } }; - self.state.elements.push(ElementInstance::new(element.kind, items)); + self.state.elements.push(ElementInstance::new(element.kind.clone(), items)); elem_addrs.push((i + elem_count) as Addr); } @@ -408,19 +391,21 @@ impl Store { pub(crate) fn init_data( &mut self, mem_addrs: &[MemAddr], + global_addrs: &[Addr], + func_addrs: &[FuncAddr], data: &[Data], _idx: ModuleInstanceAddr, ) -> Result<(Box<[Addr]>, Option)> { let data_count = self.state.data.len(); let mut data_addrs = Vec::with_capacity(data_count); for (i, data) in data.iter().enumerate() { - let data_val = match data.kind { + let data_val = match &data.kind { tinywasm_types::DataKind::Active { mem: mem_addr, offset } => { - let Some(mem_addr) = mem_addrs.get(mem_addr as usize) else { + let Some(mem_addr) = mem_addrs.get(*mem_addr as usize) else { return Err(Error::Other(format!("memory {mem_addr} not found for data segment {i}"))); }; - let offset = self.eval_size_const(offset)?; + let offset = self.eval_size_const(offset, global_addrs, func_addrs)?; let Some(mem) = self.state.memories.get_mut(*mem_addr as usize) else { return Err(Error::Other(format!("memory {mem_addr} not found for data segment {i}"))); }; @@ -482,55 +467,130 @@ impl Store { } /// Evaluate a constant expression that's either a i32 or a i64 as a global or a const instruction - fn eval_size_const(&self, const_instr: tinywasm_types::ConstInstruction) -> Result { - Ok(match const_instr { - ConstInstruction::I32Const(i) => i64::from(i), - ConstInstruction::I64Const(i) => i, - ConstInstruction::GlobalGet(addr) => match self.state.globals[addr as usize].value.get() { - TinyWasmValue::Value32(i) => i64::from(i), - TinyWasmValue::Value64(i) => i as i64, - other => return Err(Error::Other(format!("expected i32 or i64, got {other:?}"))), - }, - #[cfg(feature = "debug")] - other => return Err(Error::Other(format!("expected i32, got {other:?}"))), - #[cfg(not(feature = "debug"))] - _ => return Err(Error::Other("expected i32 or i64".to_string())), - }) + fn eval_size_const( + &self, + const_instrs: &[tinywasm_types::ConstInstruction], + module_global_addrs: &[Addr], + module_func_addrs: &[FuncAddr], + ) -> Result { + let value = self.eval_const(const_instrs, module_global_addrs, module_func_addrs)?; + match value { + TinyWasmValue::Value32(i) => Ok(i64::from(i)), + TinyWasmValue::Value64(i) => Ok(i as i64), + other => Err(Error::Other(format!("expected i32 or i64, got {other:?}"))), + } } /// Evaluate a constant expression fn eval_const( &self, - const_instr: &tinywasm_types::ConstInstruction, + const_instrs: &[tinywasm_types::ConstInstruction], module_global_addrs: &[Addr], module_func_addrs: &[FuncAddr], ) -> Result { use tinywasm_types::ConstInstruction::*; - let val = match const_instr { - F32Const(f) => (*f).into(), - F64Const(f) => (*f).into(), - I32Const(i) => (*i).into(), - I64Const(i) => (*i).into(), - V128Const(i) => (*i).into(), - GlobalGet(addr) => { - let addr = module_global_addrs.get(*addr as usize).ok_or_else(|| { - Error::Other(format!("global {addr} not found. This should have been caught by the validator")) - })?; - - let global = - self.state.globals.get(*addr as usize).expect("global not found. This should be unreachable"); - global.value.get() - } - RefFunc(None) => TinyWasmValue::ValueRef(None), - RefExtern(None) => TinyWasmValue::ValueRef(None), - RefFunc(Some(idx)) => { - TinyWasmValue::ValueRef(Some(*module_func_addrs.get(*idx as usize).ok_or_else(|| { - Error::Other(format!("function {idx} not found. This should have been caught by the validator")) - })?)) - } - _ => return Err(Error::Other("unsupported const instruction".to_string())), + + let resolve_global = |idx: u32| -> Result { + let addr = module_global_addrs.get(idx as usize).ok_or_else(|| { + Error::Other(format!("global {idx} not found. This should have been caught by the validator")) + })?; + let global = self + .state + .globals + .get(*addr as usize) + .ok_or_else(|| Error::Other(format!("global {addr} not found")))?; + Ok(global.value.get()) }; - Ok(val) + + let resolve_func = |idx: u32| -> Result { + module_func_addrs.get(idx as usize).copied().ok_or_else(|| { + Error::Other(format!("function {idx} not found. This should have been caught by the validator")) + }) + }; + + if const_instrs.len() == 1 { + let val = match &const_instrs[0] { + F32Const(f) => (*f).into(), + F64Const(f) => (*f).into(), + I32Const(i) => (*i).into(), + I64Const(i) => (*i).into(), + V128Const(i) => (*i).into(), + GlobalGet(addr) => resolve_global(*addr)?, + RefFunc(None) => TinyWasmValue::ValueRef(None), + RefExtern(None) => TinyWasmValue::ValueRef(None), + RefFunc(Some(idx)) => TinyWasmValue::ValueRef(Some(resolve_func(*idx)?)), + _ => return Err(Error::Other("unsupported const instruction".to_string())), + }; + return Ok(val); + } + + let mut stack = Vec::with_capacity(const_instrs.len()); + for instr in const_instrs { + match instr { + I32Const(i) => stack.push(TinyWasmValue::Value32(*i as u32)), + I64Const(i) => stack.push(TinyWasmValue::Value64(*i as u64)), + F32Const(f) => stack.push(TinyWasmValue::Value32(f.to_bits())), + F64Const(f) => stack.push(TinyWasmValue::Value64(f.to_bits())), + V128Const(i) => stack.push(TinyWasmValue::Value128((*i).into())), + GlobalGet(addr) => stack.push(resolve_global(*addr)?), + RefFunc(None) | RefExtern(None) => stack.push(TinyWasmValue::ValueRef(None)), + RefFunc(Some(idx)) => stack.push(TinyWasmValue::ValueRef(Some(resolve_func(*idx)?))), + RefExtern(Some(_)) => { + return Err(Error::Other("ref.extern constants are not supported in init expressions".to_string())); + } + I32Add | I32Sub | I32Mul => { + let rhs = stack.pop().ok_or_else(|| Error::Other("const stack underflow".to_string()))?; + let lhs = stack.pop().ok_or_else(|| Error::Other("const stack underflow".to_string()))?; + let (TinyWasmValue::Value32(lhs), TinyWasmValue::Value32(rhs)) = (lhs, rhs) else { + return Err(Error::Other("type mismatch in const i32 op".to_string())); + }; + let lhs = lhs as i32; + let rhs = rhs as i32; + let out = match instr { + I32Add => lhs.wrapping_add(rhs), + I32Sub => lhs.wrapping_sub(rhs), + I32Mul => lhs.wrapping_mul(rhs), + _ => unreachable!(), + }; + stack.push(TinyWasmValue::Value32(out as u32)); + } + I64Add | I64Sub | I64Mul => { + let rhs = stack.pop().ok_or_else(|| Error::Other("const stack underflow".to_string()))?; + let lhs = stack.pop().ok_or_else(|| Error::Other("const stack underflow".to_string()))?; + let (TinyWasmValue::Value64(lhs), TinyWasmValue::Value64(rhs)) = (lhs, rhs) else { + return Err(Error::Other("type mismatch in const i64 op".to_string())); + }; + let lhs = lhs as i64; + let rhs = rhs as i64; + let out = match instr { + I64Add => lhs.wrapping_add(rhs), + I64Sub => lhs.wrapping_sub(rhs), + I64Mul => lhs.wrapping_mul(rhs), + _ => unreachable!(), + }; + stack.push(TinyWasmValue::Value64(out as u64)); + } + } + } + + let value = stack.pop().ok_or_else(|| Error::Other("empty const expression".to_string()))?; + if !stack.is_empty() { + return Err(Error::Other("const expression did not reduce to single value".to_string())); + } + Ok(value) + } + + fn eval_ref_const( + &self, + const_instrs: &[tinywasm_types::ConstInstruction], + module_global_addrs: &[Addr], + module_func_addrs: &[FuncAddr], + ) -> Result> { + let value = self.eval_const(const_instrs, module_global_addrs, module_func_addrs)?; + match value { + TinyWasmValue::ValueRef(v) => Ok(v), + other => Err(Error::Other(format!("expected reference const value, got {other:?}"))), + } } } diff --git a/crates/tinywasm/tests/generated/wasm-3.csv b/crates/tinywasm/tests/generated/wasm-3.csv index 9b3f446..70c41c4 100644 --- a/crates/tinywasm/tests/generated/wasm-3.csv +++ b/crates/tinywasm/tests/generated/wasm-3.csv @@ -1 +1 @@ -0.9.0-alpha.0,20707,554,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":165,"failed":0},{"name":"annotations.wast","passed":74,"failed":0},{"name":"binary-leb128.wast","passed":93,"failed":0},{"name":"binary.wast","passed":127,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":119,"failed":0},{"name":"br_on_non_null.wast","passed":1,"failed":11},{"name":"br_on_null.wast","passed":1,"failed":9},{"name":"br_table.wast","passed":24,"failed":162},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":172,"failed":0},{"name":"call_ref.wast","passed":4,"failed":31},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":59,"failed":6},{"name":"elem.wast","passed":137,"failed":14},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":97,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":927,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":471,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":175,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":53,"failed":71},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"id.wast","passed":7,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":198,"failed":20},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"instance.wast","passed":0,"failed":23},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":142,"failed":21},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_init.wast","passed":10,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":98,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":89,"failed":1},{"name":"memory_grow.wast","passed":106,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"obsolete-keywords.wast","passed":11,"failed":0},{"name":"ref.wast","passed":12,"failed":1},{"name":"ref_as_non_null.wast","passed":1,"failed":6},{"name":"ref_func.wast","passed":17,"failed":0},{"name":"ref_is_null.wast","passed":2,"failed":20},{"name":"ref_null.wast","passed":0,"failed":34},{"name":"return.wast","passed":84,"failed":0},{"name":"return_call.wast","passed":47,"failed":0},{"name":"return_call_indirect.wast","passed":79,"failed":0},{"name":"return_call_ref.wast","passed":11,"failed":40},{"name":"select.wast","passed":155,"failed":2},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":47,"failed":13},{"name":"table_get.wast","passed":16,"failed":0},{"name":"table_grow.wast","passed":58,"failed":21},{"name":"table_set.wast","passed":26,"failed":0},{"name":"table_size.wast","passed":39,"failed":0},{"name":"token.wast","passed":61,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type-canon.wast","passed":0,"failed":2},{"name":"type-equivalence.wast","passed":12,"failed":20},{"name":"type-rec.wast","passed":8,"failed":15},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":121,"failed":0},{"name":"unreached-valid.wast","passed":2,"failed":11},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] +0.9.0-alpha.0,20776,452,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":165,"failed":0},{"name":"annotations.wast","passed":74,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":127,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":119,"failed":0},{"name":"br_on_non_null.wast","passed":1,"failed":11},{"name":"br_on_null.wast","passed":1,"failed":9},{"name":"br_table.wast","passed":24,"failed":162},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":172,"failed":0},{"name":"call_ref.wast","passed":4,"failed":31},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":63,"failed":2},{"name":"elem.wast","passed":149,"failed":2},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":97,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":927,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":471,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":175,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":116,"failed":8},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"id.wast","passed":7,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":198,"failed":20},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"instance.wast","passed":0,"failed":23},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":142,"failed":21},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_init.wast","passed":10,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":98,"failed":0},{"name":"loop.wast","passed":120,"failed":0},{"name":"memory.wast","passed":89,"failed":1},{"name":"memory_grow.wast","passed":106,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"obsolete-keywords.wast","passed":11,"failed":0},{"name":"ref.wast","passed":12,"failed":1},{"name":"ref_as_non_null.wast","passed":1,"failed":6},{"name":"ref_func.wast","passed":17,"failed":0},{"name":"ref_is_null.wast","passed":2,"failed":20},{"name":"ref_null.wast","passed":0,"failed":34},{"name":"return.wast","passed":84,"failed":0},{"name":"return_call.wast","passed":47,"failed":0},{"name":"return_call_indirect.wast","passed":79,"failed":0},{"name":"return_call_ref.wast","passed":11,"failed":40},{"name":"select.wast","passed":155,"failed":2},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":37,"failed":9},{"name":"table_get.wast","passed":16,"failed":0},{"name":"table_grow.wast","passed":58,"failed":0},{"name":"table_set.wast","passed":26,"failed":0},{"name":"table_size.wast","passed":39,"failed":0},{"name":"token.wast","passed":61,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type-canon.wast","passed":0,"failed":2},{"name":"type-equivalence.wast","passed":12,"failed":20},{"name":"type-rec.wast","passed":10,"failed":17},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":121,"failed":0},{"name":"unreached-valid.wast","passed":2,"failed":11},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] diff --git a/crates/tinywasm/tests/generated/wasm-extended-const.csv b/crates/tinywasm/tests/generated/wasm-extended-const.csv index e20303d..ea4f784 100644 --- a/crates/tinywasm/tests/generated/wasm-extended-const.csv +++ b/crates/tinywasm/tests/generated/wasm-extended-const.csv @@ -1,2 +1,2 @@ 0.8.0,211,79,[{"name":"data.wast","passed":61,"failed":4},{"name":"elem.wast","passed":99,"failed":12},{"name":"global.wast","passed":51,"failed":63}] -0.9.0-alpha.0,211,79,[{"name":"data.wast","passed":61,"failed":4},{"name":"elem.wast","passed":99,"failed":12},{"name":"global.wast","passed":51,"failed":63}] +0.9.0-alpha.0,290,0,[{"name":"data.wast","passed":65,"failed":0},{"name":"elem.wast","passed":111,"failed":0},{"name":"global.wast","passed":114,"failed":0}] diff --git a/crates/tinywasm/tests/generated/wasm-latest.csv b/crates/tinywasm/tests/generated/wasm-latest.csv index 93e892b..305324a 100644 --- a/crates/tinywasm/tests/generated/wasm-latest.csv +++ b/crates/tinywasm/tests/generated/wasm-latest.csv @@ -1 +1 @@ -0.9.0-alpha.0,20698,531,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":165,"failed":0},{"name":"annotations.wast","passed":74,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":127,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":119,"failed":0},{"name":"br_on_non_null.wast","passed":1,"failed":11},{"name":"br_on_null.wast","passed":1,"failed":9},{"name":"br_table.wast","passed":24,"failed":162},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":172,"failed":0},{"name":"call_ref.wast","passed":4,"failed":31},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":59,"failed":6},{"name":"elem.wast","passed":137,"failed":14},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":97,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":927,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":471,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":175,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":53,"failed":71},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"id.wast","passed":7,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":198,"failed":20},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"instance.wast","passed":0,"failed":23},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":142,"failed":21},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_init.wast","passed":10,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":98,"failed":0},{"name":"loop.wast","passed":121,"failed":0},{"name":"memory.wast","passed":89,"failed":1},{"name":"memory_grow.wast","passed":106,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"obsolete-keywords.wast","passed":11,"failed":0},{"name":"ref.wast","passed":12,"failed":1},{"name":"ref_as_non_null.wast","passed":1,"failed":6},{"name":"ref_func.wast","passed":17,"failed":0},{"name":"ref_is_null.wast","passed":2,"failed":20},{"name":"ref_null.wast","passed":0,"failed":34},{"name":"return.wast","passed":84,"failed":0},{"name":"return_call.wast","passed":47,"failed":0},{"name":"return_call_indirect.wast","passed":79,"failed":0},{"name":"return_call_ref.wast","passed":11,"failed":40},{"name":"select.wast","passed":155,"failed":2},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":37,"failed":9},{"name":"table_get.wast","passed":16,"failed":0},{"name":"table_grow.wast","passed":58,"failed":0},{"name":"table_set.wast","passed":26,"failed":0},{"name":"table_size.wast","passed":39,"failed":0},{"name":"token.wast","passed":61,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type-canon.wast","passed":0,"failed":2},{"name":"type-equivalence.wast","passed":12,"failed":20},{"name":"type-rec.wast","passed":10,"failed":17},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":121,"failed":0},{"name":"unreached-valid.wast","passed":2,"failed":11},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] +0.9.0-alpha.0,20777,452,[{"name":"address.wast","passed":260,"failed":0},{"name":"align.wast","passed":165,"failed":0},{"name":"annotations.wast","passed":74,"failed":0},{"name":"binary-leb128.wast","passed":91,"failed":0},{"name":"binary.wast","passed":127,"failed":0},{"name":"block.wast","passed":223,"failed":0},{"name":"br.wast","passed":97,"failed":0},{"name":"br_if.wast","passed":119,"failed":0},{"name":"br_on_non_null.wast","passed":1,"failed":11},{"name":"br_on_null.wast","passed":1,"failed":9},{"name":"br_table.wast","passed":24,"failed":162},{"name":"call.wast","passed":91,"failed":0},{"name":"call_indirect.wast","passed":172,"failed":0},{"name":"call_ref.wast","passed":4,"failed":31},{"name":"comments.wast","passed":8,"failed":0},{"name":"const.wast","passed":778,"failed":0},{"name":"conversions.wast","passed":619,"failed":0},{"name":"custom.wast","passed":11,"failed":0},{"name":"data.wast","passed":63,"failed":2},{"name":"elem.wast","passed":149,"failed":2},{"name":"endianness.wast","passed":69,"failed":0},{"name":"exports.wast","passed":97,"failed":0},{"name":"f32.wast","passed":2514,"failed":0},{"name":"f32_bitwise.wast","passed":364,"failed":0},{"name":"f32_cmp.wast","passed":2407,"failed":0},{"name":"f64.wast","passed":2514,"failed":0},{"name":"f64_bitwise.wast","passed":364,"failed":0},{"name":"f64_cmp.wast","passed":2407,"failed":0},{"name":"fac.wast","passed":8,"failed":0},{"name":"float_exprs.wast","passed":927,"failed":0},{"name":"float_literals.wast","passed":179,"failed":0},{"name":"float_memory.wast","passed":90,"failed":0},{"name":"float_misc.wast","passed":471,"failed":0},{"name":"forward.wast","passed":5,"failed":0},{"name":"func.wast","passed":175,"failed":0},{"name":"func_ptrs.wast","passed":36,"failed":0},{"name":"global.wast","passed":116,"failed":8},{"name":"i32.wast","passed":460,"failed":0},{"name":"i64.wast","passed":416,"failed":0},{"name":"id.wast","passed":7,"failed":0},{"name":"if.wast","passed":241,"failed":0},{"name":"imports.wast","passed":198,"failed":20},{"name":"inline-module.wast","passed":1,"failed":0},{"name":"instance.wast","passed":0,"failed":23},{"name":"int_exprs.wast","passed":108,"failed":0},{"name":"int_literals.wast","passed":51,"failed":0},{"name":"labels.wast","passed":29,"failed":0},{"name":"left-to-right.wast","passed":96,"failed":0},{"name":"linking.wast","passed":142,"failed":21},{"name":"load.wast","passed":97,"failed":0},{"name":"local_get.wast","passed":36,"failed":0},{"name":"local_init.wast","passed":10,"failed":0},{"name":"local_set.wast","passed":53,"failed":0},{"name":"local_tee.wast","passed":98,"failed":0},{"name":"loop.wast","passed":121,"failed":0},{"name":"memory.wast","passed":89,"failed":1},{"name":"memory_grow.wast","passed":106,"failed":0},{"name":"memory_redundancy.wast","passed":8,"failed":0},{"name":"memory_size.wast","passed":42,"failed":0},{"name":"memory_trap.wast","passed":182,"failed":0},{"name":"names.wast","passed":486,"failed":0},{"name":"nop.wast","passed":88,"failed":0},{"name":"obsolete-keywords.wast","passed":11,"failed":0},{"name":"ref.wast","passed":12,"failed":1},{"name":"ref_as_non_null.wast","passed":1,"failed":6},{"name":"ref_func.wast","passed":17,"failed":0},{"name":"ref_is_null.wast","passed":2,"failed":20},{"name":"ref_null.wast","passed":0,"failed":34},{"name":"return.wast","passed":84,"failed":0},{"name":"return_call.wast","passed":47,"failed":0},{"name":"return_call_indirect.wast","passed":79,"failed":0},{"name":"return_call_ref.wast","passed":11,"failed":40},{"name":"select.wast","passed":155,"failed":2},{"name":"skip-stack-guard-page.wast","passed":11,"failed":0},{"name":"stack.wast","passed":7,"failed":0},{"name":"start.wast","passed":20,"failed":0},{"name":"store.wast","passed":68,"failed":0},{"name":"switch.wast","passed":28,"failed":0},{"name":"table.wast","passed":37,"failed":9},{"name":"table_get.wast","passed":16,"failed":0},{"name":"table_grow.wast","passed":58,"failed":0},{"name":"table_set.wast","passed":26,"failed":0},{"name":"table_size.wast","passed":39,"failed":0},{"name":"token.wast","passed":61,"failed":0},{"name":"traps.wast","passed":36,"failed":0},{"name":"type-canon.wast","passed":0,"failed":2},{"name":"type-equivalence.wast","passed":12,"failed":20},{"name":"type-rec.wast","passed":10,"failed":17},{"name":"type.wast","passed":3,"failed":0},{"name":"unreachable.wast","passed":64,"failed":0},{"name":"unreached-invalid.wast","passed":121,"failed":0},{"name":"unreached-valid.wast","passed":2,"failed":11},{"name":"unwind.wast","passed":50,"failed":0},{"name":"utf8-custom-section-id.wast","passed":176,"failed":0},{"name":"utf8-import-field.wast","passed":176,"failed":0},{"name":"utf8-import-module.wast","passed":176,"failed":0},{"name":"utf8-invalid-encoding.wast","passed":176,"failed":0}] diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs index 8b12811..8c0680e 100644 --- a/crates/types/src/instructions.rs +++ b/crates/types/src/instructions.rs @@ -40,6 +40,12 @@ pub enum ConstInstruction { GlobalGet(GlobalAddr), RefFunc(Option), RefExtern(Option), + I32Add, + I32Sub, + I32Mul, + I64Add, + I64Sub, + I64Mul, } /// A WebAssembly Instruction diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index 29a29e5..737c04e 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -325,7 +325,7 @@ pub struct Export { #[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))] pub struct Global { pub ty: GlobalType, - pub init: ConstInstruction, + pub init: Box<[ConstInstruction]>, } #[derive(Clone, Copy, PartialEq, Eq)] @@ -458,7 +458,7 @@ pub struct Data { #[cfg_attr(feature = "debug", derive(Debug))] #[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))] pub enum DataKind { - Active { mem: MemAddr, offset: ConstInstruction }, + Active { mem: MemAddr, offset: Box<[ConstInstruction]> }, Passive, } @@ -472,19 +472,19 @@ pub struct Element { pub ty: ValType, } -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, PartialEq)] #[cfg_attr(feature = "debug", derive(Debug))] #[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))] pub enum ElementKind { Passive, - Active { table: TableAddr, offset: ConstInstruction }, + Active { table: TableAddr, offset: Box<[ConstInstruction]> }, Declared, } -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, PartialEq)] #[cfg_attr(feature = "debug", derive(Debug))] #[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))] pub enum ElementItem { Func(FuncAddr), - Expr(ConstInstruction), + Expr(Box<[ConstInstruction]>), } diff --git a/crates/types/src/value.rs b/crates/types/src/value.rs index 8cc7f1b..f468be5 100644 --- a/crates/types/src/value.rs +++ b/crates/types/src/value.rs @@ -128,8 +128,8 @@ impl ExternRef { impl WasmValue { #[doc(hidden)] #[inline] - pub const fn const_instr(&self) -> ConstInstruction { - match self { + pub fn const_instr(&self) -> alloc::boxed::Box<[ConstInstruction]> { + alloc::boxed::Box::new([match self { Self::I32(i) => ConstInstruction::I32Const(*i), Self::I64(i) => ConstInstruction::I64Const(*i), Self::F32(i) => ConstInstruction::F32Const(*i), @@ -137,7 +137,7 @@ impl WasmValue { Self::V128(i) => ConstInstruction::V128Const(*i), Self::RefFunc(i) => ConstInstruction::RefFunc(i.addr()), Self::RefExtern(i) => ConstInstruction::RefExtern(i.addr()), - } + }]) } /// Get the default value for a given type. -- cgit v1.3.1