Better Wasmtime API for embedder (#287)
* Migrate wasm-rust-api code to wasmtime.
This commit is contained in:
committed by
Dan Gohman
parent
8ea883a603
commit
f88e92a57c
@@ -32,21 +32,24 @@
|
||||
|
||||
use cranelift_codegen::settings;
|
||||
use cranelift_codegen::settings::Configurable;
|
||||
use cranelift_native;
|
||||
use docopt::Docopt;
|
||||
use failure::{bail, format_err, Error, ResultExt};
|
||||
use failure::{bail, Error, ResultExt};
|
||||
use pretty_env_logger;
|
||||
use serde::Deserialize;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::File;
|
||||
use std::path::Component;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::exit;
|
||||
use std::rc::Rc;
|
||||
use wabt;
|
||||
use wasi_common::preopen_dir;
|
||||
use wasmtime_api::{Config, Engine, Instance, Module, Store};
|
||||
use wasmtime_environ::cache_conf;
|
||||
use wasmtime_interface_types::ModuleData;
|
||||
use wasmtime_jit::{Context, Features, InstanceHandle};
|
||||
use wasmtime_jit::Features;
|
||||
use wasmtime_wasi::instantiate_wasi;
|
||||
use wasmtime_wast::instantiate_spectest;
|
||||
|
||||
@@ -219,11 +222,12 @@ fn rmain() -> Result<(), Error> {
|
||||
args.flag_cache_dir.as_ref(),
|
||||
);
|
||||
|
||||
let isa_builder = cranelift_native::builder()
|
||||
.map_err(|s| format_err!("host machine is not a supported target: {}", s))?;
|
||||
let mut flag_builder = settings::builder();
|
||||
let mut features: Features = Default::default();
|
||||
|
||||
// Enable/disable producing of debug info.
|
||||
let debug_info = args.flag_g;
|
||||
|
||||
// Enable verifier passes in debug mode.
|
||||
if cfg!(debug_assertions) {
|
||||
flag_builder.enable("enable_verifier")?;
|
||||
@@ -240,14 +244,20 @@ fn rmain() -> Result<(), Error> {
|
||||
flag_builder.set("opt_level", "best")?;
|
||||
}
|
||||
|
||||
let isa = isa_builder.finish(settings::Flags::new(flag_builder));
|
||||
let mut context = Context::with_isa(isa).with_features(features);
|
||||
let config = Config::new(settings::Flags::new(flag_builder), features, debug_info);
|
||||
let engine = Rc::new(RefCell::new(Engine::new(config)));
|
||||
let store = Rc::new(RefCell::new(Store::new(engine)));
|
||||
|
||||
let mut module_registry = HashMap::new();
|
||||
|
||||
// Make spectest available by default.
|
||||
context.name_instance("spectest".to_owned(), instantiate_spectest()?);
|
||||
module_registry.insert(
|
||||
"spectest".to_owned(),
|
||||
Instance::from_handle(store.clone(), instantiate_spectest()?)?,
|
||||
);
|
||||
|
||||
// Make wasi available by default.
|
||||
let global_exports = context.get_global_exports();
|
||||
let global_exports = store.borrow().global_exports().clone();
|
||||
let preopen_dirs = compute_preopen_dirs(&args.flag_dir, &args.flag_mapdir);
|
||||
let argv = compute_argv(&args.arg_file, &args.arg_arg);
|
||||
let environ = compute_environ(&args.flag_env);
|
||||
@@ -255,62 +265,98 @@ fn rmain() -> Result<(), Error> {
|
||||
let wasi = if args.flag_wasi_c {
|
||||
#[cfg(feature = "wasi-c")]
|
||||
{
|
||||
instantiate_wasi_c("", global_exports, &preopen_dirs, &argv, &environ)?
|
||||
instantiate_wasi_c("", global_exports.clone(), &preopen_dirs, &argv, &environ)?
|
||||
}
|
||||
#[cfg(not(feature = "wasi-c"))]
|
||||
{
|
||||
bail!("wasi-c feature not enabled at build time")
|
||||
}
|
||||
} else {
|
||||
instantiate_wasi("", global_exports, &preopen_dirs, &argv, &environ)?
|
||||
instantiate_wasi("", global_exports.clone(), &preopen_dirs, &argv, &environ)?
|
||||
};
|
||||
|
||||
context.name_instance("wasi_unstable".to_owned(), wasi);
|
||||
|
||||
// Enable/disable producing of debug info.
|
||||
context.set_debug_info(args.flag_g);
|
||||
module_registry.insert(
|
||||
"wasi_unstable".to_owned(),
|
||||
Instance::from_handle(store.clone(), wasi)?,
|
||||
);
|
||||
|
||||
// Load the preload wasm modules.
|
||||
for filename in &args.flag_preload {
|
||||
let path = Path::new(&filename);
|
||||
instantiate_module(&mut context, path)
|
||||
instantiate_module(store.clone(), &module_registry, path)
|
||||
.with_context(|_| format!("failed to process preload at `{}`", path.display()))?;
|
||||
}
|
||||
|
||||
// Load the main wasm module.
|
||||
let path = Path::new(&args.arg_file);
|
||||
handle_module(&mut context, &args, path)
|
||||
handle_module(store, &module_registry, &args, path)
|
||||
.with_context(|_| format!("failed to process main module `{}`", path.display()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn instantiate_module(
|
||||
context: &mut Context,
|
||||
store: Rc<RefCell<Store>>,
|
||||
module_registry: &HashMap<String, (Instance, HashMap<String, usize>)>,
|
||||
path: &Path,
|
||||
) -> Result<(InstanceHandle, Vec<u8>), Error> {
|
||||
) -> Result<(Rc<RefCell<Instance>>, Rc<RefCell<Module>>, Vec<u8>), Error> {
|
||||
// Read the wasm module binary.
|
||||
let data = read_wasm(path.to_path_buf())?;
|
||||
|
||||
// Compile and instantiating a wasm module.
|
||||
let handle = context.instantiate_module(None, &data)?;
|
||||
Ok((handle, data))
|
||||
let module = Rc::new(RefCell::new(Module::new(store.clone(), &data)?));
|
||||
|
||||
// Resolve import using module_registry.
|
||||
let imports = module
|
||||
.borrow()
|
||||
.imports()
|
||||
.iter()
|
||||
.map(|i| {
|
||||
let module_name = i.module().to_string();
|
||||
if let Some((instance, map)) = module_registry.get(&module_name) {
|
||||
let field_name = i.name().to_string();
|
||||
if let Some(export_index) = map.get(&field_name) {
|
||||
Ok(instance.exports()[*export_index].clone())
|
||||
} else {
|
||||
bail!(
|
||||
"Import {} was not found in module {}",
|
||||
field_name,
|
||||
module_name
|
||||
)
|
||||
}
|
||||
} else {
|
||||
bail!("Import module {} was not found", module_name)
|
||||
}
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
let instance = Rc::new(RefCell::new(Instance::new(
|
||||
store.clone(),
|
||||
module.clone(),
|
||||
&imports,
|
||||
)?));
|
||||
|
||||
Ok((instance, module, data))
|
||||
}
|
||||
|
||||
fn handle_module(context: &mut Context, args: &Args, path: &Path) -> Result<(), Error> {
|
||||
let (mut instance, data) = instantiate_module(context, path)?;
|
||||
fn handle_module(
|
||||
store: Rc<RefCell<Store>>,
|
||||
module_registry: &HashMap<String, (Instance, HashMap<String, usize>)>,
|
||||
args: &Args,
|
||||
path: &Path,
|
||||
) -> Result<(), Error> {
|
||||
let (instance, _module, data) = instantiate_module(store.clone(), module_registry, path)?;
|
||||
|
||||
// If a function to invoke was given, invoke it.
|
||||
if let Some(f) = &args.flag_invoke {
|
||||
let data = ModuleData::new(&data)?;
|
||||
invoke_export(context, &mut instance, &data, f, args)?;
|
||||
invoke_export(store, instance, &data, f, args)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn invoke_export(
|
||||
context: &mut Context,
|
||||
instance: &mut InstanceHandle,
|
||||
store: Rc<RefCell<Store>>,
|
||||
instance: Rc<RefCell<Instance>>,
|
||||
data: &ModuleData,
|
||||
name: &str,
|
||||
args: &Args,
|
||||
@@ -318,11 +364,13 @@ fn invoke_export(
|
||||
use wasm_webidl_bindings::ast;
|
||||
use wasmtime_interface_types::Value;
|
||||
|
||||
let mut handle = instance.borrow().handle().clone();
|
||||
|
||||
// Use the binding information in `ModuleData` to figure out what arguments
|
||||
// need to be passed to the function that we're invoking. Currently we take
|
||||
// the CLI parameters and attempt to parse them into function arguments for
|
||||
// the function we'll invoke.
|
||||
let binding = data.binding_for_export(instance, name)?;
|
||||
let binding = data.binding_for_export(&mut handle, name)?;
|
||||
if binding.param_types()?.len() > 0 {
|
||||
eprintln!(
|
||||
"warning: using `--render` with a function that takes arguments \
|
||||
@@ -358,8 +406,9 @@ fn invoke_export(
|
||||
|
||||
// Invoke the function and then afterwards print all the results that came
|
||||
// out, if there are any.
|
||||
let mut context = store.borrow().engine().borrow().create_wasmtime_context();
|
||||
let results = data
|
||||
.invoke(context, instance, name, &values)
|
||||
.invoke(&mut context, &mut handle, name, &values)
|
||||
.with_context(|_| format!("failed to invoke `{}`", name))?;
|
||||
if results.len() > 0 {
|
||||
eprintln!(
|
||||
|
||||
Reference in New Issue
Block a user