Skip to content

Instantly share code, notes, and snippets.

@Kimundi
Last active December 18, 2017 17:14
Show Gist options
  • Save Kimundi/bb99fa6a682f752bf0a3980e5a4866bb to your computer and use it in GitHub Desktop.
Save Kimundi/bb99fa6a682f752bf0a3980e5a4866bb to your computer and use it in GitHub Desktop.
extern {
fn magic() -> i32;
}
#[no_mangle]
pub extern fn calc(a: i32, b: i32) -> i32 {
a + b + unsafe{magic()} + 10000
}
extern crate parity_wasm;
use parity_wasm::ModuleInstanceInterface;
use parity_wasm::*;
use parity_wasm::interpreter::*;
use parity_wasm::elements::*;
//use parity_wasm::common::stack::StackWithLimit;
use parity_wasm::interpreter::Error as IError;
use std::sync::Arc;
use std::collections::HashMap;
trait RuntimeValueCast {
fn rt_from(rt: RuntimeValue) -> Self;
fn value_type() -> Option<ValueType>;
fn value(&self) -> Option<RuntimeValue>;
}
macro_rules! rt_cast_impl {
($t:ty, $n:ident) => (
impl RuntimeValueCast for $t {
fn rt_from(rt: RuntimeValue) -> Self {
if let RuntimeValue::$n(x) = rt {
x
} else {
panic!()
}
}
fn value_type() -> Option<ValueType> {
Some(ValueType::$n)
}
fn value(&self) -> Option<RuntimeValue> {
Some(RuntimeValue::$n(*self))
}
}
)
}
rt_cast_impl!(i32, I32);
rt_cast_impl!(i64, I64);
rt_cast_impl!(f32, F32);
rt_cast_impl!(f64, F64);
impl RuntimeValueCast for () {
fn rt_from(_: RuntimeValue) -> Self {
()
}
fn value_type() -> Option<ValueType> {
None
}
fn value(&self) -> Option<RuntimeValue> {
None
}
}
macro_rules! wasm_import {
(trait $name:ident; $($t:tt)*) => (
trait $name: ModuleInstanceInterface {
wasm_import!($($t)*);
}
impl<T: ?Sized + ModuleInstanceInterface> $name for T {
}
);
(fn $name:ident($($argname:ident: $argtype:ty),*); $($t:tt)*) => (
fn $name(&self, $($argname: $argtype),*) {
let r = self.execute_export(
stringify!($name),
vec![$($argname.into()),*].into()
).unwrap();
assert!(r.is_none());
}
);
(fn $name:ident($($argname:ident: $argtype:ty),*) -> $ret:ty; $($t:tt)*) => (
fn $name(&self, $($argname: $argtype),*) -> $ret {
let r = self.execute_export(
stringify!($name),
vec![$($argname.into()),*].into()
).unwrap().unwrap();
RuntimeValueCast::rt_from(r)
}
);
() => ()
}
struct NativeFn<T> {
ftag: T,
fty: FunctionType,
fname: &'static str,
}
macro_rules! wasm_export {
(
struct $struct_name:ident;
enum $enum_name:ident;
$($t1:tt)*
) => (
wasm_export!{
$struct_name
$enum_name
($($t1)*)
()
()
}
);
(
$struct_name:ident
$enum_name:ident
(fn $name:ident($($argname:ident: $argtype:ty),*) -> $ret:ty $b:block $($t1:tt)*)
($($t2:tt)*)
($($t3:tt)*)
) => (
wasm_export!{
$struct_name
$enum_name
($($t1)*)
($($t2)*
fn $name($($argname: $argtype),*) -> $ret $b
)
($($t3)*
$name ($($argname: $argtype),*) -> $ret;
)
}
);
(
$struct_name:ident
$enum_name:ident
(fn $name:ident($($argname:ident: $argtype:ty),*) $b:block $($t1:tt)*)
($($t2:tt)*)
($($t3:tt)*)
) => (
wasm_export!{
$struct_name
$enum_name
($($t1)*)
($($t2)*
fn $name($($argname: $argtype),*) $b
)
($($t3)*
$name ($($argname: $argtype),*) -> ();
)
}
);
(
$struct_name:ident
$enum_name:ident
()
($($f:item)*)
($(
$name:ident ($($namearg:ident : $namety:ty),*) -> $nameret:ty;
)*)
) => (
$($f)*
#[allow(non_camel_case_types)]
enum $enum_name {
$($name),*
}
struct $struct_name {
functions: Vec<NativeFn<$enum_name>>
}
impl $struct_name {
fn new() -> Self {
$struct_name {
functions: vec![
$(
NativeFn {
ftag: $enum_name::$name,
fty: FunctionType::new(vec![$(
<$namety>::value_type().unwrap()
),*], <$nameret>::value_type()),
fname: stringify!($name),
}
),*
]
}
}
}
impl ModuleInstanceInterface for $struct_name {
fn execute_index(&self, _index: u32, _params: ExecutionParams) -> Result<Option<RuntimeValue>, IError> {
unimplemented!("execute_index")
}
fn execute_export(&self, _name: &str, _params: ExecutionParams) -> Result<Option<RuntimeValue>, IError> {
unimplemented!("execute_export")
}
fn export_entry<'b>(&self, name: &str, required_type: &ExportEntryType) -> Result<Internal, IError> {
if let ExportEntryType::Function(ref f) = *required_type {
if let Some((idx, entry)) = self.functions.iter().enumerate().find(|x| x.1.fname == name) {
if *f == FunctionSignature::Module(&entry.fty) {
return Ok(Internal::Function(idx as u32));
}
}
}
unimplemented!("export_entry")
}
fn table(&self, _index: ItemIndex) -> Result<Arc<TableInstance>, IError> {
unimplemented!("table")
}
fn memory(&self, _index: ItemIndex) -> Result<Arc<MemoryInstance>, IError> {
unimplemented!("memory")
}
fn global<'b>(&self, _global_index: ItemIndex, _variable_type: Option<VariableType>, _externals: Option<&'b HashMap<String, Arc<ModuleInstanceInterface + 'b>>>) -> Result<Arc<VariableInstance>, IError> {
unimplemented!("global")
}
fn function_type(&self, function_index: ItemIndex) -> Result<FunctionSignature, IError> {
match function_index {
ItemIndex::IndexSpace(idx) | ItemIndex::Internal(idx) => {
if let Some(x) = self.functions.get(idx as usize) {
return Ok(FunctionSignature::Module(&x.fty));
}
}
_ => {}
}
unimplemented!("function_type")
}
fn function_type_by_index(&self, _type_index: u32) -> Result<FunctionSignature, IError> {
unimplemented!("function_type_by_index")
}
fn function_reference<'b>(&self, _index: ItemIndex, _externals: Option<&'b HashMap<String, Arc<ModuleInstanceInterface + 'b>>>) -> Result<InternalFunctionReference<'b>, IError> {
unimplemented!("function_reference")
}
fn function_reference_indirect<'b>(&self, _table_idx: u32, _type_idx: u32, _func_idx: u32, _externals: Option<&'b HashMap<String, Arc<ModuleInstanceInterface + 'b>>>) -> Result<InternalFunctionReference<'b>, IError> {
unimplemented!("function_reference_indirect")
}
fn function_body<'b>(&'b self, _internal_index: u32) -> Result<Option<InternalFunction<'b>>, IError> {
Ok(None)
}
fn call_internal_function(&self, mut _outer: CallerContext, index: u32) -> Result<Option<RuntimeValue>, IError> {
let entry = &self.functions[index as usize];
match entry.ftag {
$(
$enum_name::$name => {
$(
let $namearg: $namety = _outer.value_stack.pop_as().unwrap();
)*
let ret: $nameret = $name($($namearg),*);
return Ok(ret.value());
}
)*
}
}
}
)
}
wasm_import! {
trait MyExtension;
// Wasm function exported to native
fn calc(a: i32, b: i32) -> i32;
}
wasm_export! {
struct Native;
enum NativeDispatch;
// Native function exported to wasm
fn magic() -> i32 {
99
}
}
fn main() {
let module = parity_wasm::deserialize_file("../../client/client/test.wasm").unwrap();
let program = parity_wasm::ProgramInstance::new();
let native = Arc::new(Native::new());
program.insert_loaded_module("env", native).unwrap();
let m = program.add_module("client", module, None).unwrap();
let res = m.calc(200,9000);
println!("Res: {:?}", res);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment