NativeModuleInstance

This commit is contained in:
Svyatoslav Nikolsky
2017-05-18 15:08:55 +03:00
parent 3fb35f29b2
commit 977df55323
10 changed files with 524 additions and 415 deletions

View File

@ -1,11 +1,12 @@
use std::sync::{Arc, Weak};
use std::collections::HashMap;
use builder::{module, function, export};
use builder::module;
use elements::{Module, FunctionType, ExportEntry, Internal, GlobalEntry, GlobalType,
ValueType, InitExpr, Opcode, Opcodes};
use interpreter::Error;
use interpreter::module::{ModuleInstanceInterface, ModuleInstance, ItemIndex, CallerContext};
use interpreter::env_native::NATIVE_INDEX_FUNC_MIN;
use interpreter::module::{ModuleInstanceInterface, ModuleInstance, ExecutionParams,
ItemIndex, CallerContext};
use interpreter::memory::{MemoryInstance, LINEAR_MEMORY_PAGE_SIZE};
use interpreter::table::TableInstance;
use interpreter::value::{RuntimeValue, TransmuteInto};
@ -58,44 +59,10 @@ const INDEX_FUNC_ASSERT: u32 = 1;
const INDEX_FUNC_ENLARGE_MEMORY: u32 = 2;
/// Index of getTotalMemory function.
const INDEX_FUNC_GET_TOTAL_MEMORY: u32 = 3;
/// Index of abortOnCannotGrowMemory function.
/*const INDEX_FUNC_ABORT_ON_CANNOT_GROW_MEMORY: u32 = 4;
/// Index of invoke_vi function.
const INDEX_FUNC_INVOKE_VI: u32 = 5;
/// Index of invoke function.
const INDEX_FUNC_INVOKE: u32 = 6;*/
/// Min index of reserver function.
const INDEX_FUNC_MIN_NONUSED: u32 = 7;
const INDEX_FUNC_MIN_NONUSED: u32 = 4;
/// Max index of reserved function.
const INDEX_FUNC_MAX: u32 = 10000;
/// Set of user-defined functions
pub type UserFunctions = HashMap<String, UserFunction>;
/// User function closure
pub type UserFunctionClosure = Box<UserFunctionInterface>;
/// User-defined function execution interface
pub trait UserFunctionInterface {
/// Handles the user function invocation
fn call(&mut self, module: &ModuleInstance, context: CallerContext) -> Result<Option<RuntimeValue>, Error>;
}
impl<T> UserFunctionInterface for T where T: FnMut(&ModuleInstance, CallerContext) -> Result<Option<RuntimeValue>, Error> {
fn call(&mut self, module: &ModuleInstance, context: CallerContext) -> Result<Option<RuntimeValue>, Error> {
(&mut *self)(module, context)
}
}
/// Signature of user-defined env function
pub struct UserFunction {
/// User function parameters (for signature matching)
pub params: Vec<ValueType>,
/// User function return type (for signature matching)
pub result: Option<ValueType>,
/// Executor of the function
pub closure: UserFunctionClosure,
}
const INDEX_FUNC_MAX: u32 = NATIVE_INDEX_FUNC_MIN - 1;
/// Environment parameters.
pub struct EnvParams {
@ -107,41 +74,37 @@ pub struct EnvParams {
pub allow_memory_growth: bool,
}
type UserFunctionsInternals = Vec<::std::cell::RefCell<UserFunctionClosure>>;
pub struct EnvModuleInstance {
_params: EnvParams,
user_functions: UserFunctionsInternals,
instance: ModuleInstance,
}
impl EnvModuleInstance {
pub fn new(params: EnvParams, user_functions: UserFunctionsInternals, module: Module) -> Result<Self, Error> {
pub fn new(params: EnvParams, module: Module) -> Result<Self, Error> {
let instance = ModuleInstance::new(Weak::default(), module)?;
Ok(EnvModuleInstance {
_params: params,
user_functions: user_functions,
instance: instance,
})
}
}
impl ModuleInstanceInterface for EnvModuleInstance {
fn execute_main(&self, args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error> {
self.instance.execute_main(args)
fn execute_main(&self, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
self.instance.execute_main(params)
}
fn execute_index(&self, index: u32, args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error> {
self.instance.execute_index(index, args)
fn execute_index(&self, index: u32, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
self.instance.execute_index(index, params)
}
fn execute_export(&self, name: &str, args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error> {
self.instance.execute_export(name, args)
fn execute_export(&self, name: &str, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
self.instance.execute_export(name, params)
}
fn module(&self) -> &Module {
self.instance.module()
fn export_entry(&self, name: &str) -> Result<Internal, Error> {
self.instance.export_entry(name)
}
fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance>, Error> {
@ -165,6 +128,7 @@ impl ModuleInstanceInterface for EnvModuleInstance {
}
fn call_internal_function(&self, outer: CallerContext, index: u32, _function_type: Option<&FunctionType>) -> Result<Option<RuntimeValue>, Error> {
// TODO: check function type
// to make interpreter independent of *SCRIPTEN runtime, just make abort/assert = interpreter Error
match index {
INDEX_FUNC_ABORT => self.global(ItemIndex::IndexSpace(INDEX_GLOBAL_ABORT))
@ -183,26 +147,17 @@ impl ModuleInstanceInterface for EnvModuleInstance {
.map(|g| g.get())
.map(Some),
INDEX_FUNC_MIN_NONUSED ... INDEX_FUNC_MAX => Err(Error::Trap("unimplemented".into())),
idx if idx > INDEX_FUNC_MAX && idx <= INDEX_FUNC_MAX + self.user_functions.len() as u32 => {
// user-defined function
let user_index = idx - (INDEX_FUNC_MAX+1);
let func = self.user_functions.get(user_index as usize).ok_or(Error::Trap(format!("Trying to invoke user-defined function {}", user_index)))?;
func.borrow_mut().call(&self.instance, outer)
},
// idx @ _ if idx == INDEX_FUNC_MAX + 1 => outer.value_stack.pop().map(|_| None), // TODO: `gas(i32) -> None` function
// idx @ _ if idx == INDEX_FUNC_MAX + 2 => Ok(Some(RuntimeValue::I32(0))), // TODO: `_storage_size() -> i32` function
// idx @ _ if idx == INDEX_FUNC_MAX + 3 => outer.value_stack.pop_triple().map(|_| Some(RuntimeValue::I32(0))), // TODO: `_storage_size(i32,i32,i32) -> i32` function
_ => Err(Error::Trap(format!("trying to call function with index {} in env module", index))),
}
}
}
pub fn env_module(user_functions: UserFunctions) -> Result<EnvModuleInstance, Error> {
pub fn env_module() -> Result<EnvModuleInstance, Error> {
let env_params = EnvParams::default();
debug_assert!(env_params.total_stack < env_params.total_memory);
debug_assert!((env_params.total_stack % LINEAR_MEMORY_PAGE_SIZE) == 0);
debug_assert!((env_params.total_memory % LINEAR_MEMORY_PAGE_SIZE) == 0);
let mut builder = module()
let builder = module()
// memory regions
.memory()
.with_min(env_params.total_memory / LINEAR_MEMORY_PAGE_SIZE)
@ -255,29 +210,7 @@ pub fn env_module(user_functions: UserFunctions) -> Result<EnvModuleInstance, Er
.build()
.with_export(ExportEntry::new("getTotalMemory".into(), Internal::Function(INDEX_FUNC_GET_TOTAL_MEMORY)));
let mut funcs = user_functions;
let mut internals = UserFunctionsInternals::new();
let mut index = INDEX_FUNC_MAX + 1;
for (func_name, func) in funcs.drain() {
let _location = builder.push_function(
function()
.signature().with_params(func.params).with_return_type(func.result).build()
.build()
);
let _export_idx = builder.push_export(
export()
.field(&func_name)
.internal().func(index)
.build()
);
internals.push(::std::cell::RefCell::new(func.closure));
index += 1;
}
EnvModuleInstance::new(env_params, internals, builder.build())
EnvModuleInstance::new(env_params, builder.build())
}
impl Default for EnvParams {