diff --git a/crates/cli/src/context.rs b/crates/cli/src/context.rs index 08fcff1da8..9676477f8b 100644 --- a/crates/cli/src/context.rs +++ b/crates/cli/src/context.rs @@ -39,7 +39,7 @@ impl Context { panic!("error: fuel metering is enabled but encountered: {error}") }); } - let mut linker = >::default(); + let mut linker = >::new(&engine); wasmi_wasi::define_wasi(&mut linker, &mut store, |ctx| ctx) .map_err(|error| anyhow!("failed to add WASI definitions to the linker: {error}"))?; let instance = linker diff --git a/crates/wasi/tests/wasi_wat.rs b/crates/wasi/tests/wasi_wat.rs index 7752cbcfab..dd76b2f502 100644 --- a/crates/wasi/tests/wasi_wat.rs +++ b/crates/wasi/tests/wasi_wat.rs @@ -1,20 +1,20 @@ use wasi_cap_std_sync::WasiCtxBuilder; -use wasmi::{Config, Extern, Instance, Store}; +use wasmi::{Config, Engine, Extern, Instance, Linker, Module, Store}; use wasmi_wasi::{define_wasi, WasiCtx}; -pub fn load_instance_from_wat(wat_bytes: &[u8]) -> (wasmi::Store, wasmi::Instance) { +pub fn load_instance_from_wat(wat_bytes: &[u8]) -> (Store, wasmi::Instance) { let wasm = wat2wasm(wat_bytes); let config = Config::default(); - let engine = wasmi::Engine::new(&config); - let module = wasmi::Module::new(&engine, &wasm[..]).unwrap(); - let mut linker = >::default(); + let engine = Engine::new(&config); + let module = Module::new(&engine, &wasm[..]).unwrap(); + let mut linker = >::new(&engine); // add wasi to linker let wasi = WasiCtxBuilder::new() .inherit_stdio() .inherit_args() .unwrap() .build(); - let mut store = wasmi::Store::new(&engine, wasi); + let mut store = Store::new(&engine, wasi); define_wasi(&mut linker, &mut store, |ctx| ctx).unwrap(); let instance = linker diff --git a/crates/wasmi/benches/bench/mod.rs b/crates/wasmi/benches/bench/mod.rs index c73026c7d2..b47df4bc45 100644 --- a/crates/wasmi/benches/bench/mod.rs +++ b/crates/wasmi/benches/bench/mod.rs @@ -58,7 +58,7 @@ pub fn load_module_from_file(file_name: &str) -> wasmi::Module { /// If the benchmark Wasm file could not be opened, read or parsed. pub fn load_instance_from_file(file_name: &str) -> (wasmi::Store<()>, wasmi::Instance) { let module = load_module_from_file(file_name); - let linker = >::default(); + let linker = >::new(module.engine()); let mut store = wasmi::Store::new(module.engine(), ()); let instance = linker .instantiate(&mut store, &module) @@ -86,7 +86,7 @@ pub fn load_instance_from_wat(wat_bytes: &[u8]) -> (wasmi::Store<()>, wasmi::Ins let wasm = wat2wasm(wat_bytes); let engine = wasmi::Engine::new(&bench_config()); let module = wasmi::Module::new(&engine, &wasm[..]).unwrap(); - let linker = >::default(); + let linker = >::new(&engine); let mut store = wasmi::Store::new(&engine, ()); let instance = linker .instantiate(&mut store, &module) diff --git a/crates/wasmi/benches/benches.rs b/crates/wasmi/benches/benches.rs index c384e5885c..2e92d97722 100644 --- a/crates/wasmi/benches/benches.rs +++ b/crates/wasmi/benches/benches.rs @@ -113,7 +113,7 @@ fn bench_translate_erc1155(c: &mut Criterion) { fn bench_instantiate_wasm_kernel(c: &mut Criterion) { c.bench_function("instantiate/wasm_kernel", |b| { let module = load_module_from_file(WASM_KERNEL); - let linker = >::default(); + let linker = >::new(module.engine()); b.iter(|| { let mut store = Store::new(module.engine(), ()); let _instance = linker.instantiate(&mut store, &module).unwrap(); @@ -128,7 +128,7 @@ fn bench_instantiate_contract(c: &mut Criterion, name: &str, path: &str) { let module = load_module_from_file(path); let engine = module.engine(); let mut store = Store::new(&engine, ()); - let mut linker = >::default(); + let mut linker = >::new(&engine); linker .define( "env", @@ -857,7 +857,7 @@ fn bench_execute_host_calls(c: &mut Criterion) { let wasm = wat2wasm(include_bytes!("wat/host_calls.wat")); let engine = Engine::default(); let module = Module::new(&engine, &wasm[..]).unwrap(); - let mut linker = >::default(); + let mut linker = >::new(&engine); let mut store = Store::new(&engine, ()); let host_call = Func::wrap(&mut store, |value: i64| value.wrapping_sub(1)); linker.define("benchmark", "host_call", host_call).unwrap(); diff --git a/crates/wasmi/src/engine/mod.rs b/crates/wasmi/src/engine/mod.rs index da2799b630..5d6d5fb0d9 100644 --- a/crates/wasmi/src/engine/mod.rs +++ b/crates/wasmi/src/engine/mod.rs @@ -43,7 +43,7 @@ pub(crate) use self::{ func_args::{FuncFinished, FuncParams, FuncResults}, func_types::DedupFuncType, }; -use super::{func::FuncEntityInternal, AsContextMut, Func}; +use super::{func::FuncEntityInner, AsContextMut, Func}; use crate::{ core::{Trap, TrapCode}, FuncType, @@ -131,6 +131,11 @@ impl Engine { self.inner.config() } + /// Returns `true` if both [`Engine`] references `a` and `b` refer to the same [`Engine`]. + pub fn same(a: &Engine, b: &Engine) -> bool { + Arc::ptr_eq(&a.inner, &b.inner) + } + /// Allocates a new function type to the engine. pub(super) fn alloc_func_type(&self, func_type: FuncType) -> DedupFuncType { self.inner.alloc_func_type(func_type) @@ -589,12 +594,12 @@ impl<'engine> EngineExecutor<'engine> { { self.initialize_args(params); match func.as_internal(ctx.as_context()) { - FuncEntityInternal::Wasm(wasm_func) => { + FuncEntityInner::Wasm(wasm_func) => { let mut frame = self.stack.call_wasm_root(wasm_func, &self.res.code_map)?; let mut cache = InstanceCache::from(frame.instance()); self.execute_wasm_func(ctx.as_context_mut(), &mut frame, &mut cache)?; } - FuncEntityInternal::Host(host_func) => { + FuncEntityInner::Host(host_func) => { let host_func = host_func.clone(); self.stack .call_host_root(ctx.as_context_mut(), host_func, &self.res.func_types)?; @@ -681,10 +686,10 @@ impl<'engine> EngineExecutor<'engine> { }, CallOutcome::NestedCall(called_func) => { match called_func.as_internal(ctx.as_context()) { - FuncEntityInternal::Wasm(wasm_func) => { + FuncEntityInner::Wasm(wasm_func) => { *frame = self.stack.call_wasm(frame, wasm_func, &self.res.code_map)?; } - FuncEntityInternal::Host(host_func) => { + FuncEntityInner::Host(host_func) => { cache.reset_default_memory_bytes(); let host_func = host_func.clone(); self.stack diff --git a/crates/wasmi/src/engine/stack/frames.rs b/crates/wasmi/src/engine/stack/frames.rs index b48dd5428e..ef44daf8bb 100644 --- a/crates/wasmi/src/engine/stack/frames.rs +++ b/crates/wasmi/src/engine/stack/frames.rs @@ -21,8 +21,11 @@ pub struct FuncFrame { impl FuncFrame { /// Creates a new [`FuncFrame`]. - pub fn new(ip: InstructionPtr, instance: Instance) -> Self { - Self { ip, instance } + pub fn new(ip: InstructionPtr, instance: &Instance) -> Self { + Self { + ip, + instance: *instance, + } } /// Returns the current instruction pointer. @@ -66,7 +69,7 @@ impl CallStack { } /// Initializes the [`CallStack`] given the Wasm function. - pub(crate) fn init(&mut self, ip: InstructionPtr, instance: Instance) -> FuncFrame { + pub(crate) fn init(&mut self, ip: InstructionPtr, instance: &Instance) -> FuncFrame { self.clear(); FuncFrame::new(ip, instance) } diff --git a/crates/wasmi/src/engine/tests.rs b/crates/wasmi/src/engine/tests.rs index f6302b6e75..bbc6f3dc1e 100644 --- a/crates/wasmi/src/engine/tests.rs +++ b/crates/wasmi/src/engine/tests.rs @@ -143,7 +143,7 @@ fn implicit_return_no_value() { "#, ); let expected = [Instruction::Return(drop_keep(0, 0))]; - assert_func_bodies(&wasm, [expected]); + assert_func_bodies(wasm, [expected]); } #[test] @@ -161,7 +161,7 @@ fn implicit_return_with_value() { Instruction::constant(0), Instruction::Return(drop_keep(0, 1)), ]; - assert_func_bodies(&wasm, [expected]); + assert_func_bodies(wasm, [expected]); } #[test] @@ -175,7 +175,7 @@ fn implicit_return_param() { "#, ); let expected = [Instruction::Return(drop_keep(1, 0))]; - assert_func_bodies(&wasm, [expected]); + assert_func_bodies(wasm, [expected]); } #[test] @@ -193,7 +193,7 @@ fn get_local() { Instruction::local_get(1), Instruction::Return(drop_keep(1, 1)), ]; - assert_func_bodies(&wasm, [expected]); + assert_func_bodies(wasm, [expected]); } #[test] @@ -215,7 +215,7 @@ fn get_local_2() { Instruction::Drop, Instruction::Return(drop_keep(2, 1)), ]; - assert_func_bodies(&wasm, [expected]); + assert_func_bodies(wasm, [expected]); } #[test] @@ -239,7 +239,7 @@ fn get_local_3() { Instruction::Drop, Instruction::Return(drop_keep(2, 0)), ]; - assert_func_bodies(&wasm, [expected]); + assert_func_bodies(wasm, [expected]); } #[test] @@ -258,7 +258,7 @@ fn explicit_return() { Instruction::local_get(1), Instruction::Return(drop_keep(1, 1)), ]; - assert_func_bodies(&wasm, [expected]); + assert_func_bodies(wasm, [expected]); } #[test] @@ -280,7 +280,7 @@ fn simple_add() { Instruction::I32Add, Instruction::Return(drop_keep(2, 1)), ]; - assert_func_bodies(&wasm, [expected]); + assert_func_bodies(wasm, [expected]); } #[test] @@ -310,7 +310,7 @@ fn simple_mul_add() { Instruction::I32Mul, Instruction::Return(drop_keep(2, 1)), ]; - assert_func_bodies(&wasm, [expected]); + assert_func_bodies(wasm, [expected]); } #[test] @@ -331,7 +331,7 @@ fn drop_locals() { Instruction::local_set(1), Instruction::Return(drop_keep(2, 0)), ]; - assert_func_bodies(&wasm, [expected]); + assert_func_bodies(wasm, [expected]); } macro_rules! params { @@ -364,7 +364,7 @@ fn if_without_else() { /* 4 */ Instruction::constant(3), /* 5 */ Instruction::Return(drop_keep(1, 1)), ]; - assert_func_bodies(&wasm, [expected]); + assert_func_bodies(wasm, [expected]); } #[test] @@ -396,7 +396,7 @@ fn if_else() { /* 6 */ Instruction::local_set(1), /* 7 */ Instruction::Return(drop_keep(1, 0)), ]; - assert_func_bodies(&wasm, [expected]); + assert_func_bodies(wasm, [expected]); } #[test] @@ -425,7 +425,7 @@ fn if_else_returns_result() { /* 5 */ Instruction::Drop, /* 6 */ Instruction::Return(drop_keep(0, 0)), ]; - assert_func_bodies(&wasm, [expected]); + assert_func_bodies(wasm, [expected]); } #[test] @@ -462,7 +462,7 @@ fn if_else_branch_from_true_branch() { /* 9 */ Instruction::Drop, /* 10 */ Instruction::Return(drop_keep(0, 0)), ]; - assert_func_bodies(&wasm, [expected]); + assert_func_bodies(wasm, [expected]); } #[test] @@ -499,7 +499,7 @@ fn if_else_branch_from_false_branch() { /* 9 */ Instruction::Drop, /* 10 */ Instruction::Return(drop_keep(0, 0)), ]; - assert_func_bodies(&wasm, [expected]); + assert_func_bodies(wasm, [expected]); } #[test] @@ -535,7 +535,7 @@ fn if_else_both_unreachable_before_end() { /* 7 */ Instruction::constant(3), /* 8 */ Instruction::Return(drop_keep(1, 1)), ]; - assert_func_bodies(&wasm, [expected]); + assert_func_bodies(wasm, [expected]); } #[test] @@ -561,7 +561,7 @@ fn loop_() { /* 3 */ Instruction::Drop, /* 4 */ Instruction::Return(drop_keep(0, 0)), ]; - assert_func_bodies(&wasm, [expected]); + assert_func_bodies(wasm, [expected]); } #[test] @@ -577,7 +577,7 @@ fn loop_empty() { "#, ); let expected = [Instruction::Return(drop_keep(0, 0))]; - assert_func_bodies(&wasm, [expected]); + assert_func_bodies(wasm, [expected]); } #[test] @@ -609,7 +609,7 @@ fn spec_as_br_if_value_cond() { /* 5 */ Instruction::Br(params!(5 => 6, drop: 1, keep: 1)), /* 6 */ Instruction::Return(drop_keep(0, 1)), ]; - assert_func_bodies(&wasm, [expected]); + assert_func_bodies(wasm, [expected]); } #[test] @@ -635,7 +635,7 @@ fn br_table() { /* 3 */ Instruction::Br(params!(3 => 4, drop: 0, keep: 0)), /* 4 */ Instruction::Return(drop_keep(0, 0)), ]; - assert_func_bodies(&wasm, [expected]); + assert_func_bodies(wasm, [expected]); } #[test] @@ -667,7 +667,7 @@ fn br_table_returns_result() { /* 6 */ Instruction::Drop, /* 7 */ Instruction::Return(drop_keep(0, 0)), ]; - assert_func_bodies(&wasm, [expected]); + assert_func_bodies(wasm, [expected]); } #[test] @@ -696,7 +696,7 @@ fn wabt_example() { /* 4 */ Instruction::constant(2), /* 5 */ Instruction::Return(drop_keep(1, 1)), ]; - assert_func_bodies(&wasm, [expected]); + assert_func_bodies(wasm, [expected]); } #[test] @@ -712,7 +712,7 @@ fn br_return() { "#, ); let expected = [Instruction::Return(drop_keep(0, 0))]; - assert_func_bodies(&wasm, [expected]); + assert_func_bodies(wasm, [expected]); } #[test] @@ -733,7 +733,7 @@ fn br_if_return() { Instruction::ReturnIfNez(drop_keep(1, 0)), Instruction::Return(drop_keep(1, 0)), ]; - assert_func_bodies(&wasm, [expected]); + assert_func_bodies(wasm, [expected]); } #[test] @@ -761,7 +761,7 @@ fn br_table_return() { /* 4 */ Instruction::Return(drop_keep(1, 0)), /* 5 */ Instruction::Return(drop_keep(1, 0)), ]; - assert_func_bodies(&wasm, [expected]); + assert_func_bodies(wasm, [expected]); } /// Returns the default [`FuelCosts`]. @@ -787,7 +787,7 @@ fn metered_simple_01() { Instruction::local_get(1), Instruction::Return(drop_keep(1, 1)), ]; - assert_func_bodies_metered(&wasm, [expected]); + assert_func_bodies_metered(wasm, [expected]); } #[test] @@ -814,7 +814,7 @@ fn metered_simple_02() { Instruction::Drop, Instruction::Return(drop_keep(1, 1)), ]; - assert_func_bodies_metered(&wasm, [expected]); + assert_func_bodies_metered(wasm, [expected]); } #[test] @@ -847,7 +847,7 @@ fn metered_simple_03() { Instruction::I32Mul, Instruction::Return(drop_keep(2, 1)), ]; - assert_func_bodies_metered(&wasm, [expected]); + assert_func_bodies_metered(wasm, [expected]); } #[test] @@ -884,7 +884,7 @@ fn metered_if_01() { /* 8 */ Instruction::Return(drop_keep(3, 1)), // end if /* 9 */ Instruction::Return(drop_keep(3, 1)), ]; - assert_func_bodies_metered(&wasm, [expected]); + assert_func_bodies_metered(wasm, [expected]); } #[test] @@ -930,7 +930,7 @@ fn metered_block_in_if_01() { /* 9 */ Instruction::Return(drop_keep(3, 1)), // end if /* 10 */ Instruction::Return(drop_keep(3, 1)), ]; - assert_func_bodies_metered(&wasm, [expected]); + assert_func_bodies_metered(wasm, [expected]); } #[test] @@ -970,7 +970,7 @@ fn metered_block_in_if_02() { /* 7 */ Instruction::local_get(1), /* 8 */ Instruction::Return(drop_keep(3, 1)), // end if ]; - assert_func_bodies_metered(&wasm, [expected]); + assert_func_bodies_metered(wasm, [expected]); } #[test] @@ -1013,7 +1013,7 @@ fn metered_loop_in_if() { /* 9 */ Instruction::local_get(1), /*10 */ Instruction::Return(drop_keep(3, 1)), ]; - assert_func_bodies_metered(&wasm, [expected]); + assert_func_bodies_metered(wasm, [expected]); } #[test] @@ -1058,7 +1058,7 @@ fn metered_nested_blocks() { Instruction::Drop, Instruction::Return(drop_keep(1, 1)), ]; - assert_func_bodies_metered(&wasm, [expected]); + assert_func_bodies_metered(wasm, [expected]); } #[test] @@ -1108,7 +1108,7 @@ fn metered_nested_loops() { Instruction::Drop, Instruction::Return(drop_keep(1, 1)), ]; - assert_func_bodies_metered(&wasm, [expected]); + assert_func_bodies_metered(wasm, [expected]); } #[test] @@ -1142,7 +1142,7 @@ fn metered_global_bump() { Instruction::GlobalGet(GlobalIdx::from(0)), Instruction::Return(drop_keep(1, 1)), ]; - assert_func_bodies_metered(&wasm, [expected]); + assert_func_bodies_metered(wasm, [expected]); } #[test] @@ -1172,7 +1172,7 @@ fn metered_calls_01() { Instruction::Call(FuncIdx::from(0)), Instruction::Return(drop_keep(0, 1)), ]; - assert_func_bodies_metered(&wasm, [expected_f0, expected_f1]); + assert_func_bodies_metered(wasm, [expected_f0, expected_f1]); } #[test] @@ -1213,7 +1213,7 @@ fn metered_calls_02() { Instruction::Call(FuncIdx::from(0)), Instruction::Return(drop_keep(2, 1)), ]; - assert_func_bodies_metered(&wasm, [expected_f0, expected_f1]); + assert_func_bodies_metered(wasm, [expected_f0, expected_f1]); } #[test] @@ -1282,7 +1282,7 @@ fn metered_load_01() { Instruction::I32Load(Offset::from(0)), Instruction::Return(drop_keep(1, 1)), ]; - assert_func_bodies_metered(&wasm, [expected]); + assert_func_bodies_metered(wasm, [expected]); } #[test] @@ -1308,5 +1308,5 @@ fn metered_store_01() { Instruction::I32Store(Offset::from(0)), Instruction::Return(drop_keep(2, 0)), ]; - assert_func_bodies_metered(&wasm, [expected]); + assert_func_bodies_metered(wasm, [expected]); } diff --git a/crates/wasmi/src/func/mod.rs b/crates/wasmi/src/func/mod.rs index 0859c94326..59f8873381 100644 --- a/crates/wasmi/src/func/mod.rs +++ b/crates/wasmi/src/func/mod.rs @@ -22,7 +22,7 @@ use super::{ StoreContext, Stored, }; -use crate::{core::Trap, engine::ResumableCall, Error, Value}; +use crate::{core::Trap, engine::ResumableCall, Engine, Error, Value}; use alloc::{boxed::Box, sync::Arc}; use core::{fmt, fmt::Debug, num::NonZeroU32}; use wasmi_arena::ArenaIndex; @@ -53,13 +53,29 @@ pub struct FuncEntity { /// We wrap this enum in a struct so that we can make its /// variants private. This is advantageous since they are /// implementation details and not important to the user. - internal: FuncEntityInternal, + inner: FuncEntityInner, } impl Clone for FuncEntity { fn clone(&self) -> Self { Self { - internal: self.internal.clone(), + inner: self.inner.clone(), + } + } +} + +impl From for FuncEntity { + fn from(wasm_func: WasmFuncEntity) -> Self { + Self { + inner: FuncEntityInner::Wasm(wasm_func), + } + } +} + +impl From> for FuncEntity { + fn from(host_func: HostFuncEntity) -> Self { + Self { + inner: FuncEntityInner::Host(host_func), } } } @@ -67,47 +83,38 @@ impl Clone for FuncEntity { impl FuncEntity { /// Creates a new Wasm function from the given raw parts. pub fn new_wasm(signature: DedupFuncType, body: FuncBody, instance: Instance) -> Self { - Self { - internal: FuncEntityInternal::Wasm(WasmFuncEntity::new(signature, body, instance)), - } + Self::from(WasmFuncEntity::new(signature, body, instance)) } /// Creates a new host function from the given dynamically typed closure. pub fn new( - ctx: impl AsContextMut, + engine: &Engine, ty: FuncType, func: impl Fn(Caller<'_, T>, &[Value], &mut [Value]) -> Result<(), Trap> + Send + Sync + 'static, ) -> Self { - Self { - internal: FuncEntityInternal::Host(HostFuncEntity::new(ctx, ty, func)), - } + Self::from(HostFuncEntity::new(engine, ty, func)) } /// Creates a new host function from the given dynamically typed closure. - pub fn wrap( - ctx: impl AsContextMut, - func: impl IntoFunc, - ) -> Self { - Self { - internal: FuncEntityInternal::Host(HostFuncEntity::wrap(ctx, func)), - } + pub fn wrap(engine: &Engine, func: impl IntoFunc) -> Self { + Self::from(HostFuncEntity::wrap(engine, func)) } - /// Returns the internal function entity. + /// Returns a shared reference to the [`FuncEntityInner`]. /// /// # Note /// /// This can be used to efficiently match against host or Wasm /// function entities and efficiently extract their properties. - pub(crate) fn as_internal(&self) -> &FuncEntityInternal { - &self.internal + pub(crate) fn as_internal(&self) -> &FuncEntityInner { + &self.inner } /// Returns the signature of the Wasm function. pub fn ty_dedup(&self) -> &DedupFuncType { match self.as_internal() { - FuncEntityInternal::Wasm(func) => func.ty_dedup(), - FuncEntityInternal::Host(func) => func.ty_dedup(), + FuncEntityInner::Wasm(func) => func.ty_dedup(), + FuncEntityInner::Host(func) => func.ty_dedup(), } } } @@ -116,14 +123,14 @@ impl FuncEntity { /// /// This can either be a host function or a Wasm function. #[derive(Debug)] -pub(crate) enum FuncEntityInternal { +pub(crate) enum FuncEntityInner { /// A Wasm function instance. Wasm(WasmFuncEntity), /// A host function instance. Host(HostFuncEntity), } -impl Clone for FuncEntityInternal { +impl Clone for FuncEntityInner { fn clone(&self) -> Self { match self { Self::Wasm(func) => Self::Wasm(func.clone()), @@ -156,8 +163,8 @@ impl WasmFuncEntity { } /// Returns the instance where the [`Func`] belong to. - pub fn instance(&self) -> Instance { - self.instance + pub fn instance(&self) -> &Instance { + &self.instance } /// Returns the Wasm function body of the [`Func`]. @@ -217,7 +224,7 @@ impl Debug for HostFuncEntity { impl HostFuncEntity { /// Creates a new host function from the given dynamically typed closure. pub fn new( - mut ctx: impl AsContextMut, + engine: &Engine, ty: FuncType, func: impl Fn(Caller<'_, T>, &[Value], &mut [Value]) -> Result<(), Trap> + Send + Sync + 'static, ) -> Self { @@ -240,7 +247,7 @@ impl HostFuncEntity { func(caller, params, results)?; Ok(func_results.encode_results_from_slice(results).unwrap()) }); - let signature = ctx.as_context_mut().store.inner.alloc_func_type(ty.clone()); + let signature = engine.alloc_func_type(ty.clone()); Self { signature, trampoline, @@ -248,12 +255,9 @@ impl HostFuncEntity { } /// Creates a new host function from the given statically typed closure. - pub fn wrap( - mut ctx: impl AsContextMut, - func: impl IntoFunc, - ) -> Self { + pub fn wrap(engine: &Engine, func: impl IntoFunc) -> Self { let (signature, trampoline) = func.into_func(); - let signature = ctx.as_context_mut().store.inner.alloc_func_type(signature); + let signature = engine.alloc_func_type(signature); Self { signature, trampoline, @@ -323,7 +327,8 @@ impl Func { ty: FuncType, func: impl Fn(Caller<'_, T>, &[Value], &mut [Value]) -> Result<(), Trap> + Send + Sync + 'static, ) -> Self { - let func = FuncEntity::new(ctx.as_context_mut(), ty, func); + let engine = ctx.as_context().store.engine(); + let func = FuncEntity::new(engine, ty, func); ctx.as_context_mut().store.alloc_func(func) } @@ -332,7 +337,8 @@ impl Func { mut ctx: impl AsContextMut, func: impl IntoFunc, ) -> Self { - let func = FuncEntity::wrap(ctx.as_context_mut(), func); + let engine = ctx.as_context().store.engine(); + let func = FuncEntity::wrap(engine, func); ctx.as_context_mut().store.alloc_func(func) } @@ -485,7 +491,7 @@ impl Func { pub(crate) fn as_internal<'a, T: 'a>( &self, ctx: impl Into>, - ) -> &'a FuncEntityInternal { + ) -> &'a FuncEntityInner { ctx.into().store.resolve_func(self).as_internal() } } diff --git a/crates/wasmi/src/lib.rs b/crates/wasmi/src/lib.rs index d2d3217bb7..e468836e0c 100644 --- a/crates/wasmi/src/lib.rs +++ b/crates/wasmi/src/lib.rs @@ -46,7 +46,7 @@ //! //! // In order to create Wasm module instances and link their imports //! // and exports we require a `Linker`. -//! let mut linker = >::new(); +//! let mut linker = >::new(&engine); //! // Instantiation of a Wasm module requires defining its imports and then //! // afterwards we can fetch exports by name, as well as asserting the //! // type signature of the function with `get_typed_func`. diff --git a/crates/wasmi/src/linker.rs b/crates/wasmi/src/linker.rs index f23f9a2e85..5edadd28fd 100644 --- a/crates/wasmi/src/linker.rs +++ b/crates/wasmi/src/linker.rs @@ -1,6 +1,9 @@ use super::{AsContextMut, Error, Extern, InstancePre, Module}; use crate::{ + func::HostFuncEntity, module::{ImportName, ImportType}, + AsContext, + Engine, ExternType, FuncType, GlobalType, @@ -15,7 +18,6 @@ use alloc::{ use core::{ fmt, fmt::{Debug, Display}, - marker::PhantomData, num::NonZeroUsize, ops::Deref, }; @@ -291,20 +293,102 @@ struct ImportKey { name: Symbol, } +/// A [`Linker`] definition. +enum Definition { + /// An external item from an [`Instance`](crate::Instance). + Extern(Extern), + /// A [`Linker`] internal host function. + HostFunc(HostFuncEntity), +} + +impl Clone for Definition { + fn clone(&self) -> Self { + match self { + Self::Extern(definition) => Self::Extern(*definition), + Self::HostFunc(host_func) => Self::HostFunc(host_func.clone()), + } + } +} + +/// [`Debug`]-wrapper for the definitions of a [`Linker`]. +pub struct DebugDefinitions<'a, T> { + /// The [`Engine`] of the [`Linker`]. + engine: &'a Engine, + /// The definitions of the [`Linker`]. + definitions: &'a BTreeMap>, +} + +impl<'a, T> DebugDefinitions<'a, T> { + /// Create a new [`Debug`]-wrapper for the [`Linker`] definitions. + fn new(linker: &'a Linker) -> Self { + Self { + engine: linker.engine(), + definitions: &linker.definitions, + } + } +} + +impl<'a, T> Debug for DebugDefinitions<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut map = f.debug_map(); + for (name, definition) in self.definitions { + match definition { + Definition::Extern(definition) => { + map.entry(name, definition); + } + Definition::HostFunc(definition) => { + map.entry(name, &DebugHostFuncEntity::new(self.engine, definition)); + } + } + } + map.finish() + } +} + +/// [`Debug`]-wrapper for [`HostFuncEntity`] in the [`Linker`]. +pub struct DebugHostFuncEntity<'a, T> { + /// The [`Engine`] of the [`Linker`]. + engine: &'a Engine, + /// The host function to be [`Debug`] formatted. + host_func: &'a HostFuncEntity, +} + +impl<'a, T> DebugHostFuncEntity<'a, T> { + /// Create a new [`Debug`]-wrapper for the [`HostFuncEntity`]. + fn new(engine: &'a Engine, host_func: &'a HostFuncEntity) -> Self { + Self { engine, host_func } + } +} + +impl<'a, T> Debug for DebugHostFuncEntity<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.engine + .resolve_func_type(self.host_func.ty_dedup(), |func_type| { + f.debug_struct("HostFunc").field("ty", func_type).finish() + }) + } +} + /// A linker used to define module imports and instantiate module instances. pub struct Linker { + /// The underlying [`Engine`] for the [`Linker`]. + /// + /// # Note + /// + /// Primarily required to define [`Linker`] owned host functions + // using [`Linker::func_wrap`] and [`Linker::func_new`]. TODO: implement methods + engine: Engine, /// Allows to efficiently store strings and deduplicate them.. strings: StringInterner, /// Stores the definitions given their names. - definitions: BTreeMap, - marker: PhantomData T>, + definitions: BTreeMap>, } impl Debug for Linker { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Linker") .field("strings", &self.strings) - .field("definitions", &self.definitions) + .field("definitions", &DebugDefinitions::new(self)) .finish() } } @@ -312,29 +396,34 @@ impl Debug for Linker { impl Clone for Linker { fn clone(&self) -> Linker { Self { + engine: self.engine.clone(), strings: self.strings.clone(), definitions: self.definitions.clone(), - marker: self.marker, } } } impl Default for Linker { fn default() -> Self { - Self::new() + Self::new(&Engine::default()) } } impl Linker { /// Creates a new linker. - pub fn new() -> Self { + pub fn new(engine: &Engine) -> Self { Self { + engine: engine.clone(), strings: StringInterner::default(), definitions: BTreeMap::default(), - marker: PhantomData, } } + /// Returns the underlying [`Engine`] of the [`Linker`]. + pub fn engine(&self) -> &Engine { + &self.engine + } + /// Define a new item in this [`Linker`]. /// /// # Errors @@ -384,35 +473,55 @@ impl Linker { }); } Entry::Vacant(v) => { - v.insert(item); + v.insert(Definition::Extern(item)); } } Ok(()) } - /// Looks up a previously defined extern value in this [`Linker`]. + /// Looks up a defined [`Extern`] by name in this [`Linker`]. + /// + /// Returns `None` if this name was not previously defined in this [`Linker`]. /// - /// Returns `None` if this name was not previously defined in this - /// [`Linker`]. - pub fn resolve(&self, module: &str, name: &str) -> Option { + /// # Panics + /// + /// If the [`Engine`] of this [`Linker`] and the [`Engine`] of `context` are not the same. + pub fn get( + &self, + context: impl AsContext, + module: &str, + name: &str, + ) -> Option { + assert!(Engine::same( + context.as_context().store.engine(), + self.engine() + )); let key = ImportKey { module: self.strings.get(module)?, name: self.strings.get(name)?, }; - self.definitions.get(&key).copied() + if let Some(Definition::Extern(item)) = self.definitions.get(&key) { + return Some(*item); + } + None } /// Instantiates the given [`Module`] using the definitions in the [`Linker`]. /// + /// # Panics + /// + /// If the [`Engine`] of the [`Linker`] and `context` are not the same. + /// /// # Errors /// /// - If the linker does not define imports of the instantiated [`Module`]. /// - If any imported item does not satisfy its type requirements. pub fn instantiate( &self, - mut context: impl AsContextMut, + mut context: impl AsContextMut, module: &Module, ) -> Result { + assert!(Engine::same(self.engine(), context.as_context().engine())); let externals = module .imports() .map(|import| self.process_import(&mut context, import)) @@ -422,19 +531,24 @@ impl Linker { /// Processes a single [`Module`] import. /// + /// # Panics + /// + /// If the [`Engine`] of the [`Linker`] and `context` are not the same. + /// /// # Errors /// /// If the imported item does not satisfy constraints set by the [`Module`]. fn process_import( &self, - context: impl AsContextMut, + context: impl AsContextMut, import: ImportType, ) -> Result { + assert!(Engine::same(self.engine(), context.as_context().engine())); let import_name = import.import_name(); let module_name = import.module(); let field_name = import.name(); let resolved = self - .resolve(module_name, field_name) + .get(context.as_context(), module_name, field_name) .ok_or_else(|| LinkerError::missing_definition(&import))?; let invalid_type = || LinkerError::invalid_type_definition(&import, &resolved.ty(&context)); match import.ty() { diff --git a/crates/wasmi/src/module/instantiate/tests.rs b/crates/wasmi/src/module/instantiate/tests.rs index 48ce863439..71d11d8695 100644 --- a/crates/wasmi/src/module/instantiate/tests.rs +++ b/crates/wasmi/src/module/instantiate/tests.rs @@ -29,7 +29,7 @@ fn try_instantiate_from_wat(wat: &str) -> Result<(Store<()>, Instance), Error> { let engine = Engine::default(); let module = Module::new(&engine, &mut &wasm[..])?; let mut store = Store::new(&engine, ()); - let mut linker = >::new(); + let mut linker = >::new(&engine); // Define one memory that can be used by the tests as import. let memory_type = MemoryType::new(4, None)?; let memory = Memory::new(&mut store, memory_type)?; diff --git a/crates/wasmi/src/store.rs b/crates/wasmi/src/store.rs index 511000dd1c..a3bc12490f 100644 --- a/crates/wasmi/src/store.rs +++ b/crates/wasmi/src/store.rs @@ -260,15 +260,6 @@ impl StoreInner { &mut self.fuel } - /// Allocates a new [`FuncType`] and returns a [`DedupFuncType`] reference to it. - /// - /// # Note - /// - /// This deduplicates [`FuncType`] instances that compare as equal. - pub fn alloc_func_type(&mut self, func_type: FuncType) -> DedupFuncType { - self.engine.alloc_func_type(func_type) - } - /// Wraps an entitiy `Idx` (index type) as a [`Stored`] type. /// /// # Note diff --git a/crates/wasmi/tests/e2e/v1/fuel_metering.rs b/crates/wasmi/tests/e2e/v1/fuel_metering.rs index de904958ba..c8aa768494 100644 --- a/crates/wasmi/tests/e2e/v1/fuel_metering.rs +++ b/crates/wasmi/tests/e2e/v1/fuel_metering.rs @@ -10,7 +10,7 @@ fn test_setup() -> (Store<()>, Linker<()>) { config.consume_fuel(true); let engine = Engine::new(&config); let store = Store::new(&engine, ()); - let linker = Linker::new(); + let linker = Linker::new(&engine); (store, linker) } diff --git a/crates/wasmi/tests/e2e/v1/host_calls_wasm.rs b/crates/wasmi/tests/e2e/v1/host_calls_wasm.rs index 5e2fb8d021..a30a4ff3b2 100644 --- a/crates/wasmi/tests/e2e/v1/host_calls_wasm.rs +++ b/crates/wasmi/tests/e2e/v1/host_calls_wasm.rs @@ -3,15 +3,16 @@ use wasmi::{Caller, Engine, Extern, Func, Linker, Module, Store}; -fn test_setup() -> Store<()> { +fn test_setup() -> (Store<()>, Linker<()>) { let engine = Engine::default(); - Store::new(&engine, ()) + let store = Store::new(&engine, ()); + let linker = >::new(&engine); + (store, linker) } #[test] fn host_calls_wasm() { - let mut store = test_setup(); - let mut linker = >::new(); + let (mut store, mut linker) = test_setup(); let host_fn = Func::wrap(&mut store, |mut caller: Caller<()>, input: i32| -> i32 { let wasm_fn = caller .get_export("square") diff --git a/crates/wasmi/tests/e2e/v1/resumable_call.rs b/crates/wasmi/tests/e2e/v1/resumable_call.rs index 573cdd9fcd..a264b9719d 100644 --- a/crates/wasmi/tests/e2e/v1/resumable_call.rs +++ b/crates/wasmi/tests/e2e/v1/resumable_call.rs @@ -19,14 +19,15 @@ use wasmi::{ }; use wasmi_core::{Trap, TrapCode, ValueType}; -fn test_setup() -> Store<()> { +fn test_setup() -> (Store<()>, Linker<()>) { let engine = Engine::default(); - Store::new(&engine, ()) + let store = Store::new(&engine, ()); + let linker = >::new(&engine); + (store, linker) } fn resumable_call_smoldot_common(wasm: &str) -> (Store<()>, TypedResumableInvocation) { - let mut store = test_setup(); - let mut linker = >::new(); + let (mut store, mut linker) = test_setup(); // The important part about this test is that this // host function has more results than parameters. let host_fn = Func::new( @@ -98,7 +99,7 @@ fn resumable_call_smoldot_02() { #[test] fn resumable_call_host() { - let mut store = test_setup(); + let (mut store, _linker) = test_setup(); let host_fn = Func::wrap(&mut store, || -> Result<(), Trap> { Err(Trap::i32_exit(100)) }); @@ -125,8 +126,7 @@ fn resumable_call_host() { #[test] fn resumable_call() { - let mut store = test_setup(); - let mut linker = >::new(); + let (mut store, mut linker) = test_setup(); let host_fn = Func::wrap(&mut store, |input: i32| -> Result { match input { 1 => Err(Trap::i32_exit(10)), diff --git a/crates/wasmi/tests/spec/context.rs b/crates/wasmi/tests/spec/context.rs index 4533014a6a..bfc3390e2c 100644 --- a/crates/wasmi/tests/spec/context.rs +++ b/crates/wasmi/tests/spec/context.rs @@ -50,7 +50,7 @@ impl<'a> TestContext<'a> { /// Creates a new [`TestContext`] with the given [`TestDescriptor`]. pub fn new(descriptor: &'a TestDescriptor, config: Config) -> Self { let engine = Engine::new(&config); - let mut linker = Linker::default(); + let mut linker = Linker::new(&engine); let mut store = Store::new(&engine, ()); let default_memory = Memory::new(&mut store, MemoryType::new(1, Some(2)).unwrap()).unwrap(); let default_table = Table::new(