summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/parser/Cargo.toml4
-rw-r--r--crates/parser/src/lib.rs22
-rw-r--r--crates/tinywasm/Cargo.toml5
-rw-r--r--crates/tinywasm/src/store/data.rs27
-rw-r--r--crates/tinywasm/src/store/element.rs19
-rw-r--r--crates/tinywasm/src/store/function.rs11
-rw-r--r--crates/tinywasm/src/store/global.rs39
-rw-r--r--crates/tinywasm/src/store/memory.rs162
-rw-r--r--crates/tinywasm/src/store/mod.rs218
-rw-r--r--crates/tinywasm/src/store/table.rs123
-rw-r--r--crates/tinywasm/tests/testsuite/run.rs6
-rw-r--r--crates/types/Cargo.toml10
-rw-r--r--crates/types/src/archive.rs92
-rw-r--r--crates/types/src/instructions.rs14
-rw-r--r--crates/types/src/lib.rs114
15 files changed, 512 insertions, 354 deletions
diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml
index 1592f85..df8acce 100644
--- a/crates/parser/Cargo.toml
+++ b/crates/parser/Cargo.toml
@@ -11,9 +11,9 @@ repository.workspace=true
# fork of wasmparser with no_std support, see https://github.com/bytecodealliance/wasmtime/issues/3495
wasmparser={version="0.100", package="wasmparser-nostd", default-features=false}
log={version="0.4", optional=true}
-tinywasm-types={version="0.3.0-alpha.0", path="../types"}
+tinywasm-types={version="0.3.0-alpha.0", path="../types", default-features=false}
[features]
default=["std", "logging"]
logging=["log"]
-std=[]
+std=["tinywasm-types/std"]
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs
index edcd280..c608232 100644
--- a/crates/parser/src/lib.rs
+++ b/crates/parser/src/lib.rs
@@ -25,7 +25,7 @@ mod module;
use alloc::{string::ToString, vec::Vec};
pub use error::*;
use module::ModuleReader;
-use tinywasm_types::WasmFunction;
+use tinywasm_types::{TypedWasmFunction, WasmFunction};
use wasmparser::Validator;
pub use tinywasm_types::TinyWasmModule;
@@ -116,19 +116,13 @@ impl TryFrom<ModuleReader> for TinyWasmModule {
.code
.into_iter()
.zip(code_type_addrs)
- .map(|(f, ty_idx)| {
- (
- ty_idx,
- WasmFunction {
- instructions: f.body,
- locals: f.locals,
- ty: reader
- .func_types
- .get(ty_idx as usize)
- .expect("No func type for func, this is a bug")
- .clone(),
- },
- )
+ .map(|(f, ty_idx)| TypedWasmFunction {
+ type_addr: ty_idx,
+ wasm_function: WasmFunction {
+ instructions: f.body,
+ locals: f.locals,
+ ty: reader.func_types.get(ty_idx as usize).expect("No func type for func, this is a bug").clone(),
+ },
})
.collect::<Vec<_>>();
diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml
index a9e24bf..dd76f3d 100644
--- a/crates/tinywasm/Cargo.toml
+++ b/crates/tinywasm/Cargo.toml
@@ -29,11 +29,12 @@ plotters={version="0.3"}
pretty_env_logger="0.5"
[features]
-default=["std", "parser", "logging"]
+default=["std", "parser", "logging", "archive"]
logging=["log", "tinywasm-types/logging", "tinywasm-parser?/logging"]
std=["tinywasm-parser?/std", "tinywasm-types/std"]
parser=["tinywasm-parser"]
-unsafe=[]
+unsafe=["tinywasm-types/unsafe"]
+archive=["tinywasm-types/archive"]
[[test]]
name="generate-charts"
diff --git a/crates/tinywasm/src/store/data.rs b/crates/tinywasm/src/store/data.rs
new file mode 100644
index 0000000..efbb858
--- /dev/null
+++ b/crates/tinywasm/src/store/data.rs
@@ -0,0 +1,27 @@
+use alloc::vec::Vec;
+use tinywasm_types::*;
+
+/// A WebAssembly Data Instance
+///
+/// See <https://webassembly.github.io/spec/core/exec/runtime.html#data-instances>
+#[derive(Debug)]
+pub(crate) struct DataInstance {
+ pub(crate) data: Option<Vec<u8>>,
+ pub(crate) _owner: ModuleInstanceAddr, // index into store.module_instances
+}
+
+impl DataInstance {
+ pub(crate) fn new(data: Option<Vec<u8>>, owner: ModuleInstanceAddr) -> Self {
+ Self { data, _owner: owner }
+ }
+
+ pub(crate) fn drop(&mut self) -> Option<()> {
+ match self.data {
+ None => None,
+ Some(_) => {
+ let _ = self.data.take();
+ Some(())
+ }
+ }
+ }
+}
diff --git a/crates/tinywasm/src/store/element.rs b/crates/tinywasm/src/store/element.rs
new file mode 100644
index 0000000..6563dff
--- /dev/null
+++ b/crates/tinywasm/src/store/element.rs
@@ -0,0 +1,19 @@
+use crate::TableElement;
+use alloc::vec::Vec;
+use tinywasm_types::*;
+
+/// A WebAssembly Element Instance
+///
+/// See <https://webassembly.github.io/spec/core/exec/runtime.html#element-instances>
+#[derive(Debug)]
+pub(crate) struct ElementInstance {
+ pub(crate) kind: ElementKind,
+ pub(crate) items: Option<Vec<TableElement>>, // none is the element was dropped
+ _owner: ModuleInstanceAddr, // index into store.module_instances
+}
+
+impl ElementInstance {
+ pub(crate) fn new(kind: ElementKind, owner: ModuleInstanceAddr, items: Option<Vec<TableElement>>) -> Self {
+ Self { kind, _owner: owner, items }
+ }
+}
diff --git a/crates/tinywasm/src/store/function.rs b/crates/tinywasm/src/store/function.rs
new file mode 100644
index 0000000..7508d00
--- /dev/null
+++ b/crates/tinywasm/src/store/function.rs
@@ -0,0 +1,11 @@
+use crate::Function;
+use tinywasm_types::*;
+
+#[derive(Debug, Clone)]
+/// A WebAssembly Function Instance
+///
+/// See <https://webassembly.github.io/spec/core/exec/runtime.html#function-instances>
+pub(crate) struct FunctionInstance {
+ pub(crate) func: Function,
+ pub(crate) owner: ModuleInstanceAddr, // index into store.module_instances, none for host functions
+}
diff --git a/crates/tinywasm/src/store/global.rs b/crates/tinywasm/src/store/global.rs
new file mode 100644
index 0000000..fbcc402
--- /dev/null
+++ b/crates/tinywasm/src/store/global.rs
@@ -0,0 +1,39 @@
+use alloc::{format, string::ToString};
+use tinywasm_types::*;
+
+use crate::{runtime::RawWasmValue, Error, Result};
+
+/// A WebAssembly Global Instance
+///
+/// See <https://webassembly.github.io/spec/core/exec/runtime.html#global-instances>
+#[derive(Debug)]
+pub(crate) struct GlobalInstance {
+ pub(crate) value: RawWasmValue,
+ pub(crate) ty: GlobalType,
+ pub(crate) _owner: ModuleInstanceAddr, // index into store.module_instances
+}
+
+impl GlobalInstance {
+ pub(crate) fn new(ty: GlobalType, value: RawWasmValue, owner: ModuleInstanceAddr) -> Self {
+ Self { ty, value, _owner: owner }
+ }
+
+ pub(crate) fn get(&self) -> WasmValue {
+ self.value.attach_type(self.ty.ty)
+ }
+
+ pub(crate) fn set(&mut self, val: WasmValue) -> Result<()> {
+ if val.val_type() != self.ty.ty {
+ return Err(Error::Other(format!(
+ "global type mismatch: expected {:?}, got {:?}",
+ self.ty.ty,
+ val.val_type()
+ )));
+ }
+ if !self.ty.mutable {
+ return Err(Error::Other("global is immutable".to_string()));
+ }
+ self.value = val.into();
+ Ok(())
+ }
+}
diff --git a/crates/tinywasm/src/store/memory.rs b/crates/tinywasm/src/store/memory.rs
index a087b1d..9b527d3 100644
--- a/crates/tinywasm/src/store/memory.rs
+++ b/crates/tinywasm/src/store/memory.rs
@@ -205,122 +205,92 @@ pub(crate) unsafe trait MemLoadable<const T: usize>: Sized + Copy {
fn from_be_bytes(bytes: [u8; T]) -> Self;
}
-#[allow(unsafe_code)]
-unsafe impl MemLoadable<1> for u8 {
- fn from_le_bytes(bytes: [u8; 1]) -> Self {
- bytes[0]
- }
- fn from_be_bytes(bytes: [u8; 1]) -> Self {
- bytes[0]
- }
-}
+macro_rules! impl_mem_loadable_for_primitive {
+ ($($type:ty, $size:expr),*) => {
+ $(
+ #[allow(unsafe_code)]
+ unsafe impl MemLoadable<$size> for $type {
+ fn from_le_bytes(bytes: [u8; $size]) -> Self {
+ <$type>::from_le_bytes(bytes)
+ }
-#[allow(unsafe_code)]
-unsafe impl MemLoadable<2> for u16 {
- fn from_le_bytes(bytes: [u8; 2]) -> Self {
- Self::from_le_bytes(bytes)
- }
- fn from_be_bytes(bytes: [u8; 2]) -> Self {
- Self::from_be_bytes(bytes)
+ fn from_be_bytes(bytes: [u8; $size]) -> Self {
+ <$type>::from_be_bytes(bytes)
+ }
+ }
+ )*
}
}
-#[allow(unsafe_code)]
-unsafe impl MemLoadable<4> for u32 {
- fn from_le_bytes(bytes: [u8; 4]) -> Self {
- Self::from_le_bytes(bytes)
- }
- fn from_be_bytes(bytes: [u8; 4]) -> Self {
- Self::from_be_bytes(bytes)
- }
-}
+impl_mem_loadable_for_primitive!(
+ u8, 1, i8, 1, u16, 2, i16, 2, u32, 4, i32, 4, f32, 4, u64, 8, i64, 8, f64, 8, u128, 16, i128, 16
+);
-#[allow(unsafe_code)]
-unsafe impl MemLoadable<8> for u64 {
- fn from_le_bytes(bytes: [u8; 8]) -> Self {
- Self::from_le_bytes(bytes)
- }
- fn from_be_bytes(bytes: [u8; 8]) -> Self {
- Self::from_be_bytes(bytes)
- }
-}
+#[cfg(test)]
+mod memory_instance_tests {
+ use super::*;
+ use tinywasm_types::{MemoryArch, MemoryType, ModuleInstanceAddr};
-#[allow(unsafe_code)]
-unsafe impl MemLoadable<16> for u128 {
- fn from_le_bytes(bytes: [u8; 16]) -> Self {
- Self::from_le_bytes(bytes)
+ fn create_test_memory() -> MemoryInstance {
+ let kind = MemoryType { arch: MemoryArch::I32, page_count_initial: 1, page_count_max: Some(2) };
+ let owner = ModuleInstanceAddr::default();
+ MemoryInstance::new(kind, owner)
}
- fn from_be_bytes(bytes: [u8; 16]) -> Self {
- Self::from_be_bytes(bytes)
- }
-}
-#[allow(unsafe_code)]
-unsafe impl MemLoadable<1> for i8 {
- fn from_le_bytes(bytes: [u8; 1]) -> Self {
- bytes[0] as i8
- }
- fn from_be_bytes(bytes: [u8; 1]) -> Self {
- bytes[0] as i8
+ #[test]
+ fn test_memory_store_and_load() {
+ let mut memory = create_test_memory();
+ let data_to_store = [1, 2, 3, 4];
+ assert!(memory.store(0, 0, &data_to_store, data_to_store.len()).is_ok());
+ let loaded_data = memory.load(0, 0, data_to_store.len()).unwrap();
+ assert_eq!(loaded_data, &data_to_store);
}
-}
-#[allow(unsafe_code)]
-unsafe impl MemLoadable<2> for i16 {
- fn from_le_bytes(bytes: [u8; 2]) -> Self {
- Self::from_le_bytes(bytes)
- }
- fn from_be_bytes(bytes: [u8; 2]) -> Self {
- Self::from_be_bytes(bytes)
+ #[test]
+ fn test_memory_store_out_of_bounds() {
+ let mut memory = create_test_memory();
+ let data_to_store = [1, 2, 3, 4];
+ assert!(memory.store(memory.data.len(), 0, &data_to_store, data_to_store.len()).is_err());
}
-}
-#[allow(unsafe_code)]
-unsafe impl MemLoadable<4> for i32 {
- fn from_le_bytes(bytes: [u8; 4]) -> Self {
- Self::from_le_bytes(bytes)
+ #[test]
+ fn test_memory_fill() {
+ let mut memory = create_test_memory();
+ assert!(memory.fill(0, 10, 42).is_ok());
+ assert_eq!(&memory.data[0..10], &[42; 10]);
}
- fn from_be_bytes(bytes: [u8; 4]) -> Self {
- Self::from_be_bytes(bytes)
- }
-}
-#[allow(unsafe_code)]
-unsafe impl MemLoadable<8> for i64 {
- fn from_le_bytes(bytes: [u8; 8]) -> Self {
- Self::from_le_bytes(bytes)
- }
- fn from_be_bytes(bytes: [u8; 8]) -> Self {
- Self::from_be_bytes(bytes)
+ #[test]
+ fn test_memory_fill_out_of_bounds() {
+ let mut memory = create_test_memory();
+ assert!(memory.fill(memory.data.len(), 10, 42).is_err());
}
-}
-#[allow(unsafe_code)]
-unsafe impl MemLoadable<16> for i128 {
- fn from_le_bytes(bytes: [u8; 16]) -> Self {
- Self::from_le_bytes(bytes)
- }
- fn from_be_bytes(bytes: [u8; 16]) -> Self {
- Self::from_be_bytes(bytes)
+ #[test]
+ fn test_memory_copy_within() {
+ let mut memory = create_test_memory();
+ memory.fill(0, 10, 1).unwrap();
+ assert!(memory.copy_within(10, 0, 10).is_ok());
+ assert_eq!(&memory.data[10..20], &[1; 10]);
}
-}
-#[allow(unsafe_code)]
-unsafe impl MemLoadable<4> for f32 {
- fn from_le_bytes(bytes: [u8; 4]) -> Self {
- Self::from_le_bytes(bytes)
+ #[test]
+ fn test_memory_copy_within_out_of_bounds() {
+ let mut memory = create_test_memory();
+ assert!(memory.copy_within(memory.data.len(), 0, 10).is_err());
}
- fn from_be_bytes(bytes: [u8; 4]) -> Self {
- Self::from_be_bytes(bytes)
- }
-}
-#[allow(unsafe_code)]
-unsafe impl MemLoadable<8> for f64 {
- fn from_le_bytes(bytes: [u8; 8]) -> Self {
- Self::from_le_bytes(bytes)
+ #[test]
+ fn test_memory_grow() {
+ let mut memory = create_test_memory();
+ let original_pages = memory.page_count();
+ assert_eq!(memory.grow(1), Some(original_pages as i32));
+ assert_eq!(memory.page_count(), original_pages + 1);
}
- fn from_be_bytes(bytes: [u8; 8]) -> Self {
- Self::from_be_bytes(bytes)
+
+ #[test]
+ fn test_memory_grow_out_of_bounds() {
+ let mut memory = create_test_memory();
+ assert!(memory.grow(MAX_PAGES as i32 + 1).is_none());
}
}
diff --git a/crates/tinywasm/src/store/mod.rs b/crates/tinywasm/src/store/mod.rs
index 1526eb1..be885a7 100644
--- a/crates/tinywasm/src/store/mod.rs
+++ b/crates/tinywasm/src/store/mod.rs
@@ -1,5 +1,5 @@
use crate::log;
-use alloc::{boxed::Box, format, rc::Rc, string::ToString, vec, vec::Vec};
+use alloc::{boxed::Box, format, rc::Rc, string::ToString, vec::Vec};
use core::{
cell::RefCell,
sync::atomic::{AtomicUsize, Ordering},
@@ -11,8 +11,18 @@ use crate::{
Error, Function, ModuleInstance, Result, Trap,
};
+mod data;
+mod element;
+mod function;
+mod global;
mod memory;
+mod table;
+pub(crate) use data::*;
+pub(crate) use element::*;
+pub(crate) use function::*;
+pub(crate) use global::*;
pub(crate) use memory::*;
+pub(crate) use table::*;
// global store id counter
static STORE_ID: AtomicUsize = AtomicUsize::new(0);
@@ -118,14 +128,14 @@ impl Store {
/// Add functions to the store, returning their addresses in the store
pub(crate) fn init_funcs(
&mut self,
- funcs: Vec<(u32, WasmFunction)>,
+ funcs: Vec<TypedWasmFunction>,
idx: ModuleInstanceAddr,
) -> Result<Vec<FuncAddr>> {
let func_count = self.data.funcs.len();
let mut func_addrs = Vec::with_capacity(func_count);
- for (i, (_, func)) in funcs.into_iter().enumerate() {
- self.data.funcs.push(FunctionInstance { func: Function::Wasm(Rc::new(func)), owner: idx });
+ for (i, func) in funcs.into_iter().enumerate() {
+ self.data.funcs.push(FunctionInstance { func: Function::Wasm(Rc::new(func.wasm_function)), owner: idx });
func_addrs.push((i + func_count) as FuncAddr);
}
@@ -448,203 +458,3 @@ impl Store {
.map(|global| global.borrow_mut().value = value)
}
}
-
-#[derive(Debug, Clone)]
-/// A WebAssembly Function Instance
-///
-/// See <https://webassembly.github.io/spec/core/exec/runtime.html#function-instances>
-pub(crate) struct FunctionInstance {
- pub(crate) func: Function,
- pub(crate) owner: ModuleInstanceAddr, // index into store.module_instances, none for host functions
-}
-
-#[derive(Debug, Clone, Copy)]
-pub(crate) enum TableElement {
- Uninitialized,
- Initialized(Addr),
-}
-
-impl From<Option<Addr>> for TableElement {
- fn from(addr: Option<Addr>) -> Self {
- match addr {
- None => TableElement::Uninitialized,
- Some(addr) => TableElement::Initialized(addr),
- }
- }
-}
-
-impl TableElement {
- pub(crate) fn addr(&self) -> Option<Addr> {
- match self {
- TableElement::Uninitialized => None,
- TableElement::Initialized(addr) => Some(*addr),
- }
- }
-
- pub(crate) fn map<F: FnOnce(Addr) -> Addr>(self, f: F) -> Self {
- match self {
- TableElement::Uninitialized => TableElement::Uninitialized,
- TableElement::Initialized(addr) => TableElement::Initialized(f(addr)),
- }
- }
-}
-
-const MAX_TABLE_SIZE: u32 = 10000000;
-
-/// A WebAssembly Table Instance
-///
-/// See <https://webassembly.github.io/spec/core/exec/runtime.html#table-instances>
-#[derive(Debug)]
-pub(crate) struct TableInstance {
- pub(crate) elements: Vec<TableElement>,
- pub(crate) kind: TableType,
- pub(crate) _owner: ModuleInstanceAddr, // index into store.module_instances
-}
-
-impl TableInstance {
- pub(crate) fn new(kind: TableType, owner: ModuleInstanceAddr) -> Self {
- Self { elements: vec![TableElement::Uninitialized; kind.size_initial as usize], kind, _owner: owner }
- }
-
- pub(crate) fn get_wasm_val(&self, addr: usize) -> Result<WasmValue> {
- let val = self.get(addr)?.addr();
-
- Ok(match self.kind.element_type {
- ValType::RefFunc => val.map(WasmValue::RefFunc).unwrap_or(WasmValue::RefNull(ValType::RefFunc)),
- ValType::RefExtern => val.map(WasmValue::RefExtern).unwrap_or(WasmValue::RefNull(ValType::RefExtern)),
- _ => unimplemented!("unsupported table type: {:?}", self.kind.element_type),
- })
- }
-
- pub(crate) fn get(&self, addr: usize) -> Result<&TableElement> {
- self.elements.get(addr).ok_or_else(|| Error::Trap(Trap::UndefinedElement { index: addr }))
- }
-
- pub(crate) fn set(&mut self, table_idx: usize, value: Addr) -> Result<()> {
- self.grow_to_fit(table_idx + 1).map(|_| self.elements[table_idx] = TableElement::Initialized(value))
- }
-
- pub(crate) fn grow_to_fit(&mut self, new_size: usize) -> Result<()> {
- if new_size > self.elements.len() {
- if new_size > self.kind.size_max.unwrap_or(MAX_TABLE_SIZE) as usize {
- return Err(crate::Trap::TableOutOfBounds { offset: new_size, len: 1, max: self.elements.len() }.into());
- }
-
- self.elements.resize(new_size, TableElement::Uninitialized);
- }
- Ok(())
- }
-
- pub(crate) fn size(&self) -> i32 {
- self.elements.len() as i32
- }
-
- fn resolve_func_ref(&self, func_addrs: &[u32], addr: Addr) -> Addr {
- if self.kind.element_type != ValType::RefFunc {
- return addr;
- }
-
- *func_addrs
- .get(addr as usize)
- .expect("error initializing table: function not found. This should have been caught by the validator")
- }
-
- // Initialize the table with the given elements
- pub(crate) fn init_raw(&mut self, offset: i32, init: &[TableElement]) -> Result<()> {
- let offset = offset as usize;
- let end = offset.checked_add(init.len()).ok_or_else(|| {
- Error::Trap(crate::Trap::TableOutOfBounds { offset, len: init.len(), max: self.elements.len() })
- })?;
-
- if end > self.elements.len() || end < offset {
- return Err(crate::Trap::TableOutOfBounds { offset, len: init.len(), max: self.elements.len() }.into());
- }
-
- self.elements[offset..end].copy_from_slice(init);
- log::debug!("table: {:?}", self.elements);
- Ok(())
- }
-
- // Initialize the table with the given elements (resolves function references)
- pub(crate) fn init(&mut self, func_addrs: &[u32], offset: i32, init: &[TableElement]) -> Result<()> {
- let init = init.iter().map(|item| item.map(|addr| self.resolve_func_ref(func_addrs, addr))).collect::<Vec<_>>();
-
- self.init_raw(offset, &init)
- }
-}
-
-/// A WebAssembly Global Instance
-///
-/// See <https://webassembly.github.io/spec/core/exec/runtime.html#global-instances>
-#[derive(Debug)]
-pub(crate) struct GlobalInstance {
- pub(crate) value: RawWasmValue,
- pub(crate) ty: GlobalType,
- pub(crate) _owner: ModuleInstanceAddr, // index into store.module_instances
-}
-
-impl GlobalInstance {
- pub(crate) fn new(ty: GlobalType, value: RawWasmValue, owner: ModuleInstanceAddr) -> Self {
- Self { ty, value, _owner: owner }
- }
-
- pub(crate) fn get(&self) -> WasmValue {
- self.value.attach_type(self.ty.ty)
- }
-
- pub(crate) fn set(&mut self, val: WasmValue) -> Result<()> {
- if val.val_type() != self.ty.ty {
- return Err(Error::Other(format!(
- "global type mismatch: expected {:?}, got {:?}",
- self.ty.ty,
- val.val_type()
- )));
- }
- if !self.ty.mutable {
- return Err(Error::Other("global is immutable".to_string()));
- }
- self.value = val.into();
- Ok(())
- }
-}
-
-/// A WebAssembly Element Instance
-///
-/// See <https://webassembly.github.io/spec/core/exec/runtime.html#element-instances>
-#[derive(Debug)]
-pub(crate) struct ElementInstance {
- pub(crate) kind: ElementKind,
- pub(crate) items: Option<Vec<TableElement>>, // none is the element was dropped
- _owner: ModuleInstanceAddr, // index into store.module_instances
-}
-
-impl ElementInstance {
- pub(crate) fn new(kind: ElementKind, owner: ModuleInstanceAddr, items: Option<Vec<TableElement>>) -> Self {
- Self { kind, _owner: owner, items }
- }
-}
-
-/// A WebAssembly Data Instance
-///
-/// See <https://webassembly.github.io/spec/core/exec/runtime.html#data-instances>
-#[derive(Debug)]
-pub(crate) struct DataInstance {
- pub(crate) data: Option<Vec<u8>>,
- pub(crate) _owner: ModuleInstanceAddr, // index into store.module_instances
-}
-
-impl DataInstance {
- pub(crate) fn new(data: Option<Vec<u8>>, owner: ModuleInstanceAddr) -> Self {
- Self { data, _owner: owner }
- }
-
- pub(crate) fn drop(&mut self) -> Option<()> {
- match self.data {
- None => None,
- Some(_) => {
- let _ = self.data.take();
- Some(())
- }
- }
- }
-}
diff --git a/crates/tinywasm/src/store/table.rs b/crates/tinywasm/src/store/table.rs
new file mode 100644
index 0000000..7b4c568
--- /dev/null
+++ b/crates/tinywasm/src/store/table.rs
@@ -0,0 +1,123 @@
+use crate::log;
+use alloc::{vec, vec::Vec};
+
+use tinywasm_types::*;
+
+use crate::{
+ Error, Result, Trap,
+};
+
+const MAX_TABLE_SIZE: u32 = 10000000;
+
+/// A WebAssembly Table Instance
+///
+/// See <https://webassembly.github.io/spec/core/exec/runtime.html#table-instances>
+#[derive(Debug)]
+pub(crate) struct TableInstance {
+ pub(crate) elements: Vec<TableElement>,
+ pub(crate) kind: TableType,
+ pub(crate) _owner: ModuleInstanceAddr, // index into store.module_instances
+}
+
+impl TableInstance {
+ pub(crate) fn new(kind: TableType, owner: ModuleInstanceAddr) -> Self {
+ Self { elements: vec![TableElement::Uninitialized; kind.size_initial as usize], kind, _owner: owner }
+ }
+
+ pub(crate) fn get_wasm_val(&self, addr: usize) -> Result<WasmValue> {
+ let val = self.get(addr)?.addr();
+
+ Ok(match self.kind.element_type {
+ ValType::RefFunc => val.map(WasmValue::RefFunc).unwrap_or(WasmValue::RefNull(ValType::RefFunc)),
+ ValType::RefExtern => val.map(WasmValue::RefExtern).unwrap_or(WasmValue::RefNull(ValType::RefExtern)),
+ _ => unimplemented!("unsupported table type: {:?}", self.kind.element_type),
+ })
+ }
+
+ pub(crate) fn get(&self, addr: usize) -> Result<&TableElement> {
+ self.elements.get(addr).ok_or_else(|| Error::Trap(Trap::UndefinedElement { index: addr }))
+ }
+
+ pub(crate) fn set(&mut self, table_idx: usize, value: Addr) -> Result<()> {
+ self.grow_to_fit(table_idx + 1).map(|_| self.elements[table_idx] = TableElement::Initialized(value))
+ }
+
+ pub(crate) fn grow_to_fit(&mut self, new_size: usize) -> Result<()> {
+ if new_size > self.elements.len() {
+ if new_size > self.kind.size_max.unwrap_or(MAX_TABLE_SIZE) as usize {
+ return Err(crate::Trap::TableOutOfBounds { offset: new_size, len: 1, max: self.elements.len() }.into());
+ }
+
+ self.elements.resize(new_size, TableElement::Uninitialized);
+ }
+ Ok(())
+ }
+
+ pub(crate) fn size(&self) -> i32 {
+ self.elements.len() as i32
+ }
+
+ fn resolve_func_ref(&self, func_addrs: &[u32], addr: Addr) -> Addr {
+ if self.kind.element_type != ValType::RefFunc {
+ return addr;
+ }
+
+ *func_addrs
+ .get(addr as usize)
+ .expect("error initializing table: function not found. This should have been caught by the validator")
+ }
+
+ // Initialize the table with the given elements
+ pub(crate) fn init_raw(&mut self, offset: i32, init: &[TableElement]) -> Result<()> {
+ let offset = offset as usize;
+ let end = offset.checked_add(init.len()).ok_or_else(|| {
+ Error::Trap(crate::Trap::TableOutOfBounds { offset, len: init.len(), max: self.elements.len() })
+ })?;
+
+ if end > self.elements.len() || end < offset {
+ return Err(crate::Trap::TableOutOfBounds { offset, len: init.len(), max: self.elements.len() }.into());
+ }
+
+ self.elements[offset..end].copy_from_slice(init);
+ log::debug!("table: {:?}", self.elements);
+ Ok(())
+ }
+
+ // Initialize the table with the given elements (resolves function references)
+ pub(crate) fn init(&mut self, func_addrs: &[u32], offset: i32, init: &[TableElement]) -> Result<()> {
+ let init = init.iter().map(|item| item.map(|addr| self.resolve_func_ref(func_addrs, addr))).collect::<Vec<_>>();
+
+ self.init_raw(offset, &init)
+ }
+}
+
+#[derive(Debug, Clone, Copy)]
+pub(crate) enum TableElement {
+ Uninitialized,
+ Initialized(TableAddr),
+}
+
+impl From<Option<Addr>> for TableElement {
+ fn from(addr: Option<Addr>) -> Self {
+ match addr {
+ None => TableElement::Uninitialized,
+ Some(addr) => TableElement::Initialized(addr),
+ }
+ }
+}
+
+impl TableElement {
+ pub(crate) fn addr(&self) -> Option<Addr> {
+ match self {
+ TableElement::Uninitialized => None,
+ TableElement::Initialized(addr) => Some(*addr),
+ }
+ }
+
+ pub(crate) fn map<F: FnOnce(Addr) -> Addr>(self, f: F) -> Self {
+ match self {
+ TableElement::Uninitialized => TableElement::Uninitialized,
+ TableElement::Initialized(addr) => TableElement::Initialized(f(addr)),
+ }
+ }
+}
diff --git a/crates/tinywasm/tests/testsuite/run.rs b/crates/tinywasm/tests/testsuite/run.rs
index de5d5ab..125a9d6 100644
--- a/crates/tinywasm/tests/testsuite/run.rs
+++ b/crates/tinywasm/tests/testsuite/run.rs
@@ -137,7 +137,7 @@ impl TestSuite {
for (name, addr) in modules {
log::debug!("registering module: {}", name);
- imports.link_module(&name, *addr)?;
+ imports.link_module(name, *addr)?;
}
Ok(imports)
@@ -199,7 +199,7 @@ impl TestSuite {
QuoteWat::QuoteModule(_, quoted_wat) => {
let wat = quoted_wat
.iter()
- .map(|(_, s)| std::str::from_utf8(&s).expect("failed to convert wast to utf8"))
+ .map(|(_, s)| std::str::from_utf8(s).expect("failed to convert wast to utf8"))
.collect::<Vec<_>>()
.join("\n");
@@ -444,7 +444,7 @@ impl TestSuite {
continue;
}
};
- let expected = expected.get(0).expect("expected global value");
+ let expected = expected.first().expect("expected global value");
let module_global = module_global.attach_type(expected.val_type());
if !module_global.eq_loose(expected) {
diff --git a/crates/types/Cargo.toml b/crates/types/Cargo.toml
index bc6769a..76e5679 100644
--- a/crates/types/Cargo.toml
+++ b/crates/types/Cargo.toml
@@ -9,10 +9,12 @@ repository.workspace=true
[dependencies]
log={version="0.4", optional=true}
-rkyv={version="0.7", optional=true, default-features=false, features=["size_32"]}
+rkyv={version="0.7", optional=true, default-features=false, features=["size_32", "validation"]}
+bytecheck={version="0.7", optional=true}
[features]
-default=["std", "logging"]
-std=["rkyv/std"]
-serialize=["dep:rkyv", "dep:log"]
+default=["std", "logging", "archive", "unsafe"]
+std=["rkyv?/std"]
+archive=["dep:rkyv", "dep:bytecheck"]
logging=["dep:log"]
+unsafe=[]
diff --git a/crates/types/src/archive.rs b/crates/types/src/archive.rs
new file mode 100644
index 0000000..00a9911
--- /dev/null
+++ b/crates/types/src/archive.rs
@@ -0,0 +1,92 @@
+use crate::TinyWasmModule;
+use rkyv::{
+ check_archived_root,
+ ser::{serializers::AllocSerializer, Serializer},
+ Deserialize,
+};
+
+// 16 bytes
+const TWASM_MAGIC_PREFIX: &[u8; 4] = b"TWAS";
+const TWASM_VERSION: &[u8; 2] = b"01";
+
+#[rustfmt::skip]
+const TWASM_MAGIC: [u8; 16] = [ TWASM_MAGIC_PREFIX[0], TWASM_MAGIC_PREFIX[1], TWASM_MAGIC_PREFIX[2], TWASM_MAGIC_PREFIX[3], TWASM_VERSION[0], TWASM_VERSION[1], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+
+pub use rkyv::AlignedVec;
+
+fn validate_magic(wasm: &[u8]) -> Result<usize, &str> {
+ if wasm.len() < TWASM_MAGIC.len() {
+ return Err("Invalid twasm: too short");
+ }
+ if &wasm[..TWASM_MAGIC_PREFIX.len()] != TWASM_MAGIC_PREFIX {
+ return Err("Invalid twasm: invalid magic number");
+ }
+ if &wasm[TWASM_MAGIC_PREFIX.len()..TWASM_MAGIC_PREFIX.len() + TWASM_VERSION.len()] != TWASM_VERSION {
+ return Err("Invalid twasm: invalid version");
+ }
+ if wasm[TWASM_MAGIC_PREFIX.len() + TWASM_VERSION.len()..TWASM_MAGIC.len()] != [0; 10] {
+ return Err("Invalid twasm: invalid padding");
+ }
+
+ Ok(TWASM_MAGIC.len())
+}
+
+impl TinyWasmModule {
+ /// Creates a TinyWasmModule from a slice of bytes.
+ pub fn from_twasm(wasm: &[u8]) -> Result<TinyWasmModule, &str> {
+ let len = validate_magic(wasm)?;
+ let root = check_archived_root::<Self>(&wasm[len..]).map_err(|e| {
+ log::error!("Error checking archived root: {}", e);
+ "Error checking archived root"
+ })?;
+
+ Ok(root.deserialize(&mut rkyv::Infallible).unwrap())
+ }
+
+ #[cfg(feature = "unsafe")]
+ #[allow(unsafe_code)]
+ /// Creates a TinyWasmModule from a slice of bytes.
+ ///
+ /// # Safety
+ /// This function is only safe to call if the bytes have been created by
+ /// a trusted source. Otherwise, it may cause undefined behavior.
+ pub unsafe fn from_twasm_unchecked(wasm: &[u8]) -> Self {
+ let len = validate_magic(wasm).unwrap();
+ rkyv::archived_root::<TinyWasmModule>(&wasm[len..]).deserialize(&mut rkyv::Infallible).unwrap()
+ }
+
+ /// Serializes the TinyWasmModule into a vector of bytes.
+ /// AlignedVec can be deferenced as a slice of bytes and
+ /// implements io::Write when the `std` feature is enabled.
+ pub fn serialize_twasm(&self) -> rkyv::AlignedVec {
+ let mut serializer = AllocSerializer::<0>::default();
+ serializer.pad(TWASM_MAGIC.len()).unwrap();
+ serializer.serialize_value(self).unwrap();
+ let mut out = serializer.into_serializer().into_inner();
+ out[..TWASM_MAGIC.len()].copy_from_slice(&TWASM_MAGIC);
+ out
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_serialize() {
+ let wasm = TinyWasmModule::default();
+ let twasm = wasm.serialize_twasm();
+ let wasm2 = TinyWasmModule::from_twasm(&twasm).unwrap();
+ assert_eq!(wasm, wasm2);
+ }
+
+ #[cfg(feature = "unsafe")]
+ #[test]
+ fn test_serialize_unchecked() {
+ let wasm = TinyWasmModule::default();
+ let twasm = wasm.serialize_twasm();
+ #[allow(unsafe_code)]
+ let wasm2 = unsafe { TinyWasmModule::from_twasm_unchecked(&twasm) };
+ assert_eq!(wasm, wasm2);
+ }
+}
diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs
index 1061d10..0e2eafe 100644
--- a/crates/types/src/instructions.rs
+++ b/crates/types/src/instructions.rs
@@ -3,6 +3,8 @@ use crate::{DataAddr, ElemAddr, MemAddr};
use super::{FuncAddr, GlobalAddr, LabelAddr, LocalAddr, TableAddr, TypeAddr, ValType};
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
+#[cfg_attr(feature = "archive", archive(check_bytes))]
pub enum BlockArgs {
Empty,
Type(ValType),
@@ -10,7 +12,9 @@ pub enum BlockArgs {
}
/// Represents a memory immediate in a WebAssembly memory instruction.
-#[derive(Debug, Copy, Clone)]
+#[derive(Debug, Copy, Clone, PartialEq)]
+#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
+#[cfg_attr(feature = "archive", archive(check_bytes))]
pub struct MemoryArg {
pub mem_addr: MemAddr,
pub align: u8,
@@ -23,7 +27,9 @@ type BrTableLen = usize;
type EndOffset = usize;
type ElseOffset = usize;
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone, Copy, PartialEq)]
+#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
+#[cfg_attr(feature = "archive", archive(check_bytes))]
pub enum ConstInstruction {
I32Const(i32),
I64Const(i64),
@@ -46,7 +52,9 @@ pub enum ConstInstruction {
/// This makes it easier to implement the label stack iteratively.
///
/// See <https://webassembly.github.io/spec/core/binary/instructions.html>
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone, Copy, PartialEq)]
+#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
+#[cfg_attr(feature = "archive", archive(check_bytes))]
pub enum Instruction {
// Custom Instructions
BrLabel(LabelAddr),
diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs
index 2ccf869..547379c 100644
--- a/crates/types/src/lib.rs
+++ b/crates/types/src/lib.rs
@@ -1,10 +1,11 @@
-#![no_std]
-#![forbid(unsafe_code)]
#![doc(test(
no_crate_inject,
attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_assignments, unused_variables))
))]
#![warn(missing_debug_implementations, rust_2018_idioms, unreachable_pub)]
+#![cfg_attr(not(feature = "std"), no_std)]
+#![cfg_attr(not(feature = "unsafe"), forbid(unsafe_code))]
+#![cfg_attr(feature = "unsafe", deny(unused_unsafe))]
//! Types used by [`tinywasm`](https://docs.rs/tinywasm) and [`tinywasm_parser`](https://docs.rs/tinywasm_parser).
@@ -28,22 +29,25 @@ use core::{fmt::Debug, ops::Range};
use alloc::boxed::Box;
pub use instructions::*;
+#[cfg(feature = "archive")]
+pub mod archive;
+
/// A TinyWasm WebAssembly Module
///
/// This is the internal representation of a WebAssembly module in TinyWasm.
/// TinyWasmModules are validated before being created, so they are guaranteed to be valid (as long as they were created by TinyWasm).
/// This means you should not trust a TinyWasmModule created by a third party to be valid.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Default, PartialEq)]
+#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
+#[cfg_attr(feature = "archive", archive(check_bytes))]
pub struct TinyWasmModule {
/// The version of the WebAssembly module.
pub version: Option<u16>,
-
/// The start function of the WebAssembly module.
pub start_func: Option<FuncAddr>,
/// The functions of the WebAssembly module.
- pub funcs: Box<[(u32, WasmFunction)]>,
-
+ pub funcs: Box<[TypedWasmFunction]>,
/// The types of the WebAssembly module.
pub func_types: Box<[FuncType]>,
@@ -90,6 +94,7 @@ pub enum WasmValue {
}
impl WasmValue {
+ #[inline]
pub fn const_instr(&self) -> ConstInstruction {
match self {
Self::I32(i) => ConstInstruction::I32Const(*i),
@@ -106,6 +111,7 @@ impl WasmValue {
}
/// Get the default value for a given type.
+ #[inline]
pub fn default_for(ty: ValType) -> Self {
match ty {
ValType::I32 => Self::I32(0),
@@ -117,6 +123,7 @@ impl WasmValue {
}
}
+ #[inline]
pub fn eq_loose(&self, other: &Self) -> bool {
match (self, other) {
(Self::I32(a), Self::I32(b)) => a == b,
@@ -144,36 +151,45 @@ impl WasmValue {
}
impl From<i32> for WasmValue {
+ #[inline]
fn from(i: i32) -> Self {
Self::I32(i)
}
}
impl From<i64> for WasmValue {
+ #[inline]
fn from(i: i64) -> Self {
Self::I64(i)
}
}
impl From<f32> for WasmValue {
+ #[inline]
fn from(i: f32) -> Self {
Self::F32(i)
}
}
impl From<f64> for WasmValue {
+ #[inline]
fn from(i: f64) -> Self {
Self::F64(i)
}
}
+#[cold]
+fn cold() {}
+
impl TryFrom<WasmValue> for i32 {
type Error = ();
+ #[inline]
fn try_from(value: WasmValue) -> Result<Self, Self::Error> {
match value {
WasmValue::I32(i) => Ok(i),
_ => {
+ cold();
crate::log::error!("i32: try_from failed: {:?}", value);
Err(())
}
@@ -184,10 +200,12 @@ impl TryFrom<WasmValue> for i32 {
impl TryFrom<WasmValue> for i64 {
type Error = ();
+ #[inline]
fn try_from(value: WasmValue) -> Result<Self, Self::Error> {
match value {
WasmValue::I64(i) => Ok(i),
_ => {
+ cold();
crate::log::error!("i64: try_from failed: {:?}", value);
Err(())
}
@@ -198,10 +216,12 @@ impl TryFrom<WasmValue> for i64 {
impl TryFrom<WasmValue> for f32 {
type Error = ();
+ #[inline]
fn try_from(value: WasmValue) -> Result<Self, Self::Error> {
match value {
WasmValue::F32(i) => Ok(i),
_ => {
+ cold();
crate::log::error!("f32: try_from failed: {:?}", value);
Err(())
}
@@ -212,10 +232,12 @@ impl TryFrom<WasmValue> for f32 {
impl TryFrom<WasmValue> for f64 {
type Error = ();
+ #[inline]
fn try_from(value: WasmValue) -> Result<Self, Self::Error> {
match value {
WasmValue::F64(i) => Ok(i),
_ => {
+ cold();
crate::log::error!("f64: try_from failed: {:?}", value);
Err(())
}
@@ -240,6 +262,7 @@ impl Debug for WasmValue {
impl WasmValue {
/// Get the type of a [`WasmValue`]
+ #[inline]
pub fn val_type(&self) -> ValType {
match self {
Self::I32(_) => ValType::I32,
@@ -255,6 +278,8 @@ impl WasmValue {
/// Type of a WebAssembly value.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
+#[cfg_attr(feature = "archive", archive(check_bytes))]
pub enum ValType {
/// A 32-bit integer.
I32,
@@ -271,6 +296,7 @@ pub enum ValType {
}
impl ValType {
+ #[inline]
pub fn default_value(&self) -> WasmValue {
WasmValue::default_for(*self)
}
@@ -280,6 +306,8 @@ impl ValType {
///
/// See <https://webassembly.github.io/spec/core/syntax/types.html#external-types>
#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
+#[cfg_attr(feature = "archive", archive(check_bytes))]
pub enum ExternalKind {
/// A WebAssembly Function.
Func,
@@ -322,6 +350,7 @@ pub enum ExternVal {
}
impl ExternVal {
+ #[inline]
pub fn kind(&self) -> ExternalKind {
match self {
Self::Func(_) => ExternalKind::Func,
@@ -331,6 +360,7 @@ impl ExternVal {
}
}
+ #[inline]
pub fn new(kind: ExternalKind, addr: Addr) -> Self {
match kind {
ExternalKind::Func => Self::Func(addr),
@@ -345,6 +375,8 @@ impl ExternVal {
///
/// See <https://webassembly.github.io/spec/core/syntax/types.html#function-types>
#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
+#[cfg_attr(feature = "archive", archive(check_bytes))]
pub struct FuncType {
pub params: Box<[ValType]>,
pub results: Box<[ValType]>,
@@ -352,20 +384,33 @@ pub struct FuncType {
impl FuncType {
/// Get the number of parameters of a function type.
+ #[inline]
pub fn empty() -> Self {
Self { params: Box::new([]), results: Box::new([]) }
}
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
+#[cfg_attr(feature = "archive", archive(check_bytes))]
pub struct WasmFunction {
pub instructions: Box<[Instruction]>,
pub locals: Box<[ValType]>,
pub ty: FuncType,
}
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
+#[cfg_attr(feature = "archive", archive(check_bytes))]
+pub struct TypedWasmFunction {
+ pub type_addr: u32,
+ pub wasm_function: WasmFunction,
+}
+
/// A WebAssembly Module Export
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
+#[cfg_attr(feature = "archive", archive(check_bytes))]
pub struct Export {
/// The name of the export.
pub name: Box<str>,
@@ -375,19 +420,25 @@ pub struct Export {
pub index: u32,
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
+#[cfg_attr(feature = "archive", archive(check_bytes))]
pub struct Global {
pub ty: GlobalType,
pub init: ConstInstruction,
}
#[derive(Debug, Clone, Copy, PartialEq)]
+#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
+#[cfg_attr(feature = "archive", archive(check_bytes))]
pub struct GlobalType {
pub mutable: bool,
pub ty: ValType,
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
+#[cfg_attr(feature = "archive", archive(check_bytes))]
pub struct TableType {
pub element_type: ValType,
pub size_initial: u32,
@@ -404,10 +455,12 @@ impl TableType {
}
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
/// Represents a memory's type.
#[derive(Copy)]
+#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
+#[cfg_attr(feature = "archive", archive(check_bytes))]
pub struct MemoryType {
pub arch: MemoryArch,
pub page_count_initial: u64,
@@ -418,30 +471,28 @@ impl MemoryType {
pub fn new_32(page_count_initial: u64, page_count_max: Option<u64>) -> Self {
Self { arch: MemoryArch::I32, page_count_initial, page_count_max }
}
-
- // pub fn new_64(page_count_initial: u64, page_count_max: Option<u64>) -> Self {
- // Self {
- // arch: MemoryArch::I64,
- // page_count_initial,
- // page_count_max,
- // }
- // }
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
+#[cfg_attr(feature = "archive", archive(check_bytes))]
pub enum MemoryArch {
I32,
I64,
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
+#[cfg_attr(feature = "archive", archive(check_bytes))]
pub struct Import {
pub module: Box<str>,
pub name: Box<str>,
pub kind: ImportKind,
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
+#[cfg_attr(feature = "archive", archive(check_bytes))]
pub enum ImportKind {
Function(TypeAddr),
Table(TableType),
@@ -450,6 +501,7 @@ pub enum ImportKind {
}
impl From<&ImportKind> for ExternalKind {
+ #[inline]
fn from(kind: &ImportKind) -> Self {
match kind {
ImportKind::Function(_) => Self::Func,
@@ -460,20 +512,26 @@ impl From<&ImportKind> for ExternalKind {
}
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
+#[cfg_attr(feature = "archive", archive(check_bytes))]
pub struct Data {
pub data: Box<[u8]>,
pub range: Range<usize>,
pub kind: DataKind,
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
+#[cfg_attr(feature = "archive", archive(check_bytes))]
pub enum DataKind {
Active { mem: MemAddr, offset: ConstInstruction },
Passive,
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
+#[cfg_attr(feature = "archive", archive(check_bytes))]
pub struct Element {
pub kind: ElementKind,
pub items: Box<[ElementItem]>,
@@ -481,14 +539,18 @@ pub struct Element {
pub ty: ValType,
}
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone, Copy, PartialEq)]
+#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
+#[cfg_attr(feature = "archive", archive(check_bytes))]
pub enum ElementKind {
Passive,
Active { table: TableAddr, offset: ConstInstruction },
Declared,
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
+#[cfg_attr(feature = "archive", archive(check_bytes))]
pub enum ElementItem {
Func(FuncAddr),
Expr(ConstInstruction),