summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/cli/src/bin.rs8
-rw-r--r--crates/parser/src/lib.rs36
-rw-r--r--crates/parser/src/module.rs83
-rw-r--r--crates/tinywasm/benches/argon2id.rs15
-rw-r--r--crates/tinywasm/benches/fibonacci.rs15
-rw-r--r--crates/tinywasm/benches/tinywasm.rs16
-rw-r--r--crates/tinywasm/benches/tinywasm_modes.rs19
-rw-r--r--crates/tinywasm/src/imports.rs12
-rw-r--r--crates/tinywasm/src/instance.rs80
-rw-r--r--crates/tinywasm/src/interpreter/executor.rs9
-rw-r--r--crates/tinywasm/src/lib.rs17
-rw-r--r--crates/tinywasm/src/module.rs179
-rw-r--r--crates/tinywasm/src/store/function.rs8
-rw-r--r--crates/tinywasm/src/store/mod.rs5
-rw-r--r--crates/tinywasm/tests/host_func_signature_check.rs10
-rw-r--r--crates/tinywasm/tests/import_linking.rs14
-rw-r--r--crates/tinywasm/tests/imported_table_init.rs6
-rw-r--r--crates/tinywasm/tests/internal_refs.rs14
-rw-r--r--crates/tinywasm/tests/memory_backends.rs16
-rw-r--r--crates/tinywasm/tests/memory_ref_api.rs6
-rw-r--r--crates/tinywasm/tests/module_descriptors.rs4
-rw-r--r--crates/tinywasm/tests/resume_execution.rs23
-rw-r--r--crates/tinywasm/tests/store_ownership.rs10
-rw-r--r--crates/tinywasm/tests/testsuite/run.rs12
-rw-r--r--crates/tinywasm/tests/testsuite/util.rs10
-rw-r--r--crates/tinywasm/tests/typed_lookup.rs10
-rw-r--r--crates/types/Cargo.toml2
-rw-r--r--crates/types/src/archive.rs18
-rw-r--r--crates/types/src/lib.rs226
29 files changed, 420 insertions, 463 deletions
diff --git a/crates/cli/src/bin.rs b/crates/cli/src/bin.rs
index 5fd50f9..9b283c3 100644
--- a/crates/cli/src/bin.rs
+++ b/crates/cli/src/bin.rs
@@ -4,7 +4,7 @@ use argh::FromArgs;
use args::WasmArg;
use eyre::Result;
use log::{debug, info};
-use tinywasm::{Module, types::WasmValue};
+use tinywasm::{Module, ModuleInstance, types::WasmValue};
use crate::args::to_wasm_args;
mod args;
@@ -90,11 +90,11 @@ fn main() -> Result<()> {
true => {
let wat = std::fs::read_to_string(path)?;
let wasm = wat::wat2wasm(&wat);
- tinywasm::Module::parse_bytes(&wasm)?
+ tinywasm::parse_bytes(&wasm)?
}
#[cfg(not(feature = "wat"))]
true => return Err(eyre::eyre!("wat support is not enabled in this build")),
- false => tinywasm::Module::parse_file(path)?,
+ false => tinywasm::parse_file(path)?,
};
match engine {
@@ -106,7 +106,7 @@ fn main() -> Result<()> {
fn run(module: Module, func: Option<String>, args: &[WasmValue]) -> Result<()> {
let mut store = tinywasm::Store::default();
- let instance = module.instantiate(&mut store, None)?;
+ let instance = ModuleInstance::instantiate(&mut store, &module, None)?;
if let Some(func) = func {
let func = instance.func_untyped(&store, &func)?;
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs
index 0b5af2e..7b3dfa2 100644
--- a/crates/parser/src/lib.rs
+++ b/crates/parser/src/lib.rs
@@ -39,7 +39,7 @@ pub use error::*;
use module::ModuleReader;
use wasmparser::{Validator, WasmFeatures};
-pub use tinywasm_types::TinyWasmModule;
+pub use tinywasm_types::Module;
/// Parser optimization and lowering options.
#[non_exhaustive]
@@ -113,8 +113,8 @@ impl Parser {
Validator::new_with_features(features)
}
- /// Parse a [`TinyWasmModule`] from bytes
- pub fn parse_module_bytes(&self, wasm: impl AsRef<[u8]>) -> Result<TinyWasmModule> {
+ /// Parse a [`Module`] from bytes
+ pub fn parse_module_bytes(&self, wasm: impl AsRef<[u8]>) -> Result<Module> {
let wasm = wasm.as_ref();
let mut validator = Self::create_validator(self.options.clone());
let mut reader = ModuleReader::default();
@@ -131,16 +131,16 @@ impl Parser {
}
#[cfg(feature = "std")]
- /// Parse a [`TinyWasmModule`] from a file. Requires `std` feature.
- pub fn parse_module_file(&self, path: impl AsRef<crate::std::path::Path> + Clone) -> Result<TinyWasmModule> {
+ /// Parse a [`Module`] from a file. Requires `std` feature.
+ pub fn parse_module_file(&self, path: impl AsRef<crate::std::path::Path> + Clone) -> Result<Module> {
let file = crate::std::fs::File::open(&path)
.map_err(|e| ParseError::Other(alloc::format!("Error opening file {:?}: {}", path.as_ref(), e)))?;
self.parse_module_stream(&mut crate::std::io::BufReader::new(file))
}
#[cfg(feature = "std")]
- /// Parse a [`TinyWasmModule`] from a stream. Requires `std` feature.
- pub fn parse_module_stream(&self, mut stream: impl std::io::Read) -> Result<TinyWasmModule> {
+ /// Parse a [`Module`] from a stream. Requires `std` feature.
+ pub fn parse_module_stream(&self, mut stream: impl std::io::Read) -> Result<Module> {
let mut validator = Self::create_validator(self.options.clone());
let mut reader = ModuleReader::default();
let mut buffer = alloc::vec::Vec::new();
@@ -170,10 +170,30 @@ impl Parser {
}
}
-impl TryFrom<ModuleReader> for TinyWasmModule {
+impl TryFrom<ModuleReader> for Module {
type Error = ParseError;
fn try_from(reader: ModuleReader) -> Result<Self> {
reader.into_module(&ParserOptions::default())
}
}
+
+/// Parse a module from bytes
+pub fn parse_bytes(wasm: &[u8]) -> Result<Module> {
+ let data = Parser::new().parse_module_bytes(wasm)?;
+ Ok(data)
+}
+
+#[cfg(feature = "std")]
+/// Parse a module from a file. Requires the `std` feature.
+pub fn parse_file(path: impl AsRef<crate::std::path::Path> + Clone) -> Result<Module> {
+ let data = Parser::new().parse_module_file(path)?;
+ Ok(data)
+}
+
+#[cfg(feature = "std")]
+/// Parse a module from a stream. Requires `parser` and `std` features.
+pub fn parse_stream(stream: impl crate::std::io::Read) -> Result<Module> {
+ let data = Parser::new().parse_module_stream(stream)?;
+ Ok(data)
+}
diff --git a/crates/parser/src/module.rs b/crates/parser/src/module.rs
index 9c4d6b4..47257fe 100644
--- a/crates/parser/src/module.rs
+++ b/crates/parser/src/module.rs
@@ -1,5 +1,6 @@
use crate::log::debug;
use crate::{ParseError, ParserOptions, Result, conversion, optimize};
+use alloc::sync::Arc;
use alloc::{format, string::ToString, vec::Vec};
use tinywasm_types::*;
use wasmparser::{FuncValidatorAllocations, Payload, Validator};
@@ -12,7 +13,7 @@ pub(crate) struct ModuleReader {
pub(crate) version: Option<u16>,
pub(crate) start_func: Option<u32>,
- pub(crate) func_types: Vec<FuncType>,
+ pub(crate) func_types: Vec<Arc<FuncType>>,
pub(crate) code_type_addrs: Vec<u32>,
pub(crate) exports: Vec<Export>,
pub(crate) code: Vec<Code>,
@@ -53,8 +54,8 @@ impl ModuleReader {
validator.type_section(&reader)?;
self.func_types = reader
.into_iter()
- .map(|t| conversion::convert_module_type(t?))
- .collect::<Result<Vec<FuncType>>>()?;
+ .map(|t| conversion::convert_module_type(t?).map(Arc::new))
+ .collect::<Result<Vec<Arc<FuncType>>>>()?;
}
Payload::GlobalSection(reader) => {
@@ -167,7 +168,7 @@ impl ModuleReader {
Ok(())
}
- pub(crate) fn into_module(self, options: &ParserOptions) -> Result<TinyWasmModule> {
+ pub(crate) fn into_module(self, options: &ParserOptions) -> Result<Module> {
if !self.end_reached {
return Err(ParseError::EndNotReached);
}
@@ -176,73 +177,57 @@ impl ModuleReader {
return Err(ParseError::Other("Code and code type address count mismatch".to_string()));
}
- let Self {
- start_func,
- func_types,
- code_type_addrs,
- exports,
- code,
- globals,
- table_types,
- memory_types,
- imports,
- data,
- elements,
- ..
- } = self;
-
- let imported_func_count = imports.iter().filter(|i| matches!(&i.kind, ImportKind::Function(_))).count();
- let imported_memory_count = imports.iter().filter(|i| matches!(&i.kind, ImportKind::Memory(_))).count() as u32;
- let has_local_memory_export =
- exports.iter().any(|export| export.kind == ExternalKind::Memory && export.index >= imported_memory_count);
- let has_active_data_segment_on_local_memory = data.iter().any(|data| match &data.kind {
- DataKind::Active { mem, .. } => *mem >= imported_memory_count,
+ let imported_func_count = self.imports.iter().filter(|i| matches!(&i.kind, ImportKind::Function(_))).count();
+ let import_mem_count = self.imports.iter().filter(|i| matches!(&i.kind, ImportKind::Memory(_))).count() as u32;
+ let has_local_mem_export =
+ self.exports.iter().any(|export| export.kind == ExternalKind::Memory && export.index >= import_mem_count);
+ let has_active_data_segment_on_local_memory = self.data.iter().any(|data| match &data.kind {
+ DataKind::Active { mem, .. } => *mem >= import_mem_count,
DataKind::Passive => false,
});
let optimize_local_memory_allocation = options.optimize_local_memory_allocation();
- let mut local_memory_allocation = if memory_types.is_empty() {
+ let mut local_memory_allocation = if self.memory_types.is_empty() {
LocalMemoryAllocation::Skip
} else if !optimize_local_memory_allocation || has_active_data_segment_on_local_memory {
LocalMemoryAllocation::Eager
- } else if has_local_memory_export {
+ } else if has_local_mem_export {
LocalMemoryAllocation::Lazy
} else {
LocalMemoryAllocation::Skip
};
- let mut funcs = Vec::with_capacity(code.len());
+ let mut funcs = Vec::with_capacity(self.code.len());
- for (func_idx, ((instructions, mut data, locals), ty_idx)) in code.into_iter().zip(code_type_addrs).enumerate()
+ for (func_idx, ((instructions, mut data, locals), ty_idx)) in
+ self.code.into_iter().zip(self.code_type_addrs).enumerate()
{
- let ty = func_types.get(ty_idx as usize).expect("No func type for func, this is a bug").clone();
+ let ty = self.func_types.get(ty_idx as usize).expect("No func type for func, this is a bug").clone();
let params = ValueCounts::from_iter(ty.params());
let self_func = (imported_func_count + func_idx) as u32;
- let optimized = optimize::optimize_instructions(
- instructions,
- &mut data,
- self_func,
- imported_memory_count,
- optimize_local_memory_allocation && local_memory_allocation != LocalMemoryAllocation::Eager,
- );
+ let local_mem_alloc =
+ optimize_local_memory_allocation && local_memory_allocation != LocalMemoryAllocation::Eager;
+ let optimized =
+ optimize::optimize_instructions(instructions, &mut data, self_func, import_mem_count, local_mem_alloc);
if optimized.uses_local_memory {
local_memory_allocation = LocalMemoryAllocation::Eager;
}
- funcs.push(WasmFunction { instructions: ArcSlice::from(optimized.instructions), data, locals, params, ty });
+ funcs.push(WasmFunction { instructions: optimized.instructions.into(), data, locals, params, ty }.into());
}
- Ok(TinyWasmModule {
+ Ok(ModuleInner {
funcs: funcs.into(),
- func_types: func_types.into(),
- globals: globals.into(),
- table_types: table_types.into(),
- imports: imports.into(),
- start_func,
- data: data.into(),
- exports: exports.into(),
- elements: elements.into(),
- memory_types: memory_types.into(),
+ func_types: self.func_types.into(),
+ globals: self.globals.into(),
+ table_types: self.table_types.into(),
+ imports: self.imports.into(),
+ start_func: self.start_func,
+ data: self.data.into(),
+ exports: self.exports.into(),
+ elements: self.elements.into(),
+ memory_types: self.memory_types.into(),
local_memory_allocation,
- })
+ }
+ .into())
}
}
diff --git a/crates/tinywasm/benches/argon2id.rs b/crates/tinywasm/benches/argon2id.rs
index 277b904..dbd86e5 100644
--- a/crates/tinywasm/benches/argon2id.rs
+++ b/crates/tinywasm/benches/argon2id.rs
@@ -1,29 +1,29 @@
use criterion::{Criterion, criterion_group, criterion_main};
use eyre::Result;
use tinywasm::{ModuleInstance, Store, types};
-use types::TinyWasmModule;
+use types::Module;
const WASM: &[u8] = include_bytes!("../../../examples/rust/out/argon2id.wasm");
-fn argon2id_parse() -> Result<TinyWasmModule> {
+fn argon2id_parse() -> Result<Module> {
let parser = tinywasm_parser::Parser::new();
let data = parser.parse_module_bytes(WASM)?;
Ok(data)
}
-fn argon2id_to_twasm(module: &TinyWasmModule) -> Result<Vec<u8>> {
+fn argon2id_to_twasm(module: &Module) -> Result<Vec<u8>> {
let twasm = module.serialize_twasm()?;
Ok(twasm)
}
-fn argon2id_from_twasm(twasm: &[u8]) -> Result<TinyWasmModule> {
- let module = TinyWasmModule::from_twasm(twasm)?;
+fn argon2id_from_twasm(twasm: &[u8]) -> Result<Module> {
+ let module = Module::try_from_twasm(twasm)?;
Ok(module)
}
-fn argon2id_run(module: TinyWasmModule) -> Result<()> {
+fn argon2id_run(module: Module) -> Result<()> {
let mut store = Store::default();
- let instance = ModuleInstance::instantiate(&mut store, module.into(), None)?;
+ let instance = ModuleInstance::instantiate(&mut store, &module, None)?;
let argon2 = instance.func::<(i32, i32, i32), i32>(&store, "argon2id")?;
argon2.call(&mut store, (1000, 2, 1))?;
Ok(())
@@ -38,6 +38,7 @@ fn criterion_benchmark(c: &mut Criterion) {
group.bench_function("argon2id_parse", |b| b.iter(argon2id_parse));
group.bench_function("argon2id_to_twasm", |b| b.iter(|| argon2id_to_twasm(&module)));
group.bench_function("argon2id_from_twasm", |b| b.iter(|| argon2id_from_twasm(&twasm)));
+
group.measurement_time(std::time::Duration::from_secs(10));
group.bench_function("argon2id", |b| b.iter(|| argon2id_run(module.clone())));
}
diff --git a/crates/tinywasm/benches/fibonacci.rs b/crates/tinywasm/benches/fibonacci.rs
index 51bfa52..e0737da 100644
--- a/crates/tinywasm/benches/fibonacci.rs
+++ b/crates/tinywasm/benches/fibonacci.rs
@@ -1,28 +1,28 @@
use criterion::{Criterion, criterion_group, criterion_main};
use eyre::Result;
use tinywasm::{ModuleInstance, Store, types};
-use types::TinyWasmModule;
+use types::Module;
const WASM: &[u8] = include_bytes!("../../../examples/rust/out/fibonacci.wasm");
-fn fibonacci_parse() -> Result<TinyWasmModule> {
+fn fibonacci_parse() -> Result<Module> {
let parser = tinywasm_parser::Parser::new();
let data = parser.parse_module_bytes(WASM)?;
Ok(data)
}
-fn fibonacci_to_twasm(module: &TinyWasmModule) -> Result<Vec<u8>> {
+fn fibonacci_to_twasm(module: &Module) -> Result<Vec<u8>> {
let twasm = module.serialize_twasm()?;
Ok(twasm)
}
-fn fibonacci_from_twasm(twasm: &[u8]) -> Result<TinyWasmModule> {
- Ok(TinyWasmModule::from_twasm(twasm)?)
+fn fibonacci_from_twasm(twasm: &[u8]) -> Result<Module> {
+ Ok(Module::try_from_twasm(twasm)?)
}
-fn fibonacci_run(module: TinyWasmModule, recursive: bool, n: i32) -> Result<()> {
+fn fibonacci_run(module: Module, recursive: bool, n: i32) -> Result<()> {
let mut store = Store::default();
- let instance = ModuleInstance::instantiate(&mut store, module.into(), None)?;
+ let instance = ModuleInstance::instantiate(&mut store, &module, None)?;
let argon2 = instance.func::<i32, i32>(
&store,
match recursive {
@@ -43,6 +43,7 @@ fn criterion_benchmark(c: &mut Criterion) {
group.bench_function("fibonacci_parse", |b| b.iter(fibonacci_parse));
group.bench_function("fibonacci_to_twasm", |b| b.iter(|| fibonacci_to_twasm(&module)));
group.bench_function("fibonacci_from_twasm", |b| b.iter(|| fibonacci_from_twasm(&twasm)));
+
group.measurement_time(std::time::Duration::from_secs(10));
group.bench_function("fibonacci_iterative_60", |b| b.iter(|| fibonacci_run(module.clone(), false, 60)));
group.bench_function("fibonacci_recursive_26", |b| b.iter(|| fibonacci_run(module.clone(), true, 26)));
diff --git a/crates/tinywasm/benches/tinywasm.rs b/crates/tinywasm/benches/tinywasm.rs
index 48458d7..7d50d72 100644
--- a/crates/tinywasm/benches/tinywasm.rs
+++ b/crates/tinywasm/benches/tinywasm.rs
@@ -3,32 +3,32 @@ use eyre::Result;
use tinywasm::{
Engine, FuncContext, HostFunction, Imports, MemoryBackend, ModuleInstance, Store, engine::Config, types,
};
-use types::TinyWasmModule;
+use types::Module;
const WASM: &[u8] = include_bytes!("../../../examples/rust/out/tinywasm.wasm");
-fn tinywasm_parse() -> Result<TinyWasmModule> {
+fn tinywasm_parse() -> Result<Module> {
let parser = tinywasm_parser::Parser::new();
let data = parser.parse_module_bytes(WASM)?;
Ok(data)
}
-fn tinywasm_to_twasm(module: &TinyWasmModule) -> Result<Vec<u8>> {
+fn tinywasm_to_twasm(module: &Module) -> Result<Vec<u8>> {
let twasm = module.serialize_twasm()?;
Ok(twasm)
}
-fn tinywasm_from_twasm(twasm: &[u8]) -> Result<TinyWasmModule> {
- let module = TinyWasmModule::from_twasm(twasm)?;
+fn tinywasm_from_twasm(twasm: &[u8]) -> Result<Module> {
+ let module = Module::try_from_twasm(twasm)?;
Ok(module)
}
-fn tinywasm_run(module: TinyWasmModule) -> Result<()> {
+fn tinywasm_run(module: &Module) -> Result<()> {
let engine = Engine::new(Config::default().with_memory_backend(MemoryBackend::paged(64 * 1024)));
let mut store = Store::new(engine);
let mut imports = Imports::default();
imports.define("env", "printi32", HostFunction::from(&mut store, |_: FuncContext<'_>, _: i32| Ok(())));
- let instance = ModuleInstance::instantiate(&mut store, module.into(), Some(imports)).expect("instantiate");
+ let instance = ModuleInstance::instantiate(&mut store, module, Some(imports)).expect("instantiate");
let hello = instance.func::<(), ()>(&store, "hello").expect("func_typed");
hello.call(&mut store, ()).expect("call");
Ok(())
@@ -44,7 +44,7 @@ fn criterion_benchmark(c: &mut Criterion) {
group.bench_function("tinywasm_to_twasm", |b| b.iter(|| tinywasm_to_twasm(&module)));
group.bench_function("tinywasm_from_twasm", |b| b.iter(|| tinywasm_from_twasm(&twasm)));
group.measurement_time(std::time::Duration::from_secs(10));
- group.bench_function("tinywasm", |b| b.iter(|| tinywasm_run(module.clone())));
+ group.bench_function("tinywasm", |b| b.iter(|| tinywasm_run(&module)));
}
criterion_group!(benches, criterion_benchmark);
diff --git a/crates/tinywasm/benches/tinywasm_modes.rs b/crates/tinywasm/benches/tinywasm_modes.rs
index d7636f8..ed89b7b 100644
--- a/crates/tinywasm/benches/tinywasm_modes.rs
+++ b/crates/tinywasm/benches/tinywasm_modes.rs
@@ -1,7 +1,7 @@
use criterion::{BatchSize, Criterion, criterion_group, criterion_main};
use eyre::Result;
use tinywasm::engine::{Config, FuelPolicy};
-use tinywasm::types::TinyWasmModule;
+use tinywasm::types::Module;
use tinywasm::{Engine, ExecProgress, FuncContext, FunctionTyped, HostFunction, Imports, ModuleInstance, Store};
const WASM: &[u8] = include_bytes!("../../../examples/rust/out/tinywasm.wasm");
@@ -9,12 +9,12 @@ const FUEL_PER_ROUND: u32 = 512;
const TIME_BUDGET_PER_ROUND: core::time::Duration = core::time::Duration::from_micros(50);
const BENCH_MEASUREMENT_TIME: core::time::Duration = core::time::Duration::from_secs(10);
-fn tinywasm_parse() -> Result<TinyWasmModule> {
+fn tinywasm_parse() -> Result<Module> {
let parser = tinywasm_parser::Parser::new();
Ok(parser.parse_module_bytes(WASM)?)
}
-fn setup_typed_func(module: TinyWasmModule, engine: Option<Engine>) -> Result<(Store, FunctionTyped<(), ()>)> {
+fn setup_typed_func(module: &Module, engine: Option<Engine>) -> Result<(Store, FunctionTyped<(), ()>)> {
let mut store = match engine {
Some(engine) => Store::new(engine),
None => Store::default(),
@@ -23,7 +23,7 @@ fn setup_typed_func(module: TinyWasmModule, engine: Option<Engine>) -> Result<(S
let mut imports = Imports::default();
imports.define("env", "printi32", HostFunction::from(&mut store, |_: FuncContext<'_>, _: i32| Ok(())));
- let instance = ModuleInstance::instantiate(&mut store, module.into(), Some(imports))?;
+ let instance = ModuleInstance::instantiate(&mut store, module, Some(imports))?;
let func = instance.func::<(), ()>(&store, "hello")?;
Ok((store, func))
}
@@ -61,10 +61,7 @@ fn criterion_benchmark(c: &mut Criterion) {
let per_instruction_engine = Engine::new(Config::new().with_fuel_policy(FuelPolicy::PerInstruction));
group.bench_function("resume_fuel_per_instruction", |b| {
b.iter_batched_ref(
- || {
- setup_typed_func(module.clone(), Some(per_instruction_engine.clone()))
- .expect("setup fuel per-instruction")
- },
+ || setup_typed_func(&module, Some(per_instruction_engine.clone())).expect("setup fuel per-instruction"),
|(store, func)| run_resume_with_fuel(store, func).expect("run fuel per-instruction"),
BatchSize::LargeInput,
)
@@ -73,7 +70,7 @@ fn criterion_benchmark(c: &mut Criterion) {
let weighted_engine = Engine::new(Config::new().with_fuel_policy(FuelPolicy::Weighted));
group.bench_function("resume_fuel_weighted", |b| {
b.iter_batched_ref(
- || setup_typed_func(module.clone(), Some(weighted_engine.clone())).expect("setup fuel weighted"),
+ || setup_typed_func(&module, Some(weighted_engine.clone())).expect("setup fuel weighted"),
|(store, func)| run_resume_with_fuel(store, func).expect("run fuel weighted"),
BatchSize::LargeInput,
)
@@ -81,7 +78,7 @@ fn criterion_benchmark(c: &mut Criterion) {
group.bench_function("resume_time_budget", |b| {
b.iter_batched_ref(
- || setup_typed_func(module.clone(), None).expect("setup time budget"),
+ || setup_typed_func(&module, None).expect("setup time budget"),
|(store, func)| run_resume_with_time_budget(store, func).expect("run time budget"),
BatchSize::LargeInput,
)
@@ -89,7 +86,7 @@ fn criterion_benchmark(c: &mut Criterion) {
group.bench_function("call", |b| {
b.iter_batched_ref(
- || setup_typed_func(module.clone(), None).expect("setup call"),
+ || setup_typed_func(&module, None).expect("setup call"),
|(store, func)| run_call(store, func).expect("run call"),
BatchSize::LargeInput,
)
diff --git a/crates/tinywasm/src/imports.rs b/crates/tinywasm/src/imports.rs
index d82b8a4..fff2a8f 100644
--- a/crates/tinywasm/src/imports.rs
+++ b/crates/tinywasm/src/imports.rs
@@ -66,12 +66,12 @@ impl From<&Import> for ExternName {
/// ```rust
/// # use log;
/// # fn main() -> tinywasm::Result<()> {
-/// use tinywasm::{Global, HostFunction, Imports, Memory, Module, Store, Table};
+/// use tinywasm::{Global, HostFunction, Imports, Memory, ModuleInstance, Store, Table};
/// use tinywasm::types::{WasmType, TableType, MemoryType, WasmValue};
/// # let wasm = wat::parse_str("(module)").expect("valid wat");
-/// # let module = Module::parse_bytes(&wasm)?;
+/// # let module = tinywasm::parse_bytes(&wasm)?;
/// # let mut store = Store::default();
-/// # let my_other_instance = module.instantiate(&mut store, None)?;
+/// # let my_other_instance = ModuleInstance::instantiate(&mut store, &module, None)?;
/// let mut imports = Imports::new();
///
/// // function args can be either a single
@@ -245,12 +245,12 @@ impl Imports {
pub(crate) fn link(
self,
store: &mut crate::Store,
- module: &crate::Module,
+ module: &Module,
_idx: ModuleInstanceAddr,
) -> Result<ResolvedImports> {
let mut imports = ResolvedImports::new();
- for import in &*module.0.imports {
+ for import in &*module.imports {
if let Some(defined) = self.take_defined(import) {
match defined {
Extern::Global(global) => {
@@ -284,7 +284,6 @@ impl Imports {
return Err(LinkingError::incompatible_import_type(import).into());
};
let import_func_type = module
- .0
.func_types
.get(*ty as usize)
.ok_or_else(|| LinkingError::incompatible_import_type(import))?;
@@ -332,7 +331,6 @@ impl Imports {
(ExternVal::Func(func_addr), ImportKind::Function(ty)) => {
let func = store.state.get_func(func_addr);
let import_func_type = module
- .0
.func_types
.get(*ty as usize)
.ok_or_else(|| LinkingError::incompatible_import_type(import))?;
diff --git a/crates/tinywasm/src/instance.rs b/crates/tinywasm/src/instance.rs
index 6b4f407..90a95e3 100644
--- a/crates/tinywasm/src/instance.rs
+++ b/crates/tinywasm/src/instance.rs
@@ -1,9 +1,10 @@
use alloc::boxed::Box;
+use alloc::sync::Arc;
use alloc::{format, rc::Rc};
use tinywasm_types::*;
use crate::func::{FromWasmValueTuple, IntoWasmValueTuple, WasmTypesFromTuple};
-use crate::{Error, Function, FunctionTyped, Global, Imports, Memory, Module, Result, Store, Table};
+use crate::{Error, Function, FunctionTyped, Global, Imports, Memory, Result, Store, Table};
/// A typed view over an exported extern value.
pub enum ExternItem {
@@ -30,7 +31,7 @@ pub struct ModuleInstance(pub(crate) Rc<ModuleInstanceInner>);
pub(crate) struct ModuleInstanceInner {
pub(crate) store_id: usize,
pub(crate) idx: ModuleInstanceAddr,
- pub(crate) types: ArcSlice<FuncType>,
+ pub(crate) types: Arc<[Arc<FuncType>]>,
pub(crate) func_addrs: Box<[FuncAddr]>,
pub(crate) table_addrs: Box<[TableAddr]>,
pub(crate) mem_addrs: Box<[MemAddr]>,
@@ -38,9 +39,45 @@ pub(crate) struct ModuleInstanceInner {
pub(crate) elem_addrs: Box<[ElemAddr]>,
pub(crate) data_addrs: Box<[DataAddr]>,
pub(crate) func_start: Option<FuncAddr>,
- pub(crate) exports: ArcSlice<Export>,
+ pub(crate) exports: Arc<[Export]>,
}
+// impl ModuleInstance {
+// #[cfg(feature = "parser")]
+// /// Parse a module from bytes. Requires `parser` feature.
+// pub fn from_wasm_bytes(wasm: &[u8]) -> Result<Self> {
+// let data = tinywasm_parser::Parser::new().parse_module_bytes(wasm)?;
+// Ok(data.into())
+// }
+
+// #[cfg(all(feature = "parser", feature = "std"))]
+// /// Parse a module from a file. Requires `parser` and `std` features.
+// pub fn from_wasm_file(path: impl AsRef<crate::std::path::Path> + Clone) -> Result<Self> {
+// let data = tinywasm_parser::Parser::new().parse_module_file(path)?;
+// Ok(data.into())
+// }
+
+// #[cfg(all(feature = "parser", feature = "std"))]
+// /// Parse a module from a stream. Requires `parser` and `std` features.
+// pub fn from_wasm_stream(stream: impl crate::std::io::Read) -> Result<Self> {
+// let data = tinywasm_parser::Parser::new().parse_module_stream(stream)?;
+// Ok(data.into())
+// }
+
+// /// 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>
+// pub fn instantiate(self, store: &mut Store, imports: Option<Imports>) -> Result<ModuleInstance> {
+// let instance = ModuleInstance::instantiate(store, self, imports)?;
+// let _ = instance.start(store)?;
+// Ok(instance)
+// }
+// }
+
impl ModuleInstanceInner {
#[inline]
pub(crate) fn func_ty(&self, addr: FuncAddr) -> &FuncType {
@@ -127,37 +164,44 @@ impl ModuleInstance {
/// Instantiate the module in the given store
///
/// See <https://webassembly.github.io/spec/core/exec/modules.html#exec-instantiation>
- pub fn instantiate(store: &mut Store, module: Module, imports: Option<Imports>) -> Result<Self> {
+ pub fn instantiate(store: &mut Store, module: &Module, imports: Option<Imports>) -> Result<Self> {
+ let instance = ModuleInstance::instantiate_no_start(store, module, imports)?;
+ let _ = instance.start(store)?;
+ Ok(instance)
+ }
+
+ /// Instantiate the module in the given store (without running the start function)
+ ///
+ /// See <https://webassembly.github.io/spec/core/exec/modules.html#exec-instantiation>
+ pub fn instantiate_no_start(store: &mut Store, module: &Module, imports: Option<Imports>) -> Result<Self> {
let idx = store.next_module_instance_idx();
- let mut addrs = imports.unwrap_or_default().link(store, &module, idx)?;
+ let mut addrs = imports.unwrap_or_default().link(store, module, idx)?;
- addrs.funcs.extend(store.init_funcs(&module.0.funcs, idx));
- addrs.tables.extend(store.init_tables(&module.0.table_types, idx));
- match module.0.local_memory_allocation {
+ addrs.funcs.extend(store.init_funcs(&module.funcs, idx));
+ addrs.tables.extend(store.init_tables(&module.table_types, idx));
+ match module.local_memory_allocation {
LocalMemoryAllocation::Skip => {}
- LocalMemoryAllocation::Lazy => {
- addrs.memories.extend(store.init_lazy_memories(&module.0.memory_types, idx)?)
- }
- LocalMemoryAllocation::Eager => addrs.memories.extend(store.init_memories(&module.0.memory_types, idx)?),
+ LocalMemoryAllocation::Lazy => addrs.memories.extend(store.init_lazy_memories(&module.memory_types, idx)?),
+ LocalMemoryAllocation::Eager => addrs.memories.extend(store.init_memories(&module.memory_types, idx)?),
}
- let global_addrs = store.init_globals(addrs.globals, &module.0.globals, &addrs.funcs, idx)?;
+ let global_addrs = store.init_globals(addrs.globals, &module.globals, &addrs.funcs, idx)?;
let (elem_addrs, elem_trapped) =
- store.init_elements(&addrs.tables, &addrs.funcs, &global_addrs, &module.0.elements, idx)?;
+ store.init_elements(&addrs.tables, &addrs.funcs, &global_addrs, &module.elements, idx)?;
let (data_addrs, data_trapped) =
- store.init_data(&addrs.memories, &global_addrs, &addrs.funcs, &module.0.data, idx)?;
+ store.init_data(&addrs.memories, &global_addrs, &addrs.funcs, &module.data, idx)?;
let instance = ModuleInstanceInner {
store_id: store.id(),
idx,
- types: module.0.func_types.clone(),
+ types: module.func_types.clone(),
func_addrs: addrs.funcs.into_boxed_slice(),
table_addrs: addrs.tables.into_boxed_slice(),
mem_addrs: addrs.memories.into_boxed_slice(),
global_addrs: global_addrs.into_boxed_slice(),
elem_addrs,
data_addrs,
- func_start: module.0.start_func,
- exports: module.0.exports.clone(),
+ func_start: module.start_func,
+ exports: module.exports.clone(),
};
let instance = Rc::new(instance);
diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs
index acd14f6..fd7658b 100644
--- a/crates/tinywasm/src/interpreter/executor.rs
+++ b/crates/tinywasm/src/interpreter/executor.rs
@@ -7,6 +7,7 @@ use super::no_std_floats::NoStdFloatExt;
use alloc::boxed::Box;
use alloc::rc::Rc;
+use alloc::sync::Arc;
use interpreter::stack::CallFrame;
use tinywasm_types::*;
@@ -23,7 +24,7 @@ const FUEL_COST_CALL_TOTAL: u32 = 5;
pub(crate) struct Executor<'store, const BUDGETED: bool> {
cf: CallFrame,
- func: Rc<WasmFunction>,
+ func: Arc<WasmFunction>,
module: Rc<ModuleInstanceInner>,
store: &'store mut Store,
}
@@ -113,14 +114,14 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
}};
}
- let next = match self.func.instructions.0.get(self.cf.instr_ptr as usize) {
+ let next = match self.func.instructions.get(self.cf.instr_ptr as usize) {
Some(instr) => instr,
None => {
cold_path();
unreachable!(
"Instruction pointer out of bounds: {} ({} instructions)",
self.cf.instr_ptr,
- self.func.instructions.0.len()
+ self.func.instructions.len()
)
}
};
@@ -785,7 +786,7 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
wasm_func: WasmFunctionInstance,
func_addr: FuncAddr,
) -> Result<(), Trap> {
- if !Rc::ptr_eq(&self.func, &wasm_func.func) {
+ if !Arc::ptr_eq(&self.func, &wasm_func.func) {
self.func = wasm_func.func.clone();
}
diff --git a/crates/tinywasm/src/lib.rs b/crates/tinywasm/src/lib.rs
index d352042..5f7fa5c 100644
--- a/crates/tinywasm/src/lib.rs
+++ b/crates/tinywasm/src/lib.rs
@@ -32,17 +32,17 @@
#![cfg_attr(docsrs, feature(doc_cfg))]
//!
//! ## Getting Started
-//! The easiest way to get started is to use the [`Module::parse_bytes`] function to load a
+//! The easiest way to get started is to use the [`crate::parse_bytes`] function to load a
//! WebAssembly module from bytes. This will parse the module and validate it, returning
//! a [`Module`] that can be used to instantiate the module.
//!
//!
//! ```rust
-//! use tinywasm::{Store, Module};
+//! use tinywasm::{ModuleInstance, Store};
//!
//! // Load a module from bytes
//! let wasm = include_bytes!("../../../examples/wasm/add.wasm");
-//! let module = Module::parse_bytes(wasm)?;
+//! let module = tinywasm::parse_bytes(wasm)?;
//!
//! // Create a new store
//! // Stores are used to allocate objects like functions and globals
@@ -52,7 +52,7 @@
//! // This will allocate the module and its globals into the store
//! // and execute the module's start function.
//! // Every ModuleInstance has its own ID space for functions, globals, etc.
-//! let instance = module.instantiate(&mut store, None)?;
+//! let instance = ModuleInstance::instantiate(&mut store, &module, None)?;
//!
//! // Get a typed handle to the exported "add" function
//! // Alternatively, you can use `instance.func` to get an untyped handle
@@ -99,14 +99,12 @@ pub use error::*;
pub use func::{ExecProgress, FuncContext, FuncExecution, FuncExecutionTyped, Function, FunctionTyped, HostFunction};
pub use imports::*;
pub use instance::{ExternItem, ModuleInstance};
-pub use module::{ExportType, ImportType, Module, ModuleExport, ModuleImport};
pub use reference::*;
pub use store::*;
mod func;
mod imports;
mod instance;
-mod module;
mod reference;
mod store;
@@ -123,11 +121,18 @@ pub mod parser {
pub use tinywasm_parser::*;
}
+#[cfg(feature = "parser")]
+pub use parser::parse_bytes;
+#[cfg(all(feature = "parser", feature = "std"))]
+pub use parser::{parse_file, parse_stream};
+
/// Re-export of [`tinywasm_types`].
pub mod types {
pub use tinywasm_types::*;
}
+pub use tinywasm_types::Module;
+
pub(crate) fn unlikely(b: bool) -> bool {
if b {
core::hint::cold_path();
diff --git a/crates/tinywasm/src/module.rs b/crates/tinywasm/src/module.rs
deleted file mode 100644
index f725054..0000000
--- a/crates/tinywasm/src/module.rs
+++ /dev/null
@@ -1,179 +0,0 @@
-use crate::{Imports, ModuleInstance, Result, Store};
-use tinywasm_types::{ExternalKind, FuncType, TinyWasmModule};
-
-/// A module import descriptor.
-pub struct ModuleImport<'a> {
- /// Importing module name.
- pub module: &'a str,
- /// Import name.
- pub name: &'a str,
- /// Import type.
- pub ty: ImportType<'a>,
-}
-
-/// A module export descriptor.
-pub struct ModuleExport<'a> {
- /// Export name.
- pub name: &'a str,
- /// Export type.
- pub ty: ExportType<'a>,
-}
-
-/// Imported entity type.
-pub enum ImportType<'a> {
- /// Imported function type.
- Func(&'a FuncType),
- /// Imported table type.
- Table(&'a tinywasm_types::TableType),
- /// Imported memory type.
- Memory(&'a tinywasm_types::MemoryType),
- /// Imported global type.
- Global(&'a tinywasm_types::GlobalType),
-}
-
-/// Exported entity type.
-pub enum ExportType<'a> {
- /// Exported function type.
- Func(&'a FuncType),
- /// Exported table type.
- Table(&'a tinywasm_types::TableType),
- /// Exported memory type.
- Memory(&'a tinywasm_types::MemoryType),
- /// Exported global type.
- Global(&'a tinywasm_types::GlobalType),
-}
-
-/// A WebAssembly Module
-///
-/// See <https://webassembly.github.io/spec/core/syntax/modules.html#syntax-module>
-#[derive(Clone)]
-#[cfg_attr(feature = "debug", derive(Debug))]
-pub struct Module(pub(crate) alloc::sync::Arc<TinyWasmModule>);
-
-impl From<&TinyWasmModule> for Module {
- fn from(data: &TinyWasmModule) -> Self {
- Self(alloc::sync::Arc::new(data.clone()))
- }
-}
-
-impl From<TinyWasmModule> for Module {
- fn from(data: TinyWasmModule) -> Self {
- Self(alloc::sync::Arc::new(data))
- }
-}
-
-impl Module {
- #[cfg(feature = "parser")]
- /// Parse a module from bytes. Requires `parser` feature.
- pub fn parse_bytes(wasm: &[u8]) -> Result<Self> {
- let data = tinywasm_parser::Parser::new().parse_module_bytes(wasm)?;
- Ok(data.into())
- }
-
- #[cfg(all(feature = "parser", feature = "std"))]
- /// Parse a module from a file. Requires `parser` and `std` features.
- pub fn parse_file(path: impl AsRef<crate::std::path::Path> + Clone) -> Result<Self> {
- let data = tinywasm_parser::Parser::new().parse_module_file(path)?;
- Ok(data.into())
- }
-
- #[cfg(all(feature = "parser", feature = "std"))]
- /// Parse a module from a stream. Requires `parser` and `std` features.
- pub fn parse_stream(stream: impl crate::std::io::Read) -> Result<Self> {
- let data = tinywasm_parser::Parser::new().parse_module_stream(stream)?;
- Ok(data.into())
- }
-
- /// 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>
- pub fn instantiate(self, store: &mut Store, imports: Option<Imports>) -> Result<ModuleInstance> {
- let instance = ModuleInstance::instantiate(store, self, imports)?;
- let _ = instance.start(store)?;
- Ok(instance)
- }
-
- /// Returns an iterator over the module's import descriptors.
- ///
- /// The returned data mirrors the module's import section and preserves order.
- pub fn imports(&self) -> impl Iterator<Item = ModuleImport<'_>> {
- self.0.imports.iter().filter_map(|import| {
- let ty = match &import.kind {
- tinywasm_types::ImportKind::Function(type_idx) => {
- Some(ImportType::Func(self.0.func_types.get(*type_idx as usize)?))
- }
- tinywasm_types::ImportKind::Table(table_ty) => Some(ImportType::Table(table_ty)),
- tinywasm_types::ImportKind::Memory(memory_ty) => Some(ImportType::Memory(memory_ty)),
- tinywasm_types::ImportKind::Global(global_ty) => Some(ImportType::Global(global_ty)),
- }?;
-
- Some(ModuleImport { module: import.module.as_ref(), name: import.name.as_ref(), ty })
- })
- }
-
- /// Returns an iterator over the module's export descriptors.
- ///
- /// The returned data mirrors the module's export section and preserves order.
- pub fn exports(&self) -> impl Iterator<Item = ModuleExport<'_>> {
- self.0.exports.iter().filter_map(|export| {
- let imports = self.0.imports.iter();
- let idx = export.index as usize;
- let ty = match export.kind {
- ExternalKind::Func => {
- let imported_funcs =
- imports.filter(|import| matches!(import.kind, tinywasm_types::ImportKind::Function(_))).count();
- if idx < imported_funcs {
- ExportType::Func(imported_func_type(&self.0, idx)?)
- } else {
- let local_idx = idx - imported_funcs;
- ExportType::Func(&self.0.funcs.get(local_idx)?.ty)
- }
- }
- ExternalKind::Table => ExportType::Table(self.0.table_types.get(idx)?),
- ExternalKind::Memory => ExportType::Memory(self.0.memory_types.get(idx)?),
- ExternalKind::Global => {
- let imported_globals =
- imports.filter(|import| matches!(import.kind, tinywasm_types::ImportKind::Global(_))).count();
- if idx < imported_globals {
- ExportType::Global(imported_global_type(&self.0, idx)?)
- } else {
- let local_idx = idx - imported_globals;
- ExportType::Global(&self.0.globals.get(local_idx)?.ty)
- }
- }
- };
-
- Some(ModuleExport { name: export.name.as_ref(), ty })
- })
- }
-}
-
-fn imported_func_type(module: &TinyWasmModule, function_index: usize) -> Option<&FuncType> {
- let mut seen = 0usize;
- for import in module.imports.iter() {
- if let tinywasm_types::ImportKind::Function(type_idx) = import.kind {
- if seen == function_index {
- return module.func_types.get(type_idx as usize);
- }
- seen += 1;
- }
- }
- None
-}
-
-fn imported_global_type(module: &TinyWasmModule, global_index: usize) -> Option<&tinywasm_types::GlobalType> {
- let mut seen = 0usize;
- for import in module.imports.iter() {
- if let tinywasm_types::ImportKind::Global(global_ty) = &import.kind {
- if seen == global_index {
- return Some(global_ty);
- }
- seen += 1;
- }
- }
- None
-}
diff --git a/crates/tinywasm/src/store/function.rs b/crates/tinywasm/src/store/function.rs
index 56479dc..a7a22d5 100644
--- a/crates/tinywasm/src/store/function.rs
+++ b/crates/tinywasm/src/store/function.rs
@@ -1,4 +1,4 @@
-use alloc::rc::Rc;
+use alloc::{rc::Rc, sync::Arc};
use tinywasm_types::*;
use crate::func::HostFunction;
@@ -27,15 +27,15 @@ impl FunctionInstance {
}
impl FunctionInstance {
- pub(crate) fn new_wasm(func: WasmFunction, owner: ModuleInstanceAddr) -> Self {
- Self::Wasm(WasmFunctionInstance { func: Rc::new(func), owner })
+ pub(crate) fn new_wasm(func: Arc<WasmFunction>, owner: ModuleInstanceAddr) -> Self {
+ Self::Wasm(WasmFunctionInstance { func, owner })
}
}
#[derive(Clone)]
#[cfg_attr(feature = "debug", derive(Debug))]
pub(crate) struct WasmFunctionInstance {
- pub(crate) func: Rc<WasmFunction>,
+ pub(crate) func: Arc<WasmFunction>,
pub(crate) owner: ModuleInstanceAddr,
}
diff --git a/crates/tinywasm/src/store/mod.rs b/crates/tinywasm/src/store/mod.rs
index d26cb8a..773f4cb 100644
--- a/crates/tinywasm/src/store/mod.rs
+++ b/crates/tinywasm/src/store/mod.rs
@@ -1,4 +1,5 @@
use alloc::rc::Rc;
+use alloc::sync::Arc;
use alloc::{boxed::Box, format, string::ToString, vec::Vec};
use core::sync::atomic::{AtomicUsize, Ordering};
use tinywasm_types::*;
@@ -118,7 +119,7 @@ impl State {
}
/// Get a wasm function at the actual index in the store, panicking if it's a host function (which should be guaranteed by the validator)
- pub(crate) fn get_wasm_func(&self, addr: FuncAddr) -> &Rc<WasmFunction> {
+ pub(crate) fn get_wasm_func(&self, addr: FuncAddr) -> &Arc<WasmFunction> {
match self.funcs.get(addr as usize) {
Some(func) => match func {
FunctionInstance::Wasm(wasm_func) => &wasm_func.func,
@@ -262,7 +263,7 @@ impl Store {
// Linking related functions
impl Store {
/// Add functions to the store, returning their addresses in the store
- pub(crate) fn init_funcs(&mut self, funcs: &[WasmFunction], idx: ModuleInstanceAddr) -> Vec<FuncAddr> {
+ pub(crate) fn init_funcs(&mut self, funcs: &[Arc<WasmFunction>], idx: ModuleInstanceAddr) -> Vec<FuncAddr> {
let func_count = self.state.funcs.len();
let mut func_addrs = Vec::with_capacity(func_count);
for (i, func) in funcs.iter().enumerate() {
diff --git a/crates/tinywasm/tests/host_func_signature_check.rs b/crates/tinywasm/tests/host_func_signature_check.rs
index 0b09a51..ef8b2a1 100644
--- a/crates/tinywasm/tests/host_func_signature_check.rs
+++ b/crates/tinywasm/tests/host_func_signature_check.rs
@@ -1,7 +1,7 @@
use eyre::Result;
use std::fmt::Write;
use tinywasm::{
- FuncContext, HostFunction, Imports, Module, Store,
+ FuncContext, HostFunction, Imports, Module, ModuleInstance, Store,
types::{FuncType, WasmType, WasmValue},
};
use tinywasm_types::ExternRef;
@@ -39,7 +39,7 @@ fn test_return_invalid_type() -> Result<()> {
let hfn = HostFunction::from_untyped(&mut store, &ty, |_: FuncContext<'_>, _| Ok(returned_values.to_vec()));
imports.define("host", "hfn", hfn);
- let instance = module.clone().instantiate(&mut store, Some(imports)).unwrap();
+ let instance = ModuleInstance::instantiate(&mut store, &module, Some(imports)).unwrap();
let caller = instance.func_untyped(&store, "call_hfn").unwrap();
// Return-type mismatch is only observable at call time.
let should_succeed = returned_values.iter().map(WasmType::from).eq(ty.results().iter().copied());
@@ -63,7 +63,7 @@ fn test_linking_invalid_untyped_func() -> Result<()> {
imports.define("host", "hfn", tried_fn);
let should_succeed = ty == expected_func_ty;
- let link_res = module.clone().instantiate(&mut store, Some(imports));
+ let link_res = ModuleInstance::instantiate(&mut store, module, Some(imports));
assert_eq!(link_res.is_ok(), should_succeed);
}
}
@@ -108,7 +108,7 @@ fn test_linking_invalid_typed_func() -> Result<()> {
for typed_fn in matching_none {
let mut imports = Imports::new();
imports.define("host", "hfn", typed_fn);
- let link_failure = module.clone().instantiate(&mut store, Some(imports));
+ let link_failure = ModuleInstance::instantiate(&mut store, &module, Some(imports));
assert!(link_failure.is_err(), "Expected linking to fail for mismatched typed func, but it succeeded");
}
}
@@ -165,5 +165,5 @@ fn proxy_module(func_ty: &FuncType) -> Module {
"#
);
let wasm = wat::parse_str(wasm_text).expect("failed to parse wat");
- Module::parse_bytes(&wasm).expect("failed to make module")
+ tinywasm::parse_bytes(&wasm).expect("failed to make module")
}
diff --git a/crates/tinywasm/tests/import_linking.rs b/crates/tinywasm/tests/import_linking.rs
index 3ab13ff..712148e 100644
--- a/crates/tinywasm/tests/import_linking.rs
+++ b/crates/tinywasm/tests/import_linking.rs
@@ -1,5 +1,5 @@
use eyre::Result;
-use tinywasm::{Error, Imports, Module, Store};
+use tinywasm::{Error, Imports, Module, ModuleInstance, Store};
const WASM_ADD: &str = r#"
(module
@@ -20,8 +20,8 @@ const WASM_IMPORT: &str = r#"
"#;
fn parse_modules() -> Result<(Module, Module)> {
- let add = Module::parse_bytes(&wat::parse_str(WASM_ADD)?)?;
- let import = Module::parse_bytes(&wat::parse_str(WASM_IMPORT)?)?;
+ let add = tinywasm::parse_bytes(&wat::parse_str(WASM_ADD)?)?;
+ let import = tinywasm::parse_bytes(&wat::parse_str(WASM_IMPORT)?)?;
Ok((add, import))
}
@@ -30,11 +30,11 @@ fn link_module_links_same_store_instance() -> Result<()> {
let (add_module, import_module) = parse_modules()?;
let mut store = Store::default();
- let add_instance = add_module.instantiate(&mut store, None)?;
+ let add_instance = ModuleInstance::instantiate(&mut store, &add_module, None)?;
let mut imports = Imports::new();
imports.link_module("adder", add_instance)?;
- let instance = import_module.instantiate(&mut store, Some(imports))?;
+ let instance = ModuleInstance::instantiate(&mut store, &import_module, Some(imports))?;
let main = instance.func::<(), i32>(&store, "main")?;
assert_eq!(main.call(&mut store, ())?, 3);
Ok(())
@@ -45,13 +45,13 @@ fn link_module_rejects_cross_store_instance() -> Result<()> {
let (add_module, import_module) = parse_modules()?;
let mut source_store = Store::default();
- let add_instance = add_module.instantiate(&mut source_store, None)?;
+ let add_instance = ModuleInstance::instantiate(&mut source_store, &add_module, None)?;
let mut target_store = Store::default();
let mut imports = Imports::new();
imports.link_module("adder", add_instance)?;
- let err = import_module.instantiate(&mut target_store, Some(imports)).unwrap_err();
+ let err = ModuleInstance::instantiate(&mut target_store, &import_module, Some(imports)).unwrap_err();
assert!(matches!(err, Error::InvalidStore));
Ok(())
}
diff --git a/crates/tinywasm/tests/imported_table_init.rs b/crates/tinywasm/tests/imported_table_init.rs
index b92401d..4e2a587 100644
--- a/crates/tinywasm/tests/imported_table_init.rs
+++ b/crates/tinywasm/tests/imported_table_init.rs
@@ -1,6 +1,6 @@
use eyre::Result;
use tinywasm::types::{FuncRef, TableType, WasmType, WasmValue};
-use tinywasm::{Imports, Module, Store, Table};
+use tinywasm::{Imports, ModuleInstance, Store, Table};
#[test]
fn imported_table_uses_provided_init_value() -> Result<()> {
@@ -16,14 +16,14 @@ fn imported_table_uses_provided_init_value() -> Result<()> {
"#,
)?;
- let module = Module::parse_bytes(&wasm)?;
+ let module = tinywasm::parse_bytes(&wasm)?;
let mut store = Store::default();
let mut imports = Imports::new();
let table =
Table::new(&mut store, TableType::new(WasmType::RefFunc, 3, None), WasmValue::RefFunc(FuncRef::new(Some(0))))?;
imports.define("host", "table", table);
- let instance = module.instantiate(&mut store, Some(imports))?;
+ let instance = ModuleInstance::instantiate(&mut store, &module, Some(imports))?;
let slot_is_null = instance.func::<i32, i32>(&store, "slot_is_null")?;
assert_eq!(slot_is_null.call(&mut store, 0)?, 0);
diff --git a/crates/tinywasm/tests/internal_refs.rs b/crates/tinywasm/tests/internal_refs.rs
index 9bd091e..eb0a7c2 100644
--- a/crates/tinywasm/tests/internal_refs.rs
+++ b/crates/tinywasm/tests/internal_refs.rs
@@ -1,6 +1,6 @@
use eyre::Result;
use tinywasm::types::{FuncRef, WasmValue};
-use tinywasm::{ExternItem, Module, Store};
+use tinywasm::{ExternItem, ModuleInstance, Store};
#[test]
#[cfg(feature = "guest_debug")]
@@ -18,9 +18,9 @@ fn private_items_are_accessible_by_index() -> Result<()> {
"#,
)?;
- let module = Module::parse_bytes(&wasm)?;
+ let module = tinywasm::parse_bytes(&wasm)?;
let mut store = Store::default();
- let instance = module.instantiate(&mut store, None)?;
+ let instance = ModuleInstance::instantiate(&mut store, &module, None)?;
let func = instance.func_by_index(&store, 0)?;
assert_eq!(func.call(&mut store, &[])?, vec![WasmValue::I32(7)]);
@@ -50,9 +50,9 @@ fn exported_tables_and_globals_have_handle_and_helper_apis() -> Result<()> {
"#,
)?;
- let module = Module::parse_bytes(&wasm)?;
+ let module = tinywasm::parse_bytes(&wasm)?;
let mut store = Store::default();
- let instance = module.instantiate(&mut store, None)?;
+ let instance = ModuleInstance::instantiate(&mut store, &module, None)?;
assert_eq!(instance.global_get(&store, "g")?, WasmValue::I32(3));
assert_eq!(instance.global("g")?.get(&store)?, WasmValue::I32(3));
@@ -83,9 +83,9 @@ fn extern_item_lookup_returns_expected_kinds() -> Result<()> {
"#,
)?;
- let module = Module::parse_bytes(&wasm)?;
+ let module = tinywasm::parse_bytes(&wasm)?;
let mut store = Store::default();
- let instance = module.instantiate(&mut store, None)?;
+ let instance = ModuleInstance::instantiate(&mut store, &module, None)?;
assert!(matches!(instance.extern_item("f")?, ExternItem::Func(_)));
assert!(matches!(instance.extern_item("m")?, ExternItem::Memory(_)));
diff --git a/crates/tinywasm/tests/memory_backends.rs b/crates/tinywasm/tests/memory_backends.rs
index cd9f770..8b7d630 100644
--- a/crates/tinywasm/tests/memory_backends.rs
+++ b/crates/tinywasm/tests/memory_backends.rs
@@ -7,7 +7,7 @@ use std::io::{Read, Seek, SeekFrom, Write};
use eyre::Result;
use tinywasm::engine::Config;
use tinywasm::types::{MemoryArch, MemoryType};
-use tinywasm::{Engine, Memory, MemoryBackend, Module, PagedMemory, Store};
+use tinywasm::{Engine, Memory, MemoryBackend, Module, ModuleInstance, PagedMemory, Store};
use tinywasm_parser::{Parser, ParserOptions};
fn instantiate_module_with_counting_backend(module: Module) -> Result<usize> {
@@ -20,14 +20,14 @@ fn instantiate_module_with_counting_backend(module: Module) -> Result<usize> {
let engine = Engine::new(Config::new().with_memory_backend(backend));
let mut store = Store::new(engine);
- let _ = module.instantiate(&mut store, None)?;
+ let _ = ModuleInstance::instantiate(&mut store, &module, None)?;
Ok(created.load(Ordering::Relaxed))
}
fn instantiate_with_counting_backend(wat: &str) -> Result<usize> {
let wasm = wat::parse_str(wat)?;
- let module = Module::parse_bytes(&wasm)?;
+ let module = tinywasm::parse_bytes(&wasm)?;
instantiate_module_with_counting_backend(module)
}
@@ -35,7 +35,7 @@ fn instantiate_exported_memory_with_counting_backend(
wat: &str,
) -> Result<(Store, tinywasm::ModuleInstance, Arc<AtomicUsize>)> {
let wasm = wat::parse_str(wat)?;
- let module = Module::parse_bytes(&wasm)?;
+ let module = tinywasm::parse_bytes(&wasm)?;
let created = Arc::new(AtomicUsize::new(0));
let factory_calls = created.clone();
let backend = MemoryBackend::custom(move |ty| {
@@ -44,7 +44,7 @@ fn instantiate_exported_memory_with_counting_backend(
});
let engine = Engine::new(Config::new().with_memory_backend(backend));
let mut store = Store::new(engine);
- let instance = module.instantiate(&mut store, None)?;
+ let instance = ModuleInstance::instantiate(&mut store, &module, None)?;
Ok((store, instance, created))
}
@@ -58,10 +58,10 @@ fn paged_backend_works_for_module_memories() -> Result<()> {
"#,
)?;
- let module = Module::parse_bytes(&wasm)?;
+ let module = tinywasm::parse_bytes(&wasm)?;
let config = Config::new().with_memory_backend(MemoryBackend::paged(8));
let mut store = Store::new(Engine::new(config));
- let instance = module.instantiate(&mut store, None)?;
+ let instance = ModuleInstance::instantiate(&mut store, &module, None)?;
let memory = instance.memory("memory")?;
memory.copy_from_slice(&mut store, 6, &[1, 2, 3, 4, 5, 6, 7, 8])?;
@@ -184,7 +184,7 @@ fn disabled_local_memory_allocation_optimization_keeps_old_behavior() -> Result<
"#,
)?;
let parser = Parser::with_options(ParserOptions::default().with_local_memory_allocation_optimization(false));
- let module = Module::from(parser.parse_module_bytes(&wasm)?);
+ let module = parser.parse_module_bytes(&wasm)?;
let created = instantiate_module_with_counting_backend(module)?;
diff --git a/crates/tinywasm/tests/memory_ref_api.rs b/crates/tinywasm/tests/memory_ref_api.rs
index 97252f4..6f72477 100644
--- a/crates/tinywasm/tests/memory_ref_api.rs
+++ b/crates/tinywasm/tests/memory_ref_api.rs
@@ -1,5 +1,5 @@
use eyre::Result;
-use tinywasm::{Module, Store};
+use tinywasm::{ModuleInstance, Store};
#[test]
fn memory_ref_mut_copy_within_uses_src_then_dst_order() -> Result<()> {
@@ -11,9 +11,9 @@ fn memory_ref_mut_copy_within_uses_src_then_dst_order() -> Result<()> {
"#,
)?;
- let module = Module::parse_bytes(&wasm)?;
+ let module = tinywasm::parse_bytes(&wasm)?;
let mut store = Store::default();
- let instance = module.instantiate(&mut store, None)?;
+ let instance = ModuleInstance::instantiate(&mut store, &module, None)?;
let memory = instance.memory("memory")?;
memory.copy_from_slice(&mut store, 0, &[1, 2, 3, 4])?;
diff --git a/crates/tinywasm/tests/module_descriptors.rs b/crates/tinywasm/tests/module_descriptors.rs
index 6c8c1ad..3804df8 100644
--- a/crates/tinywasm/tests/module_descriptors.rs
+++ b/crates/tinywasm/tests/module_descriptors.rs
@@ -1,6 +1,6 @@
use eyre::Result;
use tinywasm::types::WasmType;
-use tinywasm::{ExportType, ImportType, Module};
+use tinywasm_types::{ExportType, ImportType};
#[test]
fn module_descriptors_resolve_imported_and_local_export_types() -> Result<()> {
@@ -23,7 +23,7 @@ fn module_descriptors_resolve_imported_and_local_export_types() -> Result<()> {
"#,
)?;
- let module = Module::parse_bytes(&wasm)?;
+ let module = tinywasm::parse_bytes(&wasm)?;
let imports: Vec<_> = module.imports().collect();
assert_eq!(imports.len(), 2);
diff --git a/crates/tinywasm/tests/resume_execution.rs b/crates/tinywasm/tests/resume_execution.rs
index 06b666f..82e8a11 100644
--- a/crates/tinywasm/tests/resume_execution.rs
+++ b/crates/tinywasm/tests/resume_execution.rs
@@ -1,6 +1,7 @@
use eyre::Result;
+use tinywasm::ModuleInstance;
use tinywasm::engine::{Config, FuelPolicy};
-use tinywasm::{ExecProgress, Module, types::WasmValue};
+use tinywasm::{ExecProgress, types::WasmValue};
#[cfg(feature = "std")]
use std::time::Duration;
@@ -10,15 +11,15 @@ const ADD_WASM: &[u8] = include_bytes!("../../../examples/wasm/add.wasm");
#[test]
fn typed_resume_matches_non_budgeted_call() -> Result<()> {
- let module = Module::parse_bytes(FIBONACCI_WASM)?;
+ let module = tinywasm::parse_bytes(FIBONACCI_WASM)?;
let mut store_full = tinywasm::Store::default();
- let instance_full = module.clone().instantiate(&mut store_full, None)?;
+ let instance_full = ModuleInstance::instantiate(&mut store_full, &module, None)?;
let func_full = instance_full.func::<i32, i32>(&store_full, "fibonacci_recursive")?;
let expected = func_full.call(&mut store_full, 20)?;
let mut store_budgeted = tinywasm::Store::default();
- let instance_budgeted = module.instantiate(&mut store_budgeted, None)?;
+ let instance_budgeted = ModuleInstance::instantiate(&mut store_budgeted, &module, None)?;
let func_budgeted = instance_budgeted.func::<i32, i32>(&store_budgeted, "fibonacci_recursive")?;
let mut exec = func_budgeted.call_resumable(&mut store_budgeted, 20)?;
@@ -38,9 +39,9 @@ fn typed_resume_matches_non_budgeted_call() -> Result<()> {
#[test]
fn untyped_resume_supports_zero_fuel() -> Result<()> {
- let module = Module::parse_bytes(ADD_WASM)?;
+ let module = tinywasm::parse_bytes(ADD_WASM)?;
let mut store = tinywasm::Store::default();
- let instance = module.instantiate(&mut store, None)?;
+ let instance = ModuleInstance::instantiate(&mut store, &module, None)?;
let func = instance.func_untyped(&store, "add")?;
let mut exec = func.call_resumable(&mut store, &[WasmValue::I32(20), WasmValue::I32(22)])?;
@@ -58,15 +59,15 @@ fn untyped_resume_supports_zero_fuel() -> Result<()> {
#[test]
fn weighted_call_fuel_requires_more_rounds() -> Result<()> {
- let module = Module::parse_bytes(FIBONACCI_WASM)?;
+ let module = tinywasm::parse_bytes(FIBONACCI_WASM)?;
let mut per_instr_store = tinywasm::Store::default();
- let instance_per_instr = module.clone().instantiate(&mut per_instr_store, None)?;
+ let instance_per_instr = ModuleInstance::instantiate(&mut per_instr_store, &module, None)?;
let func_per_instr = instance_per_instr.func::<i32, i32>(&per_instr_store, "fibonacci_recursive")?;
let mut weighted_store =
tinywasm::Store::new(tinywasm::Engine::new(Config::new().with_fuel_policy(FuelPolicy::Weighted)));
- let instance_weighted = module.instantiate(&mut weighted_store, None)?;
+ let instance_weighted = ModuleInstance::instantiate(&mut weighted_store, &module, None)?;
let func_weighted = instance_weighted.func::<i32, i32>(&weighted_store, "fibonacci_recursive")?;
let fuel = 64;
@@ -101,9 +102,9 @@ fn weighted_call_fuel_requires_more_rounds() -> Result<()> {
#[cfg(feature = "std")]
#[test]
fn time_budget_zero_suspends_then_completes() -> Result<()> {
- let module = Module::parse_bytes(ADD_WASM)?;
+ let module = tinywasm::parse_bytes(ADD_WASM)?;
let mut store = tinywasm::Store::default();
- let instance = module.instantiate(&mut store, None)?;
+ let instance = ModuleInstance::instantiate(&mut store, &module, None)?;
let func = instance.func::<(i32, i32), i32>(&store, "add")?;
let mut exec = func.call_resumable(&mut store, (20, 22))?;
diff --git a/crates/tinywasm/tests/store_ownership.rs b/crates/tinywasm/tests/store_ownership.rs
index 0f81ea3..acf8e42 100644
--- a/crates/tinywasm/tests/store_ownership.rs
+++ b/crates/tinywasm/tests/store_ownership.rs
@@ -1,5 +1,5 @@
use eyre::Result;
-use tinywasm::{Module, Store};
+use tinywasm::{ModuleInstance, Store};
const MODULE_WAT: &str = r#"
(module
@@ -14,10 +14,10 @@ const MODULE_WAT: &str = r#"
#[test]
fn func_handle_rejects_wrong_store() -> Result<()> {
let wasm = wat::parse_str(MODULE_WAT)?;
- let module = Module::parse_bytes(&wasm)?;
+ let module = tinywasm::parse_bytes(&wasm)?;
let mut owner_store = Store::default();
- let instance = module.instantiate(&mut owner_store, None)?;
+ let instance = ModuleInstance::instantiate(&mut owner_store, &module, None)?;
let func = instance.func_untyped(&owner_store, "add")?;
let mut other_store = Store::default();
@@ -30,10 +30,10 @@ fn func_handle_rejects_wrong_store() -> Result<()> {
#[test]
fn memory_access_rejects_wrong_store() -> Result<()> {
let wasm = wat::parse_str(MODULE_WAT)?;
- let module = Module::parse_bytes(&wasm)?;
+ let module = tinywasm::parse_bytes(&wasm)?;
let mut owner_store = Store::default();
- let instance = module.instantiate(&mut owner_store, None)?;
+ let instance = ModuleInstance::instantiate(&mut owner_store, &module, None)?;
let memory = instance.memory("memory")?;
let other_store = Store::default();
diff --git a/crates/tinywasm/tests/testsuite/run.rs b/crates/tinywasm/tests/testsuite/run.rs
index 5b1d11c..cfa7f54 100644
--- a/crates/tinywasm/tests/testsuite/run.rs
+++ b/crates/tinywasm/tests/testsuite/run.rs
@@ -215,11 +215,9 @@ impl TestSuite {
debug!("got wat module");
let result = catch_unwind_silent(|| {
let (name, bytes) = encode_quote_wat(module);
- let m = parse_module_bytes(&bytes).expect("failed to parse module bytes");
-
+ let module = parse_module_bytes(&bytes).expect("failed to parse module bytes");
let imports = Self::imports(&mut store, module_registry.modules()).unwrap();
- let module_instance = tinywasm::Module::from(m)
- .instantiate(&mut store, Some(imports))
+ let module_instance = ModuleInstance::instantiate(&mut store, &module, Some(imports))
.expect("failed to instantiate module");
(name, module_instance)
@@ -319,9 +317,8 @@ impl TestSuite {
wast::WastExecute::Wat(mut wat) => {
let module = parse_module_bytes(&wat.encode().expect("failed to encode module"))
.expect("failed to parse module");
- let module = tinywasm::Module::from(module);
let imports = Self::imports(&mut store, module_registry.modules()).unwrap();
- module.instantiate(&mut store, Some(imports))?;
+ ModuleInstance::instantiate(&mut store, &module, Some(imports))?;
return Ok(());
}
wast::WastExecute::Get { module: _, global: _, .. } => {
@@ -370,9 +367,8 @@ impl TestSuite {
let res = catch_unwind_silent(|| {
let module = parse_module_bytes(&module.encode().expect("failed to encode module"))
.expect("failed to parse module");
- let module = tinywasm::Module::from(module);
let imports = Self::imports(&mut store, module_registry.modules()).unwrap();
- module.instantiate(&mut store, Some(imports))
+ ModuleInstance::instantiate(&mut store, &module, Some(imports))
});
match res {
diff --git a/crates/tinywasm/tests/testsuite/util.rs b/crates/tinywasm/tests/testsuite/util.rs
index e03f08b..61c163e 100644
--- a/crates/tinywasm/tests/testsuite/util.rs
+++ b/crates/tinywasm/tests/testsuite/util.rs
@@ -1,7 +1,8 @@
use std::panic::{self, AssertUnwindSafe};
use eyre::{Result, bail, eyre};
-use tinywasm_types::{ExternRef, FuncRef, ModuleInstanceAddr, TinyWasmModule, WasmType, WasmValue};
+use tinywasm::ModuleInstance;
+use tinywasm_types::{ExternRef, FuncRef, Module, ModuleInstanceAddr, WasmType, WasmValue};
use wasm_testsuite::wast;
use wasm_testsuite::wast::{QuoteWat, core::AbstractHeapType};
@@ -31,7 +32,7 @@ pub fn exec_fn_instance(
}
pub fn exec_fn(
- module: Option<&TinyWasmModule>,
+ module: Option<&Module>,
name: &str,
args: &[tinywasm_types::WasmValue],
imports: Option<tinywasm::Imports>,
@@ -41,8 +42,7 @@ pub fn exec_fn(
};
let mut store = tinywasm::Store::default();
- let module = tinywasm::Module::from(module);
- let instance = module.instantiate(&mut store, imports)?;
+ let instance = ModuleInstance::instantiate(&mut store, module, imports)?;
instance.func_untyped(&store, name)?.call(&mut store, args)
}
@@ -78,7 +78,7 @@ pub fn encode_quote_wat(module: QuoteWat) -> (Option<String>, Vec<u8>) {
}
}
-pub fn parse_module_bytes(bytes: &[u8]) -> Result<TinyWasmModule> {
+pub fn parse_module_bytes(bytes: &[u8]) -> Result<Module> {
let parser = tinywasm_parser::Parser::new();
Ok(parser.parse_module_bytes(bytes)?)
}
diff --git a/crates/tinywasm/tests/typed_lookup.rs b/crates/tinywasm/tests/typed_lookup.rs
index acc6a7a..15b31b1 100644
--- a/crates/tinywasm/tests/typed_lookup.rs
+++ b/crates/tinywasm/tests/typed_lookup.rs
@@ -1,5 +1,5 @@
use eyre::Result;
-use tinywasm::Module;
+use tinywasm::ModuleInstance;
#[test]
fn func_typed_rejects_wrong_param_or_result_types() -> Result<()> {
@@ -14,9 +14,9 @@ fn func_typed_rejects_wrong_param_or_result_types() -> Result<()> {
"#,
)?;
- let module = Module::parse_bytes(&wasm)?;
+ let module = tinywasm::parse_bytes(&wasm)?;
let mut store = tinywasm::Store::default();
- let instance = module.instantiate(&mut store, None)?;
+ let instance = ModuleInstance::instantiate(&mut store, &module, None)?;
assert!(instance.func::<(i32, i32), i32>(&store, "add").is_ok());
assert!(instance.func::<i32, i32>(&store, "add").is_err());
@@ -37,9 +37,9 @@ fn func_typed_rejects_partial_multi_value_results() -> Result<()> {
"#,
)?;
- let module = Module::parse_bytes(&wasm)?;
+ let module = tinywasm::parse_bytes(&wasm)?;
let mut store = tinywasm::Store::default();
- let instance = module.instantiate(&mut store, None)?;
+ let instance = ModuleInstance::instantiate(&mut store, &module, None)?;
assert!(instance.func::<(), (i32, i32)>(&store, "pair").is_ok());
assert!(instance.func::<(), i32>(&store, "pair").is_err());
diff --git a/crates/types/Cargo.toml b/crates/types/Cargo.toml
index 94832c1..77e0be7 100644
--- a/crates/types/Cargo.toml
+++ b/crates/types/Cargo.toml
@@ -13,7 +13,7 @@ categories.workspace=true
[dependencies]
log={workspace=true, optional=true}
postcard={version="1.1", optional=true, default-features=false, features=["alloc"]}
-serde={version="1.0", optional=true, default-features=false, features=["alloc"]}
+serde={version="1.0", optional=true, default-features=false, features=["alloc", "rc"]}
[features]
default=["std", "log", "archive", "debug"]
diff --git a/crates/types/src/archive.rs b/crates/types/src/archive.rs
index dc98e30..2636230 100644
--- a/crates/types/src/archive.rs
+++ b/crates/types/src/archive.rs
@@ -2,7 +2,7 @@ use core::fmt::{Display, Formatter};
use alloc::vec::Vec;
-use crate::TinyWasmModule;
+use crate::Module;
#[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];
@@ -47,14 +47,14 @@ extern crate std;
impl core::error::Error for TwasmError {}
-impl TinyWasmModule {
- /// Creates a `TinyWasmModule` from a slice of bytes.
- pub fn from_twasm(wasm: &[u8]) -> Result<Self, TwasmError> {
+impl Module {
+ /// Creates a [`Module`] from a slice of bytes.
+ pub fn try_from_twasm(wasm: &[u8]) -> Result<Self, TwasmError> {
let len = validate_magic(wasm)?;
postcard::from_bytes(&wasm[len..]).map_err(TwasmError::InvalidArchive)
}
- /// Serializes the `TinyWasmModule` into a vector of bytes.
+ /// Serializes the [`Module`] into a vector of bytes.
pub fn serialize_twasm(&self) -> Result<Vec<u8>, TwasmError> {
let buf = Vec::from(TWASM_MAGIC);
postcard::to_extend(self, buf).map_err(TwasmError::InvalidArchive)
@@ -67,17 +67,17 @@ mod tests {
#[test]
fn test_invalid_magic() {
- let wasm = TinyWasmModule::default();
+ let wasm = Module::default();
let mut twasm = wasm.serialize_twasm().expect("should serialize");
twasm[0] = 0;
- assert!(matches!(TinyWasmModule::from_twasm(&twasm), Err(TwasmError::InvalidMagic)));
+ assert!(matches!(Module::try_from_twasm(&twasm), Err(TwasmError::InvalidMagic)));
}
#[test]
fn test_invalid_version() {
- let wasm = TinyWasmModule::default();
+ let wasm = Module::default();
let mut twasm = wasm.serialize_twasm().expect("should serialize");
twasm[4] = 0;
- assert!(matches!(TinyWasmModule::from_twasm(&twasm), Err(TwasmError::InvalidVersion)));
+ assert!(matches!(Module::try_from_twasm(&twasm), Err(TwasmError::InvalidVersion)));
}
}
diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs
index 914e8c4..6196beb 100644
--- a/crates/types/src/lib.rs
+++ b/crates/types/src/lib.rs
@@ -10,10 +10,7 @@
extern crate alloc;
use alloc::{boxed::Box, sync::Arc};
-use core::{
- fmt::Debug,
- ops::{Deref, Range},
-};
+use core::ops::{Deref, Range};
// Memory defaults
const MEM_PAGE_SIZE: u64 = 65536;
@@ -63,12 +60,31 @@ 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.
+/// [`Module`] 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 [`Module`] created by a third party to be valid.
#[derive(Clone, Default, PartialEq)]
#[cfg_attr(feature = "debug", derive(Debug))]
#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
-pub struct TinyWasmModule {
+pub struct Module(Arc<ModuleInner>);
+
+impl From<ModuleInner> for Module {
+ fn from(inner: ModuleInner) -> Self {
+ Self(Arc::new(inner))
+ }
+}
+
+impl Deref for Module {
+ type Target = ModuleInner;
+ fn deref(&self) -> &ModuleInner {
+ &self.0
+ }
+}
+
+#[doc(hidden)]
+#[derive(Clone, Default, PartialEq)]
+#[cfg_attr(feature = "debug", derive(Debug))]
+#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
+pub struct ModuleInner {
/// Optional address of the start function
///
/// Corresponds to the `start` section of the original WebAssembly module.
@@ -77,52 +93,174 @@ pub struct TinyWasmModule {
/// Optimized and validated WebAssembly functions
///
/// Contains data from to the `code`, `func`, and `type` sections of the original WebAssembly module.
- pub funcs: ArcSlice<WasmFunction>,
+ pub funcs: Arc<[Arc<WasmFunction>]>,
/// A vector of type definitions, indexed by `TypeAddr`
///
/// Corresponds to the `type` section of the original WebAssembly module.
- pub func_types: ArcSlice<FuncType>,
+ pub func_types: Arc<[Arc<FuncType>]>,
/// Exported items of the WebAssembly module.
///
/// Corresponds to the `export` section of the original WebAssembly module.
- pub exports: ArcSlice<Export>,
+ pub exports: Arc<[Export]>,
/// Global components of the WebAssembly module.
///
/// Corresponds to the `global` section of the original WebAssembly module.
- pub globals: ArcSlice<Global>,
+ pub globals: Arc<[Global]>,
/// Table components of the WebAssembly module used to initialize tables.
///
/// Corresponds to the `table` section of the original WebAssembly module.
- pub table_types: ArcSlice<TableType>,
+ pub table_types: Arc<[TableType]>,
/// Memory components of the WebAssembly module used to initialize memories.
///
/// Corresponds to the `memory` section of the original WebAssembly module.
- pub memory_types: ArcSlice<MemoryType>,
+ pub memory_types: Arc<[MemoryType]>,
/// Imports of the WebAssembly module.
///
/// Corresponds to the `import` section of the original WebAssembly module.
- pub imports: ArcSlice<Import>,
+ pub imports: Arc<[Import]>,
/// Data segments of the WebAssembly module.
///
/// Corresponds to the `data` section of the original WebAssembly module.
- pub data: ArcSlice<Data>,
+ pub data: Arc<[Data]>,
/// Element segments of the WebAssembly module.
///
/// Corresponds to the `elem` section of the original WebAssembly module.
- pub elements: ArcSlice<Element>,
+ pub elements: Arc<[Element]>,
/// How instantiation should prepare the module's local memories.
pub local_memory_allocation: LocalMemoryAllocation,
}
+impl Module {
+ /// Returns an iterator over the module's import descriptors.
+ ///
+ /// The returned data mirrors the module's import section and preserves order.
+ pub fn imports(&self) -> impl Iterator<Item = ModuleImport<'_>> {
+ self.0.imports.iter().filter_map(|import| {
+ let ty = match &import.kind {
+ ImportKind::Function(type_idx) => Some(ImportType::Func(self.0.func_types.get(*type_idx as usize)?)),
+ ImportKind::Table(table_ty) => Some(ImportType::Table(table_ty)),
+ ImportKind::Memory(memory_ty) => Some(ImportType::Memory(memory_ty)),
+ ImportKind::Global(global_ty) => Some(ImportType::Global(global_ty)),
+ }?;
+
+ Some(ModuleImport { module: import.module.as_ref(), name: import.name.as_ref(), ty })
+ })
+ }
+
+ /// Returns an iterator over the module's export descriptors.
+ ///
+ /// The returned data mirrors the module's export section and preserves order.
+ pub fn exports(&self) -> impl Iterator<Item = ModuleExport<'_>> {
+ fn imported_func_type(module: &ModuleInner, function_index: usize) -> Option<&FuncType> {
+ let mut seen = 0usize;
+ for import in module.imports.iter() {
+ if let ImportKind::Function(type_idx) = import.kind {
+ if seen == function_index {
+ return module.func_types.get(type_idx as usize).map(|ty| &**ty);
+ }
+ seen += 1;
+ }
+ }
+ None
+ }
+
+ fn imported_global_type(module: &Module, global_index: usize) -> Option<&GlobalType> {
+ let mut seen = 0usize;
+ for import in module.imports.iter() {
+ if let ImportKind::Global(global_ty) = &import.kind {
+ if seen == global_index {
+ return Some(global_ty);
+ }
+ seen += 1;
+ }
+ }
+ None
+ }
+
+ self.0.exports.iter().filter_map(move |export| {
+ let imports = self.0.imports.iter();
+ let idx = export.index as usize;
+ let ty = match export.kind {
+ ExternalKind::Func => {
+ let imported_funcs =
+ imports.filter(|import| matches!(import.kind, ImportKind::Function(_))).count();
+ if idx < imported_funcs {
+ ExportType::Func(imported_func_type(&self.0, idx)?)
+ } else {
+ let local_idx = idx - imported_funcs;
+ ExportType::Func(&self.0.funcs.get(local_idx)?.ty)
+ }
+ }
+ ExternalKind::Table => ExportType::Table(self.0.table_types.get(idx)?),
+ ExternalKind::Memory => ExportType::Memory(self.0.memory_types.get(idx)?),
+ ExternalKind::Global => {
+ let imported_globals =
+ imports.filter(|import| matches!(import.kind, ImportKind::Global(_))).count();
+ if idx < imported_globals {
+ ExportType::Global(imported_global_type(self, idx)?)
+ } else {
+ let local_idx = idx - imported_globals;
+ ExportType::Global(&self.0.globals.get(local_idx)?.ty)
+ }
+ }
+ };
+
+ Some(ModuleExport { name: export.name.as_ref(), ty })
+ })
+ }
+}
+
+/// A module export descriptor.
+pub struct ModuleExport<'a> {
+ /// Export name.
+ pub name: &'a str,
+ /// Export type.
+ pub ty: ExportType<'a>,
+}
+
+/// A module import descriptor.
+pub struct ModuleImport<'a> {
+ /// Importing module name.
+ pub module: &'a str,
+ /// Import name.
+ pub name: &'a str,
+ /// Import type.
+ pub ty: ImportType<'a>,
+}
+
+/// Imported entity type.
+pub enum ImportType<'a> {
+ /// Imported function type.
+ Func(&'a FuncType),
+ /// Imported table type.
+ Table(&'a TableType),
+ /// Imported memory type.
+ Memory(&'a MemoryType),
+ /// Imported global type.
+ Global(&'a GlobalType),
+}
+
+/// Exported entity type.
+pub enum ExportType<'a> {
+ /// Exported function type.
+ Func(&'a FuncType),
+ /// Exported table type.
+ Table(&'a TableType),
+ /// Exported memory type.
+ Memory(&'a MemoryType),
+ /// Exported global type.
+ Global(&'a GlobalType),
+}
+
/// How instantiation should prepare local memories declared by the module.
#[derive(Clone, Copy, PartialEq, Eq, Default)]
#[cfg_attr(feature = "debug", derive(Debug))]
@@ -275,63 +413,11 @@ impl<'a> FromIterator<&'a WasmType> for ValueCounts {
#[cfg_attr(feature = "debug", derive(Debug))]
#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
pub struct WasmFunction {
- pub instructions: ArcSlice<Instruction>,
+ pub instructions: Box<[Instruction]>,
pub data: WasmFunctionData,
pub locals: ValueCounts,
pub params: ValueCounts,
- pub ty: FuncType,
-}
-
-#[doc(hidden)]
-#[derive(Clone, PartialEq)]
-// wrapper around Arc<[T]> to support serde serialization and deserialization
-pub struct ArcSlice<T>(pub Arc<[T]>);
-
-impl<T: Debug> Debug for ArcSlice<T> {
- fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
- self.0.as_ref().fmt(f)
- }
-}
-
-impl<T> From<alloc::vec::Vec<T>> for ArcSlice<T> {
- fn from(vec: alloc::vec::Vec<T>) -> Self {
- Self(Arc::from(vec))
- }
-}
-
-impl<T> Default for ArcSlice<T> {
- fn default() -> Self {
- Self(Arc::from([]))
- }
-}
-
-impl<T> Deref for ArcSlice<T> {
- type Target = [T];
-
- fn deref(&self) -> &Self::Target {
- self.0.as_ref()
- }
-}
-
-impl<T> FromIterator<T> for ArcSlice<T> {
- fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
- Self(Arc::from_iter(iter))
- }
-}
-
-#[cfg(feature = "archive")]
-impl<T: serde::Serialize> serde::Serialize for ArcSlice<T> {
- fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
- self.0.as_ref().serialize(serializer)
- }
-}
-
-#[cfg(feature = "archive")]
-impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for ArcSlice<T> {
- fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
- let vec: alloc::vec::Vec<T> = alloc::vec::Vec::deserialize(deserializer)?;
- Ok(Self(Arc::from(vec)))
- }
+ pub ty: Arc<FuncType>,
}
#[derive(Clone, PartialEq, Eq, Default)]