Skip to content

Commit

Permalink
Revert "feat: Update wasm::Module to enable wasm component model (#121
Browse files Browse the repository at this point in the history
)" (#122)

This reverts commit 8258443.
  • Loading branch information
stevenj committed Feb 8, 2024
1 parent 8258443 commit 048f1b3
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 139 deletions.
18 changes: 0 additions & 18 deletions hermes/bin/src/event.rs

This file was deleted.

3 changes: 1 addition & 2 deletions hermes/bin/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
//! Intentionally empty
//! This file exists, so that doc tests can be used inside binary crates.

pub(crate) mod event;
pub(crate) mod wasm;
mod wasm;
3 changes: 1 addition & 2 deletions hermes/bin/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
//! The Hermes Node.

pub(crate) mod event;
mod runtime;
pub(crate) mod wasm;
mod wasm;

fn main() {
println!("Hello, world!");
Expand Down
4 changes: 2 additions & 2 deletions hermes/bin/src/wasm/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ impl Context {
}

/// Increments the module's execution counter and sets the event name to be executed
pub(crate) fn use_for(&mut self, event_name: String) {
self.event_name = Some(event_name);
pub(crate) fn use_for(&mut self, even_name: String) {
self.event_name = Some(even_name);
self.counter += 1;
}

Expand Down
7 changes: 5 additions & 2 deletions hermes/bin/src/wasm/engine.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
//! WASM engine implementation
//! Wrapper over the `wasmtime::Engine` struct with some specific configuration setup.

use std::ops::{Deref, DerefMut};
use std::{
error::Error,
ops::{Deref, DerefMut},
};

use wasmtime::{Config as WasmConfig, Engine as WasmEngine};

Expand Down Expand Up @@ -30,7 +33,7 @@ impl Engine {
///
/// - `wasmtime::Error`: engine initialization error.
#[allow(dead_code)]
pub(crate) fn new() -> anyhow::Result<Self> {
pub(crate) fn new() -> Result<Self, Box<dyn Error>> {
let mut config = WasmConfig::new();
config.wasm_component_model(true);
config.consume_fuel(false);
Expand Down
4 changes: 2 additions & 2 deletions hermes/bin/src/wasm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
//! All implementation based on [wasmtime](https://crates.io/crates/wasmtime) crate dependency.

pub(crate) mod context;
pub(crate) mod engine;
pub(crate) mod module;
mod engine;
mod module;
168 changes: 57 additions & 111 deletions hermes/bin/src/wasm/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,60 +4,19 @@
//!
//! All implementation based on [wasmtime](https://crates.io/crates/wasmtime) crate dependency.

use std::error::Error;

use wasmtime::{
component::{
Component as WasmModule, Instance as WasmInstance, InstancePre as WasmInstancePre,
Linker as WasmLinker,
},
Store as WasmStore,
InstancePre as WasmInstancePre, Linker as WasmLinker, Module as WasmModule, Store as WasmStore,
WasmParams, WasmResults,
};

use super::{context::Context, engine::Engine};
use crate::event::HermesEventPayload;

/// Interface for linking WASM imports
pub(crate) trait Host<Context> {
pub(crate) trait LinkImport<Context> {
/// Link imports to the `wasmtime::Linker`
fn link_imports(linker: &mut WasmLinker<Context>) -> anyhow::Result<()>;
}

/// Interface for WASM module instance
pub(crate) trait Instance: Sized {
/// Instantiate WASM module instance
fn instantiate(
store: &mut WasmStore<Context>, pre_instance: &WasmInstancePre<Context>,
) -> anyhow::Result<Self>;
}

impl Instance for WasmInstance {
fn instantiate(
mut store: &mut WasmStore<Context>, pre_instance: &WasmInstancePre<Context>,
) -> anyhow::Result<Self> {
let instance = pre_instance.instantiate(&mut store)?;
Ok(instance)
}
}

/// Structure defines an abstraction over the WASM module instance.
/// It holds the state of the WASM module along with its context data.
/// It is used to interact with the WASM module.
pub(crate) struct ModuleInstance<I: Instance> {
/// `wasmtime::Store` entity
#[allow(dead_code)]
pub(crate) store: WasmStore<Context>,
/// `Instance` entity
#[allow(dead_code)]
pub(crate) instance: I,
}

impl<I: Instance> ModuleInstance<I> {
/// Instantiates WASM module
pub(crate) fn new(
mut store: WasmStore<Context>, pre_instance: &WasmInstancePre<Context>,
) -> anyhow::Result<Self> {
let instance = I::instantiate(&mut store, pre_instance)?;
Ok(Self { store, instance })
}
fn link(&self, linker: &mut WasmLinker<Context>) -> Result<(), Box<dyn Error>>;
}

/// Structure defines an abstraction over the WASM module
Expand All @@ -68,7 +27,7 @@ impl<I: Instance> ModuleInstance<I> {
/// The primary goal for it is to make a WASM state *immutable* along WASM module
/// execution. It means that `Module::call_func` execution does not have as side effect
/// for the WASM module's state, it becomes unchanged.
pub(crate) struct Module<H: Host<Context>> {
pub(crate) struct Module {
/// `wasmtime::InstancePre` entity
///
/// A reason why it is used a `wasmtime::InstancePre` instead of `wasmtime::Instance`
Expand All @@ -82,78 +41,67 @@ pub(crate) struct Module<H: Host<Context>> {

/// `Context` entity
context: Context,

/// `Host` type
_host: std::marker::PhantomData<H>,
}

impl<H: Host<Context>> Module<H> {
impl Module {
/// Instantiate WASM module
///
/// # Errors
/// - `wasmtime::Error`: WASM call error
#[allow(dead_code)]
pub(crate) fn new(app_name: String, module_bytes: &[u8]) -> anyhow::Result<Self> {
let engine = Engine::new()?;
pub(crate) fn new(
engine: Engine, app_name: String, module_bytes: &[u8],
imports: &[Box<dyn LinkImport<Context>>],
) -> Result<Self, Box<dyn Error>> {
let module = WasmModule::new(&engine, module_bytes)?;

let mut linker = WasmLinker::new(&engine);
H::link_imports(&mut linker)?;
for import in imports {
import.link(&mut linker)?;
}
let pre_instance = linker.instantiate_pre(&module)?;

Ok(Self {
pre_instance,
engine,
context: Context::new(app_name),
_host: std::marker::PhantomData,
})
}

/// Executes a Hermes event by calling some WASM function.
/// This function abstraction over actual execution of the WASM function,
/// actual definition is inside `HermesEventPayload` trait implementation.
///
/// Call WASM module's function.
/// For each call creates a brand new `wasmtime::Store` instance, which means that
/// is has an initial state, based on the provided context for each call.
///
/// # Errors
/// - `wasmtime::Error`: WASM call error
#[allow(dead_code)]
pub(crate) fn execute_event<I: Instance>(
&mut self, event: &impl HermesEventPayload<ModuleInstance<I>>,
) -> anyhow::Result<()> {
self.context.use_for(event.event_name().to_string());

let store = WasmStore::new(&self.engine, self.context.clone());
let mut instance = ModuleInstance::new(store, &self.pre_instance)?;
event.execute(&mut instance)?;
Ok(())
pub(crate) fn call_func<Args, Ret>(
&mut self, name: &str, args: Args,
) -> Result<Ret, Box<dyn Error>>
where
Args: WasmParams,
Ret: WasmResults,
{
self.context.use_for(name.to_string());

let mut store = WasmStore::new(&self.engine, self.context.clone());
let instance = self.pre_instance.instantiate(&mut store)?;
let func = instance.get_typed_func(&mut store, name)?;
Ok(func.call(&mut store, args)?)
}
}

#[cfg(test)]
mod tests {
use super::*;

struct TestHost;
impl Host<Context> for TestHost {
fn link_imports(_linker: &mut WasmLinker<Context>) -> anyhow::Result<()> {
Ok(())
}
}

struct TestEvent;
impl HermesEventPayload<ModuleInstance<WasmInstance>> for TestEvent {
fn event_name(&self) -> &str {
"inc-global"
}
struct ImportHelloFunc;

fn execute(&self, instance: &mut ModuleInstance<WasmInstance>) -> anyhow::Result<()> {
let func = instance
.instance
.get_typed_func::<(), (i32,)>(&mut instance.store, "inc-global")?;
let (res,) = func.call(&mut instance.store, ())?;
assert_eq!(res, 1);
impl LinkImport<Context> for ImportHelloFunc {
fn link(&self, linker: &mut WasmLinker<Context>) -> Result<(), Box<dyn Error>> {
linker.func_wrap("", "hello", || {
println!("hello");
})?;
Ok(())
}
}
Expand All @@ -162,33 +110,31 @@ mod tests {
/// Tests that after instantiation of `Module` its state does not change after each
/// `Module::call_func` execution
fn preserve_module_state_test() {
let engine = Engine::new().expect("");
let wat = r#"
(component
(core module $Module
(export "inc-global" (func $inc_global))
(func $inc_global (result i32)
global.get $global_val
i32.const 1
i32.add
global.set $global_val
global.get $global_val
)
(global $global_val (mut i32) (i32.const 0))
)
(core instance $module (instantiate (module $Module)))
(func $inc_global (result s32) (canon lift (core func $module "inc-global")))
(export "inc-global" (func $inc_global))
)"#;

let mut module = Module::<TestHost>::new("app".to_string(), wat.as_bytes())
.expect("cannot load a WASM module");
(module
(import "" "hello" (func $hello_0))
(export "call_hello" (func $call_hello))
(func $call_hello (result i32)
global.get $global_val
i32.const 1
i32.add
global.set $global_val
global.get $global_val
)
(global $global_val (mut i32) (i32.const 0))
)"#;

let mut module = Module::new(engine, "app".to_string(), wat.as_bytes(), &[Box::new(
ImportHelloFunc,
)])
.expect("");

for _ in 0..10 {
module
.execute_event(&TestEvent)
.expect("cannot execute `TestEvent` event");
let res: i32 = module.call_func("call_hello", ()).expect("");
assert_eq!(res, 1);
}
}
}

0 comments on commit 048f1b3

Please sign in to comment.