Created
August 4, 2021 19:24
-
-
Save uint/be1d83734a76d8cb79cc09c2b0b2a753 to your computer and use it in GitHub Desktop.
wasmer middleware import injection MWE
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::sync::Mutex; | |
use loupe::MemoryUsage; | |
use wasmer::{FunctionMiddleware, FunctionType, ModuleMiddleware, Type}; | |
use wasmer_types::{FunctionIndex, ImportIndex}; | |
use wasmer_vm::ModuleInfo; | |
#[derive(Debug, MemoryUsage)] | |
struct MyMiddleware { | |
// This would then be passed to FunctionMiddleware things, which would use | |
// this to inject calls of the imported function into the Wasm code and so on... | |
fn_index: Mutex<Option<FunctionIndex>>, | |
} | |
impl MyMiddleware { | |
fn new() -> Self { | |
Self { | |
fn_index: Mutex::new(None), | |
} | |
} | |
} | |
#[derive(Debug, MemoryUsage)] | |
struct MyFunctionMiddleware; | |
impl ModuleMiddleware for MyMiddleware { | |
fn transform_module_info(&self, mod_info: &mut ModuleInfo) { | |
let mut fn_index = self.fn_index.lock().unwrap(); | |
if fn_index.is_some() { | |
panic!("MyModuleMiddleware::transform_module_info: Attempting to use the middleware from multiple modules."); | |
} | |
// Essentially we're trying to register an imported function in the | |
// module here. | |
let sig = mod_info.signatures.push(FunctionType::new([Type::I32], [])); | |
*fn_index = Some(mod_info.functions.push(sig)); | |
let import_index = mod_info.imports().len(); | |
mod_info.imports.insert( | |
( | |
"profiling".to_string(), | |
"start_measurement".to_string(), | |
import_index as u32, | |
), | |
ImportIndex::Function(fn_index.unwrap()), | |
); | |
mod_info.num_imported_functions += 1; | |
} | |
fn generate_function_middleware( | |
&self, | |
_local_function_index: wasmer::LocalFunctionIndex, | |
) -> Box<dyn FunctionMiddleware> { | |
Box::new(MyFunctionMiddleware) | |
} | |
} | |
impl FunctionMiddleware for MyFunctionMiddleware {} | |
#[cfg(test)] | |
mod tests { | |
use std::sync::Arc; | |
use wasmer::{CompilerConfig, Cranelift, Function, Instance, Module, Store, Universal, imports, wat2wasm}; | |
use wasmer_types::Value; | |
use crate::MyMiddleware; | |
const WAT: &[u8] = br#" | |
(module | |
(type $t0 (func (param i32) (result i32))) | |
(func $add_one (export "add_one") (type $t0) (param $p0 i32) (result i32) | |
get_local $p0 | |
i32.const 1 | |
i32.add) | |
(func $multisub (export "multisub") (type $t0) (param $p0 i32) (result i32) | |
get_local $p0 | |
i32.const 2 | |
i32.mul | |
call $sub_one | |
i32.const 1 | |
i32.sub) | |
(func $sub_one (type $t0) (param $p0 i32) (result i32) | |
get_local $p0 | |
i32.const 1 | |
i32.sub)) | |
"#; | |
#[test] | |
fn middleware_test() { | |
let profiling = Arc::new(MyMiddleware::new()); | |
// Create the module with our middleware. | |
let mut compiler_config = Cranelift::default(); | |
compiler_config.push_middleware(profiling.clone()); | |
let store = Store::new(&Universal::new(compiler_config).engine()); | |
let wasm = wat2wasm(WAT).unwrap(); | |
let module = Module::new(&store, wasm).unwrap(); | |
let imports = imports! { | |
"profiling" => { | |
"start_measurement" => Function::new_native(&store, |_: u32| println!("start measuring")), | |
} | |
}; | |
let instance = Instance::new(&module, &imports).unwrap(); | |
let add_one_fn = instance.exports.get_function("add_one").unwrap(); | |
let result = add_one_fn.call(&[Value::I32(42)]).unwrap(); | |
assert_eq!(result[0], Value::I32(43)); | |
} | |
} |
Output:
failures:
---- tests::middleware_test stdout ----
start measuring
thread 'tests::middleware_test' panicked at 'assertion failed: `(left == right)`
left: `I32(0)`,
right: `I32(43)`', src/lib.rs:110:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Quick
Cargo.toml
for this: