From 5de0533875b6f439ea9e562cba93204ec15e3ba8 Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 16 Apr 2026 23:29:00 +0200 Subject: chore: remove ref stack Signed-off-by: Henry --- crates/parser/src/conversion.rs | 4 +- crates/parser/src/optimize.rs | 38 ---------- crates/parser/src/visit.rs | 62 ++++++---------- crates/tinywasm/src/engine.rs | 12 +-- crates/tinywasm/src/interpreter/executor.rs | 41 ++++++----- .../tinywasm/src/interpreter/stack/call_stack.rs | 2 - .../tinywasm/src/interpreter/stack/value_stack.rs | 29 ++------ crates/tinywasm/src/interpreter/values.rs | 86 ++++++++++++++++------ crates/tinywasm/src/store/mod.rs | 16 ++-- crates/types/src/instructions.rs | 7 +- crates/types/src/lib.rs | 5 +- crates/types/src/value.rs | 52 ++++++++++--- 12 files changed, 179 insertions(+), 175 deletions(-) (limited to 'crates') diff --git a/crates/parser/src/conversion.rs b/crates/parser/src/conversion.rs index 19ce975..32f2944 100644 --- a/crates/parser/src/conversion.rs +++ b/crates/parser/src/conversion.rs @@ -191,8 +191,8 @@ pub(crate) fn convert_module_code( local_counts.c128 += 1; } Some(wasmparser::ValType::Ref(_)) => { - local_addr_map.push(local_counts.cref); - local_counts.cref += 1; + local_addr_map.push(local_counts.c32); + local_counts.c32 += 1; } None => return Err(crate::ParseError::UnsupportedOperator("Unknown local type".to_string())), } diff --git a/crates/parser/src/optimize.rs b/crates/parser/src/optimize.rs index 1369d7a..c066c29 100644 --- a/crates/parser/src/optimize.rs +++ b/crates/parser/src/optimize.rs @@ -21,7 +21,6 @@ fn rewrite(instructions: &mut [Instruction], self_func_addr: u32) { Instruction::LocalCopy32(a, b) if a == b => instructions[read] = Instruction::Nop, Instruction::LocalCopy64(a, b) if a == b => instructions[read] = Instruction::Nop, Instruction::LocalCopy128(a, b) if a == b => instructions[read] = Instruction::Nop, - Instruction::LocalCopyRef(a, b) if a == b => instructions[read] = Instruction::Nop, Instruction::Call(addr) if addr == self_func_addr => instructions[read] = Instruction::CallSelf, Instruction::ReturnCall(addr) if addr == self_func_addr => instructions[read] = Instruction::ReturnCallSelf, Instruction::I32Add => { @@ -154,16 +153,6 @@ fn rewrite(instructions: &mut [Instruction], self_func_addr: u32) { instructions[read] = Instruction::Nop; } } - Instruction::LocalGetRef(dst) => { - if read > 0 - && let Instruction::LocalSetRef(src) = instructions[read - 1] - && src == dst - { - instructions[read - 1] = Instruction::LocalTeeRef(src); - instructions[read] = Instruction::Nop; - } - } - Instruction::LocalSet32(dst) => { if read > 0 { match instructions[read - 1] { @@ -243,16 +232,6 @@ fn rewrite(instructions: &mut [Instruction], self_func_addr: u32) { if src == dst { Instruction::Nop } else { Instruction::LocalCopy128(src, dst) }; } } - Instruction::LocalSetRef(dst) => { - if read > 0 - && let Instruction::LocalGetRef(src) = instructions[read - 1] - { - instructions[read - 1] = Instruction::Nop; - instructions[read] = - if src == dst { Instruction::Nop } else { Instruction::LocalCopyRef(src, dst) }; - } - } - Instruction::LocalTee32(dst) => { if read > 0 && let Instruction::LocalGet32(src) = instructions[read - 1] @@ -289,15 +268,6 @@ fn rewrite(instructions: &mut [Instruction], self_func_addr: u32) { instructions[read] = Instruction::Nop; } } - Instruction::LocalTeeRef(dst) => { - if read > 0 - && let Instruction::LocalGetRef(src) = instructions[read - 1] - && src == dst - { - instructions[read] = Instruction::Nop; - } - } - Instruction::Drop32 => { if read > 0 && let Instruction::LocalTee32(local) = instructions[read - 1] @@ -322,14 +292,6 @@ fn rewrite(instructions: &mut [Instruction], self_func_addr: u32) { instructions[read] = Instruction::Nop; } } - Instruction::DropRef => { - if read > 0 - && let Instruction::LocalTeeRef(local) = instructions[read - 1] - { - instructions[read - 1] = Instruction::LocalSetRef(local); - instructions[read] = Instruction::Nop; - } - } _ => {} } } diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs index 94cb4ea..e6f415b 100644 --- a/crates/parser/src/visit.rs +++ b/crates/parser/src/visit.rs @@ -22,7 +22,6 @@ struct StackBase { s32: u16, s64: u16, s128: u16, - sref: u16, } struct LoweringCtx { @@ -214,7 +213,7 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild wasmparser::ValType::I64 => Instruction::GlobalSet64(global_index), wasmparser::ValType::F64 => Instruction::GlobalSet64(global_index), wasmparser::ValType::V128 => Instruction::GlobalSet128(global_index), - wasmparser::ValType::Ref(_) => Instruction::GlobalSetRef(global_index), + wasmparser::ValType::Ref(_) => Instruction::GlobalSet32(global_index), }) } } @@ -227,7 +226,7 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild wasmparser::ValType::I64 => Instruction::Drop64, wasmparser::ValType::F64 => Instruction::Drop64, wasmparser::ValType::V128 => Instruction::Drop128, - wasmparser::ValType::Ref(_) => Instruction::DropRef, + wasmparser::ValType::Ref(_) => Instruction::Drop32, }) } } @@ -257,7 +256,7 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild self.instructions.push(Instruction::LocalGet128(resolved_idx)); } wasmparser::ValType::Ref(_) => { - self.instructions.push(Instruction::LocalGetRef(resolved_idx)); + self.instructions.push(Instruction::LocalGet32(resolved_idx)); } } } @@ -272,7 +271,7 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild wasmparser::ValType::I64 => Instruction::LocalSet64(resolved_idx), wasmparser::ValType::F64 => Instruction::LocalSet64(resolved_idx), wasmparser::ValType::V128 => Instruction::LocalSet128(resolved_idx), - wasmparser::ValType::Ref(_) => Instruction::LocalSetRef(resolved_idx), + wasmparser::ValType::Ref(_) => Instruction::LocalSet32(resolved_idx), }) } } @@ -286,7 +285,7 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild wasmparser::ValType::I64 => Instruction::LocalTee64(resolved_idx), wasmparser::ValType::F64 => Instruction::LocalTee64(resolved_idx), wasmparser::ValType::V128 => Instruction::LocalTee128(resolved_idx), - wasmparser::ValType::Ref(_) => Instruction::LocalTeeRef(resolved_idx), + wasmparser::ValType::Ref(_) => Instruction::LocalTee32(resolved_idx), }) } } @@ -457,8 +456,8 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild } fn visit_typed_select_multi(&mut self, tys: Vec) -> Self::Output { - let (c32, c64, c128, cref) = Self::label_keep_counts(&tys); - self.instructions.push(Instruction::SelectMulti(tinywasm_types::ValueCounts { c32, c64, c128, cref })); + let (c32, c64, c128) = Self::label_keep_counts(&tys); + self.instructions.push(Instruction::SelectMulti(tinywasm_types::ValueCounts { c32, c64, c128 })); } fn visit_typed_select(&mut self, ty: wasmparser::ValType) -> Self::Output { @@ -468,7 +467,7 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild wasmparser::ValType::I64 => Instruction::Select64, wasmparser::ValType::F64 => Instruction::Select64, wasmparser::ValType::V128 => Instruction::Select128, - wasmparser::ValType::Ref(_) => Instruction::SelectRef, + wasmparser::ValType::Ref(_) => Instruction::Select32, }); } @@ -595,7 +594,7 @@ impl FunctionBuilder { wasmparser::ValType::I32 | wasmparser::ValType::F32 => base.s32 += 1, wasmparser::ValType::I64 | wasmparser::ValType::F64 => base.s64 += 1, wasmparser::ValType::V128 => base.s128 += 1, - wasmparser::ValType::Ref(_) => base.sref += 1, + wasmparser::ValType::Ref(_) => base.s32 += 1, } } } @@ -617,16 +616,8 @@ impl FunctionBuilder { Some(idx) } - fn emit_dropkeep(&mut self, base: StackBase, c32: u16, c64: u16, c128: u16, cref: u16) { - if base.s32 == 0 - && c32 == 0 - && base.s64 == 0 - && c64 == 0 - && base.s128 == 0 - && c128 == 0 - && base.sref == 0 - && cref == 0 - { + fn emit_dropkeep(&mut self, base: StackBase, c32: u16, c64: u16, c128: u16) { + if base.s32 == 0 && c32 == 0 && base.s64 == 0 && c64 == 0 && base.s128 == 0 && c128 == 0 { return; } @@ -635,26 +626,21 @@ impl FunctionBuilder { && base.s64 <= u8::MAX as u16 && c64 <= u8::MAX as u16 && base.s128 <= u8::MAX as u16 - && c128 <= u8::MAX as u16 - && base.sref <= u8::MAX as u16 - && cref <= u8::MAX as u16; + && c128 <= u8::MAX as u16; if fits_u8 { - self.instructions.push(Instruction::DropKeepSmall { - base32: base.s32 as u8, + self.instructions.push(Instruction::DropKeep { + base32: base.s32, keep32: c32 as u8, - base64: base.s64 as u8, + base64: base.s64, keep64: c64 as u8, - base128: base.s128 as u8, + base128: base.s128, keep128: c128 as u8, - base_ref: base.sref as u8, - keep_ref: cref as u8, }); } else { self.instructions.push(Instruction::DropKeep32(base.s32, c32)); self.instructions.push(Instruction::DropKeep64(base.s64, c64)); self.instructions.push(Instruction::DropKeep128(base.s128, c128)); - self.instructions.push(Instruction::DropKeepRef(base.sref, cref)); } } @@ -673,18 +659,18 @@ impl FunctionBuilder { } } - fn label_keep_counts(label_types: &[wasmparser::ValType]) -> (u16, u16, u16, u16) { - let (mut c32, mut c64, mut c128, mut cref) = (0, 0, 0, 0); + fn label_keep_counts(label_types: &[wasmparser::ValType]) -> (u16, u16, u16) { + let (mut c32, mut c64, mut c128) = (0, 0, 0); for ty in label_types { match ty { wasmparser::ValType::I32 | wasmparser::ValType::F32 => c32 += 1, wasmparser::ValType::I64 | wasmparser::ValType::F64 => c64 += 1, wasmparser::ValType::V128 => c128 += 1, - wasmparser::ValType::Ref(_) => cref += 1, + wasmparser::ValType::Ref(_) => c32 += 1, } } - (c32, c64, c128, cref) + (c32, c64, c128) } fn emit_dropkeep_to_label(&mut self, label_depth: u32) { @@ -698,9 +684,9 @@ impl FunctionBuilder { let base = self.stack_base_at_frame(label_depth as usize); let label_types: Vec<_> = self.label_types_for_frame(frame); - let (c32, c64, c128, cref) = Self::label_keep_counts(&label_types); + let (c32, c64, c128) = Self::label_keep_counts(&label_types); - self.emit_dropkeep(base, c32, c64, c128, cref); + self.emit_dropkeep(base, c32, c64, c128); } fn label_types_for_frame(&self, frame: &wasmparser::Frame) -> Vec { @@ -746,8 +732,8 @@ impl FunctionBuilder { let base = self.stack_base_at_frame(depth as usize); let label_types: Vec<_> = self.label_types_for_frame(frame); - let (c32, c64, c128, cref) = Self::label_keep_counts(&label_types); - self.emit_dropkeep(base, c32, c64, c128, cref); + let (c32, c64, c128) = Self::label_keep_counts(&label_types); + self.emit_dropkeep(base, c32, c64, c128); let jump_ip = self.instructions.len(); self.instructions.push(Instruction::Jump(0)); diff --git a/crates/tinywasm/src/engine.rs b/crates/tinywasm/src/engine.rs index ce84f3d..c8f05e9 100644 --- a/crates/tinywasm/src/engine.rs +++ b/crates/tinywasm/src/engine.rs @@ -39,8 +39,8 @@ pub enum FuelPolicy { Weighted, } -/// Default size for the 32-bit value stack (i32, f32 values). -pub const DEFAULT_VALUE_STACK_32_SIZE: usize = 32 * 1024; // 32k slots +/// Default size for the 32-bit value stack (i32, f32, ref values). +pub const DEFAULT_VALUE_STACK_32_SIZE: usize = 36 * 1024; // 36k slots /// Default size for the 64-bit value stack (i64, f64 values). pub const DEFAULT_VALUE_STACK_64_SIZE: usize = 32 * 1024; // 32k slots @@ -48,9 +48,6 @@ pub const DEFAULT_VALUE_STACK_64_SIZE: usize = 32 * 1024; // 32k slots /// Default size for the 128-bit value stack (v128 values). pub const DEFAULT_VALUE_STACK_128_SIZE: usize = 4 * 1024; // 4k slots -/// Default size for the reference value stack (funcref, externref values). -pub const DEFAULT_VALUE_STACK_REF_SIZE: usize = 4 * 1024; // 4k slots - /// Default maximum size for the call stack (function frames). pub const DEFAULT_MAX_CALL_STACK_SIZE: usize = 1024; // 1024 frames @@ -59,14 +56,12 @@ pub const DEFAULT_MAX_CALL_STACK_SIZE: usize = 1024; // 1024 frames #[cfg_attr(feature = "debug", derive(Debug))] #[non_exhaustive] pub struct Config { - /// Size of the 32-bit value stack (i32, f32 values). + /// Size of the 32-bit value stack (i32, f32, ref values). pub stack_32_size: usize, /// Size of the 64-bit value stack (i64, f64 values). pub stack_64_size: usize, /// Size of the 128-bit value stack (v128 values). pub stack_128_size: usize, - /// Size of the reference value stack (funcref, externref values). - pub stack_ref_size: usize, /// Maximum size of the call stack pub max_call_stack_size: usize, /// Fuel accounting policy used by budgeted execution. @@ -92,7 +87,6 @@ impl Default for Config { stack_32_size: DEFAULT_VALUE_STACK_32_SIZE, stack_64_size: DEFAULT_VALUE_STACK_64_SIZE, stack_128_size: DEFAULT_VALUE_STACK_128_SIZE, - stack_ref_size: DEFAULT_VALUE_STACK_REF_SIZE, max_call_stack_size: DEFAULT_MAX_CALL_STACK_SIZE, fuel_policy: FuelPolicy::default(), } diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs index fd7d49e..a6052a9 100644 --- a/crates/tinywasm/src/interpreter/executor.rs +++ b/crates/tinywasm/src/interpreter/executor.rs @@ -135,11 +135,9 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { Drop32 => self.store.stack.values.drop::(), Drop64 => self.store.stack.values.drop::(), Drop128 => self.store.stack.values.drop::(), - DropRef => self.store.stack.values.drop::(), Select32 => self.store.stack.values.select::()?, Select64 => self.store.stack.values.select::()?, Select128 => self.store.stack.values.select::()?, - SelectRef => self.store.stack.values.select::()?, SelectMulti(counts) => self.store.stack.values.select_multi(*counts), Call(v) => { self.exec_call_direct::(*v)?; continue; } CallSelf => { self.exec_call_self::()?; continue; } @@ -150,28 +148,24 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { Jump(ip) => { self.exec_jump(*ip); continue; } JumpIfZero(ip) => if self.exec_jump_if_zero(*ip) { continue; }, JumpIfNonZero(ip) => if self.exec_jump_if_non_zero(*ip) { continue; }, - DropKeepSmall { base32, keep32, base64, keep64, base128, keep128, base_ref, keep_ref } => { - let mut base = self.cf.stack_base(); base.s32 += *base32 as u32; base.s64 += *base64 as u32; base.s128 += *base128 as u32; base.sref += *base_ref as u32; - self.store.stack.values.truncate_keep_counts(base, ValueCounts { c32: *keep32 as u16, c64: *keep64 as u16, c128: *keep128 as u16, cref: *keep_ref as u16 }); + DropKeep { base32, keep32, base64, keep64, base128, keep128 } => { + let mut base = self.cf.stack_base(); base.s32 += *base32 as u32; base.s64 += *base64 as u32; base.s128 += *base128 as u32; + self.store.stack.values.truncate_keep_counts(base, ValueCounts { c32: *keep32 as u16, c64: *keep64 as u16, c128: *keep128 as u16 }); } DropKeep32(base, keep) => self.store.stack.values.stack_32.truncate_keep((self.cf.stack_base().s32 + *base as u32) as usize, *keep as usize), DropKeep64(base, keep) => self.store.stack.values.stack_64.truncate_keep((self.cf.stack_base().s64 + *base as u32) as usize, *keep as usize), DropKeep128(base, keep) => self.store.stack.values.stack_128.truncate_keep((self.cf.stack_base().s128 + *base as u32) as usize, *keep as usize), - DropKeepRef(base, keep) => self.store.stack.values.stack_ref.truncate_keep((self.cf.stack_base().sref + *base as u32) as usize, *keep as usize), BranchTable(default_ip, start, len) => { self.exec_branch_table(*default_ip, *start, *len); continue; } Return => { if self.exec_return() { return Ok(Some(())); } continue; } LocalGet32(local_index) => self.store.stack.values.push(self.store.stack.values.local_get::(&self.cf, *local_index))?, LocalGet64(local_index) => self.store.stack.values.push(self.store.stack.values.local_get::(&self.cf, *local_index))?, LocalGet128(local_index) => self.store.stack.values.push(self.store.stack.values.local_get::(&self.cf, *local_index))?, - LocalGetRef(local_index) => self.store.stack.values.push(self.store.stack.values.local_get::(&self.cf, *local_index))?, LocalSet32(local_index) => stack_op!(local_set_pop Value32, local_index), LocalSet64(local_index) => stack_op!(local_set_pop Value64, local_index), LocalSet128(local_index) => stack_op!(local_set_pop Value128, local_index), - LocalSetRef(local_index) => stack_op!(local_set_pop ValueRef, local_index), LocalCopy32(from, to) => self.store.stack.values.local_set(&self.cf, *to, self.store.stack.values.local_get::(&self.cf, *from)), LocalCopy64(from, to) => self.store.stack.values.local_set(&self.cf, *to, self.store.stack.values.local_get::(&self.cf, *from)), LocalCopy128(from, to) => self.store.stack.values.local_set(&self.cf, *to, self.store.stack.values.local_get::(&self.cf, *from)), - LocalCopyRef(from, to) => self.store.stack.values.local_set(&self.cf, *to, self.store.stack.values.local_get::(&self.cf, *from)), I32AddLocals(a, b) => self.store.stack.values.push(self.store.stack.values.local_get::(&self.cf, *a).wrapping_add(self.store.stack.values.local_get::(&self.cf, *b)))?, I64AddLocals(a, b) => self.store.stack.values.push(self.store.stack.values.local_get::(&self.cf, *a).wrapping_add(self.store.stack.values.local_get::(&self.cf, *b)))?, I32AddConst(c) => stack_op!(unary i32, |v| v.wrapping_add(*c)), @@ -192,12 +186,10 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { LocalTee32(local_index) => stack_op!(local_tee Value32, local_index), LocalTee64(local_index) => stack_op!(local_tee Value64, local_index), LocalTee128(local_index) => stack_op!(local_tee Value128, local_index), - LocalTeeRef(local_index) => stack_op!(local_tee ValueRef, local_index), GlobalGet(global_index) => self.exec_global_get(*global_index)?, - GlobalSet32(global_index) => self.exec_global_set::(*global_index), + GlobalSet32(global_index) => self.exec_global_set_32(*global_index), GlobalSet64(global_index) => self.exec_global_set::(*global_index), GlobalSet128(global_index) => self.exec_global_set::(*global_index), - GlobalSetRef(global_index) => self.exec_global_set::(*global_index), I32Const(val) => self.exec_const(*val)?, I64Const(val) => self.exec_const(*val)?, F32Const(val) => self.exec_const(*val)?, @@ -302,8 +294,8 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { I64Popcnt => stack_op!(unary i64, |v| i64::from(v.count_ones())), // Reference types - RefFunc(func_idx) => self.exec_const::(Some(self.module.resolve_func_addr(*func_idx)))?, - RefNull(_) => self.exec_const::(None)?, + RefFunc(func_idx) => self.exec_const(ValueRef::from_addr(Some(self.module.resolve_func_addr(*func_idx))))?, + RefNull(_) => self.exec_const(ValueRef::NULL)?, RefIsNull => self.exec_ref_is_null()?, MemorySize(addr) => self.exec_memory_size(*addr)?, MemoryGrow(addr) => self.exec_memory_grow(*addr)?, @@ -909,11 +901,24 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { let val = self.store.stack.values.pop::().into(); self.store.state.set_global_val(self.module.resolve_global_addr(global_index), val); } + + fn exec_global_set_32(&mut self, global_index: u32) { + let global_addr = self.module.resolve_global_addr(global_index); + let raw = self.store.stack.values.pop::(); + let ty = self.store.state.get_global(global_addr).ty.ty; + let value = match ty { + WasmType::I32 | WasmType::F32 => TinyWasmValue::Value32(raw), + WasmType::RefExtern | WasmType::RefFunc => TinyWasmValue::ValueRef(ValueRef::from_raw(raw)), + WasmType::I64 | WasmType::F64 | WasmType::V128 => unreachable!("invalid global.set.32 target type"), + }; + self.store.state.set_global_val(global_addr, value); + } + fn exec_const(&mut self, val: T) -> Result<()> { self.store.stack.values.push(val) } fn exec_ref_is_null(&mut self) -> Result<()> { - let is_null = i32::from(self.store.stack.values.pop::().is_none()); + let is_null = i32::from(self.store.stack.values.pop::().is_null()); self.store.stack.values.push::(is_null) } @@ -1137,7 +1142,7 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { let val = self.store.stack.values.pop::(); let idx = self.store.stack.values.pop::() as u32; let table = self.store.state.get_table_mut(self.module.resolve_table_addr(table_index)); - table.set(idx, val.into()) + table.set(idx, val.addr().into()) } fn exec_table_size(&mut self, table_index: u32) -> Result<()> { let table = self.store.state.get_table(self.module.resolve_table_addr(table_index)); @@ -1194,7 +1199,7 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { let n = self.store.stack.values.pop::(); let val = self.store.stack.values.pop::(); - match table.grow(n, val.into()) { + match table.grow(n, val.addr().into()) { Ok(()) => self.store.stack.values.push(sz)?, Err(_) => self.store.stack.values.push(-1_i32)?, } @@ -1221,7 +1226,7 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> { return Ok(()); } - table.fill(self.module.func_addrs(), i as usize, n as usize, val.into()) + table.fill(self.module.func_addrs(), i as usize, n as usize, val.addr().into()) } } diff --git a/crates/tinywasm/src/interpreter/stack/call_stack.rs b/crates/tinywasm/src/interpreter/stack/call_stack.rs index dfc71bc..fbf5ca5 100644 --- a/crates/tinywasm/src/interpreter/stack/call_stack.rs +++ b/crates/tinywasm/src/interpreter/stack/call_stack.rs @@ -48,7 +48,6 @@ pub(crate) struct StackBase { pub(crate) s32: u32, pub(crate) s64: u32, pub(crate) s128: u32, - pub(crate) sref: u32, } impl CallFrame { @@ -67,7 +66,6 @@ impl CallFrame { s32: self.locals_base.s32 + self.stack_offset.c32 as u32, s64: self.locals_base.s64 + self.stack_offset.c64 as u32, s128: self.locals_base.s128 + self.stack_offset.c128 as u32, - sref: self.locals_base.sref + self.stack_offset.cref as u32, } } diff --git a/crates/tinywasm/src/interpreter/stack/value_stack.rs b/crates/tinywasm/src/interpreter/stack/value_stack.rs index 189282f..f59f3b6 100644 --- a/crates/tinywasm/src/interpreter/stack/value_stack.rs +++ b/crates/tinywasm/src/interpreter/stack/value_stack.rs @@ -4,16 +4,14 @@ use alloc::boxed::Box; use alloc::vec::Vec; use tinywasm_types::{ExternRef, FuncRef, LocalAddr, ValueCounts, WasmType, WasmValue}; -use crate::{Result, Trap, engine::Config, interpreter::*}; - use super::{CallFrame, StackBase}; +use crate::{Result, Trap, engine::Config, interpreter::*}; #[cfg_attr(feature = "debug", derive(Debug))] pub(crate) struct ValueStack { pub(crate) stack_32: Stack, pub(crate) stack_64: Stack, pub(crate) stack_128: Stack, - pub(crate) stack_ref: Stack, } #[cfg_attr(feature = "debug", derive(Debug))] @@ -160,7 +158,6 @@ impl ValueStack { stack_32: Stack::new(config.stack_32_size), stack_64: Stack::new(config.stack_64_size), stack_128: Stack::new(config.stack_128_size), - stack_ref: Stack::new(config.stack_ref_size), } } @@ -168,12 +165,11 @@ impl ValueStack { self.stack_32.clear(); self.stack_64.clear(); self.stack_128.clear(); - self.stack_ref.clear(); } #[inline(always)] pub(crate) fn len(&self) -> usize { - self.stack_32.len + self.stack_64.len + self.stack_128.len + self.stack_ref.len + self.stack_32.len + self.stack_64.len + self.stack_128.len } #[inline(always)] @@ -213,7 +209,6 @@ impl ValueStack { self.stack_32.select_many(counts.c32 as usize, condition); self.stack_64.select_many(counts.c64 as usize, condition); self.stack_128.select_many(counts.c128 as usize, condition); - self.stack_ref.select_many(counts.cref as usize, condition); } pub(crate) fn pop_types<'a>( @@ -239,13 +234,7 @@ impl ValueStack { } else { self.stack_128.enter_locals(params.c128 as usize, locals.c128 as usize)? }; - let locals_baseref = if params.cref == 0 && locals.cref == 0 { - self.stack_ref.len as u32 - } else { - self.stack_ref.enter_locals(params.cref as usize, locals.cref as usize)? - }; - - Ok(StackBase { s32: locals_base32, s64: locals_base64, s128: locals_base128, sref: locals_baseref }) + Ok(StackBase { s32: locals_base32, s64: locals_base64, s128: locals_base128 }) } pub(crate) fn truncate_keep_counts(&mut self, base: StackBase, keep: ValueCounts) { @@ -253,14 +242,12 @@ impl ValueStack { self.stack_32.len = base.s32 as usize; self.stack_64.len = base.s64 as usize; self.stack_128.len = base.s128 as usize; - self.stack_ref.len = base.sref as usize; return; } self.stack_32.truncate_keep(base.s32 as usize, keep.c32 as usize); self.stack_64.truncate_keep(base.s64 as usize, keep.c64 as usize); self.stack_128.truncate_keep(base.s128 as usize, keep.c128 as usize); - self.stack_ref.truncate_keep(base.sref as usize, keep.cref as usize); } #[inline] @@ -288,7 +275,7 @@ impl ValueStack { TinyWasmValue::Value32(v) => self.stack_32.push(v)?, TinyWasmValue::Value64(v) => self.stack_64.push(v)?, TinyWasmValue::Value128(v) => self.stack_128.push(v)?, - TinyWasmValue::ValueRef(v) => self.stack_ref.push(v)?, + TinyWasmValue::ValueRef(v) => self.stack_32.push(v.raw())?, } Ok(()) } @@ -299,8 +286,8 @@ impl ValueStack { WasmType::I64 => WasmValue::I64(self.pop()), WasmType::F32 => WasmValue::F32(self.pop()), WasmType::F64 => WasmValue::F64(self.pop()), - WasmType::RefExtern => WasmValue::RefExtern(ExternRef::new(self.pop())), - WasmType::RefFunc => WasmValue::RefFunc(FuncRef::new(self.pop())), + WasmType::RefExtern => WasmValue::RefExtern(ExternRef::from_raw(self.pop::().raw())), + WasmType::RefFunc => WasmValue::RefFunc(FuncRef::from_raw(self.pop::().raw())), WasmType::V128 => WasmValue::V128(self.pop::().into()), } } @@ -312,8 +299,8 @@ impl ValueStack { WasmValue::I64(v) => self.stack_64.push(*v as u64)?, WasmValue::F32(v) => self.stack_32.push(v.to_bits())?, WasmValue::F64(v) => self.stack_64.push(v.to_bits())?, - WasmValue::RefExtern(v) => self.stack_ref.push(v.addr())?, - WasmValue::RefFunc(v) => self.stack_ref.push(v.addr())?, + WasmValue::RefExtern(v) => self.stack_32.push(v.raw())?, + WasmValue::RefFunc(v) => self.stack_32.push(v.raw())?, WasmValue::V128(v) => self.stack_128.push((*v).into())?, } } diff --git a/crates/tinywasm/src/interpreter/values.rs b/crates/tinywasm/src/interpreter/values.rs index 7726e57..eae0c53 100644 --- a/crates/tinywasm/src/interpreter/values.rs +++ b/crates/tinywasm/src/interpreter/values.rs @@ -6,8 +6,49 @@ use tinywasm_types::{ExternRef, FuncRef, WasmType, WasmValue}; pub(crate) type Value32 = u32; pub(crate) type Value64 = u64; -pub(crate) type ValueRef = Option; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) struct ValueRef(u32); + +impl Default for ValueRef { + fn default() -> Self { + Self::NULL + } +} + +impl ValueRef { + pub(crate) const NULL: Self = Self(u32::MAX); + + #[inline] + pub(crate) const fn from_raw(raw: u32) -> Self { + Self(raw) + } + + #[inline] + pub(crate) const fn from_addr(addr: Option) -> Self { + match addr { + Some(addr) => Self(addr), + None => Self::NULL, + } + } + + #[inline] + pub(crate) const fn addr(self) -> Option { + if self.is_null() { None } else { Some(self.0) } + } + + #[inline] + pub(crate) const fn is_null(self) -> bool { + self.0 == Self::NULL.0 + } + + #[inline] + pub(crate) const fn raw(self) -> u32 { + self.0 + } +} + +#[allow(private_interfaces)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] /// A untyped WebAssembly value pub enum TinyWasmValue { @@ -47,6 +88,7 @@ impl TinyWasmValue { } /// Converts the value to a reference value (returns None if the value is not a reference value) + #[allow(private_interfaces, dead_code)] pub fn as_ref(self) -> Option { match self { Self::ValueRef(v) => Some(v), @@ -61,8 +103,8 @@ impl TinyWasmValue { (Self::Value64(v), WasmType::I64) => Some(WasmValue::I64(v as i64)), (Self::Value32(v), WasmType::F32) => Some(WasmValue::F32(f32::from_bits(v))), (Self::Value64(v), WasmType::F64) => Some(WasmValue::F64(f64::from_bits(v))), - (Self::ValueRef(v), WasmType::RefExtern) => Some(WasmValue::RefExtern(ExternRef::new(v))), - (Self::ValueRef(v), WasmType::RefFunc) => Some(WasmValue::RefFunc(FuncRef::new(v))), + (Self::ValueRef(v), WasmType::RefExtern) => Some(WasmValue::RefExtern(ExternRef::from_raw(v.raw()))), + (Self::ValueRef(v), WasmType::RefFunc) => Some(WasmValue::RefFunc(FuncRef::from_raw(v.raw()))), (Self::Value128(v), WasmType::V128) => Some(WasmValue::V128((v).into())), (_, WasmType::I32 | WasmType::F32) => None, (_, WasmType::I64 | WasmType::F64) => None, @@ -79,8 +121,8 @@ impl From<&WasmValue> for TinyWasmValue { WasmValue::I64(v) => Self::Value64(*v as u64), WasmValue::F32(v) => Self::Value32(v.to_bits()), WasmValue::F64(v) => Self::Value64(v.to_bits()), - WasmValue::RefExtern(v) => Self::ValueRef(v.addr()), - WasmValue::RefFunc(v) => Self::ValueRef(v.addr()), + WasmValue::RefExtern(v) => Self::ValueRef(ValueRef::from_addr(v.addr())), + WasmValue::RefFunc(v) => Self::ValueRef(ValueRef::from_addr(v.addr())), WasmValue::V128(v) => Self::Value128((*v).into()), } } @@ -113,48 +155,48 @@ pub(crate) trait InternalValue: sealed::Sealed + Into + Copy + De } macro_rules! impl_internalvalue { - ($( $variant:ident, $stack:ident, $stack_base:ident, $outer:ty, $to_internal:expr, $to_outer:expr )*) => { + ($( $variant:ident, $stack:ident, $stack_base:ident, $outer:ty, $to_value:expr, $to_stack:expr, $from_stack:expr )*) => { $( impl sealed::Sealed for $outer {} impl From<$outer> for TinyWasmValue { fn from(value: $outer) -> Self { - TinyWasmValue::$variant($to_internal(value)) + TinyWasmValue::$variant($to_value(value)) } } impl InternalValue for $outer { #[inline(always)] fn stack_push(stack: &mut ValueStack, value: Self) -> Result<()> { - stack.$stack.push($to_internal(value)) + stack.$stack.push($to_stack(value)) } #[inline(always)] fn local_get(stack: &ValueStack, frame: &CallFrame, index: LocalAddr) -> Self { - $to_outer(*stack.$stack.get(frame.locals_base.$stack_base as usize + index as usize)) + $from_stack(*stack.$stack.get(frame.locals_base.$stack_base as usize + index as usize)) } #[inline(always)] fn local_update(stack: &mut ValueStack, frame: &CallFrame, index: LocalAddr, func: impl FnOnce(&mut Self)) { let slot = stack.$stack.get_mut(frame.locals_base.$stack_base as usize + index as usize); - let mut value = $to_outer(*slot); + let mut value = $from_stack(*slot); func(&mut value); - *slot = $to_internal(value); + *slot = $to_stack(value); } #[inline(always)] fn local_set(stack: &mut ValueStack, frame: &CallFrame, index: LocalAddr, value: Self) { - stack.$stack.set(frame.locals_base.$stack_base as usize + index as usize, $to_internal(value)); + stack.$stack.set(frame.locals_base.$stack_base as usize + index as usize, $to_stack(value)); } #[inline(always)] fn stack_pop(stack: &mut ValueStack) -> Self { - $to_outer(stack.$stack.pop()) + $from_stack(stack.$stack.pop()) } #[inline(always)] fn stack_peek(stack: &ValueStack) -> Self { - $to_outer(*stack.$stack.last()) + $from_stack(*stack.$stack.last()) } } )* @@ -162,12 +204,12 @@ macro_rules! impl_internalvalue { } impl_internalvalue! { - Value32, stack_32, s32, u32, |v| v, |v| v - Value64, stack_64, s64, u64, |v| v, |v| v - Value32, stack_32, s32, i32, |v: i32| u32::from_ne_bytes(v.to_ne_bytes()), |v: u32| i32::from_ne_bytes(v.to_ne_bytes()) - Value64, stack_64, s64, i64, |v: i64| u64::from_ne_bytes(v.to_ne_bytes()), |v: u64| i64::from_ne_bytes(v.to_ne_bytes()) - Value32, stack_32, s32, f32, f32::to_bits, f32::from_bits - Value64, stack_64, s64, f64, f64::to_bits, f64::from_bits - ValueRef, stack_ref, sref, ValueRef, |v| v, |v| v - Value128, stack_128, s128, Value128, |v| v, |v| v + Value32, stack_32, s32, u32, |v| v, |v| v, |v| v + Value64, stack_64, s64, u64, |v| v, |v| v, |v| v + Value32, stack_32, s32, i32, |v: i32| u32::from_ne_bytes(v.to_ne_bytes()), |v: i32| u32::from_ne_bytes(v.to_ne_bytes()), |v: u32| i32::from_ne_bytes(v.to_ne_bytes()) + Value64, stack_64, s64, i64, |v: i64| u64::from_ne_bytes(v.to_ne_bytes()), |v: i64| u64::from_ne_bytes(v.to_ne_bytes()), |v: u64| i64::from_ne_bytes(v.to_ne_bytes()) + Value32, stack_32, s32, f32, f32::to_bits, f32::to_bits, f32::from_bits + Value64, stack_64, s64, f64, f64::to_bits, f64::to_bits, f64::from_bits + ValueRef, stack_32, s32, ValueRef, |v| v, |v: ValueRef| v.raw(), |v: u32| ValueRef(v) + Value128, stack_128, s128, Value128, |v| v, |v| v, |v| v } diff --git a/crates/tinywasm/src/store/mod.rs b/crates/tinywasm/src/store/mod.rs index 4ba6c97..57601a4 100644 --- a/crates/tinywasm/src/store/mod.rs +++ b/crates/tinywasm/src/store/mod.rs @@ -4,8 +4,8 @@ use core::sync::atomic::{AtomicUsize, Ordering}; use tinywasm_types::*; use crate::instance::ModuleInstanceInner; -use crate::interpreter::TinyWasmValue; use crate::interpreter::stack::Stack; +use crate::interpreter::{TinyWasmValue, ValueRef}; use crate::{Engine, Error, ModuleInstance, Result, Trap}; mod data; @@ -478,9 +478,9 @@ impl Store { 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)?)), + RefFunc(None) => TinyWasmValue::ValueRef(ValueRef::NULL), + RefExtern(None) => TinyWasmValue::ValueRef(ValueRef::NULL), + RefFunc(Some(idx)) => TinyWasmValue::ValueRef(ValueRef::from_addr(Some(resolve_func(*idx)?))), _ => return Err(Error::Other("unsupported const instruction".to_string())), }; return Ok(val); @@ -495,8 +495,10 @@ impl Store { 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)?))), + RefFunc(None) | RefExtern(None) => stack.push(TinyWasmValue::ValueRef(ValueRef::NULL)), + RefFunc(Some(idx)) => { + stack.push(TinyWasmValue::ValueRef(ValueRef::from_addr(Some(resolve_func(*idx)?)))) + } RefExtern(Some(_)) => { return Err(Error::Other("ref.extern constants are not supported in init expressions".to_string())); } @@ -550,7 +552,7 @@ impl Store { ) -> Result> { let value = self.eval_const(const_instrs, module_global_addrs, module_func_addrs)?; match value { - TinyWasmValue::ValueRef(v) => Ok(v), + TinyWasmValue::ValueRef(v) => Ok(v.addr()), other => Err(Error::Other(format!("expected reference const value, got {other:?}"))), } } diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs index 01398b5..7db9f79 100644 --- a/crates/types/src/instructions.rs +++ b/crates/types/src/instructions.rs @@ -59,7 +59,7 @@ pub enum ConstInstruction { #[cfg_attr(feature = "debug", derive(Debug))] #[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))] pub enum Instruction { - LocalCopy32(LocalAddr, LocalAddr), LocalCopy64(LocalAddr, LocalAddr), LocalCopy128(LocalAddr, LocalAddr), LocalCopyRef(LocalAddr, LocalAddr), + LocalCopy32(LocalAddr, LocalAddr), LocalCopy64(LocalAddr, LocalAddr), LocalCopy128(LocalAddr, LocalAddr), I32AddLocals(LocalAddr, LocalAddr), I64AddLocals(LocalAddr, LocalAddr), I32AddConst(i32), I64AddConst(i64), LocalAddConst32(LocalAddr, i32), LocalAddConst64(LocalAddr, i64), @@ -78,11 +78,10 @@ pub enum Instruction { Jump(u32), JumpIfZero(u32), JumpIfNonZero(u32), - DropKeepSmall { base32: u8, keep32: u8, base64: u8, keep64: u8, base128: u8, keep128: u8, base_ref: u8, keep_ref: u8 }, + DropKeep { base32: u16, keep32: u8, base64: u16, keep64: u8, base128: u16, keep128: u8 }, DropKeep32(u16, u16), DropKeep64(u16, u16), DropKeep128(u16, u16), - DropKeepRef(u16, u16), BranchTable(u32, u32, u32), // (default_landing_pad_ip, branch_table_start, target_count) Return, Call(FuncAddr), @@ -97,7 +96,6 @@ pub enum Instruction { Drop32, Select32, Drop64, Select64, Drop128, Select128, - DropRef, SelectRef, SelectMulti(ValueCounts), // > Variable Instructions @@ -106,7 +104,6 @@ pub enum Instruction { LocalGet32(LocalAddr), LocalSet32(LocalAddr), LocalTee32(LocalAddr), GlobalSet32(GlobalAddr), LocalGet64(LocalAddr), LocalSet64(LocalAddr), LocalTee64(LocalAddr), GlobalSet64(GlobalAddr), LocalGet128(LocalAddr), LocalSet128(LocalAddr), LocalTee128(LocalAddr), GlobalSet128(GlobalAddr), - LocalGetRef(LocalAddr), LocalSetRef(LocalAddr), LocalTeeRef(LocalAddr), GlobalSetRef(GlobalAddr), // > Memory Instructions I32Load(MemoryArg), diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index ece6086..28d52a7 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -230,13 +230,12 @@ pub struct ValueCounts { pub c32: u16, pub c64: u16, pub c128: u16, - pub cref: u16, } impl ValueCounts { #[inline] pub fn is_empty(&self) -> bool { - self.c32 == 0 && self.c64 == 0 && self.c128 == 0 && self.cref == 0 + self.c32 == 0 && self.c64 == 0 && self.c128 == 0 } } @@ -248,7 +247,7 @@ impl<'a> FromIterator<&'a WasmType> for ValueCounts { WasmType::I32 | WasmType::F32 => counts.c32 += 1, WasmType::I64 | WasmType::F64 => counts.c64 += 1, WasmType::V128 => counts.c128 += 1, - WasmType::RefExtern | WasmType::RefFunc => counts.cref += 1, + WasmType::RefExtern | WasmType::RefFunc => counts.c32 += 1, } counts }) diff --git a/crates/types/src/value.rs b/crates/types/src/value.rs index 462749b..20c822e 100644 --- a/crates/types/src/value.rs +++ b/crates/types/src/value.rs @@ -42,16 +42,18 @@ impl Debug for WasmValue { } } +const NULL_REF: u32 = u32::MAX; + #[derive(Clone, Copy, PartialEq, Eq)] -pub struct ExternRef(Option); +pub struct ExternRef(u32); #[derive(Clone, Copy, PartialEq, Eq)] -pub struct FuncRef(Option); +pub struct FuncRef(u32); #[cfg(feature = "debug")] impl Debug for ExternRef { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self.0 { + match self.addr() { Some(addr) => write!(f, "extern({addr:?})"), None => write!(f, "extern(null)"), } @@ -61,7 +63,7 @@ impl Debug for ExternRef { #[cfg(feature = "debug")] impl Debug for FuncRef { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self.0 { + match self.addr() { Some(addr) => write!(f, "func({addr:?})"), None => write!(f, "func(null)"), } @@ -72,24 +74,39 @@ impl FuncRef { #[inline] /// Create a new [`FuncRef`] from a [`FuncAddr`]. pub const fn new(addr: Option) -> Self { - Self(addr) + match addr { + Some(addr) => Self(addr), + None => Self::null(), + } } #[inline] /// Create a null [`FuncRef`]. pub const fn null() -> Self { - Self(None) + Self(NULL_REF) } #[inline] /// Check if the [`FuncRef`] is null. pub const fn is_null(&self) -> bool { - self.0.is_none() + self.0 == NULL_REF } #[inline] /// Get the [`FuncAddr`] from the [`FuncRef`]. pub const fn addr(&self) -> Option { + if self.is_null() { None } else { Some(self.0) } + } + + #[inline] + #[doc(hidden)] + pub const fn from_raw(raw: u32) -> Self { + Self(raw) + } + + #[inline] + #[doc(hidden)] + pub const fn raw(&self) -> u32 { self.0 } } @@ -99,24 +116,39 @@ impl ExternRef { /// Create a new [`ExternRef`] from an [`ExternAddr`]. /// Should only be used by the runtime. pub const fn new(addr: Option) -> Self { - Self(addr) + match addr { + Some(addr) => Self(addr), + None => Self::null(), + } } /// Create a null [`ExternRef`]. #[inline] pub const fn null() -> Self { - Self(None) + Self(NULL_REF) } /// Check if the [`ExternRef`] is null. #[inline] pub const fn is_null(&self) -> bool { - self.0.is_none() + self.0 == NULL_REF } /// Get the [`ExternAddr`] from the [`ExternRef`]. #[inline] pub const fn addr(&self) -> Option { + if self.is_null() { None } else { Some(self.0) } + } + + #[inline] + #[doc(hidden)] + pub const fn from_raw(raw: u32) -> Self { + Self(raw) + } + + #[inline] + #[doc(hidden)] + pub const fn raw(&self) -> u32 { self.0 } } -- cgit v1.3.1