Migrate wasmer-cli to new Context API

This commit is contained in:
ptitSeb
2022-06-01 15:43:07 +02:00
committed by Manos Pitsidianakis
parent cf85615e55
commit bc58b713db
9 changed files with 133 additions and 76 deletions

View File

@@ -7,9 +7,11 @@ use crate::warning;
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use std::path::PathBuf; use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
use wasmer::Context as WasmerContext;
use wasmer::*; use wasmer::*;
#[cfg(feature = "cache")] #[cfg(feature = "cache")]
use wasmer_cache::{Cache, FileSystemCache, Hash}; use wasmer_cache::{Cache, FileSystemCache, Hash};
use wasmer_types::Type as ValueType;
use structopt::StructOpt; use structopt::StructOpt;
@@ -95,6 +97,41 @@ impl Run {
}) })
} }
fn inner_run<T>(&self, mut ctx: WasmerContext<T>, 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::<Vec<String>>()
.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<()> { fn inner_execute(&self) -> Result<()> {
let module = self.get_module()?; let module = self.get_module()?;
#[cfg(feature = "emscripten")] #[cfg(feature = "emscripten")]
@@ -105,12 +142,19 @@ impl Run {
}; };
// TODO: refactor this // TODO: refactor this
if is_emscripten_module(&module) { if is_emscripten_module(&module) {
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))?; .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 = let import_object =
generate_emscripten_env(module.store(), &mut emscripten_globals, &em_env); generate_emscripten_env(&mut ctx.as_context_mut(), &mut emscripten_globals);
let mut instance = match Instance::new(&module, &import_object) { let mut instance = match Instance::new(
&mut ctx.as_context_mut(),
&module,
&import_object,
) {
Ok(instance) => instance, Ok(instance) => instance,
Err(e) => { Err(e) => {
let err: Result<(), _> = Err(e); let err: Result<(), _> = Err(e);
@@ -126,7 +170,7 @@ impl Run {
run_emscripten_instance( run_emscripten_instance(
&mut instance, &mut instance,
&mut em_env, ctx.as_context_mut(),
&mut emscripten_globals, &mut emscripten_globals,
if let Some(cn) = &self.command_name { if let Some(cn) = &self.command_name {
cn cn
@@ -142,7 +186,7 @@ impl Run {
// If WASI is enabled, try to execute it with it // If WASI is enabled, try to execute it with it
#[cfg(feature = "wasi")] #[cfg(feature = "wasi")]
let instance = { let ret = {
use std::collections::BTreeSet; use std::collections::BTreeSet;
use wasmer_wasi::WasiVersion; use wasmer_wasi::WasiVersion;
@@ -175,47 +219,28 @@ impl Run {
.map(|f| f.to_string_lossy().to_string()) .map(|f| f.to_string_lossy().to_string())
}) })
.unwrap_or_default(); .unwrap_or_default();
self.wasi let (ctx, instance) = self
.wasi
.instantiate(&module, program_name, self.args.clone()) .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 // 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"))] #[cfg(not(feature = "wasi"))]
let instance = Instance::new(&module, &imports! {})?; let ret = {
let mut ctx = WasmerContext::new(module.store(), ());
let instance = Instance::new(&mut ctx, &module, &imports! {})?;
self.inner_run(ctx, instance)
};
// If this module exports an _initialize function, run that first. ret
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::<Vec<String>>()
.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?;
}
Ok(())
} }
fn get_module(&self) -> Result<Module> { fn get_module(&self) -> Result<Module> {
@@ -350,12 +375,13 @@ impl Run {
fn invoke_function( fn invoke_function(
&self, &self,
ctx: &mut impl AsContextMut,
instance: &Instance, instance: &Instance,
invoke: &str, invoke: &str,
args: &[String], args: &[String],
) -> Result<Box<[Val]>> { ) -> Result<Box<[Value]>> {
let func: Function = self.try_find_function(instance, invoke, args)?; let func: Function = self.try_find_function(&instance, invoke, args)?;
let func_ty = func.ty(); let func_ty = func.ty(ctx);
let required_arguments = func_ty.params().len(); let required_arguments = func_ty.params().len();
let provided_arguments = args.len(); let provided_arguments = args.len();
if required_arguments != provided_arguments { if required_arguments != provided_arguments {
@@ -370,23 +396,23 @@ impl Run {
.iter() .iter()
.zip(func_ty.params().iter()) .zip(func_ty.params().iter())
.map(|(arg, param_type)| match param_type { .map(|(arg, param_type)| match param_type {
ValType::I32 => { ValueType::I32 => {
Ok(Val::I32(arg.parse().map_err(|_| { Ok(Value::I32(arg.parse().map_err(|_| {
anyhow!("Can't convert `{}` into a i32", arg) anyhow!("Can't convert `{}` into a i32", arg)
})?)) })?))
} }
ValType::I64 => { ValueType::I64 => {
Ok(Val::I64(arg.parse().map_err(|_| { Ok(Value::I64(arg.parse().map_err(|_| {
anyhow!("Can't convert `{}` into a i64", arg) anyhow!("Can't convert `{}` into a i64", arg)
})?)) })?))
} }
ValType::F32 => { ValueType::F32 => {
Ok(Val::F32(arg.parse().map_err(|_| { Ok(Value::F32(arg.parse().map_err(|_| {
anyhow!("Can't convert `{}` into a f32", arg) anyhow!("Can't convert `{}` into a f32", arg)
})?)) })?))
} }
ValType::F64 => { ValueType::F64 => {
Ok(Val::F64(arg.parse().map_err(|_| { Ok(Value::F64(arg.parse().map_err(|_| {
anyhow!("Can't convert `{}` into a f64", arg) anyhow!("Can't convert `{}` into a f64", arg)
})?)) })?))
} }
@@ -397,7 +423,7 @@ impl Run {
)), )),
}) })
.collect::<Result<Vec<_>>>()?; .collect::<Result<Vec<_>>>()?;
Ok(func.call(&invoke_args)?) Ok(func.call(ctx, &invoke_args)?)
} }
/// Create Run instance for arguments/env, /// Create Run instance for arguments/env,

View File

@@ -2,8 +2,11 @@ use crate::utils::{parse_envvar, parse_mapdir};
use anyhow::Result; use anyhow::Result;
use std::collections::BTreeSet; use std::collections::BTreeSet;
use std::path::PathBuf; use std::path::PathBuf;
use wasmer::{Instance, Module, RuntimeError, Val}; use wasmer::{AsContextMut, Context, Instance, Module, RuntimeError, Value};
use wasmer_wasi::{get_wasi_versions, is_wasix_module, WasiError, WasiState, WasiVersion}; use wasmer_wasi::{
get_wasi_versions, import_object_for_all_wasi_versions, is_wasix_module, WasiEnv, WasiError,
WasiState, WasiVersion,
};
use structopt::StructOpt; use structopt::StructOpt;
@@ -78,7 +81,7 @@ impl Wasi {
module: &Module, module: &Module,
program_name: String, program_name: String,
args: Vec<String>, args: Vec<String>,
) -> Result<Instance> { ) -> Result<(Context<WasiEnv>, Instance)> {
let args = args.iter().cloned().map(|arg| arg.into_bytes()); let args = args.iter().cloned().map(|arg| arg.into_bytes());
let mut wasi_state_builder = WasiState::new(program_name); 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( wasi_env.state.fs.is_wasix.store(
is_wasix_module(module), is_wasix_module(module),
std::sync::atomic::Ordering::Release, std::sync::atomic::Ordering::Release,
); );
let mut ctx = Context::new(module.store(), wasi_env.clone());
let import_object = wasi_env.import_object_for_all_wasi_versions(module)?; let import_object = import_object_for_all_wasi_versions(&mut ctx.as_context_mut());
let instance = Instance::new(module, &import_object)?; let instance = Instance::new(&mut ctx, &module, &import_object)?;
Ok(instance) 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. /// Helper function for handling the result of a Wasi _start function.
pub fn handle_result(&self, result: Result<Box<[Val]>, RuntimeError>) -> Result<()> { pub fn handle_result(&self, result: Result<Box<[Value]>, RuntimeError>) -> Result<()> {
match result { match result {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(err) => { Err(err) => {

View File

@@ -3,6 +3,7 @@ use crate::store::StoreOptions;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use std::path::PathBuf; use std::path::PathBuf;
use structopt::StructOpt; use structopt::StructOpt;
use wasmer::Context as WasmerContext;
use wasmer_wast::Wast as WastSpectest; use wasmer_wast::Wast as WastSpectest;
#[derive(Debug, StructOpt)] #[derive(Debug, StructOpt)]
@@ -28,7 +29,8 @@ impl Wast {
} }
fn inner_execute(&self) -> Result<()> { fn inner_execute(&self) -> Result<()> {
let (store, _compiler_name) = self.store.get_store()?; 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.fail_fast = self.fail_fast;
wast.run_file(&self.path).with_context(|| "tests failed")?; wast.run_file(&self.path).with_context(|| "tests failed")?;
eprintln!("Wast tests succeeded for `{}`.", self.path.display()); eprintln!("Wast tests succeeded for `{}`.", self.path.display());

View File

@@ -17,12 +17,12 @@ pub fn exit_with_live_runtime(_ctx: ContextMut<'_, EmEnv>) {
pub fn setTempRet0(ctx: ContextMut<'_, EmEnv>, val: i32) { pub fn setTempRet0(ctx: ContextMut<'_, EmEnv>, val: i32) {
trace!("emscripten::setTempRet0: {}", val); 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 { pub fn getTempRet0(ctx: ContextMut<'_, EmEnv>) -> i32 {
trace!("emscripten::getTempRet0"); 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 { pub fn _alarm(_ctx: ContextMut<'_, EmEnv>, _seconds: u32) -> i32 {

View File

@@ -45,7 +45,7 @@ pub fn call_memset(mut ctx: ContextMut<'_, EmEnv>, pointer: u32, value: u32, siz
pub(crate) fn get_emscripten_data<'a>( pub(crate) fn get_emscripten_data<'a>(
ctx: &'a ContextMut<'_, EmEnv>, ctx: &'a ContextMut<'_, EmEnv>,
) -> MutexGuard<'a, EmscriptenData> { ) -> MutexGuard<'a, Option<EmscriptenData>> {
ctx.data().data.lock().unwrap() ctx.data().data.lock().unwrap()
} }

View File

@@ -78,15 +78,22 @@ pub use self::utils::{
/// The environment provided to the Emscripten imports. /// The environment provided to the Emscripten imports.
pub struct EmEnv { pub struct EmEnv {
memory: Arc<RwLock<Option<Memory>>>, memory: Arc<RwLock<Option<Memory>>>,
data: Arc<Mutex<EmscriptenData>>, data: Arc<Mutex<Option<EmscriptenData>>>,
funcs: Arc<Mutex<EmscriptenFunctions>>, funcs: Arc<Mutex<EmscriptenFunctions>>,
} }
impl Default for EmEnv {
fn default() -> Self {
Self::new()
}
}
impl EmEnv { impl EmEnv {
pub fn new(data: &EmscriptenGlobalsData, mapped_dirs: HashMap<String, PathBuf>) -> Self { /// Create a new EmEnv, with default value to be set later (set_memory, set_functions and set_data)
pub fn new() -> Self {
Self { Self {
memory: Arc::new(RwLock::new(None)), 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())), funcs: Arc::new(Mutex::new(EmscriptenFunctions::new())),
} }
} }
@@ -105,11 +112,14 @@ impl EmEnv {
self.funcs = Arc::new(Mutex::new(funcs)); self.funcs = Arc::new(Mutex::new(funcs));
} }
// pub fn init_with_instance(&mut self, instance: &Instance) -> Result<(), wasmer::HostEnvInitError> { pub fn set_data(
// let mut ed = self.data.lock().unwrap(); &mut self,
// ed.init_with_instance(instance)?; data: &EmscriptenGlobalsData,
// Ok(()) mapped_dirs: HashMap<String, PathBuf>,
// } ) {
let mut w = self.data.lock().unwrap();
*w = Some(EmscriptenData::new(data.clone(), mapped_dirs));
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View File

@@ -88,7 +88,11 @@ pub fn sbrk(mut ctx: ContextMut<'_, EmEnv>, increment: i32) -> i32 {
// let old_dynamic_top = 0; // let old_dynamic_top = 0;
// let new_dynamic_top = 0; // let new_dynamic_top = 0;
let memory = ctx.data().memory(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::<i32>::new(top_ptr).deref(&ctx, &memory); let dynamictop_ptr = WasmPtr::<i32>::new(top_ptr).deref(&ctx, &memory);
let old_dynamic_top = dynamictop_ptr.read().unwrap(); let old_dynamic_top = dynamictop_ptr.read().unwrap();
let new_dynamic_top: i32 = old_dynamic_top + increment; let new_dynamic_top: i32 = old_dynamic_top + increment;

View File

@@ -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 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? // need to persist stream across calls?
// let dir: *mut libc::DIR = unsafe { libc::fdopendir(fd) }; // let dir: *mut libc::DIR = unsafe { libc::fdopendir(fd) };

View File

@@ -258,6 +258,8 @@ pub fn get_cstr_path(ctx: ContextMut<'_, EmEnv>, path: *const i8) -> Option<std:
for c in components.into_iter() { for c in components.into_iter() {
cumulative_path.push(c); cumulative_path.push(c);
if let Some(val) = data if let Some(val) = data
.as_ref()
.unwrap()
.mapped_dirs .mapped_dirs
.get(&cumulative_path.to_string_lossy().to_string()) .get(&cumulative_path.to_string_lossy().to_string())
{ {
@@ -276,12 +278,19 @@ pub fn get_cstr_path(ctx: ContextMut<'_, EmEnv>, path: *const i8) -> Option<std:
/// gets the current directory /// gets the current directory
/// handles mapdir logic /// handles mapdir logic
pub fn get_current_directory(ctx: ContextMut<'_, EmEnv>) -> Option<PathBuf> { pub fn get_current_directory(ctx: ContextMut<'_, EmEnv>) -> Option<PathBuf> {
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()); return Some(val.clone());
} }
std::env::current_dir() std::env::current_dir()
.map(|cwd| { .map(|cwd| {
if let Some(val) = get_emscripten_data(&ctx) if let Some(val) = get_emscripten_data(&ctx)
.as_ref()
.unwrap()
.mapped_dirs .mapped_dirs
.get(&cwd.to_string_lossy().to_string()) .get(&cwd.to_string_lossy().to_string())
{ {