Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wasmer3 emscripten migration #2927

Merged
merged 5 commits into from
Jun 2, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ wasmer-compiler = { version = "=2.2.1", path = "lib/compiler" }
wasmer-compiler-cranelift = { version = "=2.2.1", path = "lib/compiler-cranelift", optional = true }
wasmer-compiler-singlepass = { version = "=2.2.1", path = "lib/compiler-singlepass", optional = true }
wasmer-compiler-llvm = { version = "=2.2.1", path = "lib/compiler-llvm", optional = true }
#wasmer-emscripten = { version = "=2.2.1", path = "lib/emscripten", optional = true }
wasmer-emscripten = { version = "=2.2.1", path = "lib/emscripten", optional = true }
wasmer-engine = { version = "=2.2.1", path = "lib/engine" }
wasmer-engine-universal = { version = "=2.2.1", path = "lib/engine-universal", optional = true }
wasmer-engine-dylib = { version = "=2.2.1", path = "lib/engine-dylib", optional = true }
Expand Down Expand Up @@ -95,7 +95,7 @@ default = [
"staticlib",
#"cache",
"wasi",
#"emscripten",
"emscripten",
#"middlewares",
]
engine = []
Expand All @@ -105,7 +105,7 @@ staticlib = ["wasmer-engine-staticlib", "engine"]
#cache = ["wasmer-cache"]
wast = ["wasmer-wast"]
wasi = ["wasmer-wasi"]
#emscripten = ["wasmer-emscripten"]
emscripten = ["wasmer-emscripten"]
wat = ["wasmer/wat"]
compiler = [
"wasmer/compiler",
Expand Down
128 changes: 77 additions & 51 deletions lib/cli/src/commands/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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<()> {
let module = self.get_module()?;
#[cfg(feature = "emscripten")]
Expand All @@ -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, &mut 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);
Expand All @@ -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
Expand All @@ -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;

Expand Down Expand Up @@ -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::<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?;
}
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<Module> {
Expand Down Expand Up @@ -387,12 +412,13 @@ impl Run {

fn invoke_function(
&self,
ctx: &mut impl AsContextMut,
instance: &Instance,
invoke: &str,
args: &[String],
) -> Result<Box<[Val]>> {
) -> Result<Box<[Value]>> {
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 provided_arguments = args.len();
if required_arguments != provided_arguments {
Expand All @@ -407,23 +433,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)
})?))
}
Expand All @@ -434,7 +460,7 @@ impl Run {
)),
})
.collect::<Result<Vec<_>>>()?;
Ok(func.call(&invoke_args)?)
Ok(func.call(ctx, &invoke_args)?)
}

/// Create Run instance for arguments/env,
Expand Down
22 changes: 14 additions & 8 deletions lib/cli/src/commands/run/wasi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, WasiError, WasiState, WasiVersion};
use wasmer::{AsContextMut, Context, Instance, Module, RuntimeError, Value};
use wasmer_wasi::{
get_wasi_versions, import_object_for_all_wasi_versions, WasiEnv, WasiError, WasiState,
WasiVersion,
};

use structopt::StructOpt;

Expand Down Expand Up @@ -75,7 +78,7 @@ impl Wasi {
module: &Module,
program_name: String,
args: Vec<String>,
) -> Result<Instance> {
) -> Result<(Context<WasiEnv>, Instance)> {
let args = args.iter().cloned().map(|arg| arg.into_bytes());

let mut wasi_state_builder = WasiState::new(program_name);
Expand All @@ -93,14 +96,17 @@ impl Wasi {
}
}

let mut wasi_env = wasi_state_builder.finalize()?;
let import_object = wasi_env.import_object_for_all_wasi_versions(&module)?;
let instance = Instance::new(&module, &import_object)?;
Ok(instance)
let wasi_env = wasi_state_builder.finalize()?;
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<Box<[Val]>, RuntimeError>) -> Result<()> {
pub fn handle_result(&self, result: Result<Box<[Value]>, RuntimeError>) -> Result<()> {
match result {
Ok(_) => Ok(()),
Err(err) => {
Expand Down
4 changes: 3 additions & 1 deletion lib/cli/src/commands/wast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand All @@ -28,7 +29,8 @@ impl Wast {
}
fn inner_execute(&self) -> Result<()> {
let (store, _engine_name, _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());
Expand Down
1 change: 1 addition & 0 deletions lib/emscripten/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ libc = "^0.2"
log = "0.4"
time = { version = "0.2", features = ["std"] }
wasmer = { path = "../api", version = "=2.2.1", default-features = false, features = ["sys"] }
wasmer-types = { path = "../types", version = "=2.2.1" }

[target.'cfg(windows)'.dependencies]
getrandom = "0.2"
3 changes: 2 additions & 1 deletion lib/emscripten/src/bitwise.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::emscripten_target;
use crate::EmEnv;
use wasmer::ContextMut;

///emscripten: _llvm_bswap_i64
pub fn _llvm_bswap_i64(ctx: &EmEnv, _low: i32, high: i32) -> i32 {
pub fn _llvm_bswap_i64(ctx: ContextMut<'_, EmEnv>, _low: i32, high: i32) -> i32 {
debug!("emscripten::_llvm_bswap_i64");
emscripten_target::setTempRet0(ctx, _low.swap_bytes());
high.swap_bytes()
Expand Down
Loading