diff options
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | Cargo.lock | 59 | ||||
| -rw-r--r-- | crates/parser/src/conversion.rs | 8 | ||||
| -rw-r--r-- | crates/parser/src/lib.rs | 2 | ||||
| -rw-r--r-- | crates/tinywasm/src/func.rs | 18 | ||||
| -rw-r--r-- | crates/tinywasm/src/interpreter/stack/value_stack.rs | 12 | ||||
| -rw-r--r-- | crates/tinywasm/src/interpreter/values.rs | 16 | ||||
| -rw-r--r-- | crates/tinywasm/src/module.rs | 1 | ||||
| -rw-r--r-- | crates/tinywasm/src/store/mod.rs | 17 | ||||
| -rw-r--r-- | crates/tinywasm/src/store/table.rs | 6 | ||||
| -rw-r--r-- | crates/tinywasm/tests/host_func_signature_check.rs | 5 | ||||
| -rw-r--r-- | crates/tinywasm/tests/testsuite/util.rs | 27 | ||||
| -rw-r--r-- | crates/types/src/instructions.rs | 6 | ||||
| -rw-r--r-- | crates/types/src/value.rs | 122 |
14 files changed, 192 insertions, 108 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index e52cdc6..ab30d8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - **Breaking:**: New backwards-incompatible version of the twasm format (upgraded `rkyv` to 0.8.0) +- **Breaking:**: `RefNull` has been removed and replaced with new `FuncRef` and `ExternRef` structs - Increased MSRV to 1.83.0 ### Fixed @@ -25,19 +25,20 @@ checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "argh" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7af5ba06967ff7214ce4c7419c7d185be7ecd6cc4965a8f6e1d8ce0398aad219" +checksum = "34ff18325c8a36b82f992e533ece1ec9f9a9db446bd1c14d4f936bac88fcd240" dependencies = [ "argh_derive", "argh_shared", + "rust-fuzzy-search", ] [[package]] name = "argh_derive" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56df0aeedf6b7a2fc67d06db35b09684c3e8da0c95f8f27685cb17e08413d87a" +checksum = "adb7b2b83a50d329d5d8ccc620f5c7064028828538bdf5646acd60dc1f767803" dependencies = [ "argh_shared", "proc-macro2", @@ -47,9 +48,9 @@ dependencies = [ [[package]] name = "argh_shared" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5693f39141bda5760ecc4111ab08da40565d1771038c4a0250f03457ec707531" +checksum = "a464143cc82dedcdc3928737445362466b7674b5db4e2eb8e869846d6d84f4f6" dependencies = [ "serde", ] @@ -202,9 +203,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -221,9 +222,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" @@ -363,9 +364,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.167" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libm" @@ -473,9 +474,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -578,6 +579,12 @@ dependencies = [ ] [[package]] +name = "rust-fuzzy-search" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a157657054ffe556d8858504af8a672a054a6e0bd9e8ee531059100c0fa11bb2" + +[[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -594,24 +601,24 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" [[package]] name = "serde" -version = "1.0.215" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", @@ -620,9 +627,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.134" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" dependencies = [ "itoa", "memchr", @@ -638,9 +645,9 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "syn" -version = "2.0.90" +version = "2.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a" dependencies = [ "proc-macro2", "quote", @@ -668,9 +675,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" dependencies = [ "tinyvec_macros", ] diff --git a/crates/parser/src/conversion.rs b/crates/parser/src/conversion.rs index 1ebe392..273dd44 100644 --- a/crates/parser/src/conversion.rs +++ b/crates/parser/src/conversion.rs @@ -251,8 +251,12 @@ pub(crate) fn process_const_operators(ops: OperatorsReader<'_>) -> Result<ConstI assert!(matches!(ops[ops.len() - 1], wasmparser::Operator::End)); match &ops[ops.len() - 2] { - wasmparser::Operator::RefNull { hty } => Ok(ConstInstruction::RefNull(convert_heaptype(*hty))), - wasmparser::Operator::RefFunc { function_index } => Ok(ConstInstruction::RefFunc(*function_index)), + 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()))), diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index dcb05f0..04da9da 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -65,6 +65,7 @@ impl Parser { memory64: true, custom_page_sizes: true, + extended_const: false, wide_arithmetic: false, gc_types: true, stack_switching: false, @@ -73,7 +74,6 @@ impl Parser { component_model_values: false, component_model_more_flags: false, exceptions: false, - extended_const: false, gc: false, memory_control: false, relaxed_simd: false, diff --git a/crates/tinywasm/src/func.rs b/crates/tinywasm/src/func.rs index 47a2cdf..f5a9873 100644 --- a/crates/tinywasm/src/func.rs +++ b/crates/tinywasm/src/func.rs @@ -2,7 +2,7 @@ use crate::interpreter::stack::{CallFrame, Stack}; use crate::{log, unlikely, Function}; use crate::{Error, FuncContext, Result, Store}; use alloc::{boxed::Box, format, string::String, string::ToString, vec, vec::Vec}; -use tinywasm_types::{FuncType, ModuleInstanceAddr, ValType, WasmValue}; +use tinywasm_types::{ExternRef, FuncRef, FuncType, ModuleInstanceAddr, ValType, WasmValue}; #[derive(Debug)] /// A function handle @@ -219,6 +219,18 @@ impl ToValType for f64 { } } +impl ToValType for FuncRef { + fn to_val_type() -> ValType { + ValType::RefFunc + } +} + +impl ToValType for ExternRef { + fn to_val_type() -> ValType { + ValType::RefExtern + } +} + macro_rules! impl_val_types_from_tuple { ($($t:ident),+) => { impl<$($t),+> ValTypesFromTuple for ($($t,)+) @@ -251,11 +263,15 @@ impl_from_wasm_value_tuple_single!(i32); impl_from_wasm_value_tuple_single!(i64); impl_from_wasm_value_tuple_single!(f32); impl_from_wasm_value_tuple_single!(f64); +impl_from_wasm_value_tuple_single!(FuncRef); +impl_from_wasm_value_tuple_single!(ExternRef); impl_into_wasm_value_tuple_single!(i32); impl_into_wasm_value_tuple_single!(i64); impl_into_wasm_value_tuple_single!(f32); impl_into_wasm_value_tuple_single!(f64); +impl_into_wasm_value_tuple_single!(FuncRef); +impl_into_wasm_value_tuple_single!(ExternRef); impl_val_types_from_tuple!(T1); impl_val_types_from_tuple!(T1, T2); diff --git a/crates/tinywasm/src/interpreter/stack/value_stack.rs b/crates/tinywasm/src/interpreter/stack/value_stack.rs index ab739a3..ea6a082 100644 --- a/crates/tinywasm/src/interpreter/stack/value_stack.rs +++ b/crates/tinywasm/src/interpreter/stack/value_stack.rs @@ -1,5 +1,5 @@ use alloc::vec::Vec; -use tinywasm_types::{ValType, ValueCounts, ValueCountsSmall, WasmValue}; +use tinywasm_types::{ExternRef, FuncRef, ValType, ValueCounts, ValueCountsSmall, WasmValue}; use crate::{interpreter::*, Result}; @@ -173,14 +173,8 @@ impl ValueStack { ValType::V128 => WasmValue::V128(self.pop()), ValType::F32 => WasmValue::F32(self.pop()), ValType::F64 => WasmValue::F64(self.pop()), - ValType::RefExtern => match self.pop() { - Some(v) => WasmValue::RefExtern(v), - None => WasmValue::RefNull(ValType::RefExtern), - }, - ValType::RefFunc => match self.pop() { - Some(v) => WasmValue::RefFunc(v), - None => WasmValue::RefNull(ValType::RefFunc), - }, + ValType::RefExtern => WasmValue::RefExtern(ExternRef::new(self.pop())), + ValType::RefFunc => WasmValue::RefFunc(FuncRef::new(self.pop())), } } diff --git a/crates/tinywasm/src/interpreter/values.rs b/crates/tinywasm/src/interpreter/values.rs index efee9b8..712baf7 100644 --- a/crates/tinywasm/src/interpreter/values.rs +++ b/crates/tinywasm/src/interpreter/values.rs @@ -1,5 +1,5 @@ use crate::Result; -use tinywasm_types::{LocalAddr, ValType, WasmValue}; +use tinywasm_types::{ExternRef, FuncRef, LocalAddr, ValType, WasmValue}; use super::stack::{Locals, ValueStack}; @@ -107,14 +107,8 @@ impl TinyWasmValue { ValType::F32 => WasmValue::F32(f32::from_bits(self.unwrap_32())), ValType::F64 => WasmValue::F64(f64::from_bits(self.unwrap_64())), ValType::V128 => WasmValue::V128(self.unwrap_128()), - ValType::RefExtern => match self.unwrap_ref() { - Some(v) => WasmValue::RefExtern(v), - None => WasmValue::RefNull(ValType::RefExtern), - }, - ValType::RefFunc => match self.unwrap_ref() { - Some(v) => WasmValue::RefFunc(v), - None => WasmValue::RefNull(ValType::RefFunc), - }, + ValType::RefExtern => WasmValue::RefExtern(ExternRef::new(self.unwrap_ref())), + ValType::RefFunc => WasmValue::RefFunc(FuncRef::new(self.unwrap_ref())), } } } @@ -127,8 +121,8 @@ impl From<&WasmValue> for TinyWasmValue { WasmValue::V128(v) => TinyWasmValue::Value128(*v), WasmValue::F32(v) => TinyWasmValue::Value32(v.to_bits()), WasmValue::F64(v) => TinyWasmValue::Value64(v.to_bits()), - WasmValue::RefFunc(v) | WasmValue::RefExtern(v) => TinyWasmValue::ValueRef(Some(*v)), - WasmValue::RefNull(_) => TinyWasmValue::ValueRef(None), + WasmValue::RefExtern(v) => TinyWasmValue::ValueRef(v.addr()), + WasmValue::RefFunc(v) => TinyWasmValue::ValueRef(v.addr()), } } } diff --git a/crates/tinywasm/src/module.rs b/crates/tinywasm/src/module.rs index f6e8e04..26cea9c 100644 --- a/crates/tinywasm/src/module.rs +++ b/crates/tinywasm/src/module.rs @@ -47,6 +47,7 @@ impl Module { /// Instantiate the module in the given store /// /// Runs the start function if it exists + /// /// If you want to run the start function yourself, use `ModuleInstance::instantiate` /// /// See <https://webassembly.github.io/spec/core/exec/modules.html#exec-instantiation> diff --git a/crates/tinywasm/src/store/mod.rs b/crates/tinywasm/src/store/mod.rs index d4bbf33..86cbb5d 100644 --- a/crates/tinywasm/src/store/mod.rs +++ b/crates/tinywasm/src/store/mod.rs @@ -278,12 +278,13 @@ impl Store { fn elem_addr(&self, item: &ElementItem, globals: &[Addr], funcs: &[FuncAddr]) -> Result<Option<u32>> { let res = match item { - ElementItem::Func(addr) | ElementItem::Expr(ConstInstruction::RefFunc(addr)) => { + 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::RefNull(_ty)) => None, + 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")) @@ -450,10 +451,14 @@ impl Store { self.data.globals.get(*addr as usize).expect("global not found. This should be unreachable"); global.value.get() } - RefNull(t) => t.default_value().into(), - RefFunc(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")) - })?)), + 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())), }; Ok(val) } diff --git a/crates/tinywasm/src/store/table.rs b/crates/tinywasm/src/store/table.rs index 5520faf..0cbd054 100644 --- a/crates/tinywasm/src/store/table.rs +++ b/crates/tinywasm/src/store/table.rs @@ -30,8 +30,8 @@ impl TableInstance { let val = self.get(addr)?.addr(); Ok(match self.kind.element_type { - ValType::RefFunc => val.map_or(WasmValue::RefNull(ValType::RefFunc), WasmValue::RefFunc), - ValType::RefExtern => val.map_or(WasmValue::RefNull(ValType::RefExtern), WasmValue::RefExtern), + ValType::RefFunc => WasmValue::RefFunc(FuncRef::new(val)), + ValType::RefExtern => WasmValue::RefExtern(ExternRef::new(val)), _ => Err(Error::UnsupportedFeature("non-ref table".into()))?, }) } @@ -211,7 +211,7 @@ mod tests { } match table_instance.get_wasm_val(1) { - Ok(WasmValue::RefNull(ValType::RefFunc)) => {} + Ok(WasmValue::RefFunc(f)) if f.is_null() => {} _ => panic!("get_wasm_val failed to return the correct WasmValue"), } diff --git a/crates/tinywasm/tests/host_func_signature_check.rs b/crates/tinywasm/tests/host_func_signature_check.rs index 787b24a..c60ade2 100644 --- a/crates/tinywasm/tests/host_func_signature_check.rs +++ b/crates/tinywasm/tests/host_func_signature_check.rs @@ -4,6 +4,7 @@ use tinywasm::{ types::{FuncType, ValType, WasmValue}, Extern, FuncContext, Imports, Module, Store, }; +use tinywasm_types::ExternRef; const VAL_LISTS: &[&[WasmValue]] = &[ &[], @@ -11,7 +12,7 @@ const VAL_LISTS: &[&[WasmValue]] = &[ &[WasmValue::I32(0), WasmValue::I32(0)], // 2 of the same &[WasmValue::I32(0), WasmValue::I32(0), WasmValue::F64(0.0)], // add another type &[WasmValue::I32(0), WasmValue::F64(0.0), WasmValue::I32(0)], // reorder - &[WasmValue::RefExtern(0), WasmValue::F64(0.0), WasmValue::I32(0)], // all different types + &[WasmValue::RefExtern(ExternRef::null()), WasmValue::F64(0.0), WasmValue::I32(0)], // all different types ]; // (f64, i32, i32) and (f64) can be used to "match_none" @@ -37,7 +38,6 @@ fn test_return_invalid_type() -> Result<()> { for (module, func_ty, test_args) in mod_list { for result_to_try in VAL_LISTS { - println!("trying"); let mut store = Store::default(); let mut imports = Imports::new(); imports @@ -146,7 +146,6 @@ fn proxy_module(func_ty: &FuncType) -> Module { let results_text = join_surround(results, "result"); let params_text = join_surround(params, "param"); - // let params_gets: String = params.iter().enumerate().map(|(num, _)| format!("(local.get {num})\n")).collect(); let params_gets: String = params.iter().enumerate().fold(String::new(), |mut acc, (num, _)| { let _ = writeln!(acc, "(local.get {num})", num = num); acc diff --git a/crates/tinywasm/tests/testsuite/util.rs b/crates/tinywasm/tests/testsuite/util.rs index e3aafcb..b555153 100644 --- a/crates/tinywasm/tests/testsuite/util.rs +++ b/crates/tinywasm/tests/testsuite/util.rs @@ -1,9 +1,9 @@ use std::panic::{self, AssertUnwindSafe}; use eyre::{bail, eyre, Result}; -use tinywasm_types::{ModuleInstanceAddr, TinyWasmModule, ValType, WasmValue}; -use wasm_testsuite::wast::{core::AbstractHeapType, QuoteWat}; +use tinywasm_types::{ExternRef, FuncRef, ModuleInstanceAddr, TinyWasmModule, ValType, WasmValue}; use wasm_testsuite::wast; +use wasm_testsuite::wast::{core::AbstractHeapType, QuoteWat}; pub fn try_downcast_panic(panic: Box<dyn std::any::Any + Send>) -> String { let info = panic.downcast_ref::<panic::PanicHookInfo>().or(None).map(ToString::to_string).clone(); @@ -103,13 +103,13 @@ fn wastarg2tinywasmvalue(arg: wast::WastArg) -> Result<tinywasm_types::WasmValue I32(i) => WasmValue::I32(i), I64(i) => WasmValue::I64(i), V128(i) => WasmValue::V128(i128::from_le_bytes(i.to_le_bytes()).try_into().unwrap()), - RefExtern(v) => WasmValue::RefExtern(v), + RefExtern(v) => WasmValue::RefExtern(ExternRef::new(Some(v))), RefNull(t) => match t { wast::core::HeapType::Abstract { shared: false, ty: AbstractHeapType::Func } => { - WasmValue::RefNull(ValType::RefFunc) + WasmValue::RefFunc(FuncRef::null()) } wast::core::HeapType::Abstract { shared: false, ty: AbstractHeapType::Extern } => { - WasmValue::RefNull(ValType::RefExtern) + WasmValue::RefExtern(ExternRef::null()) } _ => bail!("unsupported arg type: refnull: {:?}", t), }, @@ -146,23 +146,18 @@ fn wastret2tinywasmvalue(ret: wast::WastRet) -> Result<tinywasm_types::WasmValue V128(i) => WasmValue::V128(wast_i128_to_i128(i)), RefNull(t) => match t { Some(wast::core::HeapType::Abstract { shared: false, ty: AbstractHeapType::Func }) => { - WasmValue::RefNull(ValType::RefFunc) + WasmValue::RefFunc(FuncRef::null()) } Some(wast::core::HeapType::Abstract { shared: false, ty: AbstractHeapType::Extern }) => { - WasmValue::RefNull(ValType::RefExtern) + WasmValue::RefExtern(ExternRef::null()) } _ => bail!("unsupported arg type: refnull: {:?}", t), }, - RefExtern(v) => match v { - Some(v) => WasmValue::RefExtern(v), - None => WasmValue::RefNull(ValType::RefExtern), - _ => bail!("unsupported arg type: refextern: {:?}", v), - }, - RefFunc(v) => match v { - Some(wast::token::Index::Num(n, _)) => WasmValue::RefFunc(n), - None => WasmValue::RefNull(ValType::RefFunc), + RefExtern(v) => WasmValue::RefExtern(ExternRef::new(v)), + RefFunc(v) => WasmValue::RefFunc(FuncRef::new(match v { + Some(wast::token::Index::Num(n, _)) => Some(n), _ => bail!("unsupported arg type: reffunc: {:?}", v), - }, + })), a => bail!("unsupported arg type {:?}", a), }) } diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs index fb3c1cc..8f77b31 100644 --- a/crates/types/src/instructions.rs +++ b/crates/types/src/instructions.rs @@ -1,5 +1,5 @@ use super::{FuncAddr, GlobalAddr, LabelAddr, LocalAddr, TableAddr, TypeAddr, ValType}; -use crate::{ConstIdx, DataAddr, ElemAddr, MemAddr}; +use crate::{ConstIdx, DataAddr, ElemAddr, ExternAddr, MemAddr}; /// Represents a memory immediate in a WebAssembly memory instruction. #[derive(Debug, Copy, Clone, PartialEq)] @@ -37,8 +37,8 @@ pub enum ConstInstruction { F32Const(f32), F64Const(f64), GlobalGet(GlobalAddr), - RefNull(ValType), - RefFunc(FuncAddr), + RefFunc(Option<FuncAddr>), + RefExtern(Option<ExternAddr>), } /// A WebAssembly Instruction diff --git a/crates/types/src/value.rs b/crates/types/src/value.rs index 8bbcaf2..6651c0e 100644 --- a/crates/types/src/value.rs +++ b/crates/types/src/value.rs @@ -19,12 +19,92 @@ pub enum WasmValue { // /// A 128-bit vector V128(u128), - RefExtern(ExternAddr), - RefFunc(FuncAddr), - RefNull(ValType), + RefExtern(ExternRef), + RefFunc(FuncRef), +} + +#[derive(Clone, Copy, PartialEq)] +pub struct ExternRef(Option<ExternAddr>); + +#[derive(Clone, Copy, PartialEq)] +pub struct FuncRef(Option<FuncAddr>); + +impl Debug for ExternRef { + fn fmt(&self, f: &mut alloc::fmt::Formatter<'_>) -> alloc::fmt::Result { + match self.0 { + Some(addr) => write!(f, "extern({:?})", addr), + None => write!(f, "extern(null)"), + } + } +} + +impl Debug for FuncRef { + fn fmt(&self, f: &mut alloc::fmt::Formatter<'_>) -> alloc::fmt::Result { + match self.0 { + Some(addr) => write!(f, "func({:?})", addr), + None => write!(f, "func(null)"), + } + } +} + +impl FuncRef { + /// Create a new `FuncRef` from a `FuncAddr`. + /// Should only be used by the runtime. + #[doc(hidden)] + #[inline] + pub const fn new(addr: Option<FuncAddr>) -> Self { + Self(addr) + } + + /// Create a null `FuncRef`. + #[inline] + pub const fn null() -> Self { + Self(None) + } + + /// Check if the `FuncRef` is null. + #[inline] + pub const fn is_null(&self) -> bool { + self.0.is_none() + } + + /// Get the `FuncAddr` from the `FuncRef`. + #[inline] + pub const fn addr(&self) -> Option<FuncAddr> { + self.0 + } +} + +impl ExternRef { + /// Create a new `ExternRef` from an `ExternAddr`. + /// Should only be used by the runtime. + #[doc(hidden)] + #[inline] + pub const fn new(addr: Option<ExternAddr>) -> Self { + Self(addr) + } + + /// Create a null `ExternRef`. + #[inline] + pub const fn null() -> Self { + Self(None) + } + + /// Check if the `ExternRef` is null. + #[inline] + pub const fn is_null(&self) -> bool { + self.0.is_none() + } + + /// Get the `ExternAddr` from the `ExternRef`. + #[inline] + pub const fn addr(&self) -> Option<ExternAddr> { + self.0 + } } impl WasmValue { + #[doc(hidden)] #[inline] pub fn const_instr(&self) -> ConstInstruction { match self { @@ -32,10 +112,7 @@ impl WasmValue { Self::I64(i) => ConstInstruction::I64Const(*i), Self::F32(i) => ConstInstruction::F32Const(*i), Self::F64(i) => ConstInstruction::F64Const(*i), - Self::RefFunc(i) => ConstInstruction::RefFunc(*i), - Self::RefNull(ty) => ConstInstruction::RefNull(*ty), - - // Self::RefExtern(addr) => ConstInstruction::RefExtern(*addr), + Self::RefFunc(i) => ConstInstruction::RefFunc(i.addr()), _ => unimplemented!("no const_instr for {:?}", self), } } @@ -49,17 +126,17 @@ impl WasmValue { ValType::F32 => Self::F32(0.0), ValType::F64 => Self::F64(0.0), ValType::V128 => Self::V128(0), - ValType::RefFunc => Self::RefNull(ValType::RefFunc), - ValType::RefExtern => Self::RefNull(ValType::RefExtern), + ValType::RefFunc => Self::RefFunc(FuncRef::null()), + ValType::RefExtern => Self::RefExtern(ExternRef::null()), } } + /// Check if two values are equal, ignoring differences in NaN values. #[inline] pub fn eq_loose(&self, other: &Self) -> bool { match (self, other) { (Self::I32(a), Self::I32(b)) => a == b, (Self::I64(a), Self::I64(b)) => a == b, - (Self::RefNull(v), Self::RefNull(v2)) => v == v2, (Self::RefExtern(addr), Self::RefExtern(addr2)) => addr == addr2, (Self::RefFunc(addr), Self::RefFunc(addr2)) => addr == addr2, (Self::F32(a), Self::F32(b)) => { @@ -121,25 +198,17 @@ impl WasmValue { } #[doc(hidden)] - pub fn as_ref_extern(&self) -> Option<ExternAddr> { - match self { - Self::RefExtern(addr) => Some(*addr), - _ => None, - } - } - - #[doc(hidden)] - pub fn as_ref_func(&self) -> Option<FuncAddr> { + pub fn as_ref_extern(&self) -> Option<ExternRef> { match self { - Self::RefFunc(addr) => Some(*addr), + Self::RefExtern(ref_extern) => Some(*ref_extern), _ => None, } } #[doc(hidden)] - pub fn as_ref_null(&self) -> Option<ValType> { + pub fn as_ref_func(&self) -> Option<FuncRef> { match self { - Self::RefNull(ty) => Some(*ty), + Self::RefFunc(ref_func) => Some(*ref_func), _ => None, } } @@ -156,9 +225,8 @@ impl Debug for WasmValue { WasmValue::F32(i) => write!(f, "f32({i})"), WasmValue::F64(i) => write!(f, "f64({i})"), WasmValue::V128(i) => write!(f, "v128({i:?})"), - WasmValue::RefExtern(addr) => write!(f, "ref.extern({addr:?})"), - WasmValue::RefFunc(addr) => write!(f, "ref.func({addr:?})"), - WasmValue::RefNull(ty) => write!(f, "ref.null({ty:?})"), + WasmValue::RefExtern(i) => write!(f, "ref({i:?})"), + WasmValue::RefFunc(i) => write!(f, "func({i:?})"), } } } @@ -175,7 +243,6 @@ impl WasmValue { Self::V128(_) => ValType::V128, Self::RefExtern(_) => ValType::RefExtern, Self::RefFunc(_) => ValType::RefFunc, - Self::RefNull(ty) => *ty, } } } @@ -206,6 +273,7 @@ impl ValType { WasmValue::default_for(*self) } + #[doc(hidden)] #[inline] pub fn is_simd(&self) -> bool { matches!(self, ValType::V128) @@ -241,4 +309,4 @@ macro_rules! impl_conversion_for_wasmvalue { } } -impl_conversion_for_wasmvalue! { i32 => I32, i64 => I64, f32 => F32, f64 => F64, u128 => V128 } +impl_conversion_for_wasmvalue! { i32 => I32, i64 => I64, f32 => F32, f64 => F64, u128 => V128, ExternRef => RefExtern, FuncRef => RefFunc } |
