mirror of
https://github.com/fluencelabs/parity-wasm
synced 2025-06-17 00:41:49 +00:00
Use Externals mechanism instead of HostState
This commit is contained in:
@ -3,7 +3,7 @@
|
|||||||
extern crate parity_wasm;
|
extern crate parity_wasm;
|
||||||
|
|
||||||
use std::env::args;
|
use std::env::args;
|
||||||
use parity_wasm::interpreter::{ModuleInstance, HostState};
|
use parity_wasm::interpreter::{ModuleInstance, EmptyExternals};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args: Vec<_> = args().collect();
|
let args: Vec<_> = args().collect();
|
||||||
@ -23,12 +23,12 @@ fn main() {
|
|||||||
// - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here
|
// - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here
|
||||||
// This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197
|
// This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197
|
||||||
let main = ModuleInstance::new(&module)
|
let main = ModuleInstance::new(&module)
|
||||||
.run_start(&mut HostState::default())
|
.run_start(&mut EmptyExternals)
|
||||||
.expect("Failed to initialize module");
|
.expect("Failed to initialize module");
|
||||||
|
|
||||||
// The argument should be parsable as a valid integer
|
// The argument should be parsable as a valid integer
|
||||||
let argument: i32 = args[2].parse().expect("Integer argument required");
|
let argument: i32 = args[2].parse().expect("Integer argument required");
|
||||||
|
|
||||||
// "_call" export of function to be executed with an i32 argument and prints the result of execution
|
// "_call" export of function to be executed with an i32 argument and prints the result of execution
|
||||||
println!("Result: {:?}", main.invoke_export("_call", &[parity_wasm::RuntimeValue::I32(argument)], &mut HostState::default()));
|
println!("Result: {:?}", main.invoke_export("_call", &[parity_wasm::RuntimeValue::I32(argument)], &mut EmptyExternals));
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ use std::env::args;
|
|||||||
|
|
||||||
use parity_wasm::RuntimeValue;
|
use parity_wasm::RuntimeValue;
|
||||||
use parity_wasm::elements::{Internal, External, Type, FunctionType, ValueType};
|
use parity_wasm::elements::{Internal, External, Type, FunctionType, ValueType};
|
||||||
use parity_wasm::interpreter::{ModuleInstance, HostState};
|
use parity_wasm::interpreter::{ModuleInstance, EmptyExternals};
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -75,8 +75,8 @@ fn main() {
|
|||||||
// - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here
|
// - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here
|
||||||
// This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197
|
// This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197
|
||||||
let main = ModuleInstance::new(&module)
|
let main = ModuleInstance::new(&module)
|
||||||
.run_start(&mut HostState::default())
|
.run_start(&mut EmptyExternals)
|
||||||
.expect("Failed to initialize module");
|
.expect("Failed to initialize module");
|
||||||
|
|
||||||
println!("Result: {:?}", main.invoke_export(func_name, &args, &mut HostState::default()).expect(""));
|
println!("Result: {:?}", main.invoke_export(func_name, &args, &mut EmptyExternals).expect(""));
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,11 @@ extern crate parity_wasm;
|
|||||||
use std::env;
|
use std::env;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use parity_wasm::elements::Module;
|
use parity_wasm::elements::{Module, FunctionType, ValueType, TableType, GlobalType, MemoryType};
|
||||||
use parity_wasm::interpreter::{
|
use parity_wasm::interpreter::{
|
||||||
Error as InterpreterError, HostModule, HostModuleBuilder,
|
Error as InterpreterError, ModuleInstance, UserError,
|
||||||
ModuleInstance, UserError, HostState, StateKey
|
HostFuncIndex, Externals, RuntimeValue, GlobalInstance, TableInstance, MemoryInstance,
|
||||||
|
TableRef, MemoryRef, GlobalRef, FuncRef, TryInto, ImportResolver, FuncInstance,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -139,54 +140,123 @@ struct Runtime<'a> {
|
|||||||
game: &'a mut tictactoe::Game,
|
game: &'a mut tictactoe::Game,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<'a> StateKey for Runtime<'a> {
|
const SET_FUNC_INDEX: HostFuncIndex = 0;
|
||||||
type Static = Runtime<'static>;
|
const GET_FUNC_INDEX: HostFuncIndex = 1;
|
||||||
|
|
||||||
|
impl<'a> Externals for Runtime<'a> {
|
||||||
|
fn invoke_index(
|
||||||
|
&mut self,
|
||||||
|
index: HostFuncIndex,
|
||||||
|
args: &[RuntimeValue],
|
||||||
|
) -> Result<Option<RuntimeValue>, InterpreterError> {
|
||||||
|
match index {
|
||||||
|
SET_FUNC_INDEX => {
|
||||||
|
let idx: i32 = args[0].try_into().unwrap();
|
||||||
|
self.game.set(idx, self.player)?;
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
GET_FUNC_INDEX => {
|
||||||
|
let idx: i32 = args[0].try_into().unwrap();
|
||||||
|
let val: i32 = tictactoe::Player::into_i32(self.game.get(idx)?);
|
||||||
|
Ok(Some(val.into()))
|
||||||
|
}
|
||||||
|
_ => panic!("unknown function index")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_signature(&self, index: HostFuncIndex, sig: &FunctionType) -> bool {
|
||||||
|
match index {
|
||||||
|
SET_FUNC_INDEX => {
|
||||||
|
sig.params() == &[ValueType::I32] && sig.return_type() == None
|
||||||
|
}
|
||||||
|
GET_FUNC_INDEX => {
|
||||||
|
sig.params() == &[ValueType::I32] && sig.return_type() == Some(ValueType::I32)
|
||||||
|
}
|
||||||
|
_ => panic!("unknown function index")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn memory_by_index(&self, _index: usize) -> &MemoryInstance {
|
||||||
|
panic!("host module doesn't export any memories")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn table_by_index(&self, _index: usize) -> &TableInstance {
|
||||||
|
panic!("host module doesn't export any tables")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn global_by_index(&self, _index: usize) -> &GlobalInstance {
|
||||||
|
panic!("host module doesn't export any globals")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RuntimeImportResolver;
|
||||||
|
|
||||||
|
impl<'a> ImportResolver for RuntimeImportResolver {
|
||||||
|
fn resolve_func(
|
||||||
|
&self,
|
||||||
|
field_name: &str,
|
||||||
|
_func_type: &FunctionType,
|
||||||
|
) -> Result<FuncRef, InterpreterError> {
|
||||||
|
let func_ref = match field_name {
|
||||||
|
"set" => {
|
||||||
|
FuncInstance::alloc_host(FunctionType::new(vec![ValueType::I32], None), SET_FUNC_INDEX)
|
||||||
|
},
|
||||||
|
"get" => FuncInstance::alloc_host(FunctionType::new(vec![ValueType::I32], Some(ValueType::I32)), GET_FUNC_INDEX),
|
||||||
|
_ => return Err(
|
||||||
|
InterpreterError::Function(
|
||||||
|
format!("host module doesn't export function with name {}", field_name)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
};
|
||||||
|
Ok(func_ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_global(
|
||||||
|
&self,
|
||||||
|
_field_name: &str,
|
||||||
|
_global_type: &GlobalType,
|
||||||
|
) -> Result<GlobalRef, InterpreterError> {
|
||||||
|
Err(
|
||||||
|
InterpreterError::Global("host module doesn't export any globals".to_owned())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_memory(
|
||||||
|
&self,
|
||||||
|
_field_name: &str,
|
||||||
|
_memory_type: &MemoryType,
|
||||||
|
) -> Result<MemoryRef, InterpreterError> {
|
||||||
|
Err(
|
||||||
|
InterpreterError::Global("host module doesn't export any memories".to_owned())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_table(
|
||||||
|
&self,
|
||||||
|
_field_name: &str,
|
||||||
|
_table_type: &TableType,
|
||||||
|
) -> Result<TableRef, InterpreterError> {
|
||||||
|
Err(
|
||||||
|
InterpreterError::Global("host module doesn't export any tables".to_owned())
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn instantiate(
|
fn instantiate(
|
||||||
module: &Module,
|
module: &Module,
|
||||||
env: &HostModule,
|
|
||||||
) -> Result<Rc<ModuleInstance>, Error> {
|
) -> Result<Rc<ModuleInstance>, Error> {
|
||||||
let instance = ModuleInstance::new(module)
|
let instance = ModuleInstance::new(module)
|
||||||
.with_import("env", &*env)
|
.with_import("env", &RuntimeImportResolver)
|
||||||
.run_start(&mut HostState::default())?;
|
.assert_no_start()?;
|
||||||
|
|
||||||
Ok(instance)
|
Ok(instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn env_host_module() -> HostModule {
|
fn play(
|
||||||
HostModuleBuilder::new()
|
x_instance: Rc<ModuleInstance>,
|
||||||
.with_func1(
|
o_instance: Rc<ModuleInstance>,
|
||||||
"set",
|
game: &mut tictactoe::Game,
|
||||||
|state: &mut HostState, idx: i32| -> Result<(), InterpreterError> {
|
|
||||||
state.with_mut(move |runtime: &mut Runtime| -> Result<(), InterpreterError> {
|
|
||||||
runtime.game.set(idx, runtime.player)?;
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.with_func1(
|
|
||||||
"get",
|
|
||||||
|state: &mut HostState, idx: i32| -> Result<i32, InterpreterError> {
|
|
||||||
state.with(move |runtime: &Runtime| -> Result<i32, InterpreterError> {
|
|
||||||
let val: i32 = tictactoe::Player::into_i32(runtime.game.get(idx)?);
|
|
||||||
Ok(val)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn play<'a>(
|
|
||||||
x_module: &Module,
|
|
||||||
o_module: &Module,
|
|
||||||
host_module: &HostModule,
|
|
||||||
game: &'a mut tictactoe::Game,
|
|
||||||
) -> Result<tictactoe::GameResult, Error> {
|
) -> Result<tictactoe::GameResult, Error> {
|
||||||
// Instantiate modules of X and O players.
|
|
||||||
let x_instance = instantiate(x_module, host_module)?;
|
|
||||||
let o_instance = instantiate(o_module, host_module)?;
|
|
||||||
|
|
||||||
let mut turn_of = tictactoe::Player::X;
|
let mut turn_of = tictactoe::Player::X;
|
||||||
let game_result = loop {
|
let game_result = loop {
|
||||||
let (instance, next_turn_of) = match turn_of {
|
let (instance, next_turn_of) = match turn_of {
|
||||||
@ -199,11 +269,7 @@ fn play<'a>(
|
|||||||
player: turn_of,
|
player: turn_of,
|
||||||
game: game,
|
game: game,
|
||||||
};
|
};
|
||||||
{
|
let _ = instance.invoke_export("mk_turn", &[], &mut runtime)?;
|
||||||
let mut host_state = HostState::new();
|
|
||||||
host_state.insert::<Runtime>(&mut runtime);
|
|
||||||
let _ = instance.invoke_export("mk_turn", &[], &mut host_state)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match game.game_result() {
|
match game.game_result() {
|
||||||
@ -219,7 +285,6 @@ fn play<'a>(
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut game = tictactoe::Game::new();
|
let mut game = tictactoe::Game::new();
|
||||||
let env_host_module = env_host_module();
|
|
||||||
|
|
||||||
let args: Vec<_> = env::args().collect();
|
let args: Vec<_> = env::args().collect();
|
||||||
if args.len() < 3 {
|
if args.len() < 3 {
|
||||||
@ -229,6 +294,10 @@ fn main() {
|
|||||||
let x_module = parity_wasm::deserialize_file(&args[1]).expect("X player module to load");
|
let x_module = parity_wasm::deserialize_file(&args[1]).expect("X player module to load");
|
||||||
let o_module = parity_wasm::deserialize_file(&args[2]).expect("Y player module to load");
|
let o_module = parity_wasm::deserialize_file(&args[2]).expect("Y player module to load");
|
||||||
|
|
||||||
let result = play(&x_module, &o_module, &env_host_module, &mut game);
|
// Instantiate modules of X and O players.
|
||||||
|
let x_instance = instantiate(&x_module).unwrap();
|
||||||
|
let o_instance = instantiate(&o_module).unwrap();
|
||||||
|
|
||||||
|
let result = play(x_instance, o_instance, &mut game);
|
||||||
println!("result = {:?}, game = {:#?}", result, game);
|
println!("result = {:?}, game = {:#?}", result, game);
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,9 @@ use std::collections::HashMap;
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use elements::{FunctionType, Local, Opcodes};
|
use elements::{FunctionType, Local, Opcodes};
|
||||||
use interpreter::{Error, ModuleInstance};
|
use interpreter::{Error, ModuleInstance};
|
||||||
|
use interpreter::host::{Externals, HostFuncIndex};
|
||||||
use interpreter::runner::{prepare_function_args, FunctionContext, Interpreter};
|
use interpreter::runner::{prepare_function_args, FunctionContext, Interpreter};
|
||||||
use interpreter::host::HostFunc;
|
|
||||||
use interpreter::value::RuntimeValue;
|
use interpreter::value::RuntimeValue;
|
||||||
use interpreter::state::HostState;
|
|
||||||
use common::stack::StackWithLimit;
|
use common::stack::StackWithLimit;
|
||||||
use common::{DEFAULT_FRAME_STACK_LIMIT, DEFAULT_VALUE_STACK_LIMIT};
|
use common::{DEFAULT_FRAME_STACK_LIMIT, DEFAULT_VALUE_STACK_LIMIT};
|
||||||
|
|
||||||
@ -29,8 +28,8 @@ pub enum FuncInstance {
|
|||||||
body: Rc<FuncBody>,
|
body: Rc<FuncBody>,
|
||||||
},
|
},
|
||||||
Host {
|
Host {
|
||||||
func_type: Rc<FunctionType>,
|
func_type: FunctionType,
|
||||||
host_func: Rc<HostFunc>,
|
host_func: HostFuncIndex,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +56,7 @@ impl fmt::Debug for FuncInstance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FuncInstance {
|
impl FuncInstance {
|
||||||
pub fn alloc_internal(
|
pub(crate) fn alloc_internal(
|
||||||
module: Rc<ModuleInstance>,
|
module: Rc<ModuleInstance>,
|
||||||
func_type: Rc<FunctionType>,
|
func_type: Rc<FunctionType>,
|
||||||
body: FuncBody,
|
body: FuncBody,
|
||||||
@ -70,7 +69,7 @@ impl FuncInstance {
|
|||||||
FuncRef(Rc::new(func))
|
FuncRef(Rc::new(func))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn alloc_host(func_type: Rc<FunctionType>, host_func: Rc<HostFunc>) -> FuncRef {
|
pub fn alloc_host(func_type: FunctionType, host_func: HostFuncIndex) -> FuncRef {
|
||||||
let func = FuncInstance::Host {
|
let func = FuncInstance::Host {
|
||||||
func_type,
|
func_type,
|
||||||
host_func,
|
host_func,
|
||||||
@ -78,10 +77,10 @@ impl FuncInstance {
|
|||||||
FuncRef(Rc::new(func))
|
FuncRef(Rc::new(func))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn func_type(&self) -> Rc<FunctionType> {
|
pub fn func_type(&self) -> &FunctionType {
|
||||||
match *self {
|
match *self {
|
||||||
FuncInstance::Internal { ref func_type, .. } |
|
FuncInstance::Internal { ref func_type, .. } => func_type,
|
||||||
FuncInstance::Host { ref func_type, .. } => Rc::clone(func_type),
|
FuncInstance::Host { ref func_type, .. } => func_type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,14 +91,14 @@ impl FuncInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn invoke<'a, 'b: 'a>(
|
pub fn invoke<E: Externals>(
|
||||||
func: FuncRef,
|
func: FuncRef,
|
||||||
args: Cow<[RuntimeValue]>,
|
args: Cow<[RuntimeValue]>,
|
||||||
state: &'a mut HostState<'b>,
|
externals: &mut E,
|
||||||
) -> Result<Option<RuntimeValue>, Error> {
|
) -> Result<Option<RuntimeValue>, Error> {
|
||||||
enum InvokeKind<'a> {
|
enum InvokeKind<'a> {
|
||||||
Internal(FunctionContext),
|
Internal(FunctionContext),
|
||||||
Host(Rc<HostFunc>, &'a [RuntimeValue]),
|
Host(HostFuncIndex, &'a [RuntimeValue]),
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = match *func {
|
let result = match *func {
|
||||||
@ -117,16 +116,16 @@ impl FuncInstance {
|
|||||||
InvokeKind::Internal(context)
|
InvokeKind::Internal(context)
|
||||||
}
|
}
|
||||||
FuncInstance::Host { ref host_func, .. } => {
|
FuncInstance::Host { ref host_func, .. } => {
|
||||||
InvokeKind::Host(Rc::clone(host_func), &*args)
|
InvokeKind::Host(*host_func, &*args)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
InvokeKind::Internal(ctx) => {
|
InvokeKind::Internal(ctx) => {
|
||||||
let mut interpreter = Interpreter::new(state);
|
let mut interpreter = Interpreter::new(externals);
|
||||||
interpreter.run_function(ctx)
|
interpreter.run_function(ctx)
|
||||||
}
|
}
|
||||||
InvokeKind::Host(host_func, args) => host_func(state, args),
|
InvokeKind::Host(host_func, args) => externals.invoke_index(host_func, args),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,405 +1,50 @@
|
|||||||
use std::rc::Rc;
|
use elements::FunctionType;
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::collections::hash_map::Entry;
|
|
||||||
use elements::{FunctionType, GlobalType, MemoryType, TableType, ValueType};
|
|
||||||
use interpreter::module::{ExternVal, ModuleInstance};
|
|
||||||
use interpreter::func::FuncRef;
|
|
||||||
use interpreter::global::GlobalRef;
|
|
||||||
use interpreter::memory::MemoryRef;
|
|
||||||
use interpreter::table::TableRef;
|
|
||||||
use interpreter::func::FuncInstance;
|
|
||||||
use interpreter::global::GlobalInstance;
|
use interpreter::global::GlobalInstance;
|
||||||
use interpreter::memory::MemoryInstance;
|
use interpreter::memory::MemoryInstance;
|
||||||
use interpreter::table::TableInstance;
|
use interpreter::table::TableInstance;
|
||||||
use interpreter::value::{RuntimeValue, TryInto};
|
use interpreter::value::RuntimeValue;
|
||||||
use interpreter::Error;
|
use interpreter::Error;
|
||||||
use interpreter::ImportResolver;
|
|
||||||
use interpreter::state::HostState;
|
|
||||||
|
|
||||||
pub type HostFunc = Fn(&mut HostState, &[RuntimeValue])
|
pub type HostFuncIndex = u32;
|
||||||
-> Result<Option<RuntimeValue>, Error>;
|
|
||||||
|
|
||||||
pub struct HostModuleBuilder {
|
pub trait Externals {
|
||||||
exports: HashMap<String, ExternVal>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HostModuleBuilder {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
HostModuleBuilder {
|
|
||||||
exports: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert_func0<
|
|
||||||
Cl: Fn(&mut HostState) -> Result<Ret, Error> + 'static,
|
|
||||||
Ret: IntoReturnVal + 'static,
|
|
||||||
N: Into<String>,
|
|
||||||
>(
|
|
||||||
&mut self,
|
|
||||||
name: N,
|
|
||||||
f: Cl,
|
|
||||||
) {
|
|
||||||
let func_type = FunctionType::new(vec![], Ret::value_type());
|
|
||||||
let host_func = Rc::new(
|
|
||||||
move |state: &mut HostState, args: &[RuntimeValue]| -> Result<Option<RuntimeValue>, Error> {
|
|
||||||
assert!(args.len() == 0);
|
|
||||||
let result = f(state)?.into_return_val();
|
|
||||||
Ok(result)
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let func = FuncInstance::alloc_host(Rc::new(func_type), host_func);
|
|
||||||
self.insert_func(name, func);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert_func1<
|
|
||||||
Cl: Fn(&mut HostState, P1) -> Result<Ret, Error> + 'static,
|
|
||||||
Ret: IntoReturnVal + 'static,
|
|
||||||
P1: FromArg + 'static,
|
|
||||||
N: Into<String>,
|
|
||||||
>(
|
|
||||||
&mut self,
|
|
||||||
name: N,
|
|
||||||
f: Cl,
|
|
||||||
) {
|
|
||||||
let func_type = FunctionType::new(vec![P1::value_type()], Ret::value_type());
|
|
||||||
let host_func = Rc::new(
|
|
||||||
move |state: &mut HostState, args: &[RuntimeValue]| -> Result<Option<RuntimeValue>, Error> {
|
|
||||||
assert!(args.len() == 1);
|
|
||||||
let mut args = args.into_iter();
|
|
||||||
let result = f(
|
|
||||||
state,
|
|
||||||
P1::from_arg(args.next().unwrap())
|
|
||||||
)?.into_return_val();
|
|
||||||
Ok(result)
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let func = FuncInstance::alloc_host(Rc::new(func_type), host_func);
|
|
||||||
self.insert_func(name, func);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert_func2<
|
|
||||||
Cl: Fn(&mut HostState, P1, P2) -> Result<Ret, Error> + 'static,
|
|
||||||
Ret: IntoReturnVal + 'static,
|
|
||||||
P1: FromArg + 'static,
|
|
||||||
P2: FromArg + 'static,
|
|
||||||
N: Into<String>,
|
|
||||||
>(
|
|
||||||
&mut self,
|
|
||||||
name: N,
|
|
||||||
f: Cl,
|
|
||||||
) {
|
|
||||||
let func_type =
|
|
||||||
FunctionType::new(vec![P1::value_type(), P2::value_type()], Ret::value_type());
|
|
||||||
let host_func = Rc::new(
|
|
||||||
move |state: &mut HostState, args: &[RuntimeValue]| -> Result<Option<RuntimeValue>, Error> {
|
|
||||||
assert!(args.len() == 2);
|
|
||||||
let mut args = args.into_iter();
|
|
||||||
let result = f(
|
|
||||||
state,
|
|
||||||
P1::from_arg(args.next().unwrap()),
|
|
||||||
P2::from_arg(args.next().unwrap()),
|
|
||||||
)?.into_return_val();
|
|
||||||
Ok(result)
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let func = FuncInstance::alloc_host(Rc::new(func_type), host_func);
|
|
||||||
self.insert_func(name, func);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert_func3<
|
|
||||||
Cl: Fn(&mut HostState, P1, P2, P3) -> Result<Ret, Error> + 'static,
|
|
||||||
Ret: IntoReturnVal + 'static,
|
|
||||||
P1: FromArg + 'static,
|
|
||||||
P2: FromArg + 'static,
|
|
||||||
P3: FromArg + 'static,
|
|
||||||
N: Into<String>,
|
|
||||||
>(
|
|
||||||
&mut self,
|
|
||||||
name: N,
|
|
||||||
f: Cl,
|
|
||||||
) {
|
|
||||||
let func_type = FunctionType::new(
|
|
||||||
vec![P1::value_type(), P2::value_type(), P3::value_type()],
|
|
||||||
Ret::value_type(),
|
|
||||||
);
|
|
||||||
let host_func = Rc::new(
|
|
||||||
move |state: &mut HostState, args: &[RuntimeValue]| -> Result<Option<RuntimeValue>, Error> {
|
|
||||||
assert!(args.len() == 3);
|
|
||||||
let mut args = args.into_iter();
|
|
||||||
let result = f(
|
|
||||||
state,
|
|
||||||
P1::from_arg(args.next().unwrap()),
|
|
||||||
P2::from_arg(args.next().unwrap()),
|
|
||||||
P3::from_arg(args.next().unwrap()),
|
|
||||||
)?.into_return_val();
|
|
||||||
Ok(result)
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let func = FuncInstance::alloc_host(Rc::new(func_type), host_func);
|
|
||||||
self.insert_func(name, func);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert_func4<
|
|
||||||
Cl: Fn(&mut HostState, P1, P2, P3, P4) -> Result<Ret, Error> + 'static,
|
|
||||||
Ret: IntoReturnVal + 'static,
|
|
||||||
P1: FromArg + 'static,
|
|
||||||
P2: FromArg + 'static,
|
|
||||||
P3: FromArg + 'static,
|
|
||||||
P4: FromArg + 'static,
|
|
||||||
N: Into<String>,
|
|
||||||
>(
|
|
||||||
&mut self,
|
|
||||||
name: N,
|
|
||||||
f: Cl,
|
|
||||||
) {
|
|
||||||
let func_type = FunctionType::new(
|
|
||||||
vec![
|
|
||||||
P1::value_type(),
|
|
||||||
P2::value_type(),
|
|
||||||
P3::value_type(),
|
|
||||||
P4::value_type(),
|
|
||||||
],
|
|
||||||
Ret::value_type(),
|
|
||||||
);
|
|
||||||
let host_func = Rc::new(
|
|
||||||
move |state: &mut HostState, args: &[RuntimeValue]| -> Result<Option<RuntimeValue>, Error> {
|
|
||||||
assert!(args.len() == 4);
|
|
||||||
let mut args = args.into_iter();
|
|
||||||
let result = f(
|
|
||||||
state,
|
|
||||||
P1::from_arg(args.next().unwrap()),
|
|
||||||
P2::from_arg(args.next().unwrap()),
|
|
||||||
P3::from_arg(args.next().unwrap()),
|
|
||||||
P4::from_arg(args.next().unwrap()),
|
|
||||||
)?.into_return_val();
|
|
||||||
Ok(result)
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let func = FuncInstance::alloc_host(Rc::new(func_type), host_func);
|
|
||||||
self.insert_func(name, func);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_func0<
|
|
||||||
Cl: Fn(&mut HostState) -> Result<Ret, Error> + 'static,
|
|
||||||
Ret: IntoReturnVal + 'static,
|
|
||||||
N: Into<String>,
|
|
||||||
>(
|
|
||||||
mut self,
|
|
||||||
name: N,
|
|
||||||
f: Cl,
|
|
||||||
) -> Self {
|
|
||||||
self.insert_func0(name, f);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_func1<
|
|
||||||
Cl: Fn(&mut HostState, P1) -> Result<Ret, Error> + 'static,
|
|
||||||
Ret: IntoReturnVal + 'static,
|
|
||||||
P1: FromArg + 'static,
|
|
||||||
N: Into<String>,
|
|
||||||
>(
|
|
||||||
mut self,
|
|
||||||
name: N,
|
|
||||||
f: Cl,
|
|
||||||
) -> Self {
|
|
||||||
self.insert_func1(name, f);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_func2<
|
|
||||||
Cl: Fn(&mut HostState, P1, P2) -> Result<Ret, Error> + 'static,
|
|
||||||
Ret: IntoReturnVal + 'static,
|
|
||||||
P1: FromArg + 'static,
|
|
||||||
P2: FromArg + 'static,
|
|
||||||
N: Into<String>,
|
|
||||||
>(
|
|
||||||
mut self,
|
|
||||||
name: N,
|
|
||||||
f: Cl,
|
|
||||||
) -> Self {
|
|
||||||
self.insert_func2(name, f);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert_func<N: Into<String>>(&mut self, name: N, func: FuncRef) {
|
|
||||||
self.insert(name, ExternVal::Func(func));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert_global<N: Into<String>>(&mut self, name: N, global: GlobalRef) {
|
|
||||||
self.insert(name, ExternVal::Global(global));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert_memory<N: Into<String>>(&mut self, name: N, memory: MemoryRef) {
|
|
||||||
self.insert(name, ExternVal::Memory(memory));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert_table<N: Into<String>>(&mut self, name: N, table: TableRef) {
|
|
||||||
self.insert(name, ExternVal::Table(table));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_global<N: Into<String>>(mut self, name: N, global: GlobalRef) -> Self {
|
|
||||||
self.insert_global(name, global);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_memory<N: Into<String>>(mut self, name: N, memory: MemoryRef) -> Self {
|
|
||||||
self.insert_memory(name, memory);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_table<N: Into<String>>(mut self, name: N, table: TableRef) -> Self {
|
|
||||||
self.insert_table(name, table);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert<N: Into<String>>(&mut self, name: N, extern_val: ExternVal) {
|
|
||||||
match self.exports.entry(name.into()) {
|
|
||||||
Entry::Vacant(v) => v.insert(extern_val),
|
|
||||||
Entry::Occupied(o) => panic!("Duplicate export name {}", o.key()),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build(self) -> HostModule {
|
|
||||||
let internal_instance = Rc::new(ModuleInstance::with_exports(self.exports));
|
|
||||||
HostModule { internal_instance }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct HostModule {
|
|
||||||
internal_instance: Rc<ModuleInstance>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HostModule {
|
|
||||||
pub fn export_by_name(&self, name: &str) -> Option<ExternVal> {
|
|
||||||
self.internal_instance.export_by_name(name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ImportResolver for HostModule {
|
|
||||||
fn resolve_func(
|
|
||||||
&self,
|
|
||||||
field_name: &str,
|
|
||||||
func_type: &FunctionType,
|
|
||||||
) -> Result<FuncRef, Error> {
|
|
||||||
self.internal_instance.resolve_func(field_name, func_type)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_global(
|
|
||||||
&self,
|
|
||||||
field_name: &str,
|
|
||||||
global_type: &GlobalType,
|
|
||||||
) -> Result<GlobalRef, Error> {
|
|
||||||
self.internal_instance
|
|
||||||
.resolve_global(field_name, global_type)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_memory(
|
|
||||||
&self,
|
|
||||||
field_name: &str,
|
|
||||||
memory_type: &MemoryType,
|
|
||||||
) -> Result<MemoryRef, Error> {
|
|
||||||
self.internal_instance
|
|
||||||
.resolve_memory(field_name, memory_type)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_table(
|
|
||||||
&self,
|
|
||||||
field_name: &str,
|
|
||||||
table_type: &TableType,
|
|
||||||
) -> Result<TableRef, Error> {
|
|
||||||
self.internal_instance.resolve_table(field_name, table_type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait FromArg
|
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
fn from_arg(arg: &RuntimeValue) -> Self;
|
|
||||||
fn value_type() -> ValueType;
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_from_arg {
|
|
||||||
($ty: ident, $val_ty: ident) => {
|
|
||||||
impl FromArg for $ty {
|
|
||||||
fn from_arg(arg: &RuntimeValue) -> Self {
|
|
||||||
arg
|
|
||||||
.try_into()
|
|
||||||
.expect(
|
|
||||||
concat!("Due to validation, arg expected to be ", stringify!($val_ty))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn value_type() -> ValueType {
|
|
||||||
use self::ValueType::*;
|
|
||||||
$val_ty
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_from_arg!(i32, I32);
|
|
||||||
impl_from_arg!(u32, I32);
|
|
||||||
impl_from_arg!(i64, I64);
|
|
||||||
impl_from_arg!(u64, I64);
|
|
||||||
impl_from_arg!(f32, F32);
|
|
||||||
impl_from_arg!(f64, F64);
|
|
||||||
|
|
||||||
pub trait IntoReturnVal {
|
|
||||||
fn into_return_val(self) -> Option<RuntimeValue>;
|
|
||||||
fn value_type() -> Option<ValueType>;
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_into_return_val {
|
|
||||||
($ty: ident, $val_ty: ident) => {
|
|
||||||
impl IntoReturnVal for $ty {
|
|
||||||
fn into_return_val(self) -> Option<RuntimeValue> {
|
|
||||||
Some(self.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn value_type() -> Option<ValueType> {
|
|
||||||
use self::ValueType::*;
|
|
||||||
Some($val_ty)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_into_return_val!(i32, I32);
|
|
||||||
impl_into_return_val!(u32, I32);
|
|
||||||
impl_into_return_val!(i64, I64);
|
|
||||||
impl_into_return_val!(u64, I64);
|
|
||||||
impl_into_return_val!(f32, F32);
|
|
||||||
impl_into_return_val!(f64, F64);
|
|
||||||
|
|
||||||
impl IntoReturnVal for () {
|
|
||||||
fn into_return_val(self) -> Option<RuntimeValue> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn value_type() -> Option<ValueType> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trait Externals {
|
|
||||||
fn invoke_index(
|
fn invoke_index(
|
||||||
&mut self,
|
&mut self,
|
||||||
index: u32,
|
index: HostFuncIndex,
|
||||||
args: &[RuntimeValue],
|
args: &[RuntimeValue],
|
||||||
) -> Result<Option<RuntimeValue>, Error>;
|
) -> Result<Option<RuntimeValue>, Error>;
|
||||||
|
|
||||||
// TODO: or check signature?
|
fn check_signature(&self, index: HostFuncIndex, signature: &FunctionType) -> bool;
|
||||||
fn signature(&self, index: usize) -> &FunctionType;
|
|
||||||
|
|
||||||
fn memory_by_index(&self, index: usize) -> &MemoryInstance;
|
fn memory_by_index(&self, index: usize) -> &MemoryInstance;
|
||||||
fn table_by_index(&self, index: usize) -> &TableInstance;
|
fn table_by_index(&self, index: usize) -> &TableInstance;
|
||||||
fn global_by_index(&self, index: usize) -> &GlobalInstance;
|
fn global_by_index(&self, index: usize) -> &GlobalInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct EmptyExternals;
|
||||||
|
|
||||||
|
impl Externals for EmptyExternals {
|
||||||
|
fn invoke_index(
|
||||||
|
&mut self,
|
||||||
|
_index: HostFuncIndex,
|
||||||
|
_args: &[RuntimeValue],
|
||||||
|
) -> Result<Option<RuntimeValue>, Error> {
|
||||||
|
panic!("called invoke_index on EmptyExternals")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_signature(&self, _index: HostFuncIndex, _signature: &FunctionType) -> bool {
|
||||||
|
panic!("called check_signature on EmptyExternals")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn memory_by_index(&self, _index: usize) -> &MemoryInstance {
|
||||||
|
panic!("called memory_by_index on EmptyExternals")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn table_by_index(&self, _index: usize) -> &TableInstance {
|
||||||
|
panic!("called table_by_index on EmptyExternals")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn global_by_index(&self, _index: usize) -> &GlobalInstance {
|
||||||
|
panic!("called global_by_index on EmptyExternals")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -146,7 +146,6 @@ mod host;
|
|||||||
mod imports;
|
mod imports;
|
||||||
mod global;
|
mod global;
|
||||||
mod func;
|
mod func;
|
||||||
mod state;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
@ -154,10 +153,9 @@ mod tests;
|
|||||||
pub use self::memory::{MemoryInstance, MemoryRef};
|
pub use self::memory::{MemoryInstance, MemoryRef};
|
||||||
pub use self::table::{TableInstance, TableRef};
|
pub use self::table::{TableInstance, TableRef};
|
||||||
pub use self::program::ProgramInstance;
|
pub use self::program::ProgramInstance;
|
||||||
pub use self::value::RuntimeValue;
|
pub use self::value::{RuntimeValue, TryInto};
|
||||||
pub use self::host::{HostModule, HostModuleBuilder, HostFunc, IntoReturnVal, FromArg};
|
pub use self::host::{Externals, HostFuncIndex, EmptyExternals};
|
||||||
pub use self::imports::{ImportResolver, Imports};
|
pub use self::imports::{ImportResolver, Imports};
|
||||||
pub use self::module::ModuleInstance;
|
pub use self::module::ModuleInstance;
|
||||||
pub use self::global::{GlobalInstance, GlobalRef};
|
pub use self::global::{GlobalInstance, GlobalRef};
|
||||||
pub use self::func::{FuncInstance, FuncRef};
|
pub use self::func::{FuncInstance, FuncRef};
|
||||||
pub use self::state::{HostState, StateKey};
|
|
||||||
|
@ -10,8 +10,8 @@ use interpreter::imports::{ImportResolver, Imports};
|
|||||||
use interpreter::global::{GlobalInstance, GlobalRef};
|
use interpreter::global::{GlobalInstance, GlobalRef};
|
||||||
use interpreter::func::{FuncRef, FuncBody, FuncInstance};
|
use interpreter::func::{FuncRef, FuncBody, FuncInstance};
|
||||||
use interpreter::table::TableRef;
|
use interpreter::table::TableRef;
|
||||||
use interpreter::state::HostState;
|
|
||||||
use interpreter::memory::MemoryRef;
|
use interpreter::memory::MemoryRef;
|
||||||
|
use interpreter::host::Externals;
|
||||||
use validation::validate_module;
|
use validation::validate_module;
|
||||||
use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX};
|
use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX};
|
||||||
|
|
||||||
@ -187,7 +187,7 @@ impl ModuleInstance {
|
|||||||
"Due to validation function type should exists",
|
"Due to validation function type should exists",
|
||||||
);
|
);
|
||||||
let actual_fn_type = func.func_type();
|
let actual_fn_type = func.func_type();
|
||||||
if expected_fn_type != actual_fn_type {
|
if &*expected_fn_type != actual_fn_type {
|
||||||
return Err(Error::Instantiation(format!(
|
return Err(Error::Instantiation(format!(
|
||||||
"Expected function with type {:?}, but actual type is {:?} for entry {}",
|
"Expected function with type {:?}, but actual type is {:?} for entry {}",
|
||||||
expected_fn_type,
|
expected_fn_type,
|
||||||
@ -405,11 +405,11 @@ impl ModuleInstance {
|
|||||||
InstantiationBuilder::new(module)
|
InstantiationBuilder::new(module)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn invoke_index<'a>(
|
pub fn invoke_index<E: Externals>(
|
||||||
&self,
|
&self,
|
||||||
func_idx: u32,
|
func_idx: u32,
|
||||||
args: &[RuntimeValue],
|
args: &[RuntimeValue],
|
||||||
state: &'a mut HostState<'a>,
|
state: &mut E,
|
||||||
) -> Result<Option<RuntimeValue>, Error> {
|
) -> Result<Option<RuntimeValue>, Error> {
|
||||||
let func_instance = self.func_by_index(func_idx).ok_or_else(|| {
|
let func_instance = self.func_by_index(func_idx).ok_or_else(|| {
|
||||||
Error::Program(format!(
|
Error::Program(format!(
|
||||||
@ -420,11 +420,11 @@ impl ModuleInstance {
|
|||||||
FuncInstance::invoke(func_instance, Cow::Borrowed(args), state)
|
FuncInstance::invoke(func_instance, Cow::Borrowed(args), state)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn invoke_export<'a>(
|
pub fn invoke_export<E: Externals>(
|
||||||
&self,
|
&self,
|
||||||
func_name: &str,
|
func_name: &str,
|
||||||
args: &[RuntimeValue],
|
args: &[RuntimeValue],
|
||||||
state: &'a mut HostState<'a>,
|
state: &mut E,
|
||||||
) -> Result<Option<RuntimeValue>, Error> {
|
) -> Result<Option<RuntimeValue>, Error> {
|
||||||
let extern_val = self.export_by_name(func_name).ok_or_else(|| {
|
let extern_val = self.export_by_name(func_name).ok_or_else(|| {
|
||||||
Error::Program(format!("Module doesn't have export {}", func_name))
|
Error::Program(format!("Module doesn't have export {}", func_name))
|
||||||
@ -474,7 +474,7 @@ impl<'a> InstantiationBuilder<'a> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_start<'b>(mut self, state: &'b mut HostState<'b>) -> Result<Rc<ModuleInstance>, Error> {
|
pub fn run_start<'b, E: Externals>(mut self, state: &'b mut E) -> Result<Rc<ModuleInstance>, Error> {
|
||||||
let imports = self.imports.get_or_insert_with(|| Imports::default());
|
let imports = self.imports.get_or_insert_with(|| Imports::default());
|
||||||
let instance = ModuleInstance::instantiate_with_imports(self.module, imports)?;
|
let instance = ModuleInstance::instantiate_with_imports(self.module, imports)?;
|
||||||
|
|
||||||
|
@ -5,10 +5,9 @@ use elements::Module;
|
|||||||
use interpreter::Error;
|
use interpreter::Error;
|
||||||
use interpreter::module::{ModuleInstance};
|
use interpreter::module::{ModuleInstance};
|
||||||
use interpreter::func::{FuncInstance, FuncRef};
|
use interpreter::func::{FuncInstance, FuncRef};
|
||||||
use interpreter::host::HostModule;
|
|
||||||
use interpreter::value::RuntimeValue;
|
use interpreter::value::RuntimeValue;
|
||||||
use interpreter::imports::{Imports, ImportResolver};
|
use interpreter::imports::{Imports, ImportResolver};
|
||||||
use interpreter::state::HostState;
|
use interpreter::host::Externals;
|
||||||
|
|
||||||
/// Program instance. Program is a set of instantiated modules.
|
/// Program instance. Program is a set of instantiated modules.
|
||||||
#[deprecated]
|
#[deprecated]
|
||||||
@ -27,11 +26,11 @@ impl ProgramInstance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Instantiate module with validation.
|
/// Instantiate module with validation.
|
||||||
pub fn add_module<'a>(
|
pub fn add_module<'a, E: Externals>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &str,
|
name: &str,
|
||||||
module: Module,
|
module: Module,
|
||||||
state: &'a mut HostState<'a>,
|
externals: &'a mut E,
|
||||||
) -> Result<Rc<ModuleInstance>, Error> {
|
) -> Result<Rc<ModuleInstance>, Error> {
|
||||||
let module_instance = {
|
let module_instance = {
|
||||||
let mut imports = Imports::new();
|
let mut imports = Imports::new();
|
||||||
@ -43,7 +42,7 @@ impl ProgramInstance {
|
|||||||
}
|
}
|
||||||
ModuleInstance::new(&module)
|
ModuleInstance::new(&module)
|
||||||
.with_imports(imports)
|
.with_imports(imports)
|
||||||
.run_start(state)?
|
.run_start(externals)?
|
||||||
};
|
};
|
||||||
self.modules.insert(name.to_owned(), Rc::clone(&module_instance));
|
self.modules.insert(name.to_owned(), Rc::clone(&module_instance));
|
||||||
|
|
||||||
@ -58,49 +57,41 @@ impl ProgramInstance {
|
|||||||
self.resolvers.insert(name.to_owned(), import_resolver);
|
self.resolvers.insert(name.to_owned(), import_resolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_host_module(
|
|
||||||
&mut self,
|
|
||||||
name: &str,
|
|
||||||
host_module: HostModule,
|
|
||||||
) {
|
|
||||||
self.resolvers.insert(name.to_owned(), Box::new(host_module) as Box<ImportResolver>);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert_loaded_module(&mut self, name: &str, module: Rc<ModuleInstance>) {
|
pub fn insert_loaded_module(&mut self, name: &str, module: Rc<ModuleInstance>) {
|
||||||
self.modules.insert(name.to_owned(), module);
|
self.modules.insert(name.to_owned(), module);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn invoke_export<'a>(
|
pub fn invoke_export<'a, E: Externals>(
|
||||||
&mut self,
|
&mut self,
|
||||||
module_name: &str,
|
module_name: &str,
|
||||||
func_name: &str,
|
func_name: &str,
|
||||||
args: &[RuntimeValue],
|
args: &[RuntimeValue],
|
||||||
state: &'a mut HostState<'a>,
|
externals: &'a mut E,
|
||||||
) -> Result<Option<RuntimeValue>, Error> {
|
) -> Result<Option<RuntimeValue>, Error> {
|
||||||
let module_instance = self.modules.get(module_name).ok_or_else(|| {
|
let module_instance = self.modules.get(module_name).ok_or_else(|| {
|
||||||
Error::Program(format!("Module {} not found", module_name))
|
Error::Program(format!("Module {} not found", module_name))
|
||||||
})?;
|
})?;
|
||||||
module_instance.invoke_export(func_name, args, state)
|
module_instance.invoke_export(func_name, args, externals)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn invoke_index<'a>(
|
pub fn invoke_index<'a, E: Externals>(
|
||||||
&mut self,
|
&mut self,
|
||||||
module_name: &str,
|
module_name: &str,
|
||||||
func_idx: u32,
|
func_idx: u32,
|
||||||
args: &[RuntimeValue],
|
args: &[RuntimeValue],
|
||||||
state: &'a mut HostState<'a>,
|
externals: &'a mut E,
|
||||||
) -> Result<Option<RuntimeValue>, Error> {
|
) -> Result<Option<RuntimeValue>, Error> {
|
||||||
let module_instance = self.modules.get(module_name).cloned().ok_or_else(|| {
|
let module_instance = self.modules.get(module_name).cloned().ok_or_else(|| {
|
||||||
Error::Program(format!("Module {} not found", module_name))
|
Error::Program(format!("Module {} not found", module_name))
|
||||||
})?;
|
})?;
|
||||||
module_instance.invoke_index(func_idx, args, state)
|
module_instance.invoke_index(func_idx, args, externals)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn invoke_func<'a>(
|
pub fn invoke_func<'a, E: Externals>(
|
||||||
&mut self,
|
&mut self,
|
||||||
func_instance: FuncRef,
|
func_instance: FuncRef,
|
||||||
args: &[RuntimeValue],
|
args: &[RuntimeValue],
|
||||||
state: &'a mut HostState<'a>,
|
state: &'a mut E,
|
||||||
) -> Result<Option<RuntimeValue>, Error> {
|
) -> Result<Option<RuntimeValue>, Error> {
|
||||||
FuncInstance::invoke(func_instance.clone(), Cow::Borrowed(args), state)
|
FuncInstance::invoke(func_instance.clone(), Cow::Borrowed(args), state)
|
||||||
}
|
}
|
||||||
|
@ -14,13 +14,13 @@ use interpreter::value::{
|
|||||||
RuntimeValue, TryInto, WrapInto, TryTruncateInto, ExtendInto,
|
RuntimeValue, TryInto, WrapInto, TryTruncateInto, ExtendInto,
|
||||||
ArithmeticOps, Integer, Float, LittleEndianConvert, TransmuteInto,
|
ArithmeticOps, Integer, Float, LittleEndianConvert, TransmuteInto,
|
||||||
};
|
};
|
||||||
|
use interpreter::host::Externals;
|
||||||
use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX, BlockFrame, BlockFrameType};
|
use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX, BlockFrame, BlockFrameType};
|
||||||
use common::stack::StackWithLimit;
|
use common::stack::StackWithLimit;
|
||||||
use interpreter::state::HostState;
|
|
||||||
|
|
||||||
/// Function interpreter.
|
/// Function interpreter.
|
||||||
pub struct Interpreter<'a, 'b: 'a> {
|
pub struct Interpreter<'a, E: Externals + 'a> {
|
||||||
state: &'a mut HostState<'b>,
|
externals: &'a mut E,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Function execution context.
|
/// Function execution context.
|
||||||
@ -64,10 +64,10 @@ enum RunResult {
|
|||||||
NestedCall(FuncRef),
|
NestedCall(FuncRef),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b: 'a> Interpreter<'a, 'b> {
|
impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
pub fn new(state: &'a mut HostState<'b>) -> Interpreter<'a, 'b> {
|
pub fn new(externals: &'a mut E) -> Interpreter<'a, E> {
|
||||||
Interpreter {
|
Interpreter {
|
||||||
state: state,
|
externals,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,7 +105,7 @@ impl<'a, 'b: 'a> Interpreter<'a, 'b> {
|
|||||||
},
|
},
|
||||||
FuncInstance::Host { ref func_type, .. } => {
|
FuncInstance::Host { ref func_type, .. } => {
|
||||||
let args = prepare_function_args(func_type, &mut function_context.value_stack)?;
|
let args = prepare_function_args(func_type, &mut function_context.value_stack)?;
|
||||||
let return_val = FuncInstance::invoke(nested_func.clone(), args.into(), self.state)?;
|
let return_val = FuncInstance::invoke(nested_func.clone(), args.into(), self.externals)?;
|
||||||
if let Some(return_val) = return_val {
|
if let Some(return_val) = return_val {
|
||||||
function_context.value_stack_mut().push(return_val)?;
|
function_context.value_stack_mut().push(return_val)?;
|
||||||
}
|
}
|
||||||
@ -439,20 +439,22 @@ impl<'a, 'b: 'a> Interpreter<'a, 'b> {
|
|||||||
.expect("Due to validation table should exists");
|
.expect("Due to validation table should exists");
|
||||||
let func_ref = table.get(table_func_idx)?;
|
let func_ref = table.get(table_func_idx)?;
|
||||||
|
|
||||||
let actual_function_type = func_ref.func_type();
|
{
|
||||||
let required_function_type = context
|
let actual_function_type = func_ref.func_type();
|
||||||
.module()
|
let required_function_type = context
|
||||||
.type_by_index(type_idx)
|
.module()
|
||||||
.expect("Due to validation type should exists");
|
.type_by_index(type_idx)
|
||||||
|
.expect("Due to validation type should exists");
|
||||||
|
|
||||||
if required_function_type != actual_function_type {
|
if &*required_function_type != actual_function_type {
|
||||||
return Err(Error::Function(format!(
|
return Err(Error::Function(format!(
|
||||||
"expected function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}",
|
"expected function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}",
|
||||||
required_function_type.params(),
|
required_function_type.params(),
|
||||||
required_function_type.return_type(),
|
required_function_type.return_type(),
|
||||||
actual_function_type.params(),
|
actual_function_type.params(),
|
||||||
actual_function_type.return_type()
|
actual_function_type.return_type()
|
||||||
)));
|
)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(InstructionOutcome::ExecuteCall(func_ref))
|
Ok(InstructionOutcome::ExecuteCall(func_ref))
|
||||||
|
@ -1,138 +0,0 @@
|
|||||||
|
|
||||||
use std::any::{Any, TypeId};
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
pub unsafe trait StateKey {
|
|
||||||
type Static: ?Sized + 'static;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn type_id<T>() -> TypeId
|
|
||||||
where
|
|
||||||
T: StateKey,
|
|
||||||
T::Static: Any,
|
|
||||||
{
|
|
||||||
TypeId::of::<T::Static>()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct HostState<'a> {
|
|
||||||
data: HashMap<TypeId, *mut ()>,
|
|
||||||
_marker: ::std::marker::PhantomData<&'a mut ()>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> HostState<'a> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
HostState {
|
|
||||||
data: HashMap::default(),
|
|
||||||
_marker: ::std::marker::PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert<V: StateKey + 'a>(&mut self, val: &'a mut V) {
|
|
||||||
let ty_id = type_id::<V>();
|
|
||||||
let ptr = val as *mut V as *mut ();
|
|
||||||
let existing = self.data.insert(ty_id, ptr);
|
|
||||||
assert!(existing.is_none());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with<V: StateKey + 'a, R, F: FnOnce(&V) -> R>(&self, f: F) -> R {
|
|
||||||
let ptr = self.data.get(&type_id::<V>()).unwrap();
|
|
||||||
unsafe {
|
|
||||||
let val_ref = &*(*ptr as *const V);
|
|
||||||
f(val_ref)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_mut<V: StateKey + 'a, R, F: FnOnce(&mut V) -> R + 'static>(&mut self, f: F) -> R {
|
|
||||||
let ptr = self.data.get_mut(&type_id::<V>()).unwrap();
|
|
||||||
unsafe {
|
|
||||||
let val_ref = &mut *(*ptr as *mut V);
|
|
||||||
f(val_ref)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
struct MyState<'a>(&'a mut i32);
|
|
||||||
impl<'a> MyState<'a> {
|
|
||||||
fn inc(&mut self) {
|
|
||||||
*self.0 += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get(&self) -> i32 {
|
|
||||||
*self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Safety of this impl should be ensured by a macro.
|
|
||||||
unsafe impl<'a> StateKey for MyState<'a> {
|
|
||||||
type Static = MyState<'static>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_works() {
|
|
||||||
let mut counter = 33i32;
|
|
||||||
|
|
||||||
let new_value = {
|
|
||||||
let mut my_state = MyState(&mut counter);
|
|
||||||
let mut host_state = HostState::new();
|
|
||||||
host_state.insert::<MyState>(&mut my_state);
|
|
||||||
host_state.with_mut(|my_state: &mut MyState| {
|
|
||||||
my_state.inc();
|
|
||||||
my_state.get()
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(new_value, counter);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MyImmutableState<'a>(&'a i32);
|
|
||||||
/// Safety of this impl should be ensured by a macro.
|
|
||||||
unsafe impl<'a> StateKey for MyImmutableState<'a> {
|
|
||||||
type Static = MyImmutableState<'static>;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct StaticState(i32);
|
|
||||||
|
|
||||||
impl StaticState {
|
|
||||||
fn inc(&mut self) {
|
|
||||||
self.0 += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get(&self) -> i32 {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Safety of this impl should be ensured by a macro.
|
|
||||||
unsafe impl<'a> StateKey for StaticState {
|
|
||||||
type Static = StaticState;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn compiles_with_static() {
|
|
||||||
let mut static_state = StaticState(45);
|
|
||||||
let mut host_state = HostState::new();
|
|
||||||
host_state.insert::<StaticState>(&mut static_state);
|
|
||||||
host_state.with_mut(|my_state: &mut StaticState| {
|
|
||||||
my_state.inc();
|
|
||||||
});
|
|
||||||
host_state.with_mut(|my_state: &mut StaticState| {
|
|
||||||
my_state.inc();
|
|
||||||
assert_eq!(47, my_state.get());
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic]
|
|
||||||
fn doesnt_allow_dups() {
|
|
||||||
let mut static_state_1 = StaticState(45);
|
|
||||||
let mut static_state_2 = StaticState(45);
|
|
||||||
let mut host_state = HostState::new();
|
|
||||||
host_state.insert::<StaticState>(&mut static_state_1);
|
|
||||||
host_state.insert::<StaticState>(&mut static_state_2);
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user