diff --git a/.github/workflows/cargo-tests.yaml b/.github/workflows/cargo-tests.yaml index 60aa8f66..b8350a0f 100644 --- a/.github/workflows/cargo-tests.yaml +++ b/.github/workflows/cargo-tests.yaml @@ -16,7 +16,7 @@ jobs: fail-fast: false # test different available compute engines with different system engines matrix: - compute_driver: [ mmu, wasm ] + compute_driver: [ mmu, wasm, wasmtime-jit, wasmtime-precomp ] system_driver: [ hyper_io ] steps: # check out the code diff --git a/README.md b/README.md index fd3b6e8d..f42ea568 100644 --- a/README.md +++ b/README.md @@ -96,4 +96,7 @@ RUSTFLAGS='-C target-feature=+crt-static -C link-arg=-Wl,-fuse-ld=lld,--image-ba Also make sure that shared memory objects are executable: ``` sudo mount -o remount,exec /dev/shm -``` \ No newline at end of file +``` + +### MMU worker path +To use a `mmu_worker` that is not at the original location it was built in, set the `PROCESS_WORKER_PATH` environment variable to point to the desired binary \ No newline at end of file diff --git a/dandelion_commons/src/lib.rs b/dandelion_commons/src/lib.rs index 3fb4b256..de2b1f44 100644 --- a/dandelion_commons/src/lib.rs +++ b/dandelion_commons/src/lib.rs @@ -23,6 +23,8 @@ pub enum DandelionError { ContextMissmatch, /// domain could not be allocated because there is no space available OutOfMemory, + /// memory size is not allowed, e.g. Wasm memory must be <= 4GiB + InvalidMemorySize, /// context can't fit additional memory ContextFull, /// read buffer was misaligned for requested data type diff --git a/dispatcher/Cargo.toml b/dispatcher/Cargo.toml index 0cb283cb..082137f3 100644 --- a/dispatcher/Cargo.toml +++ b/dispatcher/Cargo.toml @@ -11,8 +11,11 @@ dandelion_commons = {path = "../dandelion_commons"} machine_interface = {path = "../machine_interface"} futures = {version = "0.3.28", default-features = false} itertools = {version = "0.11", default-features = false, features = ["use_alloc"]} +async-lock = "3.1" [features] cheri = ["machine_interface/cheri"] +mmu = ["machine_interface/mmu"] wasm = ["machine_interface/wasm"] -mmu = ["machine_interface/mmu"] \ No newline at end of file +wasmtime-jit = ["machine_interface/wasmtime-jit"] +wasmtime-precomp = ["machine_interface/wasmtime-precomp"] \ No newline at end of file diff --git a/dispatcher/src/function_registry.rs b/dispatcher/src/function_registry.rs index d3564644..1a00e030 100644 --- a/dispatcher/src/function_registry.rs +++ b/dispatcher/src/function_registry.rs @@ -1,3 +1,4 @@ +use async_lock::RwLock; use dandelion_commons::{DandelionError, DandelionResult, EngineTypeId, FunctionId}; use machine_interface::{ function_driver::{Driver, Function, FunctionConfig}, diff --git a/dispatcher/tests/dispatcher_tests.rs b/dispatcher/tests/dispatcher_tests.rs index 63fa8bc7..c3e47dcc 100644 --- a/dispatcher/tests/dispatcher_tests.rs +++ b/dispatcher/tests/dispatcher_tests.rs @@ -1,4 +1,4 @@ -#[cfg(all(test, any(feature = "cheri", feature = "mmu", feature = "wasm")))] +#[cfg(all(test, any(feature = "cheri", feature = "mmu", feature = "wasm", feature = "wasmtime-jit", feature = "wasmtime-precomp")))] mod dispatcher_tests { mod function_tests; mod registry_tests; @@ -190,4 +190,13 @@ mod dispatcher_tests { #[cfg(target_arch = "aarch64")] dispatcherTests!(sysld_wasm_aarch64; WasmMemoryDomain; Vec::new(); WasmDriver {}; vec![ComputeResource::CPU(1)]); } + + #[cfg(any(feature = "wasmtime-jit", feature = "wasmtime-precomp"))] + mod wasmtime { + use machine_interface::{ + function_driver::{compute_driver::wasmtime::WasmtimeDriver, ComputeResource}, + memory_domain::wasmtime::WasmtimeMemoryDomain, + }; + dispatcherTests!(wasm; WasmtimeMemoryDomain; Vec::new(); WasmtimeDriver {}; vec![ComputeResource::CPU(1)]); + } } diff --git a/machine_interface/Cargo.toml b/machine_interface/Cargo.toml index 126c09ed..59b1725f 100644 --- a/machine_interface/Cargo.toml +++ b/machine_interface/Cargo.toml @@ -9,6 +9,8 @@ cheri = ["std"] mmu = ["std"] hyper_io = ["std", "dep:hyper"] wasm = ["std"] +wasmtime-jit = ["std", "dep:wasmtime"] +wasmtime-precomp = ["std", "dep:wasmtime"] [build-dependencies] cmake = "0.1" @@ -32,6 +34,7 @@ tokio = { version = "1", features = ["full"] } hyper = { version = "0.14", optional = true, features = ["http1", "http2", "client", "runtime"]} libloading = { version = "0.8.1" } log = "0.4.20" +wasmtime = { version = "15.0.1", optional = true, default-features = false, features = ["cranelift", "cache"]} # disable benchmarks in library, to not run all unit tests on every benchmark # also needs to be disabled for criterion flags to work that are not available for tests diff --git a/machine_interface/build.rs b/machine_interface/build.rs new file mode 100644 index 00000000..e2dbaafd --- /dev/null +++ b/machine_interface/build.rs @@ -0,0 +1,21 @@ +fn main() { + // check if cheri is enabled and build library if so + #[cfg(feature = "cheri")] + { + use cmake::Config; + // cmake configure and build all + let _all = Config::new("c_machine_libraries") + .define("FORCE_BUILD_CHERI", "") + .build_target("all") + .build(); + // run tests tests + let _test = Config::new("c_machine_libraries") + .build_target("test") + .build(); + // install + let install = Config::new("c_machine_libraries").build(); + // passing cmake information to c + println!("cargo:rustc-link-search=native={}", install.display()); + println!("cargo:rustc-link-lib=static=cheri_lib"); + } +} diff --git a/machine_interface/src/function_driver.rs b/machine_interface/src/function_driver.rs index 97028d7b..f1369006 100644 --- a/machine_interface/src/function_driver.rs +++ b/machine_interface/src/function_driver.rs @@ -1,18 +1,25 @@ use crate::{ - memory_domain::{Context, MemoryDomain}, + memory_domain::{Context, ContextType, MemoryDomain}, DataRequirementList, Position, }; use core::pin::Pin; -use dandelion_commons::{records::Recorder, DandelionResult}; +use dandelion_commons::{records::Recorder, DandelionResult, DandelionError}; use std::{future::Future, sync::Arc}; +#[cfg(feature = "wasm")] use libloading::Library; +#[cfg(any(feature = "wasmtime-jit", feature = "wasmtime-precomp"))] +use wasmtime; +#[cfg(any(feature = "wasmtime-jit", feature = "wasmtime-precomp"))] +use crate::function_driver::compute_driver::wasmtime as wasmtime_driver; + pub mod compute_driver; mod load_utils; pub mod system_driver; mod thread_utils; +#[cfg(any(feature = "mmu", feature = "cheri"))] #[derive(Clone)] pub struct ElfConfig { // TODO change to positions @@ -28,6 +35,7 @@ pub enum SystemFunction { HTTP, } +#[cfg(feature = "wasm")] #[derive(Clone)] pub struct WasmConfig { lib: Arc, @@ -37,11 +45,25 @@ pub struct WasmConfig { system_data_struct_offset: usize, } +#[cfg(any(feature = "wasmtime-jit", feature = "wasmtime-precomp"))] +#[derive(Clone)] +pub struct WasmtimeConfig { + precompiled_module: Vec, + total_mem_size: usize, + sdk_heap_base: usize, + system_data_struct_offset: usize, + wasmtime_engine: wasmtime::Engine, // engine can be shared across threads +} + #[derive(Clone)] pub enum FunctionConfig { + #[cfg(any(feature = "mmu", feature = "cheri"))] ElfConfig(ElfConfig), SysConfig(SystemFunction), + #[cfg(feature = "wasm")] WasmConfig(WasmConfig), + #[cfg(any(feature = "wasmtime-jit", feature = "wasmtime-precomp"))] + WasmtimeConfig(WasmtimeConfig), } pub struct Function { @@ -53,15 +75,21 @@ pub struct Function { impl Function { pub fn load(&self, domain: &Box) -> DandelionResult { return match &self.config { + #[cfg(any(feature = "mmu", feature = "cheri"))] FunctionConfig::ElfConfig(_) => { load_utils::load_static(domain, &self.context, &self.requirements) - } + }, FunctionConfig::SysConfig(_) => domain.acquire_context(self.requirements.size), + #[cfg(feature = "wasm")] FunctionConfig::WasmConfig(c) => { let mut context = domain.acquire_context(c.wasm_mem_size)?; context.occupy_space(0, c.sdk_heap_base)?; Ok(context) - } + }, + #[cfg(any(feature = "wasmtime-jit", feature = "wasmtime-precomp"))] + FunctionConfig::WasmtimeConfig(c) => { + wasmtime_driver::load_context(c, domain) + }, }; } } diff --git a/machine_interface/src/function_driver/compute_driver.rs b/machine_interface/src/function_driver/compute_driver.rs index 21c455e6..5cbf5ebc 100644 --- a/machine_interface/src/function_driver/compute_driver.rs +++ b/machine_interface/src/function_driver/compute_driver.rs @@ -7,5 +7,8 @@ pub mod mmu; #[cfg(feature = "wasm")] pub mod wasm; +#[cfg(any(feature = "wasmtime-jit", feature = "wasmtime-precomp"))] +pub mod wasmtime; + #[cfg(test)] mod compute_driver_tests; diff --git a/machine_interface/src/function_driver/compute_driver/compute_driver_tests.rs b/machine_interface/src/function_driver/compute_driver/compute_driver_tests.rs index 59f948b9..2d184aa6 100644 --- a/machine_interface/src/function_driver/compute_driver/compute_driver_tests.rs +++ b/machine_interface/src/function_driver/compute_driver/compute_driver_tests.rs @@ -1,4 +1,4 @@ -#[cfg(all(test, any(feature = "cheri", feature = "mmu", feature = "wasm")))] +#[cfg(all(test, any(feature = "cheri", feature = "mmu", feature = "wasm", feature = "wasmtime-jit", feature = "wasmtime-precomp")))] mod compute_driver_tests { use crate::{ function_driver::{ComputeResource, Driver, Engine, FunctionConfig}, @@ -630,4 +630,47 @@ mod compute_driver_tests { ComputeResource::GPU(0), ]); } -} + + #[cfg(any(feature = "wasmtime-jit", feature = "wasmtime-precomp"))] + mod wasmtime { + use crate::function_driver::compute_driver::wasmtime::WasmtimeDriver; + use crate::function_driver::ComputeResource; + use crate::memory_domain::wasmtime::WasmtimeMemoryDomain; + + #[cfg(feature = "wasmtime-jit")] + driverTests!(wasm; WasmtimeMemoryDomain; Vec::new(); WasmtimeDriver {}; + vec![ + ComputeResource::CPU(1), + ComputeResource::CPU(2), + ComputeResource::CPU(3), + ]; + vec![ + ComputeResource::CPU(255), + ComputeResource::GPU(0), + ]); + + #[cfg(all(feature = "wasmtime-precomp", target_arch = "x86_64"))] + driverTests!(wasmtime_x86_64; WasmtimeMemoryDomain; Vec::new(); WasmtimeDriver {}; + vec![ + ComputeResource::CPU(1), + ComputeResource::CPU(2), + ComputeResource::CPU(3), + ]; + vec![ + ComputeResource::CPU(255), + ComputeResource::GPU(0), + ]); + + #[cfg(all(feature = "wasmtime-precomp", target_arch = "aarch64"))] + driverTests!(wasmtime_aarch64; WasmtimeMemoryDomain; Vec::new(); WasmtimeDriver {}; + vec![ + ComputeResource::CPU(1), + ComputeResource::CPU(2), + ComputeResource::CPU(3), + ]; + vec![ + ComputeResource::CPU(255), + ComputeResource::GPU(0), + ]); + } +} \ No newline at end of file diff --git a/machine_interface/src/function_driver/compute_driver/mmu.rs b/machine_interface/src/function_driver/compute_driver/mmu.rs index afcb25ab..d9c0c7a1 100644 --- a/machine_interface/src/function_driver/compute_driver/mmu.rs +++ b/machine_interface/src/function_driver/compute_driver/mmu.rs @@ -165,8 +165,7 @@ fn mmu_run_static( // that will not collide with those used by user's function // this trick gives the desired path of mmu_worker for packages within the workspace - // TODO: replace with a more general solution (e.g. environment variable) - let path = format!( + let path = std::env::var("PROCESS_WORKER_PATH").unwrap_or(format!( "{}/../target/{}-unknown-linux-gnu/{}/mmu_worker", env!("CARGO_MANIFEST_DIR"), std::env::consts::ARCH, @@ -175,7 +174,7 @@ fn mmu_run_static( } else { "release" }, - ); + )); // create a new address space (child process) and pass the shared memory let mut worker = Command::new(path) diff --git a/machine_interface/src/function_driver/compute_driver/wasm.rs b/machine_interface/src/function_driver/compute_driver/wasm.rs index 60e1410e..29525d2c 100644 --- a/machine_interface/src/function_driver/compute_driver/wasm.rs +++ b/machine_interface/src/function_driver/compute_driver/wasm.rs @@ -20,11 +20,12 @@ use libloading::{Library, Symbol}; use log::error; use std::sync::{Arc, Mutex}; -type WasmEntryPoint = fn(&mut [u8]) -> Option; +type WasmEntryPoint = fn(&mut [u8], usize) -> Option; struct WasmCommand { lib: Arc, context: Arc>>, + sysdata_offset: usize, } unsafe impl Send for WasmCommand {} @@ -45,7 +46,8 @@ impl ThreadPayload for WasmCommand { }; // call entry point - let ret = entry_point(&mut wasm_context.mem); + let ret = entry_point(&mut wasm_context.mem, self.sysdata_offset); + // put context back *guard = Some(ctx); @@ -140,6 +142,7 @@ impl Engine for WasmEngine { WasmCommand { context: context_.clone(), lib: wasm_config.lib.clone(), + sysdata_offset: wasm_config.system_data_struct_offset, }, ); diff --git a/machine_interface/src/function_driver/compute_driver/wasmtime.rs b/machine_interface/src/function_driver/compute_driver/wasmtime.rs new file mode 100644 index 00000000..6fc781dd --- /dev/null +++ b/machine_interface/src/function_driver/compute_driver/wasmtime.rs @@ -0,0 +1,373 @@ +use crate::{ + DataSet, + function_driver::{ + thread_utils::{DefaultState, ThreadCommand, ThreadController, ThreadPayload}, + ComputeResource, Driver, Engine, FunctionConfig, Function, WasmtimeConfig + }, + memory_domain::{Context, ContextType, MemoryDomain, wasmtime::{WasmtimeContext, WASM_PAGE_SIZE}}, + DataRequirementList, + interface::{_32_bit::DandelionSystemData, read_output_structs, setup_input_structs}, +}; +use dandelion_commons::{ + DandelionResult, DandelionError, + records::{RecordPoint, Recorder}, +}; +use futures::{task::Poll, StreamExt}; +use core::{ + future::{ready, Future}, + pin::Pin, +}; +use std::{ + sync::{atomic::{AtomicBool, Ordering}, Mutex, Arc}, + thread::spawn, +}; +use log::{error, info}; + +use wasmtime; + + +/// Creates and configures a WasmtimeContext given a WasmtimeConfig. +/// This results in allocation of a new wasmtime::Store and wasmtime::Memory. +/// The wasmtime::Module will be initialized in the engine. +pub fn load_context(c: &WasmtimeConfig, domain: &Box) -> DandelionResult { + + // TODO: this function currently never uses `domain.acquire_context()`. The reason + // is that the `WasmtimeContext` is using the default engine to allocate memory, + // in order to allow allocating a `WasmtimeContext` without loading a function first. + // Instead here, we just construct the context manually. This is a hack and should be + // fixed in the future. + + let pages = (c.total_mem_size + WASM_PAGE_SIZE) / WASM_PAGE_SIZE; // round up to next page + let size = pages * WASM_PAGE_SIZE; + + let mut wasm_ctx = WasmtimeContext { + store: None, + module: None, + memory: None, + }; + + // initialize store and memory + let mut store = wasmtime::Store::new(&c.wasmtime_engine, ()); + let mem_type = wasmtime::MemoryType::new(pages as u32, Some(pages as u32)); + let memory = Some( + wasmtime::Memory::new(&mut store, mem_type) + .map_err(|_| DandelionError::OutOfMemory)? + ); + wasm_ctx.store = Some(store); + wasm_ctx.memory = memory; + + // occupy clang-generated wasm memory + let mut context = Context::new( + ContextType::Wasmtime(Box::new(wasm_ctx)), + size + ); + context.occupy_space(0, c.sdk_heap_base)?; + Ok(context) +} + + +struct WasmtimeCommand { + context: Arc>>, + sysdata_offset: usize, +} + +unsafe impl Send for WasmtimeCommand {} + +impl ThreadPayload for WasmtimeCommand { + type State = DefaultState; + fn run(self, _state: &mut Self::State) -> DandelionResult<()> { + // get context + let mut guard = self.context.lock().unwrap(); + let mut ctx = guard.take().unwrap(); + + let wasm_context: &mut Box = match &mut ctx.context { + ContextType::Wasmtime(wasm_context) => wasm_context, + _ => panic!("invalid context type"), + }; + let memory = wasm_context.memory.take().unwrap(); + let store = &mut wasm_context.store.as_mut().unwrap(); + let module = wasm_context.module.take().unwrap(); + + // buffer the system data struct because it will be overridden at instantiation + let mut sysdata_buffer = [0u8; core::mem::size_of::()]; + let _ = memory.read(&store, self.sysdata_offset, &mut sysdata_buffer); + + // instantiate module + let instance = wasmtime::Instance::new(store, &module, &[memory.into()]).unwrap(); + + // write the system data struct back + let _ = memory.write(wasm_context.store.as_mut().unwrap(), self.sysdata_offset, &sysdata_buffer); + + // call entry point + let entry = instance.get_typed_func::<(), ()>(wasm_context.store.as_mut().unwrap(), "_start").unwrap(); + let ret = entry.call(wasm_context.store.as_mut().unwrap(), ()); + + // put memory back into context + wasm_context.memory = Some(memory); + + // put context back + *guard = Some(ctx); + + match ret { + Ok(_) => Ok(()), + Err(_) => Err(DandelionError::EngineError), + } + } +} + +struct WasmtimeFuture<'a> { + engine: &'a mut WasmtimeEngine, + context: Arc>>, + system_data_struct_offset: usize, +} + +impl Future for WasmtimeFuture<'_> { + type Output = (DandelionResult<()>, Context); + fn poll( + mut self: Pin<&mut Self>, + cx: &mut futures::task::Context, + ) -> futures::task::Poll { + match self.engine.thread_controller.poll_next(cx) { + Poll::Pending => return Poll::Pending, + Poll::Ready(Some(Ok(()))) => { + let mut guard = self.context.lock().unwrap(); + if !guard.is_some() { return Poll::Pending }; + let mut context = guard.take().unwrap(); + context.content.clear(); + let res = read_output_structs::(&mut context, self.system_data_struct_offset); + Poll::Ready((res, context)) + }, + _ => { + // error + let context = self.context.lock().unwrap().take().unwrap(); + Poll::Ready((Err(DandelionError::EngineError), context)) + } + } + } +} + +pub struct WasmtimeEngine { + thread_controller: ThreadController, +} + +impl Engine for WasmtimeEngine { + fn run( + &mut self, + config: &FunctionConfig, + mut context: Context, + output_set_names: &Vec, + mut recorder: Recorder, + ) -> Pin, Context)> + '_ + Send>> { + + if let Err(err) = recorder.record(RecordPoint::EngineStart) { + return Box::pin(core::future::ready((Err(err), context))); + } + + // error shorthand + use DandelionError::*; + macro_rules! err { + ($err:expr) => { + return Box::pin(ready((Err($err), context))) + }; + } + + // extract config and context + let wasm_config = match config { + FunctionConfig::WasmtimeConfig(c) => c, + _ => err!(ConfigMissmatch), + }; + + // compile module + { + let wasm_context = match &mut context.context { + ContextType::Wasmtime(wasm_context) => wasm_context, + _ => err!(ConfigMissmatch), + }; + wasm_context.module = Some( + match unsafe { + wasmtime::Module::deserialize( + &wasm_config.wasmtime_engine, + &wasm_config.precompiled_module, + ) + } { + Ok(module) => module, + Err(_) => err!(EngineError), + } + ); + } + + // setup input structs + if let Err(err) = setup_input_structs::( + &mut context, + wasm_config.system_data_struct_offset, + output_set_names + ) { err!(err) }; + + // share context with thread + let context_ = Arc::new(Mutex::new(Some(context))); + + // send run command to thread + let cmd = ThreadCommand::Run( + recorder, + WasmtimeCommand { + context: context_.clone(), + sysdata_offset: wasm_config.system_data_struct_offset, + }, + ); + + // TODO give back context if send fails (moved it into the Arc) + let r = self.thread_controller.send_command(cmd); + match r { + Ok(()) => (), + Err(_) => (), + }; + Box::::pin(WasmtimeFuture { + engine: self, + context: context_, + system_data_struct_offset: wasm_config.system_data_struct_offset, + }) + } + fn abort(&mut self) -> DandelionResult<()> { + unimplemented!() + } +} + +const SDK_HEAP_PAGES : usize = 2048; // 128MB + +pub struct WasmtimeDriver {} + +impl Driver for WasmtimeDriver { + fn start_engine(&self, resource: ComputeResource) -> DandelionResult> { + // sanity checks; extract core id + let cpu_slot = match resource { + ComputeResource::CPU(core) => core, + _ => return Err(DandelionError::EngineResourceError), + }; + // check that core is available + let available_cores = match core_affinity::get_core_ids() { + None => return Err(DandelionError::EngineResourceError), + Some(cores) => cores, + }; + if !available_cores + .iter() + .find(|x| x.id == usize::from(cpu_slot)) + .is_some() + { + return Err(DandelionError::EngineResourceError); + } + + // create channels and spawn threads + return Ok(Box::new(WasmtimeEngine { + thread_controller: ThreadController::new(cpu_slot), + })); + } + + fn parse_function( + &self, + function_config: String, + static_domain: &Box, + ) -> DandelionResult { + + info!("parsing wasmtime function {}", &function_config); + info!("pre-compilation enabled: {}", cfg!(feature = "wasmtime-precomp")); + + // shorthand to map any error below to a config missmatch + macro_rules! map_cfg_err { + ($e:expr, $dbg:expr) => { + $e.map_err(|_| { + error!($dbg); + DandelionError::ConfigMissmatch + })? + } + } + + let wasmtime_engine = wasmtime::Engine::default(); + let mut store: wasmtime::Store::<()> = wasmtime::Store::new(&wasmtime_engine, ()); + + // read file and precompile module + let wasm_module_content = map_cfg_err!{ + std::fs::read(&function_config), + "could not read function file" + }; + let precompiled_module = if cfg!(feature = "wasmtime-precomp") { + wasm_module_content + } else if cfg!(feature = "wasmtime-jit") { + map_cfg_err!{ + store.engine().precompile_module(&wasm_module_content), + "could not precompile module" + } + } else { + unreachable!() + }; + + // instantiate module to extract layout data + let module = unsafe { + map_cfg_err!{ + wasmtime::Module::deserialize(store.engine(), &precompiled_module), + "could not deserialize module" + } + }; + let memory_ty = module + .imports().next() + .ok_or_else(|| { + error!("module {} has no imports", function_config); + DandelionError::ConfigMissmatch + })? + .ty().memory() + .ok_or_else(|| { + error!("module {} has no memory import", function_config); + DandelionError::ConfigMissmatch + })? + .clone(); + let memory = map_cfg_err!{ + wasmtime::Memory::new(&mut store, memory_ty.clone()), + "could not create memory" + }; + let instance = map_cfg_err!{ + wasmtime::Instance::new(&mut store, &module, &[memory.into()]), + "could not instantiate module" + }; + + let system_data_struct_offset = { + let v = instance + .get_global(&mut store, "__dandelion_system_data") + .ok_or_else(|| { + error!("module {} has no system data struct", function_config); + DandelionError::ConfigMissmatch + })? + .get(&mut store); + match v { + wasmtime::Val::I32(x) => x as usize, + _ => return Err(DandelionError::ConfigMissmatch) + } + }; + let wasm_mem_min_pages = memory_ty.minimum() as usize; + let sdk_heap_size = SDK_HEAP_PAGES * 65536; + let sdk_heap_base = wasm_mem_min_pages * 65536; + let total_mem_size = (wasm_mem_min_pages + SDK_HEAP_PAGES) * 65536; + + let mut context = static_domain.acquire_context(total_mem_size)?; + + context.content = vec![Some( + DataSet { + ident: String::from("static"), + buffers: vec![], + } + )]; + Ok(Function { + config: FunctionConfig::WasmtimeConfig(WasmtimeConfig { + precompiled_module, + total_mem_size, + sdk_heap_base, + system_data_struct_offset, + wasmtime_engine, + }), + requirements: DataRequirementList { + size: total_mem_size, + static_requirements: vec![], + input_requirements: vec![], + }, + context, + }) + } +} \ No newline at end of file diff --git a/machine_interface/src/lib.rs b/machine_interface/src/lib.rs index e57634de..99de964c 100644 --- a/machine_interface/src/lib.rs +++ b/machine_interface/src/lib.rs @@ -1,7 +1,7 @@ pub mod function_driver; pub mod memory_domain; -#[cfg(any(feature = "cheri", feature = "mmu", feature = "wasm"))] +#[cfg(any(feature = "cheri", feature = "mmu", feature = "wasm", feature = "wasmtime-jit", feature = "wasmtime-precomp"))] mod interface; pub mod util; diff --git a/machine_interface/src/memory_domain.rs b/machine_interface/src/memory_domain.rs index 904f42f2..c07b8b29 100644 --- a/machine_interface/src/memory_domain.rs +++ b/machine_interface/src/memory_domain.rs @@ -7,6 +7,8 @@ pub mod mmu; pub mod read_only; #[cfg(feature = "wasm")] pub mod wasm; +#[cfg(any(feature = "wasmtime-jit", feature = "wasmtime-precomp"))] +pub mod wasmtime; use crate::{DataItem, DataSet, Position}; use dandelion_commons::{DandelionError, DandelionResult}; @@ -28,6 +30,8 @@ pub enum ContextType { Mmu(Box), #[cfg(feature = "wasm")] Wasm(Box), + #[cfg(any(feature = "wasmtime-jit", feature = "wasmtime-precomp"))] + Wasmtime(Box), } impl ContextTrait for ContextType { @@ -41,6 +45,8 @@ impl ContextTrait for ContextType { ContextType::Mmu(context) => context.write(offset, data), #[cfg(feature = "wasm")] ContextType::Wasm(context) => context.write(offset, data), + #[cfg(any(feature = "wasmtime-jit", feature = "wasmtime-precomp"))] + ContextType::Wasmtime(context) => context.write(offset, data), } } fn read(&self, offset: usize, read_buffer: &mut [T]) -> DandelionResult<()> { @@ -53,6 +59,8 @@ impl ContextTrait for ContextType { ContextType::Mmu(context) => context.read(offset, read_buffer), #[cfg(feature = "wasm")] ContextType::Wasm(context) => context.read(offset, read_buffer), + #[cfg(any(feature = "wasmtime-jit", feature = "wasmtime-precomp"))] + ContextType::Wasmtime(context) => context.read(offset, read_buffer), } } } @@ -247,6 +255,16 @@ pub fn transefer_memory( size, ) } + #[cfg(any(feature = "wasmtime-jit", feature = "wasmtime-precomp"))] + (ContextType::Wasmtime(destination_ctxt), ContextType::Wasmtime(source_ctxt)) => { + wasmtime::wasmtime_transfer( + destination_ctxt, + source_ctxt, + destination_offset, + source_offset, + size, + ) + } // default implementation using reads and writes (destination, source) => { let mut read_buffer: Vec = vec![0; size]; diff --git a/machine_interface/src/memory_domain/domain_tests.rs b/machine_interface/src/memory_domain/domain_tests.rs index 08165bd0..aedace23 100644 --- a/machine_interface/src/memory_domain/domain_tests.rs +++ b/machine_interface/src/memory_domain/domain_tests.rs @@ -1,21 +1,26 @@ use std::vec; -use crate::memory_domain::{transefer_memory, transfer_data_set, ContextTrait, MemoryDomain}; +use crate::memory_domain::{transefer_memory, transfer_data_set, ContextTrait, Context, MemoryDomain}; use dandelion_commons::{DandelionError, DandelionResult}; // produces binary pattern 0b0101_01010 or 0x55 const BYTEPATTERN: u8 = 85; -fn acquire(arg: Vec, acquisition_size: usize, expect_success: bool) -> () { +/// Test whether a context can be acquired, and panics if the success +/// does not match `expect_success`. +fn try_acquire(arg: Vec, acquisition_size: usize, expect_success: bool) { let init_result = D::init(arg); let domain = init_result.expect("should have initialized memory domain"); let context_result = domain.acquire_context(acquisition_size); match (expect_success, context_result) { - (true, Ok(_)) | (false, Err(DandelionError::OutOfMemory)) => assert!(true), + (true, Ok(_)) + | (false, Err(DandelionError::OutOfMemory)) + | (false, Err(DandelionError::InvalidMemorySize)) => assert!(true), (false, Ok(_)) => assert!( false, "Got okay for allocating context with size {}", acquisition_size ), + (false, Err(DandelionError::OutOfMemory)) | (false, Err(DandelionError::InvalidMemorySize)) => assert!(true), (_, Err(err)) => assert!( false, "Encountered unexpected error when acquireing context: {:?}", @@ -24,24 +29,29 @@ fn acquire(arg: Vec, acquisition_size: usize, expect_succes } } +/// Acquire a context with a given size and return it. Will panic if the +/// context cannot be acquired. +fn acquire(arg: Vec, size: usize) -> Context { + let domain = init_domain::(arg); + let context = domain + .acquire_context(size) + .expect("Context should be allocatable"); + return context; +} + fn init_domain(arg: Vec) -> Box { let init_result = D::init(arg); let domain = init_result.expect("memory domain should have been initialized"); return domain; } -fn write( - arg: Vec, - context_size: usize, +fn write( + ctx: &mut Context, offset: usize, size: usize, expect_success: bool, ) { - let domain = init_domain::(arg); - let mut context = domain - .acquire_context(context_size) - .expect("Single byte context should always be allocatable"); - let write_error = context.write(offset, &vec![BYTEPATTERN; size]); + let write_error = ctx.write(offset, &vec![BYTEPATTERN; size]); match (expect_success, write_error) { (false, Err(DandelionError::InvalidWrite)) | (true, Ok(())) => (), (false, Ok(())) => panic!("Unexpected write success"), @@ -49,42 +59,32 @@ fn write( } } -fn read( - arg: Vec, - context_size: usize, +fn read( + ctx: &mut Context, offset: usize, size: usize, expect_success: bool, ) { - let domain = init_domain::(arg); - let mut context = domain - .acquire_context(context_size) - .expect("Context should always be allocatable"); - context - .write(0, &vec![BYTEPATTERN; context_size]) + ctx + .write(0, &vec![BYTEPATTERN; ctx.size]) .expect("Writing should succeed"); let mut read_buffer = vec![0; size]; - let read_error = context.read(offset, &mut read_buffer); + let read_error = ctx.read(offset, &mut read_buffer); match (expect_success, read_error) { (true, Ok(())) => assert_eq!(vec![BYTEPATTERN; size], read_buffer), - (false, Ok(())) => panic!("Unexpected ok from read that should fail with context size: {}, read offset: {}, read size: {}", context_size, offset, size), + (false, Ok(())) => panic!("Unexpected ok from read that should fail with context size: {}, read offset: {}, read size: {}", ctx.size, offset, size), (false, Err(DandelionError::InvalidRead)) => (), (_, Err(err)) => panic!("Unexpected error while reading: {:?}", err), } } -fn transefer(arg: Vec, size: usize) { - let domain = init_domain::(arg); - let mut destination = domain - .acquire_context(size) - .expect("Context should be allocatable"); - let mut source = domain - .acquire_context(size) - .expect("Context should be allocatable"); +fn transefer(source: &mut Context, destination: &mut Context) { + assert!(source.size == destination.size); + let size = source.size; source .write(0, &vec![BYTEPATTERN; size]) .expect("Writing should succeed"); - transefer_memory(&mut destination, &mut source, 0, 0, size) + transefer_memory(destination, source, 0, 0, size) .expect("Should successfully transfer"); let mut read_buffer = vec![0; size]; destination @@ -93,22 +93,15 @@ fn transefer(arg: Vec, size: usize) { assert_eq!(vec![BYTEPATTERN; size], read_buffer); } -fn transfer_item( - arg: Vec, - context_size: usize, +fn transfer_item( + source: &mut Context, + destination: &mut Context, offset: usize, item_size: usize, source_index: usize, destination_index: usize, expect_result: DandelionResult<()>, ) { - let domain = init_domain::(arg); - let mut destination = domain - .acquire_context(context_size) - .expect("Context should be allocatable"); - let mut source = domain - .acquire_context(context_size) - .expect("Context should be allocatable"); source .write(offset, &vec![BYTEPATTERN; item_size]) .expect("Writing should succeed"); @@ -128,7 +121,7 @@ fn transfer_item( }); let set_name = ""; let transfer_error = transfer_data_set( - &mut destination, + destination, &source, destination_index, 8, @@ -164,44 +157,59 @@ macro_rules! domainTests { // domain tests #[test] fn test_aquire_success() { - acquire::<$domain>($init, 1, true); + try_acquire::<$domain>($init, 1, true); } #[test] fn test_aquire_failure() { - acquire::<$domain>($init, usize::MAX, false); + try_acquire::<$domain>($init, usize::MAX, false); } // context tests #[test] fn test_read_single_success() { - read::<$domain>($init, 1, 0, 1, true); + let mut ctx = acquire::<$domain>($init, 1); + read(&mut ctx, 0, 1, true); } #[test] fn test_read_single_oob_offset() { - read::<$domain>($init, 1, 1, 1, false); + let mut ctx = acquire::<$domain>($init, 1); + let offset = ctx.size; + read(&mut ctx, offset, 1, false); } #[test] fn test_read_single_oob_size() { - read::<$domain>($init, 1, 0, 2, false); + let mut ctx = acquire::<$domain>($init, 1); + let size = ctx.size + 1; + read(&mut ctx, 0, size, false); } #[test] fn test_write_single_oob_offset() { - write::<$domain>($init, 1, 1, 1, false); + let mut ctx = acquire::<$domain>($init, 1); + let offset = ctx.size; + write(&mut ctx, offset, 1, false); } #[test] fn test_write_single_oob_size() { - write::<$domain>($init, 1, 0, 2, false); + let mut ctx = acquire::<$domain>($init, 1); + let size = ctx.size + 1; + write(&mut ctx, 0, size, false); } #[test] fn test_transfer_single() { - transefer::<$domain>($init, 1); + let mut source = acquire::<$domain>($init, 1); + let mut destination = acquire::<$domain>($init, 1); + transefer(&mut source, &mut destination); } #[test] fn test_transfer_page() { - transefer::<$domain>($init, 4096); + let mut source = acquire::<$domain>($init, 4096); + let mut destination = acquire::<$domain>($init, 4096); + transefer(&mut source, &mut destination); } #[test] fn test_transfer_dataitem_item() { - transfer_item::<$domain>($init, 4096, 128, 256, 1, 2, Ok(())); + let mut source = acquire::<$domain>($init, 4096); + let mut destination = acquire::<$domain>($init, 4096); + transfer_item(&mut source, &mut destination, 0, 128, 1, 2, Ok(())); } // TODO // #[test] @@ -221,8 +229,11 @@ domainTests!(cheri; cheriType; Vec::new()); use super::mmu::MmuMemoryDomain as mmuType; #[cfg(feature = "mmu")] domainTests!(mmu; mmuType; Vec::new()); - #[cfg(feature = "wasm")] use super::wasm::WasmMemoryDomain as wasmType; #[cfg(feature = "wasm")] -domainTests!(wasm; wasmType; Vec::new()); \ No newline at end of file +domainTests!(wasm; wasmType; Vec::new()); +#[cfg(any(feature = "wasmtime-jit", feature = "wasmtime-precomp"))] +use super::wasmtime::WasmtimeMemoryDomain as wasmtimeType; +#[cfg(any(feature = "wasmtime-jit", feature = "wasmtime-precomp"))] +domainTests!(wasmtime; wasmtimeType; Vec::new()); \ No newline at end of file diff --git a/machine_interface/src/memory_domain/wasmtime.rs b/machine_interface/src/memory_domain/wasmtime.rs new file mode 100644 index 00000000..0bc9189e --- /dev/null +++ b/machine_interface/src/memory_domain/wasmtime.rs @@ -0,0 +1,113 @@ +use std::{fmt::{Debug, Formatter}, sync::Arc}; + +use crate::memory_domain::{Context, ContextTrait, ContextType, MemoryDomain}; +use dandelion_commons::{DandelionError, DandelionResult}; + +use wasmtime::{Module, Store, Memory, Engine, MemoryType}; + +pub static WASM_PAGE_SIZE: usize = 64 * 1024; // 64KiB +pub static MAX_WASM_MEMORY_SIZE: usize = 4 * 1024 * 1024 * 1024; // 4GiB + +pub struct WasmtimeContext { + pub store: Option>, // store initialized in load() + pub memory: Option, // must be able to take out the memory during execution + pub module: Option, // module gets compiled in Dandelion engine +} + +impl Debug for WasmtimeContext { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("WasmtimeContext") + .field("store", &self.store) + .field("module", &self.module) + .field("engine", &"") + .field("memory", &self.memory) + .finish() + } +} + +unsafe impl Send for WasmtimeContext {} +unsafe impl Sync for WasmtimeContext {} + +impl ContextTrait for WasmtimeContext { + fn write(&mut self, offset: usize, data: &[T]) -> DandelionResult<()> { + let buffer_byte_size = data.len() * std::mem::size_of::(); + let buffer = unsafe { + std::slice::from_raw_parts(data.as_ptr() as *const u8, buffer_byte_size) + }; + self.memory.unwrap().write( + self.store.as_mut().unwrap(), + offset, + buffer, + ).map_err(|_| DandelionError::InvalidWrite) + } + fn read(&self, offset: usize, read_buffer: &mut [T]) -> DandelionResult<()> { + let buffer_byte_size = read_buffer.len() * std::mem::size_of::(); + let buffer = unsafe { + std::slice::from_raw_parts_mut(read_buffer.as_mut_ptr() as *mut u8, buffer_byte_size) + }; + self.memory.unwrap().read( + self.store.as_ref().unwrap(), + offset, + buffer, + ).map_err(|_| DandelionError::InvalidRead) + } +} + +#[derive(Debug)] +pub struct WasmtimeMemoryDomain {} + +impl MemoryDomain for WasmtimeMemoryDomain { + fn init(_config: Vec) -> DandelionResult> { + Ok(Box::new(WasmtimeMemoryDomain {})) + } + fn acquire_context(&self, size: usize) -> DandelionResult { + if size > MAX_WASM_MEMORY_SIZE { + return Err(DandelionError::InvalidMemorySize); + } + let size = (size + WASM_PAGE_SIZE - 1) & !(WASM_PAGE_SIZE - 1); // round up to next page + // use default wasmtime engine + let engine = Engine::default(); + let pages = size / WASM_PAGE_SIZE; + let mut store = Store::new(&engine, ()); + let mem_type = MemoryType::new(pages as u32, Some(pages as u32)); + let memory = Some( + Memory::new(&mut store, mem_type) + .map_err(|_| DandelionError::OutOfMemory)? + ); + Ok(Context::new( + ContextType::Wasmtime(Box::new( + WasmtimeContext { + store: Some(store), + module: None, + memory, + } + )), + size + )) + } +} + +pub fn wasmtime_transfer( + destination: &mut WasmtimeContext, + source: &WasmtimeContext, + destination_offset: usize, + source_offset: usize, + size: usize, +) -> DandelionResult<()> { + + if source.memory.is_none() || destination.memory.is_none() + || source_offset + size > source.memory.unwrap().data_size(source.store.as_ref().unwrap()) + || destination_offset + size > destination.memory.unwrap().data_size(destination.store.as_ref().unwrap()) + { + return Err(DandelionError::InvalidRead); + } + + destination.memory.unwrap() + .data_mut(destination.store.as_mut().unwrap())[destination_offset..destination_offset+size] + .copy_from_slice( + &source.memory.unwrap() + .data(source.store.as_ref().unwrap())[source_offset..source_offset+size] + ); + + Ok(()) +} \ No newline at end of file diff --git a/machine_interface/tests/data/test_sysld_wasm_aarch64_basic b/machine_interface/tests/data/test_sysld_wasm_aarch64_basic index 011cc242..74259cfb 100755 Binary files a/machine_interface/tests/data/test_sysld_wasm_aarch64_basic and b/machine_interface/tests/data/test_sysld_wasm_aarch64_basic differ diff --git a/machine_interface/tests/data/test_sysld_wasm_aarch64_busy b/machine_interface/tests/data/test_sysld_wasm_aarch64_busy index 95745f28..9cd27c51 100755 Binary files a/machine_interface/tests/data/test_sysld_wasm_aarch64_busy and b/machine_interface/tests/data/test_sysld_wasm_aarch64_busy differ diff --git a/machine_interface/tests/data/test_sysld_wasm_aarch64_matmac b/machine_interface/tests/data/test_sysld_wasm_aarch64_matmac index 35c54b38..1bbf21aa 100755 Binary files a/machine_interface/tests/data/test_sysld_wasm_aarch64_matmac and b/machine_interface/tests/data/test_sysld_wasm_aarch64_matmac differ diff --git a/machine_interface/tests/data/test_sysld_wasm_aarch64_matmul b/machine_interface/tests/data/test_sysld_wasm_aarch64_matmul index 200f314d..befc1a59 100755 Binary files a/machine_interface/tests/data/test_sysld_wasm_aarch64_matmul and b/machine_interface/tests/data/test_sysld_wasm_aarch64_matmul differ diff --git a/machine_interface/tests/data/test_sysld_wasm_x86_64_basic b/machine_interface/tests/data/test_sysld_wasm_x86_64_basic index 7f6fec10..438b367f 100755 Binary files a/machine_interface/tests/data/test_sysld_wasm_x86_64_basic and b/machine_interface/tests/data/test_sysld_wasm_x86_64_basic differ diff --git a/machine_interface/tests/data/test_sysld_wasm_x86_64_busy b/machine_interface/tests/data/test_sysld_wasm_x86_64_busy index 0a6c8b83..e8cc6cbd 100755 Binary files a/machine_interface/tests/data/test_sysld_wasm_x86_64_busy and b/machine_interface/tests/data/test_sysld_wasm_x86_64_busy differ diff --git a/machine_interface/tests/data/test_sysld_wasm_x86_64_matmac b/machine_interface/tests/data/test_sysld_wasm_x86_64_matmac index dd62f071..184cda88 100755 Binary files a/machine_interface/tests/data/test_sysld_wasm_x86_64_matmac and b/machine_interface/tests/data/test_sysld_wasm_x86_64_matmac differ diff --git a/machine_interface/tests/data/test_sysld_wasm_x86_64_matmul b/machine_interface/tests/data/test_sysld_wasm_x86_64_matmul index 5a7b7a31..21cef16e 100755 Binary files a/machine_interface/tests/data/test_sysld_wasm_x86_64_matmul and b/machine_interface/tests/data/test_sysld_wasm_x86_64_matmul differ diff --git a/machine_interface/tests/data/test_wasm_basic b/machine_interface/tests/data/test_wasm_basic new file mode 100755 index 00000000..5a666b10 Binary files /dev/null and b/machine_interface/tests/data/test_wasm_basic differ diff --git a/machine_interface/tests/data/test_wasm_busy b/machine_interface/tests/data/test_wasm_busy new file mode 100755 index 00000000..a2550994 Binary files /dev/null and b/machine_interface/tests/data/test_wasm_busy differ diff --git a/machine_interface/tests/data/test_wasm_matmac b/machine_interface/tests/data/test_wasm_matmac new file mode 100755 index 00000000..902beba7 Binary files /dev/null and b/machine_interface/tests/data/test_wasm_matmac differ diff --git a/machine_interface/tests/data/test_wasm_matmul b/machine_interface/tests/data/test_wasm_matmul new file mode 100755 index 00000000..706f022c Binary files /dev/null and b/machine_interface/tests/data/test_wasm_matmul differ diff --git a/machine_interface/tests/data/test_wasmtime_aarch64_basic b/machine_interface/tests/data/test_wasmtime_aarch64_basic new file mode 100644 index 00000000..a05d5213 Binary files /dev/null and b/machine_interface/tests/data/test_wasmtime_aarch64_basic differ diff --git a/machine_interface/tests/data/test_wasmtime_aarch64_busy b/machine_interface/tests/data/test_wasmtime_aarch64_busy new file mode 100644 index 00000000..44295cd9 Binary files /dev/null and b/machine_interface/tests/data/test_wasmtime_aarch64_busy differ diff --git a/machine_interface/tests/data/test_wasmtime_aarch64_matmac b/machine_interface/tests/data/test_wasmtime_aarch64_matmac new file mode 100644 index 00000000..1eea8b16 Binary files /dev/null and b/machine_interface/tests/data/test_wasmtime_aarch64_matmac differ diff --git a/machine_interface/tests/data/test_wasmtime_aarch64_matmul b/machine_interface/tests/data/test_wasmtime_aarch64_matmul new file mode 100644 index 00000000..27d6cd7e Binary files /dev/null and b/machine_interface/tests/data/test_wasmtime_aarch64_matmul differ diff --git a/machine_interface/tests/data/test_wasmtime_x86_64_basic b/machine_interface/tests/data/test_wasmtime_x86_64_basic new file mode 100644 index 00000000..a05d5213 Binary files /dev/null and b/machine_interface/tests/data/test_wasmtime_x86_64_basic differ diff --git a/machine_interface/tests/data/test_wasmtime_x86_64_busy b/machine_interface/tests/data/test_wasmtime_x86_64_busy new file mode 100644 index 00000000..44295cd9 Binary files /dev/null and b/machine_interface/tests/data/test_wasmtime_x86_64_busy differ diff --git a/machine_interface/tests/data/test_wasmtime_x86_64_matmac b/machine_interface/tests/data/test_wasmtime_x86_64_matmac new file mode 100644 index 00000000..1eea8b16 Binary files /dev/null and b/machine_interface/tests/data/test_wasmtime_x86_64_matmac differ diff --git a/machine_interface/tests/data/test_wasmtime_x86_64_matmul b/machine_interface/tests/data/test_wasmtime_x86_64_matmul new file mode 100644 index 00000000..27d6cd7e Binary files /dev/null and b/machine_interface/tests/data/test_wasmtime_x86_64_matmul differ diff --git a/server/Cargo.toml b/server/Cargo.toml index dec27721..e562d39c 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -26,4 +26,6 @@ reqwest = { version = "0.11", default-features = false, features = ["blocking"] cheri = ["machine_interface/cheri"] mmu = ["machine_interface/mmu"] wasm = ["machine_interface/wasm"] +wasmtime-jit = ["machine_interface/wasmtime-jit"] +wasmtime-precomp = ["machine_interface/wasmtime-precomp"] hyper_io = ["machine_interface/hyper_io"] \ No newline at end of file diff --git a/server/src/main.rs b/server/src/main.rs index d4faf5e5..b7f9089a 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -25,7 +25,7 @@ use machine_interface::{ #[cfg(feature = "hyper_io")] use machine_interface::function_driver::system_driver::hyper::HyperDriver; -#[cfg(any(feature = "cheri", feature = "mmu", feature = "wasm"))] +#[cfg(any(feature = "cheri", feature = "mmu", feature = "wasm", feature = "wasmtime-jit", feature = "wasmtime-precomp"))] use machine_interface::{ function_driver::Driver, memory_domain::{Context, ContextTrait, MemoryDomain}, @@ -47,7 +47,13 @@ use machine_interface::{ function_driver::compute_driver::wasm::WasmDriver, memory_domain::wasm::WasmMemoryDomain, }; -#[cfg(not(any(feature = "cheri", feature = "mmu", feature = "wasm")))] +#[cfg(any(feature = "wasmtime-jit", feature = "wasmtime-precomp"))] +use machine_interface::{ + function_driver::compute_driver::wasmtime::WasmtimeDriver, + memory_domain::wasmtime::WasmtimeMemoryDomain, +}; + +#[cfg(not(any(feature = "cheri", feature = "mmu", feature = "wasm", feature = "wasmtime-jit", feature = "wasmtime-precomp")))] use machine_interface::{ memory_domain::{Context, ContextTrait, MemoryDomain}, DataItem, DataSet, Position, @@ -525,10 +531,10 @@ fn main() -> () { ); let mut registry; // insert specific configuration - #[cfg(all(feature = "cheri", feature = "mmu", feature = "wasm"))] + #[cfg(all(feature = "cheri", feature = "mmu", feature = "wasm", feature = "wasmtime-jit", feature = "wasmtime-precomp"))] std::compile_error!("Should only have one feature out of mmu or cheri or wasm"); #[cfg(all( - any(feature = "cheri", feature = "mmu", feature = "wasm"), + any(feature = "cheri", feature = "mmu", feature = "wasm", feature = "wasmtime-jit", feature = "wasmtime-precomp"), feature = "hyper_io" ))] { @@ -578,6 +584,40 @@ fn main() -> () { std::env::consts::ARCH )); } + #[cfg(feature = "wasmtime-jit")] + { + domains.insert( + COMPUTE_DOMAIN, + WasmtimeMemoryDomain::init(Vec::new()).expect("Should be able to initialize domain"), + ); + driver = Box::new(WasmtimeDriver {}) as Box; + mmm_path.push(format!( + "../machine_interface/tests/data/test_wasm_matmul", + )); + busy_path.push(format!( + "../machine_interface/tests/data/test_wasm_busy", + )); + #[cfg(feature = "wasmtime-precomp")] + panic!("Should only have one feature out of wasmtime-jit or wasmtime-precomp"); + } + #[cfg(feature = "wasmtime-precomp")] + { + domains.insert( + COMPUTE_DOMAIN, + WasmtimeMemoryDomain::init(Vec::new()).expect("Should be able to initialize domain"), + ); + driver = Box::new(WasmtimeDriver {}) as Box; + mmm_path.push(format!( + "../machine_interface/tests/data/test_wasmtime_{}_matmul", + std::env::consts::ARCH + )); + busy_path.push(format!( + "../machine_interface/tests/data/test_wasmtime_{}_busy", + std::env::consts::ARCH + )); + #[cfg(feature = "wasmtime-jit")] + panic!("Should only have one feature out of wasmtime-jit or wasmtime-precomp"); + } let system_driver = Box::new(HyperDriver {}); drivers.insert(COMPUTE_ENGINE, driver); drivers.insert(SYS_ENGINE, system_driver); @@ -734,7 +774,7 @@ fn main() -> () { } } #[cfg(not(all( - any(feature = "cheri", feature = "mmu", feature = "wasm"), + any(feature = "cheri", feature = "mmu", feature = "wasm", feature = "wasmtime-jit", feature = "wasmtime-precomp"), feature = "hyper_io" )))] { @@ -769,7 +809,11 @@ fn main() -> () { println!("Hello, World (mmu)"); #[cfg(feature = "wasm")] println!("Hello, World (wasm)"); - #[cfg(not(any(feature = "cheri", feature = "mmu", feature = "wasm")))] + #[cfg(feature = "wasmtime-jit")] + println!("Hello, World (wasmtime-jit)"); + #[cfg(feature = "wasmtime-precomp")] + println!("Hello, World (wasmtime-precomp)"); + #[cfg(not(any(feature = "cheri", feature = "mmu", feature = "wasm", feature = "wasmtime-jit", feature = "wasmtime-precomp")))] println!("Hello, World (native)"); // Run this server for... forever! if let Err(e) = runtime.block_on(server) {