Make it work.

This commit is contained in:
Sergey Pepyakin 2019-01-19 21:29:29 +01:00
parent 23b10d386c
commit 5f49943cfb
6 changed files with 137 additions and 49 deletions

View File

@ -20,36 +20,45 @@ pub fn codegen(ext_def: &ExtDefinition, to: &mut TokenStream) {
extern crate wasmi as _wasmi; extern crate wasmi as _wasmi;
use _wasmi::{ use _wasmi::{
Trap, RuntimeValue, RuntimeArgs, Externals, Trap, RuntimeValue, RuntimeArgs, Externals, ValueType, ModuleImportResolver,
derive_support::WasmResult, Signature, FuncRef, Error, FuncInstance,
derive_support::{
WasmResult,
ConvertibleToWasm,
},
}; };
#[inline(always)]
fn materialize_arg_ty<W: ConvertibleToWasm>(_w: Option<W>) -> ValueType {
W::VALUE_TYPE
}
#[inline(always)]
fn materialize_ret_type<W: WasmResult>(_w: Option<W>) -> Option<ValueType> {
W::VALUE_TYPE
}
#externals #externals
#module_resolver #module_resolver
}; };
}).to_tokens(to); }).to_tokens(to);
} }
fn gen_dispatch_func_arm(func: &ExternalFunc) -> TokenStream { fn emit_dispatch_func_arm(func: &ExternalFunc) -> TokenStream {
let index = func.index as usize; let index = func.index as usize;
let name = Ident::new(&func.name, Span::call_site());
let return_ty_span = func.return_ty.clone().unwrap_or_else(|| Span::call_site()); let return_ty_span = func.return_ty.clone().unwrap_or_else(|| Span::call_site());
let mut args = vec![];
let mut unmarshall_args = TokenStream::new(); let mut unmarshall_args = TokenStream::new();
for (i, arg_span) in func.args.iter().cloned().enumerate() { for (i, param) in func.args.iter().enumerate() {
let mut arg_name = "arg".to_string(); let param_span = param.ident.span();
arg_name.push_str(&i.to_string()); let ident = &param.ident;
let arg_name = Ident::new(&arg_name, arg_span.clone());
(quote_spanned! {arg_span=> (quote_spanned! {param_span=>
let #arg_name = let #ident =
args.next() args.next()
.and_then(|rt_val| rt_val.try_into()) .and_then(|rt_val| rt_val.try_into())
.unwrap(); .unwrap();
}).to_tokens(&mut unmarshall_args); }).to_tokens(&mut unmarshall_args);
args.push(quote_spanned! {arg_span=> #arg_name });
} }
let prologue = quote! { let prologue = quote! {
@ -60,21 +69,20 @@ fn gen_dispatch_func_arm(func: &ExternalFunc) -> TokenStream {
WasmResult::to_wasm_result(r) WasmResult::to_wasm_result(r)
}; };
let call = {
let args = func.args.iter().map(|param| param.ident.clone());
let name = Ident::new(&func.name, Span::call_site());
quote! {
#name( #(#args),* )
}
};
(quote! { (quote! {
#index => { #index => {
#prologue #prologue
let r = self.#name( #(#args),* ); let r = self.#call;
#epilogue #epilogue
} }
}) })
// let body = $crate::wasm_utils::constrain_closure::<
// <$returns as $crate::wasm_utils::ConvertibleToWasm>::NativeType, _
// >(|| {
// unmarshall_args!($body, $objectname, $args_iter, $( $names : $params ),*)
// });
// let r = body()?;
// return Ok(Some({ use $crate::wasm_utils::ConvertibleToWasm; r.to_runtime_value() }))
} }
fn derive_externals(ext_def: &ExtDefinition, to: &mut TokenStream) { fn derive_externals(ext_def: &ExtDefinition, to: &mut TokenStream) {
@ -83,7 +91,7 @@ fn derive_externals(ext_def: &ExtDefinition, to: &mut TokenStream) {
let mut match_arms = vec![]; let mut match_arms = vec![];
for func in &ext_def.funcs { for func in &ext_def.funcs {
match_arms.push(gen_dispatch_func_arm(func)); match_arms.push(emit_dispatch_func_arm(func));
} }
(quote::quote! { (quote::quote! {
@ -104,21 +112,95 @@ fn derive_externals(ext_def: &ExtDefinition, to: &mut TokenStream) {
}).to_tokens(to); }).to_tokens(to);
} }
fn derive_module_resolver(ext_def: &ExtDefinition, to: &mut TokenStream) { fn emit_resolve_func_arm(func: &ExternalFunc) -> TokenStream {
(quote::quote! { let index = func.index as usize;
impl #impl_generics ModuleImportResolver for #ty #where_clause { let string_ident = &func.name;
fn invoke_index( let return_ty_span = func.return_ty.clone().unwrap_or_else(|| Span::call_site());
&mut self,
index: usize, let call = {
args: RuntimeArgs, let args = func.args.iter().map(|param| {
) -> Result<Option<RuntimeValue>, Trap> { let ident = param.ident.clone();
match index { let span = param.ident.span();
#(#match_arms),* quote_spanned! {span=> #ident.unwrap() }
_ => panic!("fn with index {} is undefined", index), });
let name = Ident::new(&func.name, Span::call_site());
quote! {
Self::#name( panic!(), #(#args),* )
}
};
let init = func.args.iter().map(|param| {
let ident = &param.ident;
quote! {
let #ident = None;
}
}).collect::<Vec<_>>();
let params_materialized_tys = func.args.iter().map(|param| {
let ident = &param.ident;
let span = param.ident.span();
quote_spanned! {span=> materialize_arg_ty(#ident) }
}).collect::<Vec<_>>();
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.
if signature.params() != &[#(#params_materialized_tys),*] || signature.return_type() != #materialized_return_ty {
return Err(Error::Instantiation(
format!("Export {} has different signature {:?}", #string_ident, signature),
));
}
return Ok(FuncInstance::alloc_host(signature.clone(), #index));
}
} }
} }
// ... fn derive_module_resolver(ext_def: &ExtDefinition, to: &mut TokenStream) {
let (impl_generics, ty_generics, where_clause) = ext_def.generics.split_for_impl();
let ty = &ext_def.ty;
let mut match_arms = vec![];
for func in &ext_def.funcs {
match_arms.push(emit_resolve_func_arm(func));
}
(quote::quote! {
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)
}
} }
}).to_tokens(to); }).to_tokens(to);
} }

View File

@ -1,3 +1,5 @@
#![recursion_limit="128"]
extern crate proc_macro; extern crate proc_macro;
mod model; mod model;
@ -28,7 +30,7 @@ pub fn derive_externals(attr: TokenStream, input: TokenStream) -> TokenStream {
// and we will then need to return both the original implementation and the generated implementation // and we will then need to return both the original implementation and the generated implementation
// of externals. // of externals.
// println!("{:?}", quote::quote! { #input }.to_string()); println!("{:?}", quote::quote! { #input }.to_string());
let input = input.into(); let input = input.into();
input input
} }

