Reimplement wasmtime-wasi on top of wasmtime (#899)
* Reimplement `wasmtime-wasi` on top of `wasmtime` This commit reimplements the `wasmtime-wasi` crate on top of the `wasmtime` API crate, instead of being placed on top of the `wasmtime-*` family of internal crates. The purpose here is to continue to exercise the API as well as avoid usage of internals wherever possible and instead use the safe API as much as possible. The `wasmtime-wasi` crate's API has been updated as part of this PR as well. The general outline of it is now: * Each module snapshot has a `WasiCtxBuilder`, `WasiCtx`, and `Wasi` type. * The `WasiCtx*` types are reexported from `wasi-common`. * The `Wasi` type is synthesized by the `wig` crate's procedural macro * The `Wasi` type exposes one constructor which takes a `Store` and a `WasiCtx`, and produces a `Wasi` * Each `Wasi` struct fields for all the exported functions in that wasi module. They're all public an they all have type `wasmtime::Func` * The `Wasi` type has a `get_export` method to fetch an struct field by name. The intention here is that we can continue to make progress on #727 by integrating WASI construction into the `Instance::new` experience, but it requires everything to be part of the same system! The main oddity required by the `wasmtime-wasi` crate is that it needs access to the caller's `memory` export, if any. This is currently done with a bit of a hack and is expected to go away once interface types are more fully baked in. * Remove now no-longer-necessary APIs from `wasmtime` * rustfmt * Rename to from_abi
This commit is contained in:
@@ -34,8 +34,8 @@ pub fn witx_wasi32_types(args: TokenStream) -> TokenStream {
|
||||
|
||||
/// A single-use macro in the `wasmtime-wasi` crate.
|
||||
#[proc_macro]
|
||||
pub fn define_add_wrappers_to_module(args: TokenStream) -> TokenStream {
|
||||
wasi::add_wrappers_to_module(args.into()).into()
|
||||
pub fn define_wasi_struct(args: TokenStream) -> TokenStream {
|
||||
wasi::define_struct(args.into()).into()
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
|
||||
@@ -11,18 +11,16 @@ enum Abi {
|
||||
|
||||
/// This is a single-use macro intended to be used in the `wasmtime-wasi` crate.
|
||||
///
|
||||
/// This macro will generate a function, `add_wrappers_to_module`, which will
|
||||
/// use the input arguments to register all wasi functions inside of a `Module`
|
||||
/// instance. This will automatically assign the wasm underlying types and
|
||||
/// perform conversions from the wasm type to the underlying wasi type (often
|
||||
/// unsigned or of a smaller width).
|
||||
/// This macro will generate a structure, `Wasi`, which will create all the
|
||||
/// functions necessary to bind wasi and hook everything up via the `wasmtime`
|
||||
/// crate.
|
||||
///
|
||||
/// The generated shim functions here will also `trace!` their arguments for
|
||||
/// logging purposes. Otherwise this is hopefully somewhat straightforward!
|
||||
///
|
||||
/// I'd recommend using `cargo +nightly expand` to explore the output of this
|
||||
/// macro some more.
|
||||
pub fn add_wrappers_to_module(args: TokenStream) -> TokenStream {
|
||||
pub fn define_struct(args: TokenStream) -> TokenStream {
|
||||
let (path, _phase) = utils::witx_path_from_args(args);
|
||||
let doc = match witx::load(&[&path]) {
|
||||
Ok(doc) => doc,
|
||||
@@ -31,12 +29,18 @@ pub fn add_wrappers_to_module(args: TokenStream) -> TokenStream {
|
||||
}
|
||||
};
|
||||
|
||||
let mut add = Vec::new();
|
||||
let mut fields = Vec::new();
|
||||
let mut get_exports = Vec::new();
|
||||
let mut ctor_externs = Vec::new();
|
||||
let mut ctor_fields = Vec::new();
|
||||
|
||||
for module in doc.modules() {
|
||||
for func in module.funcs() {
|
||||
let name = func.name.as_str();
|
||||
let name_ident = Ident::new(func.name.as_str(), Span::call_site());
|
||||
fields.push(quote! { pub #name_ident: wasmtime::Func });
|
||||
get_exports.push(quote! { #name => Some(&self.#name_ident) });
|
||||
ctor_fields.push(name_ident.clone());
|
||||
|
||||
let mut shim_arg_decls = Vec::new();
|
||||
let mut params = Vec::new();
|
||||
@@ -178,56 +182,71 @@ pub fn add_wrappers_to_module(args: TokenStream) -> TokenStream {
|
||||
}
|
||||
|
||||
let format_str = format!("{}({})", name, formats.join(", "));
|
||||
add.push(quote! {
|
||||
let sig = module.signatures.push(translate_signature(
|
||||
ir::Signature {
|
||||
params: vec![#(cranelift_codegen::ir::AbiParam::new(#params)),*],
|
||||
returns: vec![#(cranelift_codegen::ir::AbiParam::new(#returns)),*],
|
||||
call_conv,
|
||||
},
|
||||
pointer_type,
|
||||
));
|
||||
let func = module.functions.push(sig);
|
||||
module
|
||||
.exports
|
||||
.insert(#name.to_owned(), Export::Function(func));
|
||||
|
||||
unsafe extern "C" fn #name_ident(
|
||||
ctx: *mut wasmtime_runtime::VMContext,
|
||||
caller_ctx: *mut wasmtime_runtime::VMContext,
|
||||
#(#shim_arg_decls),*
|
||||
) -> #ret_ty {
|
||||
log::trace!(
|
||||
#format_str,
|
||||
#(#format_args),*
|
||||
);
|
||||
let mut wasi_ctx = match get_wasi_ctx(&mut *ctx) {
|
||||
Ok(e) => e.borrow_mut(),
|
||||
Err(e) => #handle_early_error,
|
||||
};
|
||||
let memory = match get_memory(&mut *caller_ctx) {
|
||||
Ok(e) => e,
|
||||
Err(e) => #handle_early_error,
|
||||
};
|
||||
hostcalls::#name_ident(
|
||||
&mut *wasi_ctx,
|
||||
memory,
|
||||
#(#hostcall_args),*
|
||||
) #cvt_ret
|
||||
}
|
||||
finished_functions.push(#name_ident as *const _);
|
||||
let wrap = format_ident!("wrap{}", shim_arg_decls.len() + 1);
|
||||
ctor_externs.push(quote! {
|
||||
let my_cx = cx.clone();
|
||||
let #name_ident = wasmtime::Func::#wrap(
|
||||
store,
|
||||
move |mem: crate::WasiCallerMemory #(,#shim_arg_decls)*| -> #ret_ty {
|
||||
log::trace!(
|
||||
#format_str,
|
||||
#(#format_args),*
|
||||
);
|
||||
unsafe {
|
||||
let memory = match mem.get() {
|
||||
Ok(e) => e,
|
||||
Err(e) => #handle_early_error,
|
||||
};
|
||||
hostcalls::#name_ident(
|
||||
&mut my_cx.borrow_mut(),
|
||||
memory,
|
||||
#(#hostcall_args),*
|
||||
) #cvt_ret
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
quote! {
|
||||
pub fn add_wrappers_to_module(
|
||||
module: &mut Module,
|
||||
finished_functions: &mut PrimaryMap<DefinedFuncIndex, *const wasmtime_runtime::VMFunctionBody>,
|
||||
call_conv: isa::CallConv,
|
||||
pointer_type: types::Type,
|
||||
) {
|
||||
#(#add)*
|
||||
/// An instantiated instance of the wasi exports.
|
||||
///
|
||||
/// This represents a wasi module which can be used to instantiate other
|
||||
/// wasm modules. This structure exports all that various fields of the
|
||||
/// wasi instance as fields which can be used to implement your own
|
||||
/// instantiation logic, if necessary. Additionally [`Wasi::get_export`]
|
||||
/// can be used to do name-based resolution.
|
||||
pub struct Wasi {
|
||||
#(#fields,)*
|
||||
}
|
||||
|
||||
impl Wasi {
|
||||
/// Creates a new [`Wasi`] instance.
|
||||
///
|
||||
/// External values are allocated into the `store` provided and
|
||||
/// configuration of the wasi instance itself should be all
|
||||
/// contained in the `cx` parameter.
|
||||
pub fn new(store: &wasmtime::Store, cx: WasiCtx) -> Wasi {
|
||||
let cx = std::rc::Rc::new(std::cell::RefCell::new(cx));
|
||||
#(#ctor_externs)*
|
||||
|
||||
Wasi {
|
||||
#(#ctor_fields,)*
|
||||
}
|
||||
}
|
||||
|
||||
/// Looks up a field called `name` in this structure, returning it
|
||||
/// if found.
|
||||
///
|
||||
/// This is often useful when instantiating a `wasmtime` instance
|
||||
/// where name resolution often happens with strings.
|
||||
pub fn get_export(&self, name: &str) -> Option<&wasmtime::Func> {
|
||||
match name {
|
||||
#(#get_exports,)*
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user