Skip to content

Commit

Permalink
Merge pull request #2927 from wasmerio/wasmer3_emscripten_migration
Browse files Browse the repository at this point in the history
Wasmer3 emscripten migration
  • Loading branch information
ptitSeb authored Jun 2, 2022
2 parents 7cb05b7 + af270a5 commit b9b2b62
Show file tree
Hide file tree
Showing 36 changed files with 2,254 additions and 1,545 deletions.
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

0 comments on commit b9b2b62

Please sign in to comment.