Make it work.
This commit is contained in:
parent
23b10d386c
commit
5f49943cfb
|
@ -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 = ¶m.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 = ¶m.ident;
|
||||||
|
quote! {
|
||||||
|
let #ident = None;
|
||||||
|
}
|
||||||
|
}).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let params_materialized_tys = func.args.iter().map(|param| {
|
||||||
|
let ident = ¶m.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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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(¶m_name, input.span());
|
||||||
|
Param {
|
||||||
|
ident,
|
||||||
|
}
|
||||||
}).collect::<Vec<_>>();
|
}).collect::<Vec<_>>();
|
||||||
|
|
||||||
let return_ty = match sig.decl.output {
|
let return_ty = match sig.decl.output {
|
||||||
|
|
|
@ -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()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
|
|
Loading…
Reference in New Issue