From aca9e936738203b2ad97da3ca3c32839359e6c90 Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Wed, 1 Jun 2022 15:43:07 +0200 Subject: [PATCH] Migrate wasmer-cli to new Context API --- lib/cli/src/commands/run.rs | 130 ++++++++++++++---------- lib/cli/src/commands/run/wasi.rs | 23 +++-- lib/cli/src/commands/wast.rs | 4 +- lib/emscripten/src/emscripten_target.rs | 4 +- lib/emscripten/src/env/mod.rs | 2 +- lib/emscripten/src/lib.rs | 20 ++-- lib/emscripten/src/memory.rs | 6 +- lib/emscripten/src/syscalls/unix.rs | 3 +- lib/emscripten/src/utils.rs | 11 +- 9 files changed, 127 insertions(+), 76 deletions(-) diff --git a/lib/cli/src/commands/run.rs b/lib/cli/src/commands/run.rs index ec7b81a2cfc..0e9c5adb1c3 100644 --- a/lib/cli/src/commands/run.rs +++ b/lib/cli/src/commands/run.rs @@ -7,9 +7,11 @@ use crate::warning; use anyhow::{anyhow, Context, Result}; use std::path::PathBuf; use std::str::FromStr; +use wasmer::Context as WasmerContext; use wasmer::*; #[cfg(feature = "cache")] use wasmer_cache::{Cache, FileSystemCache, Hash}; +use wasmer_types::Type as ValueType; use structopt::StructOpt; @@ -95,6 +97,41 @@ impl Run { }) } + fn inner_run(&self, mut ctx: WasmerContext, instance: Instance) -> Result<()> { + let module = self.get_module()?; + // If this module exports an _initialize function, run that first. + if let Ok(initialize) = instance.exports.get_function("_initialize") { + initialize + .call(&mut ctx, &[]) + .with_context(|| "failed to run _initialize function")?; + } + + // Do we want to invoke a function? + if let Some(ref invoke) = self.invoke { + let imports = imports! {}; + let instance = Instance::new(&mut ctx, &module, &imports)?; + let result = + self.invoke_function(&mut ctx.as_context_mut(), &instance, &invoke, &self.args)?; + println!( + "{}", + result + .iter() + .map(|val| val.to_string()) + .collect::>() + .join(" ") + ); + } else { + let start: Function = self.try_find_function(&instance, "_start", &[])?; + let result = start.call(&mut ctx, &[]); + #[cfg(feature = "wasi")] + self.wasi.handle_result(result)?; + #[cfg(not(feature = "wasi"))] + result?; + } + + Ok(()) + } + fn inner_execute(&self) -> Result<()> { let module = self.get_module()?; #[cfg(feature = "emscripten")] @@ -108,12 +145,19 @@ impl Run { if self.invoke.is_some() { bail!("--invoke is not supported with emscripten modules"); } - let mut emscripten_globals = EmscriptenGlobals::new(module.store(), &module) + // create an EmEnv with default global + let mut ctx = WasmerContext::new(module.store(), EmEnv::new()); + let mut emscripten_globals = EmscriptenGlobals::new(ctx.as_context_mut(), &module) .map_err(|e| anyhow!("{}", e))?; - let mut em_env = EmEnv::new(&emscripten_globals.data, Default::default()); + ctx.data_mut() + .set_data(&emscripten_globals.data, Default::default()); let import_object = - generate_emscripten_env(module.store(), &mut emscripten_globals, &em_env); - let mut instance = match Instance::new(&module, &import_object) { + generate_emscripten_env(&mut ctx.as_context_mut(), &mut emscripten_globals); + let mut instance = match Instance::new( + &mut ctx.as_context_mut(), + &module, + &import_object, + ) { Ok(instance) => instance, Err(e) => { let err: Result<(), _> = Err(e); @@ -129,7 +173,7 @@ impl Run { run_emscripten_instance( &mut instance, - &mut em_env, + ctx.as_context_mut(), &mut emscripten_globals, if let Some(cn) = &self.command_name { cn @@ -145,7 +189,7 @@ impl Run { // If WASI is enabled, try to execute it with it #[cfg(feature = "wasi")] - let instance = { + let ret = { use std::collections::BTreeSet; use wasmer_wasi::WasiVersion; @@ -178,47 +222,28 @@ impl Run { .map(|f| f.to_string_lossy().to_string()) }) .unwrap_or_default(); - self.wasi + let (ctx, instance) = self + .wasi .instantiate(&module, program_name, self.args.clone()) - .with_context(|| "failed to instantiate WASI module")? + .with_context(|| "failed to instantiate WASI module")?; + self.inner_run(ctx, instance) } // not WASI - _ => Instance::new(&module, &imports! {})?, + _ => { + let mut ctx = WasmerContext::new(module.store(), ()); + let instance = Instance::new(&mut ctx, &module, &imports! {})?; + self.inner_run(ctx, instance) + } } }; #[cfg(not(feature = "wasi"))] - let instance = Instance::new(&module, &imports! {})?; - - // If this module exports an _initialize function, run that first. - if let Ok(initialize) = instance.exports.get_function("_initialize") { - initialize - .call(&[]) - .with_context(|| "failed to run _initialize function")?; - } - - // Do we want to invoke a function? - if let Some(ref invoke) = self.invoke { - let imports = imports! {}; - let instance = Instance::new(&module, &imports)?; - let result = self.invoke_function(&instance, invoke, &self.args)?; - println!( - "{}", - result - .iter() - .map(|val| val.to_string()) - .collect::>() - .join(" ") - ); - } else { - let start: Function = self.try_find_function(&instance, "_start", &[])?; - let result = start.call(&[]); - #[cfg(feature = "wasi")] - self.wasi.handle_result(result)?; - #[cfg(not(feature = "wasi"))] - result?; - } + let ret = { + let mut ctx = WasmerContext::new(module.store(), ()); + let instance = Instance::new(&mut ctx, &module, &imports! {})?; + self.inner_run(ctx, instance) + }; - Ok(()) + ret } fn get_module(&self) -> Result { @@ -353,12 +378,13 @@ impl Run { fn invoke_function( &self, + ctx: &mut impl AsContextMut, instance: &Instance, invoke: &str, args: &[String], - ) -> Result> { - let func: Function = self.try_find_function(instance, invoke, args)?; - let func_ty = func.ty(); + ) -> Result> { + let func: Function = self.try_find_function(&instance, invoke, args)?; + let func_ty = func.ty(ctx); let required_arguments = func_ty.params().len(); let provided_arguments = args.len(); if required_arguments != provided_arguments { @@ -373,23 +399,23 @@ impl Run { .iter() .zip(func_ty.params().iter()) .map(|(arg, param_type)| match param_type { - ValType::I32 => { - Ok(Val::I32(arg.parse().map_err(|_| { + ValueType::I32 => { + Ok(Value::I32(arg.parse().map_err(|_| { anyhow!("Can't convert `{}` into a i32", arg) })?)) } - ValType::I64 => { - Ok(Val::I64(arg.parse().map_err(|_| { + ValueType::I64 => { + Ok(Value::I64(arg.parse().map_err(|_| { anyhow!("Can't convert `{}` into a i64", arg) })?)) } - ValType::F32 => { - Ok(Val::F32(arg.parse().map_err(|_| { + ValueType::F32 => { + Ok(Value::F32(arg.parse().map_err(|_| { anyhow!("Can't convert `{}` into a f32", arg) })?)) } - ValType::F64 => { - Ok(Val::F64(arg.parse().map_err(|_| { + ValueType::F64 => { + Ok(Value::F64(arg.parse().map_err(|_| { anyhow!("Can't convert `{}` into a f64", arg) })?)) } @@ -400,7 +426,7 @@ impl Run { )), }) .collect::>>()?; - Ok(func.call(&invoke_args)?) + Ok(func.call(ctx, &invoke_args)?) } /// Create Run instance for arguments/env, diff --git a/lib/cli/src/commands/run/wasi.rs b/lib/cli/src/commands/run/wasi.rs index f7e19820791..60be4660e33 100644 --- a/lib/cli/src/commands/run/wasi.rs +++ b/lib/cli/src/commands/run/wasi.rs @@ -2,8 +2,11 @@ use crate::utils::{parse_envvar, parse_mapdir}; use anyhow::Result; use std::collections::BTreeSet; use std::path::PathBuf; -use wasmer::{Instance, Module, RuntimeError, Val}; -use wasmer_wasi::{get_wasi_versions, is_wasix_module, WasiError, WasiState, WasiVersion}; +use wasmer::{AsContextMut, Context, Instance, Module, RuntimeError, Value}; +use wasmer_wasi::{ + get_wasi_versions, import_object_for_all_wasi_versions, is_wasix_module, WasiEnv, WasiError, + WasiState, WasiVersion, +}; use structopt::StructOpt; @@ -78,7 +81,7 @@ impl Wasi { module: &Module, program_name: String, args: Vec, - ) -> Result { + ) -> Result<(Context, Instance)> { let args = args.iter().cloned().map(|arg| arg.into_bytes()); let mut wasi_state_builder = WasiState::new(program_name); @@ -96,19 +99,21 @@ impl Wasi { } } - let mut wasi_env = wasi_state_builder.finalize()?; + let wasi_env = wasi_state_builder.finalize()?; wasi_env.state.fs.is_wasix.store( is_wasix_module(module), std::sync::atomic::Ordering::Release, ); - - let import_object = wasi_env.import_object_for_all_wasi_versions(module)?; - let instance = Instance::new(module, &import_object)?; - Ok(instance) + let mut ctx = Context::new(module.store(), wasi_env.clone()); + let import_object = import_object_for_all_wasi_versions(&mut ctx.as_context_mut()); + let instance = Instance::new(&mut ctx, &module, &import_object)?; + let memory = instance.exports.get_memory("memory")?; + ctx.data_mut().set_memory(memory.clone()); + Ok((ctx, instance)) } /// Helper function for handling the result of a Wasi _start function. - pub fn handle_result(&self, result: Result, RuntimeError>) -> Result<()> { + pub fn handle_result(&self, result: Result, RuntimeError>) -> Result<()> { match result { Ok(_) => Ok(()), Err(err) => { diff --git a/lib/cli/src/commands/wast.rs b/lib/cli/src/commands/wast.rs index 580bdb205e1..5dd0352c4d1 100644 --- a/lib/cli/src/commands/wast.rs +++ b/lib/cli/src/commands/wast.rs @@ -3,6 +3,7 @@ use crate::store::StoreOptions; use anyhow::{Context, Result}; use std::path::PathBuf; use structopt::StructOpt; +use wasmer::Context as WasmerContext; use wasmer_wast::Wast as WastSpectest; #[derive(Debug, StructOpt)] @@ -28,7 +29,8 @@ impl Wast { } fn inner_execute(&self) -> Result<()> { let (store, _compiler_name) = self.store.get_store()?; - let mut wast = WastSpectest::new_with_spectest(store); + let ctx = WasmerContext::new(&store, ()); + let mut wast = WastSpectest::new_with_spectest(ctx); wast.fail_fast = self.fail_fast; wast.run_file(&self.path).with_context(|| "tests failed")?; eprintln!("Wast tests succeeded for `{}`.", self.path.display()); diff --git a/lib/emscripten/src/emscripten_target.rs b/lib/emscripten/src/emscripten_target.rs index e299e862b7c..4bf614c40f1 100644 --- a/lib/emscripten/src/emscripten_target.rs +++ b/lib/emscripten/src/emscripten_target.rs @@ -17,12 +17,12 @@ pub fn exit_with_live_runtime(_ctx: ContextMut<'_, EmEnv>) { pub fn setTempRet0(ctx: ContextMut<'_, EmEnv>, val: i32) { trace!("emscripten::setTempRet0: {}", val); - get_emscripten_data(&ctx).temp_ret_0 = val; + get_emscripten_data(&ctx).as_mut().unwrap().temp_ret_0 = val; } pub fn getTempRet0(ctx: ContextMut<'_, EmEnv>) -> i32 { trace!("emscripten::getTempRet0"); - get_emscripten_data(&ctx).temp_ret_0 + get_emscripten_data(&ctx).as_ref().unwrap().temp_ret_0 } pub fn _alarm(_ctx: ContextMut<'_, EmEnv>, _seconds: u32) -> i32 { diff --git a/lib/emscripten/src/env/mod.rs b/lib/emscripten/src/env/mod.rs index 5985293941b..fa7c1ab1edc 100644 --- a/lib/emscripten/src/env/mod.rs +++ b/lib/emscripten/src/env/mod.rs @@ -45,7 +45,7 @@ pub fn call_memset(mut ctx: ContextMut<'_, EmEnv>, pointer: u32, value: u32, siz pub(crate) fn get_emscripten_data<'a>( ctx: &'a ContextMut<'_, EmEnv>, -) -> MutexGuard<'a, EmscriptenData> { +) -> MutexGuard<'a, Option> { ctx.data().data.lock().unwrap() } diff --git a/lib/emscripten/src/lib.rs b/lib/emscripten/src/lib.rs index 855662a8cb3..33624b2f617 100644 --- a/lib/emscripten/src/lib.rs +++ b/lib/emscripten/src/lib.rs @@ -76,15 +76,16 @@ pub use self::utils::{ /// The environment provided to the Emscripten imports. pub struct EmEnv { memory: Arc>>, - data: Arc>, + data: Arc>>, funcs: Arc>, } impl EmEnv { - pub fn new(data: &EmscriptenGlobalsData, mapped_dirs: HashMap) -> Self { + /// Create a new EmEnv, with default value to be set later (set_memory, set_functions and set_data) + pub fn new() -> Self { Self { memory: Arc::new(RwLock::new(None)), - data: Arc::new(Mutex::new(EmscriptenData::new(data.clone(), mapped_dirs))), + data: Arc::new(Mutex::new(None)), funcs: Arc::new(Mutex::new(EmscriptenFunctions::new())), } } @@ -103,11 +104,14 @@ impl EmEnv { self.funcs = Arc::new(Mutex::new(funcs)); } - // pub fn init_with_instance(&mut self, instance: &Instance) -> Result<(), wasmer::HostEnvInitError> { - // let mut ed = self.data.lock().unwrap(); - // ed.init_with_instance(instance)?; - // Ok(()) - // } + pub fn set_data( + &mut self, + data: &EmscriptenGlobalsData, + mapped_dirs: HashMap, + ) { + let mut w = self.data.lock().unwrap(); + *w = Some(EmscriptenData::new(data.clone(), mapped_dirs)); + } } #[derive(Debug, Clone)] diff --git a/lib/emscripten/src/memory.rs b/lib/emscripten/src/memory.rs index eccf2d8b5c7..065aaaec429 100644 --- a/lib/emscripten/src/memory.rs +++ b/lib/emscripten/src/memory.rs @@ -88,7 +88,11 @@ pub fn sbrk(mut ctx: ContextMut<'_, EmEnv>, increment: i32) -> i32 { // let old_dynamic_top = 0; // let new_dynamic_top = 0; let memory = ctx.data().memory(0); - let top_ptr = get_emscripten_data(&ctx).globals.dynamictop_ptr; + let top_ptr = get_emscripten_data(&ctx) + .as_ref() + .unwrap() + .globals + .dynamictop_ptr; let dynamictop_ptr = WasmPtr::::new(top_ptr).deref(&ctx, &memory); let old_dynamic_top = dynamictop_ptr.read().unwrap(); let new_dynamic_top: i32 = old_dynamic_top + increment; diff --git a/lib/emscripten/src/syscalls/unix.rs b/lib/emscripten/src/syscalls/unix.rs index 109fb25d6c0..ea402a33a63 100644 --- a/lib/emscripten/src/syscalls/unix.rs +++ b/lib/emscripten/src/syscalls/unix.rs @@ -1059,7 +1059,8 @@ pub fn ___syscall220(ctx: ContextMut<'_, EmEnv>, _which: i32, mut varargs: VarAr let dirp = emscripten_memory_pointer!(ctx, ctx.data().memory(0), dirp_addr) as *mut u8; - let opened_dirs = &mut get_emscripten_data(&ctx).opened_dirs; + let data = &mut get_emscripten_data(&ctx); + let opened_dirs = &mut data.as_mut().unwrap().opened_dirs; // need to persist stream across calls? // let dir: *mut libc::DIR = unsafe { libc::fdopendir(fd) }; diff --git a/lib/emscripten/src/utils.rs b/lib/emscripten/src/utils.rs index b881f88eea6..303c277fa87 100644 --- a/lib/emscripten/src/utils.rs +++ b/lib/emscripten/src/utils.rs @@ -258,6 +258,8 @@ pub fn get_cstr_path(ctx: ContextMut<'_, EmEnv>, path: *const i8) -> Option, path: *const i8) -> Option) -> Option { - if let Some(val) = get_emscripten_data(&ctx).mapped_dirs.get(".") { + if let Some(val) = get_emscripten_data(&ctx) + .as_ref() + .unwrap() + .mapped_dirs + .get(".") + { return Some(val.clone()); } std::env::current_dir() .map(|cwd| { if let Some(val) = get_emscripten_data(&ctx) + .as_ref() + .unwrap() .mapped_dirs .get(&cwd.to_string_lossy().to_string()) {