wasmi/derive/src/codegen.rs

229 lines
6.9 KiB
Rust
Raw Normal View History

2019-01-25 12:06:04 +00:00
//! This module generates a trait implementation for `Externals` on the target type.
//! It also generates a function called `resolve` that returns a `ModuleImportResolved`.
//!
//! The code generation is rather simple but it relies heavily on type inference.
2019-01-25 10:55:25 +00:00
use crate::parser::{FuncDef, ImplBlockDef};
2019-01-25 10:03:47 +00:00
use proc_macro2::{Ident, Span, TokenStream};
2019-01-19 00:31:47 +00:00
use quote::{quote, quote_spanned, ToTokens};
2019-01-25 10:02:03 +00:00
pub fn codegen(ext_def: &ImplBlockDef, to: &mut TokenStream) {
2019-01-19 00:31:47 +00:00
let mut externals = TokenStream::new();
let mut module_resolver = TokenStream::new();
derive_externals(ext_def, &mut externals);
derive_module_resolver(ext_def, &mut module_resolver);
2019-01-25 10:03:47 +00:00
let (impl_generics, _, where_clause) = ext_def.generics.split_for_impl();
let ty = &ext_def.ty;
2019-01-19 00:31:47 +00:00
(quote! {
impl #impl_generics #ty #where_clause {
const __WASMI_DERIVE_IMPL: () = {
extern crate wasmi as _wasmi;
extern crate core as _core;
use _core::{
result::Result,
option::Option,
};
use _wasmi::{
Trap, RuntimeValue, RuntimeArgs, Externals, ValueType, ModuleImportResolver,
Signature, FuncRef, Error, FuncInstance,
derive_support::{
IntoWasmResult,
IntoWasmValue,
},
};
#[inline(always)]
fn materialize_arg_ty<W: IntoWasmValue>(_w: Option<W>) -> ValueType {
W::VALUE_TYPE
}
#[inline(always)]
fn materialize_ret_type<W: IntoWasmResult>(_w: Option<W>) -> Option<ValueType> {
W::VALUE_TYPE
}
#externals
#module_resolver
2019-01-19 00:31:47 +00:00
};
}
2019-01-25 09:43:03 +00:00
})
.to_tokens(to);
2019-01-19 00:31:47 +00:00
}
2019-01-25 10:02:03 +00:00
fn emit_dispatch_func_arm(func: &FuncDef) -> TokenStream {
2019-01-19 00:31:47 +00:00
let index = func.index as usize;
let return_ty_span = func.return_ty.clone().unwrap_or_else(|| Span::call_site());
let mut unmarshall_args = TokenStream::new();
2019-01-25 10:03:47 +00:00
for param in &func.params {
2019-01-19 20:29:29 +00:00
let param_span = param.ident.span();
let ident = &param.ident;
2019-01-19 00:31:47 +00:00
2019-01-19 20:29:29 +00:00
(quote_spanned! {param_span=>
let #ident =
2019-01-19 00:31:47 +00:00
args.next()
.and_then(|rt_val| rt_val.try_into())
.unwrap();
2019-01-25 09:43:03 +00:00
})
.to_tokens(&mut unmarshall_args);
2019-01-19 00:31:47 +00:00
}
let prologue = quote! {
let mut args = args.as_ref().iter();
#unmarshall_args
};
let epilogue = quote_spanned! {return_ty_span=>
2019-01-19 20:59:32 +00:00
IntoWasmResult::into_wasm_result(r)
2019-01-19 00:31:47 +00:00
};
2019-01-19 20:29:29 +00:00
let call = {
2019-01-25 10:02:03 +00:00
let params = func.params.iter().map(|param| param.ident.clone());
2019-01-19 20:29:29 +00:00
let name = Ident::new(&func.name, Span::call_site());
quote! {
2019-01-25 10:02:03 +00:00
#name( #(#params),* )
2019-01-19 20:29:29 +00:00
}
};
2019-01-19 00:31:47 +00:00
(quote! {
#index => {
#prologue
2019-01-19 20:29:29 +00:00
let r = self.#call;
2019-01-19 00:31:47 +00:00
#epilogue
}
})
}
2019-01-25 10:02:03 +00:00
fn derive_externals(ext_def: &ImplBlockDef, to: &mut TokenStream) {
2019-01-25 10:03:47 +00:00
let (impl_generics, _, where_clause) = ext_def.generics.split_for_impl();
2019-01-19 00:31:47 +00:00
let ty = &ext_def.ty;
let mut match_arms = vec![];
for func in &ext_def.funcs {
2019-01-19 20:29:29 +00:00
match_arms.push(emit_dispatch_func_arm(func));
2019-01-19 00:31:47 +00:00
}
(quote::quote! {
impl #impl_generics Externals for #ty #where_clause {
fn invoke_index(
&mut self,
index: usize,
args: RuntimeArgs,
) -> Result<Option<RuntimeValue>, Trap> {
match index {
#(#match_arms),*
_ => panic!("fn with index {} is undefined", index),
}
}
// ...
}
2019-01-25 09:43:03 +00:00
})
.to_tokens(to);
2019-01-19 00:31:47 +00:00
}
2019-01-25 10:02:03 +00:00
fn emit_resolve_func_arm(func: &FuncDef) -> TokenStream {
2019-01-19 20:29:29 +00:00
let index = func.index as usize;
let string_ident = &func.name;
let return_ty_span = func.return_ty.clone().unwrap_or_else(|| Span::call_site());
let call = {
2019-01-25 10:02:03 +00:00
let params = func.params.iter().map(|param| {
2019-01-19 20:29:29 +00:00
let ident = param.ident.clone();
let span = param.ident.span();
quote_spanned! {span=> #ident.unwrap() }
});
let name = Ident::new(&func.name, Span::call_site());
quote! {
2019-01-25 10:02:03 +00:00
Self::#name( panic!(), #(#params),* )
2019-01-19 20:29:29 +00:00
}
};
2019-01-25 09:43:03 +00:00
let init = func
2019-01-25 10:02:03 +00:00
.params
2019-01-25 09:43:03 +00:00
.iter()
.map(|param| {
let ident = &param.ident;
quote! {
let #ident = None;
}
})
.collect::<Vec<_>>();
let params_materialized_tys = func
2019-01-25 10:02:03 +00:00
.params
2019-01-25 09:43:03 +00:00
.iter()
.map(|param| {
let ident = &param.ident;
let span = param.ident.span();
quote_spanned! {span=> materialize_arg_ty(#ident) }
})
.collect::<Vec<_>>();
2019-01-19 20:29:29 +00:00
let materialized_return_ty = quote_spanned! { return_ty_span=>
materialize_ret_type(return_val)
};
quote! {
if name == #string_ident {
// initialize variables
#(#init)*
#[allow(unreachable_code)]
let return_val = if false {
// calling self for typeinference
Some(#call)
} else {
None
};
// at this point types of all variables and return_val are inferred.
2019-01-25 12:06:04 +00:00
if signature.params() != &[#(#params_materialized_tys),*]
|| signature.return_type() != #materialized_return_ty
{
2019-01-19 20:29:29 +00:00
return Err(Error::Instantiation(
2019-01-25 09:43:03 +00:00
format!("Export {} has different signature {:?}", #string_ident, signature),
));
2019-01-19 20:29:29 +00:00
}
return Ok(FuncInstance::alloc_host(signature.clone(), #index));
}
}
}
2019-01-25 10:02:03 +00:00
fn derive_module_resolver(ext_def: &ImplBlockDef, to: &mut TokenStream) {
2019-01-25 10:03:47 +00:00
let (impl_generics, _, where_clause) = ext_def.generics.split_for_impl();
2019-01-19 20:29:29 +00:00
let ty = &ext_def.ty;
let mut match_arms = vec![];
for func in &ext_def.funcs {
match_arms.push(emit_resolve_func_arm(func));
}
2019-01-19 00:31:47 +00:00
(quote::quote! {
2019-01-19 20:29:29 +00:00
impl #impl_generics #ty #where_clause {
fn resolver() -> impl ModuleImportResolver {
// Use a closure to have an ability to use `Self` type
let resolve_func = |name: &str, signature: &Signature| -> Result<FuncRef, Error> {
#(#match_arms)*
Err(Error::Instantiation(
format!("Export {} not found", name),
))
};
struct Resolver(fn(&str, &Signature) -> Result<FuncRef, Error>);
impl ModuleImportResolver for Resolver {
#[inline(always)]
fn resolve_func(&self, name: &str, signature: &Signature) -> Result<FuncRef, Error> {
(self.0)(name, signature)
}
}
Resolver(resolve_func)
2019-01-19 00:31:47 +00:00
}
}
}).to_tokens(to);
}