Skip to content

Commit d0c5052

Browse files
committed
refactor: incorporate user_data into Config
Signed-off-by: Cem Onem <cem.oenem@dlr.de>
1 parent c6c749b commit d0c5052

File tree

7 files changed

+56
-62
lines changed

7 files changed

+56
-62
lines changed

src/execution/config.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
/// Trait that allows user specified configuration for various items during interpretation
1+
/// Trait that allows user specified configuration for various items during interpretation. Additionally, the types
2+
/// implementing this trait can act as custom user data within an interpreter instance, passed along to each method of
3+
/// this trait and host functions whenever they are invoked.
24
///
35
/// The default implementation of all trait methods have the least overhead, i. e. most can be optimized out fully.
46
// It must always be checked that there is no additional performance penalty for the default config!
5-
pub trait Config: Default {
7+
pub trait Config {
68
/// A hook which is called before every wasm instruction
79
///
810
/// This allows the most intricate insight into the interpreters behavior, at the cost of a
@@ -12,7 +14,4 @@ pub trait Config: Default {
1214
}
1315

1416
/// Default implementation of the interpreter configuration, with all hooks empty
15-
#[derive(Default, Debug)]
16-
pub struct DefaultConfig;
17-
18-
impl Config for DefaultConfig {}
17+
impl Config for () {}

src/execution/const_interpreter_loop.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::{
22
assert_validated::UnwrapValidatedExt,
3+
config::Config,
34
core::{
45
indices::GlobalIdx,
56
reader::{span::Span, WasmReadable, WasmReader},
@@ -21,7 +22,7 @@ use crate::{
2122
/// This function assumes that the expression has been validated. Passing unvalidated code will likely result in a
2223
/// panic, or undefined behaviour.
2324
// TODO this signature might change to support hooks or match the spec better
24-
pub(crate) fn run_const<T>(
25+
pub(crate) fn run_const<T: Config>(
2526
wasm: &mut WasmReader,
2627
stack: &mut Stack,
2728
module: &ModuleInst,
@@ -118,7 +119,7 @@ pub(crate) fn run_const<T>(
118119
Ok(())
119120
}
120121

121-
pub(crate) fn run_const_span<T>(
122+
pub(crate) fn run_const_span<T: Config>(
122123
wasm: &[u8],
123124
span: &Span,
124125
module: &ModuleInst,

src/execution/function_ref.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub struct FunctionRef {
99
}
1010

1111
impl FunctionRef {
12-
pub fn new_from_name<T>(
12+
pub fn new_from_name<T: Config>(
1313
module_name: &str,
1414
function_name: &str,
1515
store: &Store<T>,
@@ -31,11 +31,7 @@ impl FunctionRef {
3131
}
3232
}
3333

34-
pub fn invoke_typed<
35-
C: Config + core::fmt::Debug,
36-
Param: InteropValueList,
37-
Returns: InteropValueList,
38-
>(
34+
pub fn invoke_typed<C: Config, Param: InteropValueList, Returns: InteropValueList>(
3935
&self,
4036
runtime: &mut RuntimeInstance<C>,
4137
params: Param,
@@ -44,9 +40,9 @@ impl FunctionRef {
4440
runtime.invoke_typed(self, params /* , store */)
4541
}
4642

47-
pub fn invoke<T, C: Config + core::fmt::Debug>(
43+
pub fn invoke<C: Config>(
4844
&self,
49-
runtime: &mut RuntimeInstance<T, C>,
45+
runtime: &mut RuntimeInstance<C>,
5046
params: Vec<Value>,
5147
// store: &mut Store,
5248
) -> Result<Vec<Value>, RuntimeError> {

src/execution/interpreter_loop.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,9 @@ use super::{little_endian::LittleEndianBytes, store::Store};
4343
/// Returns `Ok(None)` in case execution successfully terminates, `Ok(Some(required_fuel))` if execution
4444
/// terminates due to insufficient fuel, indicating how much fuel is required to resume with `required_fuel`,
4545
/// and `[Error::RuntimeError]` otherwise.
46-
pub(super) fn run<T, C: Config>(
46+
pub(super) fn run<T: Config>(
4747
resumable: &mut Resumable,
4848
store: &mut Store<T>,
49-
mut config: C,
5049
) -> Result<Option<NonZeroU32>, RuntimeError> {
5150
let stack = &mut resumable.stack;
5251
let mut current_func_addr = resumable.current_func_addr;
@@ -74,7 +73,9 @@ pub(super) fn run<T, C: Config>(
7473
use crate::core::reader::types::opcode::*;
7574
loop {
7675
// call the instruction hook
77-
config.instruction_hook(store.modules[current_module_idx].wasm_bytecode, wasm.pc);
76+
store
77+
.user_data
78+
.instruction_hook(store.modules[current_module_idx].wasm_bytecode, wasm.pc);
7879

7980
// Fuel mechanism: 1 fuel per instruction
8081
if let Some(fuel) = &mut resumable.maybe_fuel {

src/execution/mod.rs

Lines changed: 19 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use value_stack::Stack;
88

99
use crate::core::reader::types::{FuncType, ResultType};
1010
use crate::execution::assert_validated::UnwrapValidatedExt;
11-
use crate::execution::config::{Config, DefaultConfig};
11+
use crate::execution::config::Config;
1212
use crate::execution::store::Store;
1313
use crate::execution::value::Value;
1414
use crate::interop::InteropValueList;
@@ -32,50 +32,46 @@ pub mod value_stack;
3232
/// The default module name if a [RuntimeInstance] was created using [RuntimeInstance::new].
3333
pub const DEFAULT_MODULE: &str = "__interpreter_default__";
3434

35-
pub struct RuntimeInstance<'b, T = (), C = DefaultConfig>
35+
pub struct RuntimeInstance<'b, C = ()>
3636
where
37-
C: Config + core::fmt::Debug,
37+
C: Config,
3838
{
39-
pub config: C,
40-
pub store: Store<'b, T>,
39+
pub store: Store<'b, C>,
4140
}
4241

43-
impl<T: Default> Default for RuntimeInstance<'_, T, DefaultConfig> {
42+
impl Default for RuntimeInstance<'_, ()> {
4443
fn default() -> Self {
45-
Self::new(T::default())
44+
Self::new(())
4645
}
4746
}
4847

49-
impl<'b, T> RuntimeInstance<'b, T, DefaultConfig> {
50-
pub fn new(user_data: T) -> Self {
51-
Self::new_with_config(user_data, DefaultConfig)
48+
impl<'b, C: Config> RuntimeInstance<'b, C> {
49+
pub fn new(config: C) -> Self {
50+
RuntimeInstance {
51+
store: Store::new(config),
52+
}
5253
}
5354

5455
pub fn new_with_default_module(
55-
user_data: T,
56+
config: C,
5657
validation_info: &'_ ValidationInfo<'b>,
5758
) -> Result<Self, RuntimeError> {
58-
let mut instance = Self::new_with_config(user_data, DefaultConfig);
59+
let mut instance = Self::new(config);
5960
instance.add_module(DEFAULT_MODULE, validation_info)?;
6061
Ok(instance)
6162
}
6263

6364
pub fn new_named(
64-
user_data: T,
65+
config: C,
6566
module_name: &str,
6667
validation_info: &'_ ValidationInfo<'b>,
6768
// store: &mut Store,
6869
) -> Result<Self, RuntimeError> {
69-
let mut instance = Self::new_with_config(user_data, DefaultConfig);
70+
let mut instance = Self::new(config);
7071
instance.add_module(module_name, validation_info)?;
7172
Ok(instance)
7273
}
73-
}
7474

75-
impl<'b, T, C> RuntimeInstance<'b, T, C>
76-
where
77-
C: Config + core::fmt::Debug,
78-
{
7975
pub fn add_module(
8076
&mut self,
8177
module_name: &str,
@@ -84,13 +80,6 @@ where
8480
self.store.add_module(module_name, validation_info, None)
8581
}
8682

87-
pub fn new_with_config(user_data: T, config: C) -> Self {
88-
RuntimeInstance {
89-
config,
90-
store: Store::new(user_data),
91-
}
92-
}
93-
9483
pub fn get_function_by_name(
9584
&self,
9685
module_name: &str,
@@ -196,7 +185,7 @@ where
196185
&mut self,
197186
module_name: &str,
198187
name: &str,
199-
host_func: fn(&mut T, Vec<Value>) -> Vec<Value>,
188+
host_func: fn(&mut C, Vec<Value>) -> Vec<Value>,
200189
) -> Result<FunctionRef, RuntimeError> {
201190
let host_func_ty = FuncType {
202191
params: ResultType {
@@ -214,7 +203,7 @@ where
214203
module_name: &str,
215204
name: &str,
216205
host_func_ty: FuncType,
217-
host_func: fn(&mut T, Vec<Value>) -> Vec<Value>,
206+
host_func: fn(&mut C, Vec<Value>) -> Vec<Value>,
218207
) -> Result<FunctionRef, RuntimeError> {
219208
let func_addr = self.store.alloc_host_func(host_func_ty, host_func);
220209
self.store.registry.register(
@@ -225,11 +214,11 @@ where
225214
Ok(FunctionRef { func_addr })
226215
}
227216

228-
pub fn user_data(&self) -> &T {
217+
pub fn config(&self) -> &C {
229218
&self.store.user_data
230219
}
231220

232-
pub fn user_data_mut(&mut self) -> &mut T {
221+
pub fn config_mut(&mut self) -> &mut C {
233222
&mut self.store.user_data
234223
}
235224
}

src/execution/store.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use core::mem;
22

3+
use crate::config::Config;
34
use crate::core::indices::TypeIdx;
45
use crate::core::reader::span::Span;
56
use crate::core::reader::types::data::{DataModeActive, DataSegment};
@@ -28,7 +29,6 @@ use alloc::sync::Arc;
2829
use alloc::vec;
2930
use alloc::vec::Vec;
3031

31-
use super::config::DefaultConfig;
3232
use super::interpreter_loop::{data_drop, elem_drop};
3333
use super::UnwrapValidatedExt;
3434

@@ -39,7 +39,7 @@ use crate::linear_memory::LinearMemory;
3939
/// globals, element segments, and data segments that have been allocated during the life time of
4040
/// the abstract machine.
4141
/// <https://webassembly.github.io/spec/core/exec/runtime.html#store>
42-
pub struct Store<'b, T> {
42+
pub struct Store<'b, T: Config> {
4343
pub functions: Vec<FuncInst<T>>,
4444
pub memories: Vec<MemInst>,
4545
pub globals: Vec<GlobalInst>,
@@ -59,7 +59,7 @@ pub struct Store<'b, T> {
5959
pub(crate) dormitory: Dormitory,
6060
}
6161

62-
impl<'b, T> Store<'b, T> {
62+
impl<'b, T: Config> Store<'b, T> {
6363
/// Creates a new empty store with some user data
6464
pub fn new(user_data: T) -> Self {
6565
Self {
@@ -622,7 +622,7 @@ impl<'b, T> Store<'b, T> {
622622
};
623623

624624
// Run the interpreter
625-
let result = interpreter_loop::run(&mut resumable, self, DefaultConfig)?;
625+
let result = interpreter_loop::run(&mut resumable, self)?;
626626

627627
match result {
628628
None => {
@@ -666,7 +666,7 @@ impl<'b, T> Store<'b, T> {
666666
.expect("the key to always be valid as self was not dropped yet");
667667

668668
// Resume execution
669-
let result = interpreter_loop::run(resumable, self, DefaultConfig)?;
669+
let result = interpreter_loop::run(resumable, self)?;
670670

671671
match result {
672672
None => {
@@ -918,7 +918,7 @@ impl ExternVal {
918918
///
919919
/// Note: This method may panic if self does not come from the given [`Store`].
920920
///<https://webassembly.github.io/spec/core/valid/modules.html#imports>
921-
pub fn extern_type<T>(&self, store: &Store<T>) -> ExternType {
921+
pub fn extern_type<T: Config>(&self, store: &Store<T>) -> ExternType {
922922
match self {
923923
// TODO: fix ugly clone in function types
924924
ExternVal::Func(func_addr) => ExternType::Func(

tests/user_data.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
use std::sync::mpsc::Sender;
22

3-
use wasm::{RuntimeInstance, Value};
3+
use wasm::{config::Config, RuntimeInstance, Value};
44

55
#[test_log::test]
66
fn counter() {
7-
fn add_one(user_data: &mut u32, _params: Vec<Value>) -> Vec<Value> {
8-
*user_data += 1;
7+
#[derive(Debug, PartialEq)]
8+
struct MyU32(pub u32);
9+
impl Config for MyU32 {}
10+
11+
fn add_one(user_data: &mut MyU32, _params: Vec<Value>) -> Vec<Value> {
12+
user_data.0 += 1;
913

1014
Vec::new()
1115
}
1216

13-
let mut instance = RuntimeInstance::new(0);
17+
let mut instance = RuntimeInstance::new(MyU32(0));
1418
instance
1519
.add_host_function_typed::<(), ()>("host", "add_one", add_one)
1620
.unwrap();
@@ -23,23 +27,27 @@ fn counter() {
2327
.unwrap();
2428
}
2529

26-
assert_eq!(*instance.user_data(), 5);
30+
assert_eq!(*instance.config(), MyU32(5));
2731
}
2832

2933
#[test_log::test]
3034
fn channels() {
35+
struct MySender(pub Sender<String>);
36+
impl Config for MySender {}
37+
3138
let (tx, rx) = std::sync::mpsc::channel::<String>();
3239

3340
std::thread::spawn(|| {
34-
fn send_message(user_data: &mut Sender<String>, _params: Vec<Value>) -> Vec<Value> {
41+
fn send_message(user_data: &mut MySender, _params: Vec<Value>) -> Vec<Value> {
3542
user_data
43+
.0
3644
.send("Hello from host function!".to_owned())
3745
.unwrap();
3846

3947
Vec::new()
4048
}
4149

42-
let mut instance = RuntimeInstance::new(tx);
50+
let mut instance = RuntimeInstance::new(MySender(tx));
4351
instance
4452
.add_host_function_typed::<(), ()>("host", "send_message", send_message)
4553
.unwrap();

0 commit comments

Comments
 (0)