View File

@ -10,9 +10,10 @@ pub struct Signature {
pub return_ty: Option<ValueType>, pub return_ty: Option<ValueType>,
} }
#[derive(Clone)]
pub struct Param { pub struct Param {
span: proc_macro2::Span, /// A generated identifier used for temporary variables.
generated_name: String, pub ident: syn::Ident,
} }
pub struct ExternalFunc { pub struct ExternalFunc {

View File

@ -1,5 +1,5 @@
use crate::model::{self, ExtDefinition, ExternalFunc}; use crate::model::{self, ExtDefinition, ExternalFunc, Param};
use syn::{ItemImpl, ImplItem, ImplItemMethod, FnArg, ReturnType}; use syn::{ItemImpl, ImplItem, ImplItemMethod, FnArg, ReturnType, Ident};
use syn::spanned::Spanned; use syn::spanned::Spanned;
/// Parse an incoming stream of tokens into a list of external functions. /// Parse an incoming stream of tokens into a list of external functions.
@ -17,8 +17,12 @@ pub fn parse(input: proc_macro2::TokenStream) -> Result<ExtDefinition, ()> {
let index = funcs.len() as u32; let index = funcs.len() as u32;
// self TODO: handle this properly // self TODO: handle this properly
let args = sig.decl.inputs.iter().skip(1).enumerate().map(|input| { let args = sig.decl.inputs.iter().skip(1).enumerate().map(|(idx, input)| {
input.span() let param_name = format!("arg{}", idx);
let ident = Ident::new(&param_name, input.span());
Param {
ident,
}
}).collect::<Vec<_>>(); }).collect::<Vec<_>>();
let return_ty = match sig.decl.output { let return_ty = match sig.decl.output {

View File

@ -16,16 +16,19 @@ impl<T> ConvertibleToWasm for *const T { type NativeType = u32; const VALUE_TYPE
impl<T> ConvertibleToWasm for *mut T { type NativeType = u32; const VALUE_TYPE: ValueType = ValueType::I32; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as isize as i32) } } impl<T> ConvertibleToWasm for *mut T { type NativeType = u32; const VALUE_TYPE: ValueType = ValueType::I32; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as isize as i32) } }
pub trait WasmResult { pub trait WasmResult {
const VALUE_TYPE: Option<ValueType>;
fn to_wasm_result(self) -> Result<Option<RuntimeValue>, Trap>; fn to_wasm_result(self) -> Result<Option<RuntimeValue>, Trap>;
} }
impl WasmResult for () { impl WasmResult for () {
const VALUE_TYPE: Option<ValueType> = None;
fn to_wasm_result(self) -> Result<Option<RuntimeValue>, Trap> { fn to_wasm_result(self) -> Result<Option<RuntimeValue>, Trap> {
Ok(None) Ok(None)
} }
} }
impl<R: ConvertibleToWasm, E: Into<Trap>> WasmResult for Result<R, E> { impl<R: ConvertibleToWasm, E: Into<Trap>> WasmResult for Result<R, E> {
const VALUE_TYPE: Option<ValueType> = Some(R::VALUE_TYPE);
fn to_wasm_result(self) -> Result<Option<RuntimeValue>, Trap> { fn to_wasm_result(self) -> Result<Option<RuntimeValue>, Trap> {
self self
.map(|v| Some(v.to_runtime_value())) .map(|v| Some(v.to_runtime_value()))
@ -34,6 +37,7 @@ impl<R: ConvertibleToWasm, E: Into<Trap>> WasmResult for Result<R, E> {
} }
impl<E: Into<Trap>> WasmResult for Result<(), E> { impl<E: Into<Trap>> WasmResult for Result<(), E> {
const VALUE_TYPE: Option<ValueType> = None;
fn to_wasm_result(self) -> Result<Option<RuntimeValue>, Trap> { fn to_wasm_result(self) -> Result<Option<RuntimeValue>, Trap> {
self self
.map(|_| None) .map(|_| None)
@ -42,6 +46,7 @@ impl<E: Into<Trap>> WasmResult for Result<(), E> {
} }
impl<R: ConvertibleToWasm> WasmResult for R { impl<R: ConvertibleToWasm> WasmResult for R {
const VALUE_TYPE: Option<ValueType> = Some(R::VALUE_TYPE);
fn to_wasm_result(self) -> Result<Option<RuntimeValue>, Trap> { fn to_wasm_result(self) -> Result<Option<RuntimeValue>, Trap> {
Ok(Some(self.to_runtime_value())) Ok(Some(self.to_runtime_value()))
} }

View File

@ -31,10 +31,4 @@ impl<'a> NonStaticExternals<'a> {
pub fn traps(&self) -> Result<(), NoInfoError> { pub fn traps(&self) -> Result<(), NoInfoError> {
Err(NoInfoError) Err(NoInfoError)
} }
pub fn fart(&self, inbound_fart: Fart) -> Result<Fart, NoInfoError> {
Ok(inbound_fart)
} }
}
pub struct Fart;