Commit 1851bbcc authored by Guy Watson's avatar Guy Watson
Browse files

WIP add support functions and trimmings for wasmtime

parent 15ad25cb
......@@ -7,3 +7,4 @@ edition = "2021"
[dependencies]
wasmtime = "0.31.0"
structopt = "0.3.25"
......@@ -3,6 +3,7 @@ use std::fs;
use structopt::StructOpt;
use crc::{Crc, CRC_32_ISO_HDLC};
use std::sync::{Arc, Mutex};
use wasmtime::{Caller, Engine, Module, Store, Instance, Func};
/// Run a wasm program using Wasmer
......@@ -10,16 +11,16 @@ use std::sync::{Arc, Mutex};
#[structopt(name = "load-wasmtime", about = "Uses Wasmtime to load and execute a WebAssembly program.")]
struct Cli {
/// Compiler. Options are "singlepass", "cranelift", or "llvm".
#[structopt(long, required(true))]
compiler: String,
// #[structopt(long, required(true))]
// compiler: String,
/// Engine. Options are "universal" or "dylib".
#[structopt(long, required(true))]
engine: String,
// #[structopt(long, required(true))]
// engine: String,
/// Select if the compiler should apply optimizations.
#[structopt(long = "optimize")]
should_optimize: bool,
// #[structopt(long = "optimize")]
// should_optimize: bool,
/// The path to the wasm program (.wasm).
#[structopt(required(true))]
......@@ -31,77 +32,79 @@ static CRC_ALGORITHM: Crc<u32> = Crc::<u32>::new(&CRC_32_ISO_HDLC);
fn main() -> anyhow::Result<()> {
// Get command line arguments
let args = Cli::from_args();
if !(args.compiler == "singlepass"
|| args.compiler == "cranelift"
|| args.compiler == "llvm") {
panic!("Provided compiler option must be [\"singlepass\"|\"cranelift\"|\"llvm\"]");
}
if !(args.engine == "universal"
|| args.engine == "dylib") {
panic!("Provided engine option must be [\"universal\"|\"dylib\"]");
}
// if !(args.compiler == "singlepass"
// || args.compiler == "cranelift"
// || args.compiler == "llvm") {
// panic!("Provided compiler option must be [\"singlepass\"|\"cranelift\"|\"llvm\"]");
// }
// if !(args.engine == "universal"
// || args.engine == "dylib") {
// panic!("Provided engine option must be [\"universal\"|\"dylib\"]");
// }
// Instantiate the compiler and engine into a store
let config_options = (&args.compiler[..], &args.engine[..]);
let store = match config_options {
("singlepass", engine) => {
let mut compiler = Singlepass::new();
compiler
.enable_stack_check(args.should_optimize)
.canonicalize_nans(args.should_optimize);
match engine {
"universal" => Store::new(&Universal::new(compiler).engine()),
"dylib" => Store::new(&Dylib::new(compiler).engine()),
_ => panic!("engine did not match any known option"),
}
},
("cranelift", engine) => {
let mut compiler = Cranelift::new();
compiler
.canonicalize_nans(args.should_optimize)
.opt_level(
if args.should_optimize {
CraneliftOptLevel::SpeedAndSize
} else {
CraneliftOptLevel::None
});
match engine {
"universal" => Store::new(&Universal::new(compiler).engine()),
"dylib" => Store::new(&Dylib::new(compiler).engine()),
_ => panic!("engine did not match any known option"),
}
},
("llvm", engine) => {
let mut compiler = LLVM::new();
compiler
.opt_level(
if args.should_optimize {
LLVMOptLevel::Aggressive
} else {
LLVMOptLevel::None
})
.canonicalize_nans(args.should_optimize);
match engine {
"universal" => Store::new(&Universal::new(compiler).engine()),
"dylib" => Store::new(&Dylib::new(compiler).engine()),
_ => panic!("engine did not match any known option"),
}
},
(_, _) => panic!("compiler did not match any known option"),
};
// let config_options = (&args.compiler[..], &args.engine[..]);
// let store = match config_options {
// ("singlepass", engine) => {
// let mut compiler = Singlepass::new();
// compiler
// .enable_stack_check(args.should_optimize)
// .canonicalize_nans(args.should_optimize);
//
// match engine {
// "universal" => Store::new(&Universal::new(compiler).engine()),
// "dylib" => Store::new(&Dylib::new(compiler).engine()),
// _ => panic!("engine did not match any known option"),
// }
// },
//
// ("cranelift", engine) => {
// let mut compiler = Cranelift::new();
// compiler
// .canonicalize_nans(args.should_optimize)
// .opt_level(
// if args.should_optimize {
// CraneliftOptLevel::SpeedAndSize
// } else {
// CraneliftOptLevel::None
// });
//
// match engine {
// "universal" => Store::new(&Universal::new(compiler).engine()),
// "dylib" => Store::new(&Dylib::new(compiler).engine()),
// _ => panic!("engine did not match any known option"),
// }
// },
//
// ("llvm", engine) => {
// let mut compiler = LLVM::new();
// compiler
// .opt_level(
// if args.should_optimize {
// LLVMOptLevel::Aggressive
// } else {
// LLVMOptLevel::None
// })
// .canonicalize_nans(args.should_optimize);
//
// match engine {
// "universal" => Store::new(&Universal::new(compiler).engine()),
// "dylib" => Store::new(&Dylib::new(compiler).engine()),
// _ => panic!("engine did not match any known option"),
// }
// },
//
// (_, _) => panic!("compiler did not match any known option"),
// };
// Get the wasm program to test
let wasm_bytes = fs::read(args.program)?;
// Compile the Wasm module.
let module = Module::new(&store, wasm_bytes)?;
let engine = Engine::default();
let module = Module::new(&engine, wasm_bytes)?;
// Wasmer interoperability:
// Arc<...> - In order to allow the wasm code to interact with a data-structure on the rist side of things, we have to be able
......@@ -113,7 +116,6 @@ fn main() -> anyhow::Result<()> {
// Make a crc digest
let shared_digest: Arc<Mutex<Option<crc::Digest<u32>>>> = Arc::new(Mutex::new(Some(CRC_ALGORITHM.digest())));
#[derive(wasmer::WasmerEnv, Clone)]
struct Env<'a> {
digest: Arc<Mutex<Option<crc::Digest<'a, u32>>>>,
}
......@@ -127,44 +129,54 @@ fn main() -> anyhow::Result<()> {
owned_digest.finalize()
}
// Create a function to pass to wasm
let add_to_crc_func = Function::new_native_with_env(
&store,
Env { digest: shared_digest.clone() }, // These clones clone the Arc, not the underlying data
add_to_crc
let mut store = Store::new(
&engine,
Env { digest: shared_digest.clone() }
);
// let add_to_crc_wasm_func = Function::new_native(
// Create a function to pass to wasm
// let add_to_crc_func = Function::new_native_with_env(
// &store,
// add_to_crc_func
// Env { digest: shared_digest.clone() }, // These clones clone the Arc, not the underlying data
// add_to_crc
// );
let add_to_crc_func = Func::wrap(&store, |mut caller: Caller<'_, Env>, val: u32| {
add_to_crc(caller.data(), val);
});
// Create an import object with the crc function from the crc library.
let import_object = imports! {
"env" => {
"addToCrc" => add_to_crc_func// as &From<wasmer::Function>,
},
};
// let import_object = imports! {
// "env" => {
// "addToCrc" => add_to_crc_func// as &From<wasmer::Function>,
// },
// };
let import_object = [add_to_crc_func.into()];
// Instantiate the Wasm module.
let instance = Instance::new(&module, &import_object)?;
let instance = Instance::new(&mut store, &module, &import_object)?;
// Get handles for the exports
let main_func: NativeFunc<(), i32> = instance.exports.get_native_function("_main")?;
let crc_globals_func: NativeFunc<(), ()> = instance.exports.get_native_function("_crc_globals")?;
let memory = instance.exports.get_memory("_memory")?;
// let main_func: NativeFunc<(), i32> = instance.exports.get_native_function("_main")?;
// let crc_globals_func: NativeFunc<(), ()> = instance.exports.get_native_function("_crc_globals")?;
// let memory = instance.exports.get_memory("_memory")?;
let main_func = instance.get_typed_func::<(), i32, _>(&store, "_main")?;
let crc_globals_func = instance.get_typed_func::<(), (), _>(&store, "_crc_globals")?;
let memory = instance.get_memory(&store, "_memory")?;
// Call main and add the result to the crc
add_to_crc(&Env{ digest: shared_digest.clone() },main_func.call()?.try_into()?);
let main_result: i32 = main_func.call(&mut store, ())?;
add_to_crc(&Env{ digest: shared_digest.clone() },main_result.into());
// Call the crc globals function to have wasm add all of it's globals to the crc
crc_globals_func.call()?;
crc_globals_func.call(&store, ())?;
// Add the contents of memory to the crc
// Get the pointer and size in bytes
let mem_ptr: *mut i32 = memory.data_ptr() as *mut i32;
let mem_size = (memory.data_size() / 4) as isize; // bytes to i32s
let mem_ptr: *mut i32 = memory.data_ptr(&store) as *mut i32;
let mem_size = (memory.data_size(&store) / 4) as isize; //bytes to i32s
for address in 0..mem_size {
let mem_value : u32;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment