Auto-generate the hostcalls module of wasi-common (#846)
* Auto-generate shims for old `wasi_unstable` module This commit is effectively just doing what #707 already did, but applying it to the `snapshot_0` module as well. The end result is the same, where we cut down on all the boilerplate in `snapshot_0` and bring it in line with the main `wasi_snapshot_preview1` implementation. The goal here is to make it easier to change the two in tandem since they're both doing the same thing. * Migrate `wasi_common::hostcalls` to a macro This commit migrates the `hostcalls` module to being auto-generated by a macro rather than duplicating a handwritten signature for each wasi syscall. * Auto-generate snapshot_0's `hostcalls` module Similar to the previous commit, but for `snapshot_0` * Delete the `wasi-common-cbindgen` crate This is no longer needed with the hostcalls macro now, we can easily fold the definition of the cbindgen macro into the same crate. * Rustfmt * Fix windows build errors * Rustfmt * Remove now no-longer-necessary code * rustfmt
This commit is contained in:
131
crates/wasi-common/wig/src/hostcalls.rs
Normal file
131
crates/wasi-common/wig/src/hostcalls.rs
Normal file
@@ -0,0 +1,131 @@
|
||||
use crate::utils;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
|
||||
pub fn define(args: TokenStream) -> TokenStream {
|
||||
let (path, phase) = utils::witx_path_from_args(args);
|
||||
let doc = match witx::load(&[&path]) {
|
||||
Ok(doc) => doc,
|
||||
Err(e) => {
|
||||
panic!("error opening file {}: {}", path, e);
|
||||
}
|
||||
};
|
||||
|
||||
let mut ret = TokenStream::new();
|
||||
|
||||
let old = match phase.as_str() {
|
||||
"snapshot" => false,
|
||||
"old/snapshot_0" => true,
|
||||
s => panic!("unsupported phase: {}", s),
|
||||
};
|
||||
|
||||
for module in doc.modules() {
|
||||
for func in module.funcs() {
|
||||
ret.extend(generate_wrappers(&func, old));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
fn generate_wrappers(func: &witx::InterfaceFunc, old: bool) -> TokenStream {
|
||||
let name = format_ident!("{}", func.name.as_str());
|
||||
let mut arg_declarations = Vec::new();
|
||||
let mut arg_names = Vec::new();
|
||||
|
||||
for param in func.params.iter() {
|
||||
let name = utils::param_name(param);
|
||||
|
||||
if let witx::TypePassedBy::PointerLengthPair = param.tref.type_().passed_by() {
|
||||
let ptr = format_ident!("{}_ptr", name);
|
||||
let len = format_ident!("{}_len", name);
|
||||
arg_declarations.push(quote! { #ptr: super::wasi32::uintptr_t });
|
||||
arg_declarations.push(quote! { #len: super::wasi32::size_t });
|
||||
arg_names.push(ptr);
|
||||
arg_names.push(len);
|
||||
continue;
|
||||
}
|
||||
|
||||
match ¶m.tref {
|
||||
witx::TypeRef::Name(n) => {
|
||||
if n.name.as_str() == "size" {
|
||||
arg_declarations.push(quote! { #name: super::wasi32::size_t });
|
||||
} else {
|
||||
let ty_name = format_ident!("__wasi_{}_t", n.name.as_str());
|
||||
arg_declarations.push(quote! { #name: super::wasi::#ty_name });
|
||||
}
|
||||
}
|
||||
witx::TypeRef::Value(v) => match &**v {
|
||||
witx::Type::ConstPointer(_) | witx::Type::Pointer(_) => {
|
||||
arg_declarations.push(quote! { #name: super::wasi32::uintptr_t });
|
||||
}
|
||||
_ => panic!("unexpected value type"),
|
||||
},
|
||||
}
|
||||
arg_names.push(name);
|
||||
}
|
||||
|
||||
let mut ret = quote!(());
|
||||
|
||||
for (i, result) in func.results.iter().enumerate() {
|
||||
if i == 0 {
|
||||
match &result.tref {
|
||||
witx::TypeRef::Name(n) => {
|
||||
let ty_name = format_ident!("__wasi_{}_t", n.name.as_str());
|
||||
ret = quote! { super::wasi::#ty_name };
|
||||
}
|
||||
witx::TypeRef::Value(_) => panic!("unexpected value type"),
|
||||
}
|
||||
continue;
|
||||
}
|
||||
let name = utils::param_name(result);
|
||||
arg_declarations.push(quote! { #name: super::wasi32::uintptr_t });
|
||||
arg_names.push(name);
|
||||
}
|
||||
|
||||
let call = quote! {
|
||||
super::hostcalls_impl::#name(wasi_ctx, memory, #(#arg_names,)*)
|
||||
};
|
||||
let body = if func.results.len() == 0 {
|
||||
call
|
||||
} else {
|
||||
quote! {
|
||||
let ret = #call
|
||||
.err()
|
||||
.unwrap_or(super::Error::ESUCCESS)
|
||||
.as_wasi_error();
|
||||
log::trace!(" | errno={}", ret);
|
||||
ret.as_raw_errno()
|
||||
}
|
||||
};
|
||||
|
||||
let c_abi_name = if old {
|
||||
format_ident!("old_wasi_common_{}", name)
|
||||
} else {
|
||||
format_ident!("wasi_common_{}", name)
|
||||
};
|
||||
|
||||
quote! {
|
||||
pub unsafe fn #name(
|
||||
wasi_ctx: &mut super::WasiCtx,
|
||||
memory: &mut [u8],
|
||||
#(#arg_declarations,)*
|
||||
) -> #ret {
|
||||
#body
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn #c_abi_name(
|
||||
wasi_ctx: *mut super::WasiCtx,
|
||||
memory: *mut u8,
|
||||
memory_len: usize,
|
||||
#(#arg_declarations,)*
|
||||
) -> #ret {
|
||||
#name(
|
||||
&mut *wasi_ctx,
|
||||
std::slice::from_raw_parts_mut(memory, memory_len),
|
||||
#(#arg_names,)*
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
extern crate proc_macro;
|
||||
|
||||
mod hostcalls;
|
||||
mod raw_types;
|
||||
mod utils;
|
||||
mod wasi;
|
||||
@@ -36,3 +37,8 @@ pub fn witx_wasi32_types(args: TokenStream) -> TokenStream {
|
||||
pub fn define_add_wrappers_to_module(args: TokenStream) -> TokenStream {
|
||||
wasi::add_wrappers_to_module(args.into()).into()
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn define_hostcalls(args: TokenStream) -> TokenStream {
|
||||
hostcalls::define(args.into()).into()
|
||||
}
|
||||
|
||||
@@ -50,12 +50,13 @@ fn gen_datatypes(output: &mut TokenStream, doc: &witx::Document, mode: Mode) {
|
||||
|
||||
fn gen_datatype(output: &mut TokenStream, mode: Mode, namedtype: &witx::NamedType) {
|
||||
let wasi_name = format_ident!("__wasi_{}_t", namedtype.name.as_str());
|
||||
match &namedtype.dt {
|
||||
match &namedtype.tref {
|
||||
witx::TypeRef::Name(alias_to) => {
|
||||
let to = tref_tokens(mode, &alias_to.dt);
|
||||
let to = tref_tokens(mode, &alias_to.tref);
|
||||
output.extend(quote!(pub type #wasi_name = #to;));
|
||||
}
|
||||
witx::TypeRef::Value(v) => match &**v {
|
||||
witx::Type::Int(_) => panic!("unsupported int datatype"),
|
||||
witx::Type::Enum(e) => {
|
||||
let repr = int_repr_tokens(e.repr);
|
||||
output.extend(quote!(pub type #wasi_name = #repr;));
|
||||
@@ -143,7 +144,7 @@ fn gen_datatype(output: &mut TokenStream, mode: Mode, namedtype: &witx::NamedTyp
|
||||
witx::Type::Pointer { .. }
|
||||
| witx::Type::ConstPointer { .. }
|
||||
| witx::Type::Array { .. } => {
|
||||
let tref_tokens = tref_tokens(mode, &namedtype.dt);
|
||||
let tref_tokens = tref_tokens(mode, &namedtype.tref);
|
||||
output.extend(quote!(pub type #wasi_name = #tref_tokens;));
|
||||
}
|
||||
},
|
||||
@@ -156,7 +157,7 @@ fn gen_datatype(output: &mut TokenStream, mode: Mode, namedtype: &witx::NamedTyp
|
||||
}
|
||||
|
||||
fn gen_errno_strerror(output: &mut TokenStream, namedtype: &witx::NamedType) {
|
||||
let inner = match &namedtype.dt {
|
||||
let inner = match &namedtype.tref {
|
||||
witx::TypeRef::Value(v) => match &**v {
|
||||
witx::Type::Enum(e) => e,
|
||||
x => panic!("expected Enum('errno'), instead received {:?}", x),
|
||||
@@ -198,6 +199,7 @@ fn builtin_tokens(mode: Mode, builtin: witx::BuiltinType) -> TokenStream {
|
||||
Mode::Wasi => panic!("strings have target-specific size"),
|
||||
Mode::Wasi32 => quote!((u32, u32)),
|
||||
},
|
||||
witx::BuiltinType::Char8 => quote!(i8),
|
||||
witx::BuiltinType::U8 => quote!(u8),
|
||||
witx::BuiltinType::U16 => quote!(u16),
|
||||
witx::BuiltinType::U32 => quote!(u32),
|
||||
@@ -208,6 +210,11 @@ fn builtin_tokens(mode: Mode, builtin: witx::BuiltinType) -> TokenStream {
|
||||
witx::BuiltinType::S64 => quote!(i64),
|
||||
witx::BuiltinType::F32 => quote!(f32),
|
||||
witx::BuiltinType::F64 => quote!(f64),
|
||||
witx::BuiltinType::USize => match mode {
|
||||
Mode::Host => quote!(usize),
|
||||
Mode::Wasi => panic!("usize has target-specific size"),
|
||||
Mode::Wasi32 => quote!(u32),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +277,7 @@ fn namedtype_has_target_size(nt: &witx::NamedType) -> bool {
|
||||
if nt.name.as_str() == "size" {
|
||||
true
|
||||
} else {
|
||||
tref_has_target_size(&nt.dt)
|
||||
tref_has_target_size(&nt.tref)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use proc_macro2::{Literal, TokenStream, TokenTree};
|
||||
use proc_macro2::{Ident, Literal, TokenStream, TokenTree};
|
||||
|
||||
/// Given the input tokens to a macro invocation, return the path to the
|
||||
/// witx file to process.
|
||||
@@ -53,3 +53,13 @@ fn parse_string_literal(literal: Literal) -> String {
|
||||
|
||||
trimmed
|
||||
}
|
||||
|
||||
pub fn param_name(param: &witx::InterfaceFuncParam) -> Ident {
|
||||
quote::format_ident!(
|
||||
"{}",
|
||||
match param.name.as_str() {
|
||||
"in" | "type" => format!("r#{}", param.name.as_str()),
|
||||
s => s.to_string(),
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -45,13 +45,7 @@ pub fn add_wrappers_to_module(args: TokenStream) -> TokenStream {
|
||||
let mut hostcall_args = Vec::new();
|
||||
|
||||
for param in func.params.iter() {
|
||||
let name = format_ident!(
|
||||
"{}",
|
||||
match param.name.as_str() {
|
||||
"in" | "type" => format!("r#{}", param.name.as_str()),
|
||||
s => s.to_string(),
|
||||
}
|
||||
);
|
||||
let name = utils::param_name(param);
|
||||
|
||||
// Registers a new parameter to the shim we're making with the
|
||||
// given `name`, the `abi_ty` wasm type and `hex` defines
|
||||
@@ -89,6 +83,11 @@ pub fn add_wrappers_to_module(args: TokenStream) -> TokenStream {
|
||||
};
|
||||
|
||||
match &*param.tref.type_() {
|
||||
witx::Type::Int(e) => match e.repr {
|
||||
witx::IntRepr::U64 => add_param(&name, Abi::I64, false),
|
||||
_ => add_param(&name, Abi::I32, false),
|
||||
},
|
||||
|
||||
witx::Type::Enum(e) => match e.repr {
|
||||
witx::IntRepr::U64 => add_param(&name, Abi::I64, false),
|
||||
_ => add_param(&name, Abi::I32, false),
|
||||
@@ -99,12 +98,14 @@ pub fn add_wrappers_to_module(args: TokenStream) -> TokenStream {
|
||||
_ => add_param(&name, Abi::I32, true),
|
||||
},
|
||||
|
||||
witx::Type::Builtin(witx::BuiltinType::S8)
|
||||
witx::Type::Builtin(witx::BuiltinType::Char8)
|
||||
| witx::Type::Builtin(witx::BuiltinType::S8)
|
||||
| witx::Type::Builtin(witx::BuiltinType::U8)
|
||||
| witx::Type::Builtin(witx::BuiltinType::S16)
|
||||
| witx::Type::Builtin(witx::BuiltinType::U16)
|
||||
| witx::Type::Builtin(witx::BuiltinType::S32)
|
||||
| witx::Type::Builtin(witx::BuiltinType::U32) => {
|
||||
| witx::Type::Builtin(witx::BuiltinType::U32)
|
||||
| witx::Type::Builtin(witx::BuiltinType::USize) => {
|
||||
add_param(&name, Abi::I32, false);
|
||||
}
|
||||
|
||||
@@ -208,7 +209,7 @@ pub fn add_wrappers_to_module(args: TokenStream) -> TokenStream {
|
||||
Ok(e) => e,
|
||||
Err(e) => #handle_early_error,
|
||||
};
|
||||
wasi_common::hostcalls::#name_ident(
|
||||
hostcalls::#name_ident(
|
||||
wasi_ctx,
|
||||
memory,
|
||||
#(#hostcall_args),*
|
||||
|
||||
Reference in New Issue
Block a user