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,3 +1,4 @@
use std::collections::HashMap;
use std::iter::repeat;
use std::sync::{Arc, Weak};
use elements::{Module, InitExpr, Opcode, Type, FunctionType, FuncBody, Internal};
@ -11,16 +12,25 @@ use interpreter::table::TableInstance;
use interpreter::value::{RuntimeValue, TryInto, TransmuteInto};
use interpreter::variable::{VariableInstance, VariableType};
#[derive(Clone)]
/// Execution context.
pub struct ExecutionParams {
/// Arguments.
pub args: Vec<RuntimeValue>,
/// Execution-local external modules.
pub externals: HashMap<String, Arc<ModuleInstanceInterface>>,
}
/// Module instance API.
pub trait ModuleInstanceInterface {
/// Execute start function of the module.
fn execute_main(&self, args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error>;
fn execute_main(&self, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error>;
/// Execute function with the given index.
fn execute_index(&self, index: u32, args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error>;
fn execute_index(&self, index: u32, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error>;
/// Execute function with the given export name.
fn execute_export(&self, name: &str, args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error>;
/// Get module description reference.
fn module(&self) -> &Module;
fn execute_export(&self, name: &str, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error>;
/// Get export entry.
fn export_entry(&self, name: &str) -> Result<Internal, Error>;
/// Get table reference.
fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance>, Error>;
/// Get memory reference.
@ -42,7 +52,7 @@ pub enum ItemIndex {
IndexSpace(u32),
/// Internal item index (i.e. index of item in items section).
Internal(u32),
/// External item index (i.e. index of item in the import section).
/// External module item index (i.e. index of item in the import section).
External(u32),
}
@ -68,6 +78,29 @@ pub struct CallerContext<'a> {
pub frame_stack_limit: usize,
/// Stack of the input parameters
pub value_stack: &'a mut StackWithLimit<RuntimeValue>,
/// Execution-local external modules.
pub externals: &'a HashMap<String, Arc<ModuleInstanceInterface>>,
}
impl ExecutionParams {
/// Create new execution params with given externa; module override.
pub fn with_external(name: String, module: Arc<ModuleInstanceInterface>) -> Self {
let mut externals = HashMap::new();
externals.insert(name, module);
ExecutionParams {
args: Vec::new(),
externals: externals,
}
}
}
impl From<Vec<RuntimeValue>> for ExecutionParams {
fn from(args: Vec<RuntimeValue>) -> ExecutionParams {
ExecutionParams {
args: args,
externals: HashMap::new(),
}
}
}
impl ModuleInstance {
@ -149,19 +182,19 @@ impl ModuleInstance {
}
impl ModuleInstanceInterface for ModuleInstance {
fn execute_main(&self, args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error> {
fn execute_main(&self, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
let index = self.module.start_section().ok_or(Error::Program("module has no start section".into()))?;
self.execute_index(index, args)
self.execute_index(index, params)
}
fn execute_index(&self, index: u32, args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error> {
let args_len = args.len();
let mut args = StackWithLimit::with_data(args, args_len);
let caller_context = CallerContext::topmost(&mut args);
fn execute_index(&self, index: u32, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
let args_len = params.args.len();
let mut args = StackWithLimit::with_data(params.args, args_len);
let caller_context = CallerContext::topmost(&mut args, &params.externals);
self.call_function(caller_context, ItemIndex::IndexSpace(index))
}
fn execute_export(&self, name: &str, args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error> {
fn execute_export(&self, name: &str, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
let index = self.module.export_section()
.ok_or(Error::Function("missing export section".into()))
.and_then(|s| s.entries().iter()
@ -175,11 +208,16 @@ impl ModuleInstanceInterface for ModuleInstance {
_ => unreachable!(), // checked couple of lines above
})
)?;
self.execute_index(index, args)
self.execute_index(index, params)
}
fn module(&self) -> &Module {
&self.module
fn export_entry(&self, name: &str) -> Result<Internal, Error> {
self.module.export_section()
.ok_or(Error::Program(format!("trying to import {} from module without export section", name)))
.and_then(|s| s.entries().iter()
.find(|e| e.field() == name)
.map(|e| *e.internal())
.ok_or(Error::Program(format!("unresolved import {}", name))))
}
fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance>, Error> {
@ -191,7 +229,7 @@ impl ModuleInstanceInterface for ModuleInstance {
.ok_or(Error::Table(format!("trying to access external table with index {} in module without import section", index)))
.and_then(|s| s.entries().get(index as usize)
.ok_or(Error::Table(format!("trying to access external table with index {} in module with {}-entries import section", index, s.entries().len()))))
.and_then(|e| self.imports.table(e)),
.and_then(|e| self.imports.table(None, e)),
}
}
@ -204,7 +242,7 @@ impl ModuleInstanceInterface for ModuleInstance {
.ok_or(Error::Memory(format!("trying to access external memory with index {} in module without import section", index)))
.and_then(|s| s.entries().get(index as usize)
.ok_or(Error::Memory(format!("trying to access external memory with index {} in module with {}-entries import section", index, s.entries().len()))))
.and_then(|e| self.imports.memory(e)),
.and_then(|e| self.imports.memory(None, e)),
}
}
@ -217,7 +255,7 @@ impl ModuleInstanceInterface for ModuleInstance {
.ok_or(Error::Global(format!("trying to access external global with index {} in module without import section", index)))
.and_then(|s| s.entries().get(index as usize)
.ok_or(Error::Global(format!("trying to access external global with index {} in module with {}-entries import section", index, s.entries().len()))))
.and_then(|e| self.imports.global(e)),
.and_then(|e| self.imports.global(None, e)),
}
}
@ -230,7 +268,7 @@ impl ModuleInstanceInterface for ModuleInstance {
.ok_or(Error::Function(format!("trying to access external function with index {} in module without import section", index)))
.and_then(|s| s.entries().get(index as usize)
.ok_or(Error::Function(format!("trying to access external function with index {} in module with {}-entries import section", index, s.entries().len()))))
.and_then(|e| Ok((self.imports.module(e.module())?, self.imports.function(e)?)))
.and_then(|e| Ok((self.imports.module(Some(outer.externals), e.module())?, self.imports.function(Some(outer.externals), e)?)))
.and_then(|(m, index)| m.call_internal_function(outer, index, None)),
}
}
@ -263,13 +301,13 @@ impl ModuleInstanceInterface for ModuleInstance {
.ok_or(Error::Function(format!("trying to access external table with index {} in module without import section", table_index)))
.and_then(|s| s.entries().get(table_index as usize)
.ok_or(Error::Function(format!("trying to access external table with index {} in module with {}-entries import section", table_index, s.entries().len()))))
.and_then(|e| self.imports.module(e.module()))?;
.and_then(|e| self.imports.module(Some(outer.externals), e.module()))?;
module.call_internal_function(outer, index, Some(function_type))
}
}
}
fn call_internal_function(&self, outer: CallerContext, index: u32, function_type: Option<&FunctionType>) -> Result<Option<RuntimeValue>, Error> {
fn call_internal_function(&self, mut outer: CallerContext, index: u32, function_type: Option<&FunctionType>) -> Result<Option<RuntimeValue>, Error> {
// TODO: cache
// internal index = index of function in functions section && index of code in code section
// get function type index
@ -311,19 +349,20 @@ impl ModuleInstanceInterface for ModuleInstance {
let function_code = function_body.code().elements();
let value_stack_limit = outer.value_stack_limit;
let frame_stack_limit = outer.frame_stack_limit;
let locals = prepare_function_locals(actual_function_type, function_body, outer)?;
let mut innner = FunctionContext::new(self, value_stack_limit, frame_stack_limit, actual_function_type, function_code, locals)?;
let locals = prepare_function_locals(actual_function_type, function_body, &mut outer)?;
let mut innner = FunctionContext::new(self, outer.externals, value_stack_limit, frame_stack_limit, actual_function_type, function_code, locals)?;
Interpreter::run_function(&mut innner, function_code)
}
}
impl<'a> CallerContext<'a> {
/// Top most args
pub fn topmost(args: &'a mut StackWithLimit<RuntimeValue>) -> Self {
pub fn topmost(args: &'a mut StackWithLimit<RuntimeValue>, externals: &'a HashMap<String, Arc<ModuleInstanceInterface>>) -> Self {
CallerContext {
value_stack_limit: 1024,
frame_stack_limit: 1024,
value_stack: args,
externals: externals,
}
}
@ -332,12 +371,13 @@ impl<'a> CallerContext<'a> {
CallerContext {
value_stack_limit: outer.value_stack().limit() - outer.value_stack().len(),
frame_stack_limit: outer.frame_stack().limit() - outer.frame_stack().len(),
value_stack: outer.value_stack_mut(),
value_stack: &mut outer.value_stack,
externals: &outer.externals,
}
}
}
fn prepare_function_locals(function_type: &FunctionType, function_body: &FuncBody, outer: CallerContext) -> Result<Vec<VariableInstance>, Error> {
fn prepare_function_locals(function_type: &FunctionType, function_body: &FuncBody, outer: &mut CallerContext) -> Result<Vec<VariableInstance>, Error> {
// locals = function arguments + defined locals
function_type.params().iter().rev()
.map(|param_type| {
@ -370,7 +410,7 @@ fn get_initializer(expr: &InitExpr, module: &Module, imports: &ModuleImports) ->
.ok_or(Error::Global(format!("trying to initialize with external global with index {} in module without import section", index)))
.and_then(|s| s.entries().get(index as usize)
.ok_or(Error::Global(format!("trying to initialize with external global with index {} in module with {}-entries import section", index, s.entries().len()))))
.and_then(|e| imports.global(e))
.and_then(|e| imports.global(None, e))
.map(|g| g.get())
},
&Opcode::I32Const(val) => Ok(RuntimeValue::I32(val)),