mirror of
https://github.com/fluencelabs/parity-wasm
synced 2025-06-29 22:51:56 +00:00
Move instantiate into ModuleInstance
This commit is contained in:
@ -3,7 +3,7 @@ use std::rc::Rc;
|
||||
use std::marker::PhantomData;
|
||||
use std::collections::HashMap;
|
||||
use elements::{FunctionType, ValueType, GlobalType, MemoryType, TableType};
|
||||
use interpreter::store::{Store, ExternVal, ModuleInstance, GlobalInstance, FuncInstance};
|
||||
use interpreter::store::{ExternVal, ModuleInstance, GlobalInstance, FuncInstance};
|
||||
use interpreter::memory::MemoryInstance;
|
||||
use interpreter::table::TableInstance;
|
||||
use interpreter::value::RuntimeValue;
|
||||
@ -48,7 +48,7 @@ impl<St: 'static> HostModuleBuilder<St> {
|
||||
}
|
||||
|
||||
pub fn with_func0<
|
||||
Cl: Fn(&mut Store, &mut St) -> Result<Option<Ret>, Error> + 'static,
|
||||
Cl: Fn(&mut St) -> Result<Option<Ret>, Error> + 'static,
|
||||
Ret: AsReturnVal + 'static,
|
||||
F: Into<Func0<Cl, St, Ret>>,
|
||||
N: Into<String>,
|
||||
@ -68,7 +68,7 @@ impl<St: 'static> HostModuleBuilder<St> {
|
||||
}
|
||||
|
||||
pub fn with_func1<
|
||||
Cl: Fn(&mut Store, &mut St, P1) -> Result<Option<Ret>, Error> + 'static,
|
||||
Cl: Fn(&mut St, P1) -> Result<Option<Ret>, Error> + 'static,
|
||||
Ret: AsReturnVal + 'static,
|
||||
P1: FromArg + 'static,
|
||||
F: Into<Func1<Cl, St, Ret, P1>>,
|
||||
@ -89,7 +89,7 @@ impl<St: 'static> HostModuleBuilder<St> {
|
||||
}
|
||||
|
||||
pub fn with_func2<
|
||||
Cl: Fn(&mut Store, &mut St, P1, P2) -> Result<Option<Ret>, Error> + 'static,
|
||||
Cl: Fn(&mut St, P1, P2) -> Result<Option<Ret>, Error> + 'static,
|
||||
Ret: AsReturnVal + 'static,
|
||||
P1: FromArg + 'static,
|
||||
P2: FromArg + 'static,
|
||||
@ -189,7 +189,6 @@ impl HostModule {
|
||||
pub trait AnyFunc {
|
||||
fn call_as_any(
|
||||
&self,
|
||||
store: &mut Store,
|
||||
state: &mut Any,
|
||||
args: &[RuntimeValue],
|
||||
) -> Result<Option<RuntimeValue>, Error>;
|
||||
@ -238,7 +237,7 @@ impl AsReturnVal for () {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Func0<Cl: Fn(&mut Store, &mut St) -> Result<Option<Ret>, Error>, St, Ret: AsReturnVal> {
|
||||
pub struct Func0<Cl: Fn(&mut St) -> Result<Option<Ret>, Error>, St, Ret: AsReturnVal> {
|
||||
closure: Cl,
|
||||
_marker: PhantomData<(St, Ret)>,
|
||||
}
|
||||
@ -246,21 +245,20 @@ pub struct Func0<Cl: Fn(&mut Store, &mut St) -> Result<Option<Ret>, Error>, St,
|
||||
impl<
|
||||
St: 'static,
|
||||
Ret: AsReturnVal,
|
||||
Cl: Fn(&mut Store, &mut St) -> Result<Option<Ret>, Error>,
|
||||
Cl: Fn(&mut St) -> Result<Option<Ret>, Error>,
|
||||
> AnyFunc for Func0<Cl, St, Ret> {
|
||||
fn call_as_any(
|
||||
&self,
|
||||
store: &mut Store,
|
||||
state: &mut Any,
|
||||
_args: &[RuntimeValue],
|
||||
) -> Result<Option<RuntimeValue>, Error> {
|
||||
let state = state.downcast_mut::<St>().unwrap();
|
||||
let result = (self.closure)(store, state);
|
||||
let result = (self.closure)(state);
|
||||
result.map(|r| r.and_then(|r| r.as_return_val()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<St: 'static, Ret: AsReturnVal, Cl: Fn(&mut Store, &mut St) -> Result<Option<Ret>, Error>> From<Cl>
|
||||
impl<St: 'static, Ret: AsReturnVal, Cl: Fn(&mut St) -> Result<Option<Ret>, Error>> From<Cl>
|
||||
for Func0<Cl, St, Ret> {
|
||||
fn from(cl: Cl) -> Self {
|
||||
Func0 {
|
||||
@ -273,14 +271,14 @@ impl<St: 'static, Ret: AsReturnVal, Cl: Fn(&mut Store, &mut St) -> Result<Option
|
||||
impl<
|
||||
St: 'static,
|
||||
Ret: AsReturnVal,
|
||||
Cl: Fn(&mut Store, &mut St) -> Result<Option<Ret>, Error>,
|
||||
Cl: Fn(&mut St) -> Result<Option<Ret>, Error>,
|
||||
> Func0<Cl, St, Ret> {
|
||||
fn derive_func_type() -> FunctionType {
|
||||
FunctionType::new(vec![], Ret::value_type())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Func1<Cl: Fn(&mut Store, &mut St, P1) -> Result<Option<Ret>, Error>, St, Ret: AsReturnVal, P1: FromArg> {
|
||||
pub struct Func1<Cl: Fn(&mut St, P1) -> Result<Option<Ret>, Error>, St, Ret: AsReturnVal, P1: FromArg> {
|
||||
closure: Cl,
|
||||
_marker: PhantomData<(St, Ret, P1)>,
|
||||
}
|
||||
@ -289,22 +287,21 @@ impl<
|
||||
St: 'static,
|
||||
Ret: AsReturnVal,
|
||||
P1: FromArg,
|
||||
Cl: Fn(&mut Store, &mut St, P1) -> Result<Option<Ret>, Error>,
|
||||
Cl: Fn(&mut St, P1) -> Result<Option<Ret>, Error>,
|
||||
> AnyFunc for Func1<Cl, St, Ret, P1> {
|
||||
fn call_as_any(
|
||||
&self,
|
||||
store: &mut Store,
|
||||
state: &mut Any,
|
||||
args: &[RuntimeValue],
|
||||
) -> Result<Option<RuntimeValue>, Error> {
|
||||
let state = state.downcast_mut::<St>().unwrap();
|
||||
let p1 = P1::from_arg(&args[0]);
|
||||
let result = (self.closure)(store, state, p1);
|
||||
let result = (self.closure)(state, p1);
|
||||
result.map(|r| r.and_then(|r| r.as_return_val()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<St: 'static, Ret: AsReturnVal, P1: FromArg, Cl: Fn(&mut Store, &mut St, P1) -> Result<Option<Ret>, Error>> From<Cl>
|
||||
impl<St: 'static, Ret: AsReturnVal, P1: FromArg, Cl: Fn(&mut St, P1) -> Result<Option<Ret>, Error>> From<Cl>
|
||||
for Func1<Cl, St, Ret, P1> {
|
||||
fn from(cl: Cl) -> Self {
|
||||
Func1 {
|
||||
@ -318,14 +315,14 @@ impl<
|
||||
St: 'static,
|
||||
Ret: AsReturnVal,
|
||||
P1: FromArg,
|
||||
Cl: Fn(&mut Store, &mut St, P1) -> Result<Option<Ret>, Error>,
|
||||
Cl: Fn(&mut St, P1) -> Result<Option<Ret>, Error>,
|
||||
> Func1<Cl, St, Ret, P1> {
|
||||
fn derive_func_type() -> FunctionType {
|
||||
FunctionType::new(vec![P1::value_type()], Ret::value_type())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Func2<Cl: Fn(&mut Store, &mut St, P1, P2) -> Result<Option<Ret>, Error>, St, Ret: AsReturnVal, P1: FromArg, P2: FromArg> {
|
||||
pub struct Func2<Cl: Fn(&mut St, P1, P2) -> Result<Option<Ret>, Error>, St, Ret: AsReturnVal, P1: FromArg, P2: FromArg> {
|
||||
closure: Cl,
|
||||
_marker: PhantomData<(St, Ret, P1, P2)>,
|
||||
}
|
||||
@ -335,23 +332,22 @@ impl<
|
||||
Ret: AsReturnVal,
|
||||
P1: FromArg,
|
||||
P2: FromArg,
|
||||
Cl: Fn(&mut Store, &mut St, P1, P2) -> Result<Option<Ret>, Error>,
|
||||
Cl: Fn(&mut St, P1, P2) -> Result<Option<Ret>, Error>,
|
||||
> AnyFunc for Func2<Cl, St, Ret, P1, P2> {
|
||||
fn call_as_any(
|
||||
&self,
|
||||
store: &mut Store,
|
||||
state: &mut Any,
|
||||
args: &[RuntimeValue],
|
||||
) -> Result<Option<RuntimeValue>, Error> {
|
||||
let state = state.downcast_mut::<St>().unwrap();
|
||||
let p1 = P1::from_arg(&args[0]);
|
||||
let p2 = P2::from_arg(&args[1]);
|
||||
let result = (self.closure)(store, state, p1, p2);
|
||||
let result = (self.closure)(state, p1, p2);
|
||||
result.map(|r| r.and_then(|r| r.as_return_val()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<St: 'static, Ret: AsReturnVal, P1: FromArg, P2: FromArg, Cl: Fn(&mut Store, &mut St, P1, P2) -> Result<Option<Ret>, Error>> From<Cl>
|
||||
impl<St: 'static, Ret: AsReturnVal, P1: FromArg, P2: FromArg, Cl: Fn(&mut St, P1, P2) -> Result<Option<Ret>, Error>> From<Cl>
|
||||
for Func2<Cl, St, Ret, P1, P2> {
|
||||
fn from(cl: Cl) -> Self {
|
||||
Func2 {
|
||||
@ -366,7 +362,7 @@ impl<
|
||||
Ret: AsReturnVal,
|
||||
P1: FromArg,
|
||||
P2: FromArg,
|
||||
Cl: Fn(&mut Store, &mut St, P1, P2) -> Result<Option<Ret>, Error>,
|
||||
Cl: Fn(&mut St, P1, P2) -> Result<Option<Ret>, Error>,
|
||||
> Func2<Cl, St, Ret, P1, P2> {
|
||||
fn derive_func_type() -> FunctionType {
|
||||
FunctionType::new(vec![P1::value_type(), P2::value_type()], Ret::value_type())
|
||||
|
@ -2,13 +2,12 @@ use std::rc::Rc;
|
||||
use std::collections::HashMap;
|
||||
use elements::Module;
|
||||
use interpreter::Error;
|
||||
use interpreter::store::{Store, ExternVal, FuncInstance, ModuleInstance};
|
||||
use interpreter::store::{ExternVal, FuncInstance, ModuleInstance};
|
||||
use interpreter::host::HostModule;
|
||||
use interpreter::value::RuntimeValue;
|
||||
|
||||
/// Program instance. Program is a set of instantiated modules.
|
||||
pub struct ProgramInstance {
|
||||
store: Store,
|
||||
modules: HashMap<String, Rc<ModuleInstance>>,
|
||||
}
|
||||
|
||||
@ -16,7 +15,6 @@ impl ProgramInstance {
|
||||
/// Create new program instance.
|
||||
pub fn new() -> Self {
|
||||
ProgramInstance {
|
||||
store: Store::new(),
|
||||
modules: HashMap::new(),
|
||||
}
|
||||
}
|
||||
@ -43,7 +41,7 @@ impl ProgramInstance {
|
||||
extern_vals.push(extern_val);
|
||||
}
|
||||
|
||||
let module_instance = self.store.instantiate_module(&module, &extern_vals, state)?;
|
||||
let module_instance = ModuleInstance::instantiate(&module, &extern_vals, state)?;
|
||||
self.modules.insert(name.to_owned(), Rc::clone(&module_instance));
|
||||
|
||||
Ok(module_instance)
|
||||
@ -90,11 +88,11 @@ impl ProgramInstance {
|
||||
"Export {} is not a function, but {:?}",
|
||||
func_name,
|
||||
unexpected
|
||||
)))
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
||||
self.store.invoke(func_instance, args, state)
|
||||
FuncInstance::invoke(Rc::clone(&func_instance), args, state)
|
||||
}
|
||||
|
||||
pub fn invoke_index<St: 'static>(
|
||||
@ -115,15 +113,11 @@ impl ProgramInstance {
|
||||
|
||||
pub fn invoke_func<St: 'static>(
|
||||
&mut self,
|
||||
func: Rc<FuncInstance>,
|
||||
func_instance: Rc<FuncInstance>,
|
||||
args: Vec<RuntimeValue>,
|
||||
state: &mut St,
|
||||
) -> Result<Option<RuntimeValue>, Error> {
|
||||
self.store.invoke(func, args, state)
|
||||
}
|
||||
|
||||
pub fn store(&self) -> &Store {
|
||||
&self.store
|
||||
FuncInstance::invoke(Rc::clone(&func_instance), args, state)
|
||||
}
|
||||
|
||||
pub fn module(&self, name: &str) -> Option<Rc<ModuleInstance>> {
|
||||
|
@ -7,7 +7,7 @@ use std::iter::repeat;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use elements::{Opcode, BlockType, Local, FunctionType};
|
||||
use interpreter::Error;
|
||||
use interpreter::store::{Store, FuncInstance, ModuleInstance};
|
||||
use interpreter::store::{FuncInstance, ModuleInstance};
|
||||
use interpreter::value::{
|
||||
RuntimeValue, TryInto, WrapInto, TryTruncateInto, ExtendInto,
|
||||
ArithmeticOps, Integer, Float, LittleEndianConvert, TransmuteInto,
|
||||
@ -17,7 +17,6 @@ use common::stack::StackWithLimit;
|
||||
|
||||
/// Function interpreter.
|
||||
pub struct Interpreter<'a, St: 'static> {
|
||||
store: &'a mut Store,
|
||||
state: &'a mut St,
|
||||
}
|
||||
|
||||
@ -64,9 +63,8 @@ enum RunResult {
|
||||
}
|
||||
|
||||
impl<'a, St: 'static> Interpreter<'a, St> {
|
||||
pub fn new(store: &'a mut Store, state: &'a mut St) -> Interpreter<'a, St> {
|
||||
pub fn new(state: &'a mut St) -> Interpreter<'a, St> {
|
||||
Interpreter {
|
||||
store,
|
||||
state
|
||||
}
|
||||
}
|
||||
@ -78,24 +76,14 @@ impl<'a, St: 'static> Interpreter<'a, St> {
|
||||
loop {
|
||||
let mut function_context = function_stack.pop_back().expect("on loop entry - not empty; on loop continue - checking for emptiness; qed");
|
||||
let function_ref = Rc::clone(&function_context.function);
|
||||
let function_return = {
|
||||
match function_ref.body() {
|
||||
Some(function_body) => {
|
||||
let function_body = function_ref.body().expect("Host functions checked in function_return below; Internal functions always have a body; qed");
|
||||
if !function_context.is_initialized() {
|
||||
let return_type = function_context.return_type;
|
||||
function_context.initialize(&function_body.locals);
|
||||
function_context.push_frame(&function_body.labels, BlockFrameType::Function, return_type)?;
|
||||
}
|
||||
|
||||
self.do_run_function(&mut function_context, function_body.opcodes.elements(), &function_body.labels)?
|
||||
},
|
||||
None => {
|
||||
let args: Vec<_> = function_context.locals.drain(..).collect();
|
||||
let result = self.store.invoke(function_ref, args, self.state)?;
|
||||
RunResult::Return(result)
|
||||
},
|
||||
}
|
||||
};
|
||||
let function_return = self.do_run_function(&mut function_context, function_body.opcodes.elements(), &function_body.labels)?;
|
||||
|
||||
match function_return {
|
||||
RunResult::Return(return_value) => {
|
||||
@ -116,7 +104,7 @@ impl<'a, St: 'static> Interpreter<'a, St> {
|
||||
},
|
||||
FuncInstance::Host { ref func_type, .. } => {
|
||||
let args = prepare_function_args(func_type, &mut function_context.value_stack)?;
|
||||
let return_val = self.store.invoke(Rc::clone(&nested_func), args, self.state)?;
|
||||
let return_val = FuncInstance::invoke(Rc::clone(&nested_func), args, self.state)?;
|
||||
if let Some(return_val) = return_val {
|
||||
function_context.value_stack_mut().push(return_val)?;
|
||||
}
|
||||
|
@ -98,6 +98,45 @@ impl FuncInstance {
|
||||
}
|
||||
}
|
||||
|
||||
impl FuncInstance {
|
||||
pub fn invoke<St: 'static>(
|
||||
func: Rc<FuncInstance>,
|
||||
args: Vec<RuntimeValue>,
|
||||
state: &mut St,
|
||||
) -> Result<Option<RuntimeValue>, Error> {
|
||||
enum InvokeKind {
|
||||
Internal(FunctionContext),
|
||||
Host(Rc<AnyFunc>, Vec<RuntimeValue>),
|
||||
}
|
||||
|
||||
let result = match *func {
|
||||
FuncInstance::Internal { ref func_type, .. } => {
|
||||
let mut args = StackWithLimit::with_data(args, DEFAULT_VALUE_STACK_LIMIT);
|
||||
let args = prepare_function_args(func_type, &mut args)?;
|
||||
let context = FunctionContext::new(
|
||||
Rc::clone(&func),
|
||||
DEFAULT_VALUE_STACK_LIMIT,
|
||||
DEFAULT_FRAME_STACK_LIMIT,
|
||||
func_type,
|
||||
args,
|
||||
);
|
||||
InvokeKind::Internal(context)
|
||||
}
|
||||
FuncInstance::Host { ref host_func, .. } => InvokeKind::Host(Rc::clone(host_func), args),
|
||||
};
|
||||
|
||||
match result {
|
||||
InvokeKind::Internal(ctx) => {
|
||||
let mut interpreter = Interpreter::new(state);
|
||||
interpreter.run_function(ctx)
|
||||
}
|
||||
InvokeKind::Host(host_func, args) => {
|
||||
host_func.call_as_any(state as &mut Any, &args)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FuncBody {
|
||||
pub locals: Vec<Local>,
|
||||
@ -159,6 +198,211 @@ impl ModuleInstance {
|
||||
}
|
||||
}
|
||||
|
||||
fn alloc_module_internal(
|
||||
module: &Module,
|
||||
extern_vals: &[ExternVal],
|
||||
instance: &Rc<ModuleInstance>,
|
||||
) -> Result<(), Error> {
|
||||
let mut aux_data = validate_module(module)?;
|
||||
|
||||
for &Type::Function(ref ty) in module
|
||||
.type_section()
|
||||
.map(|ts| ts.types())
|
||||
.unwrap_or(&[])
|
||||
{
|
||||
let type_id = alloc_func_type(ty.clone());
|
||||
instance.push_type(type_id);
|
||||
}
|
||||
|
||||
{
|
||||
let imports = module.import_section().map(|is| is.entries()).unwrap_or(&[]);
|
||||
if imports.len() != extern_vals.len() {
|
||||
return Err(Error::Initialization(format!("extern_vals length is not equal to import section entries")));
|
||||
}
|
||||
|
||||
for (import, extern_val) in Iterator::zip(imports.into_iter(), extern_vals.into_iter())
|
||||
{
|
||||
match (import.external(), extern_val) {
|
||||
(&External::Function(fn_type_idx), &ExternVal::Func(ref func)) => {
|
||||
let expected_fn_type = instance.type_by_index(fn_type_idx).expect("Due to validation function type should exists");
|
||||
let actual_fn_type = func.func_type();
|
||||
if expected_fn_type != actual_fn_type {
|
||||
return Err(Error::Initialization(format!(
|
||||
"Expected function with type {:?}, but actual type is {:?} for entry {}",
|
||||
expected_fn_type,
|
||||
actual_fn_type,
|
||||
import.field(),
|
||||
)));
|
||||
}
|
||||
instance.push_func(Rc::clone(func))
|
||||
}
|
||||
(&External::Table(ref tt), &ExternVal::Table(ref table)) => {
|
||||
match_limits(table.limits(), tt.limits())?;
|
||||
instance.push_table(Rc::clone(table));
|
||||
}
|
||||
(&External::Memory(ref mt), &ExternVal::Memory(ref memory)) => {
|
||||
match_limits(memory.limits(), mt.limits())?;
|
||||
instance.push_memory(Rc::clone(memory));
|
||||
}
|
||||
(&External::Global(ref gl), &ExternVal::Global(ref global)) => {
|
||||
// TODO: check globals
|
||||
instance.push_global(Rc::clone(global))
|
||||
}
|
||||
(expected_import, actual_extern_val) => {
|
||||
return Err(Error::Initialization(format!(
|
||||
"Expected {:?} type, but provided {:?} extern_val",
|
||||
expected_import,
|
||||
actual_extern_val
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let funcs = module
|
||||
.function_section()
|
||||
.map(|fs| fs.entries())
|
||||
.unwrap_or(&[]);
|
||||
let bodies = module.code_section().map(|cs| cs.bodies()).unwrap_or(&[]);
|
||||
debug_assert!(
|
||||
funcs.len() == bodies.len(),
|
||||
"Due to validation func and body counts must match"
|
||||
);
|
||||
|
||||
for (index, (ty, body)) in
|
||||
Iterator::zip(funcs.into_iter(), bodies.into_iter()).enumerate()
|
||||
{
|
||||
let func_type = instance.type_by_index(ty.type_ref()).expect("Due to validation type should exists");
|
||||
let labels = aux_data.labels.remove(&index).expect(
|
||||
"At func validation time labels are collected; Collected labels are added by index; qed",
|
||||
);
|
||||
let func_body = FuncBody {
|
||||
locals: body.locals().to_vec(),
|
||||
opcodes: body.code().clone(),
|
||||
labels: labels,
|
||||
};
|
||||
let func_instance = alloc_func(instance, func_type, func_body);
|
||||
instance.push_func(func_instance);
|
||||
}
|
||||
}
|
||||
|
||||
for table_type in module.table_section().map(|ts| ts.entries()).unwrap_or(&[]) {
|
||||
let table = alloc_table(table_type)?;
|
||||
instance.push_table(table);
|
||||
}
|
||||
|
||||
for memory_type in module
|
||||
.memory_section()
|
||||
.map(|ms| ms.entries())
|
||||
.unwrap_or(&[])
|
||||
{
|
||||
let memory = alloc_memory(memory_type)?;
|
||||
instance.push_memory(memory);
|
||||
}
|
||||
|
||||
for global_entry in module
|
||||
.global_section()
|
||||
.map(|gs| gs.entries())
|
||||
.unwrap_or(&[])
|
||||
{
|
||||
let init_val = eval_init_expr(global_entry.init_expr(), &*instance);
|
||||
let global = alloc_global(global_entry.global_type().clone(), init_val);
|
||||
instance.push_global(global);
|
||||
}
|
||||
|
||||
for export in module
|
||||
.export_section()
|
||||
.map(|es| es.entries())
|
||||
.unwrap_or(&[])
|
||||
{
|
||||
let field = export.field();
|
||||
let extern_val: ExternVal = match *export.internal() {
|
||||
Internal::Function(idx) => {
|
||||
let func = instance
|
||||
.func_by_index(idx)
|
||||
.expect("Due to validation func should exists");
|
||||
ExternVal::Func(func)
|
||||
}
|
||||
Internal::Global(idx) => {
|
||||
let global = instance
|
||||
.global_by_index(idx)
|
||||
.expect("Due to validation global should exists");
|
||||
ExternVal::Global(global)
|
||||
}
|
||||
Internal::Memory(idx) => {
|
||||
let memory = instance
|
||||
.memory_by_index(idx)
|
||||
.expect("Due to validation memory should exists");
|
||||
ExternVal::Memory(memory)
|
||||
}
|
||||
Internal::Table(idx) => {
|
||||
let table = instance
|
||||
.table_by_index(idx)
|
||||
.expect("Due to validation table should exists");
|
||||
ExternVal::Table(table)
|
||||
}
|
||||
};
|
||||
instance.insert_export(field, extern_val);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn instantiate<St: 'static>(
|
||||
module: &Module,
|
||||
extern_vals: &[ExternVal],
|
||||
state: &mut St,
|
||||
) -> Result<Rc<ModuleInstance>, Error> {
|
||||
let mut instance = Rc::new(ModuleInstance::new());
|
||||
|
||||
ModuleInstance::alloc_module_internal(module, extern_vals, &instance)?;
|
||||
|
||||
for element_segment in module
|
||||
.elements_section()
|
||||
.map(|es| es.entries())
|
||||
.unwrap_or(&[])
|
||||
{
|
||||
let offset_val = match eval_init_expr(element_segment.offset(), &instance) {
|
||||
RuntimeValue::I32(v) => v as u32,
|
||||
_ => panic!("Due to validation elem segment offset should evaluate to i32"),
|
||||
};
|
||||
|
||||
let table_inst = instance
|
||||
.table_by_index(DEFAULT_TABLE_INDEX)
|
||||
.expect("Due to validation default table should exists");
|
||||
for (j, func_idx) in element_segment.members().into_iter().enumerate() {
|
||||
let func = instance
|
||||
.func_by_index(*func_idx)
|
||||
.expect("Due to validation funcs from element segments should exists");
|
||||
|
||||
table_inst.set(offset_val + j as u32, func);
|
||||
}
|
||||
}
|
||||
|
||||
for data_segment in module.data_section().map(|ds| ds.entries()).unwrap_or(&[]) {
|
||||
let offset_val = match eval_init_expr(data_segment.offset(), &instance) {
|
||||
RuntimeValue::I32(v) => v as u32,
|
||||
_ => panic!("Due to validation data segment offset should evaluate to i32"),
|
||||
};
|
||||
|
||||
let memory_inst = instance
|
||||
.memory_by_index(DEFAULT_MEMORY_INDEX)
|
||||
.expect("Due to validation default memory should exists");
|
||||
memory_inst.set(offset_val, data_segment.value())?;
|
||||
}
|
||||
|
||||
// And run module's start function, if any
|
||||
if let Some(start_fn_idx) = module.start_section() {
|
||||
let start_func = instance
|
||||
.func_by_index(start_fn_idx)
|
||||
.expect("Due to validation start function should exists");
|
||||
FuncInstance::invoke(start_func, vec![], state)?;
|
||||
}
|
||||
|
||||
Ok(instance)
|
||||
}
|
||||
|
||||
pub fn memory_by_index(&self, idx: u32) -> Option<Rc<MemoryInstance>> {
|
||||
self
|
||||
.memories
|
||||
@ -235,19 +479,12 @@ impl ModuleInstance {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Store;
|
||||
|
||||
impl Store {
|
||||
pub fn new() -> Store {
|
||||
Store::default()
|
||||
}
|
||||
|
||||
pub fn alloc_func_type(&mut self, func_type: FunctionType) -> Rc<FunctionType> {
|
||||
fn alloc_func_type(func_type: FunctionType) -> Rc<FunctionType> {
|
||||
Rc::new(func_type)
|
||||
}
|
||||
|
||||
pub fn alloc_func(&mut self, module: &Rc<ModuleInstance>, func_type: Rc<FunctionType>, body: FuncBody) -> Rc<FuncInstance> {
|
||||
fn alloc_func(module: &Rc<ModuleInstance>, func_type: Rc<FunctionType>, body: FuncBody) -> Rc<FuncInstance> {
|
||||
let func = FuncInstance::Internal {
|
||||
func_type,
|
||||
module: Rc::clone(module),
|
||||
@ -256,7 +493,7 @@ impl Store {
|
||||
Rc::new(func)
|
||||
}
|
||||
|
||||
pub fn alloc_host_func(&mut self, func_type: Rc<FunctionType>, host_func: Rc<AnyFunc>) -> Rc<FuncInstance> {
|
||||
fn alloc_host_func(func_type: Rc<FunctionType>, host_func: Rc<AnyFunc>) -> Rc<FuncInstance> {
|
||||
let func = FuncInstance::Host {
|
||||
func_type,
|
||||
host_func,
|
||||
@ -264,269 +501,21 @@ impl Store {
|
||||
Rc::new(func)
|
||||
}
|
||||
|
||||
pub fn alloc_table(&mut self, table_type: &TableType) -> Result<Rc<TableInstance>, Error> {
|
||||
fn alloc_table(table_type: &TableType) -> Result<Rc<TableInstance>, Error> {
|
||||
let table = TableInstance::new(table_type)?;
|
||||
Ok(Rc::new(table))
|
||||
}
|
||||
|
||||
pub fn alloc_memory(&mut self, mem_type: &MemoryType) -> Result<Rc<MemoryInstance>, Error> {
|
||||
fn alloc_memory(mem_type: &MemoryType) -> Result<Rc<MemoryInstance>, Error> {
|
||||
let memory = MemoryInstance::new(&mem_type)?;
|
||||
Ok(Rc::new(memory))
|
||||
}
|
||||
|
||||
pub fn alloc_global(&mut self, global_type: GlobalType, val: RuntimeValue) -> Rc<GlobalInstance> {
|
||||
fn alloc_global(global_type: GlobalType, val: RuntimeValue) -> Rc<GlobalInstance> {
|
||||
let global = GlobalInstance::new(val, global_type.is_mutable());
|
||||
Rc::new(global)
|
||||
}
|
||||
|
||||
fn alloc_module_internal(
|
||||
&mut self,
|
||||
module: &Module,
|
||||
extern_vals: &[ExternVal],
|
||||
instance: &Rc<ModuleInstance>,
|
||||
) -> Result<(), Error> {
|
||||
let mut aux_data = validate_module(module)?;
|
||||
|
||||
for &Type::Function(ref ty) in module
|
||||
.type_section()
|
||||
.map(|ts| ts.types())
|
||||
.unwrap_or(&[])
|
||||
{
|
||||
let type_id = self.alloc_func_type(ty.clone());
|
||||
instance.push_type(type_id);
|
||||
}
|
||||
|
||||
{
|
||||
let imports = module.import_section().map(|is| is.entries()).unwrap_or(&[]);
|
||||
if imports.len() != extern_vals.len() {
|
||||
return Err(Error::Initialization(format!("extern_vals length is not equal to import section entries")));
|
||||
}
|
||||
|
||||
for (import, extern_val) in Iterator::zip(imports.into_iter(), extern_vals.into_iter())
|
||||
{
|
||||
match (import.external(), extern_val) {
|
||||
(&External::Function(fn_type_idx), &ExternVal::Func(ref func)) => {
|
||||
let expected_fn_type = instance.type_by_index(fn_type_idx).expect("Due to validation function type should exists");
|
||||
let actual_fn_type = func.func_type();
|
||||
if expected_fn_type != actual_fn_type {
|
||||
return Err(Error::Initialization(format!(
|
||||
"Expected function with type {:?}, but actual type is {:?} for entry {}",
|
||||
expected_fn_type,
|
||||
actual_fn_type,
|
||||
import.field(),
|
||||
)));
|
||||
}
|
||||
instance.push_func(Rc::clone(func))
|
||||
}
|
||||
(&External::Table(ref tt), &ExternVal::Table(ref table)) => {
|
||||
match_limits(table.limits(), tt.limits())?;
|
||||
instance.push_table(Rc::clone(table));
|
||||
}
|
||||
(&External::Memory(ref mt), &ExternVal::Memory(ref memory)) => {
|
||||
match_limits(memory.limits(), mt.limits())?;
|
||||
instance.push_memory(Rc::clone(memory));
|
||||
}
|
||||
(&External::Global(ref gl), &ExternVal::Global(ref global)) => {
|
||||
// TODO: check globals
|
||||
instance.push_global(Rc::clone(global))
|
||||
}
|
||||
(expected_import, actual_extern_val) => {
|
||||
return Err(Error::Initialization(format!(
|
||||
"Expected {:?} type, but provided {:?} extern_val",
|
||||
expected_import,
|
||||
actual_extern_val
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let funcs = module
|
||||
.function_section()
|
||||
.map(|fs| fs.entries())
|
||||
.unwrap_or(&[]);
|
||||
let bodies = module.code_section().map(|cs| cs.bodies()).unwrap_or(&[]);
|
||||
debug_assert!(
|
||||
funcs.len() == bodies.len(),
|
||||
"Due to validation func and body counts must match"
|
||||
);
|
||||
|
||||
for (index, (ty, body)) in
|
||||
Iterator::zip(funcs.into_iter(), bodies.into_iter()).enumerate()
|
||||
{
|
||||
let func_type = instance.type_by_index(ty.type_ref()).expect("Due to validation type should exists");
|
||||
let labels = aux_data.labels.remove(&index).expect(
|
||||
"At func validation time labels are collected; Collected labels are added by index; qed",
|
||||
);
|
||||
let func_body = FuncBody {
|
||||
locals: body.locals().to_vec(),
|
||||
opcodes: body.code().clone(),
|
||||
labels: labels,
|
||||
};
|
||||
let func_instance = self.alloc_func(instance, func_type, func_body);
|
||||
instance.push_func(func_instance);
|
||||
}
|
||||
}
|
||||
|
||||
for table_type in module.table_section().map(|ts| ts.entries()).unwrap_or(&[]) {
|
||||
let table = self.alloc_table(table_type)?;
|
||||
instance.push_table(table);
|
||||
}
|
||||
|
||||
for memory_type in module
|
||||
.memory_section()
|
||||
.map(|ms| ms.entries())
|
||||
.unwrap_or(&[])
|
||||
{
|
||||
let memory = self.alloc_memory(memory_type)?;
|
||||
instance.push_memory(memory);
|
||||
}
|
||||
|
||||
for global_entry in module
|
||||
.global_section()
|
||||
.map(|gs| gs.entries())
|
||||
.unwrap_or(&[])
|
||||
{
|
||||
let init_val = eval_init_expr(global_entry.init_expr(), &*instance);
|
||||
let global = self.alloc_global(global_entry.global_type().clone(), init_val);
|
||||
instance.push_global(global);
|
||||
}
|
||||
|
||||
for export in module
|
||||
.export_section()
|
||||
.map(|es| es.entries())
|
||||
.unwrap_or(&[])
|
||||
{
|
||||
let field = export.field();
|
||||
let extern_val: ExternVal = match *export.internal() {
|
||||
Internal::Function(idx) => {
|
||||
let func = instance
|
||||
.func_by_index(idx)
|
||||
.expect("Due to validation func should exists");
|
||||
ExternVal::Func(func)
|
||||
}
|
||||
Internal::Global(idx) => {
|
||||
let global = instance
|
||||
.global_by_index(idx)
|
||||
.expect("Due to validation global should exists");
|
||||
ExternVal::Global(global)
|
||||
}
|
||||
Internal::Memory(idx) => {
|
||||
let memory = instance
|
||||
.memory_by_index(idx)
|
||||
.expect("Due to validation memory should exists");
|
||||
ExternVal::Memory(memory)
|
||||
}
|
||||
Internal::Table(idx) => {
|
||||
let table = instance
|
||||
.table_by_index(idx)
|
||||
.expect("Due to validation table should exists");
|
||||
ExternVal::Table(table)
|
||||
}
|
||||
};
|
||||
instance.insert_export(field, extern_val);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn instantiate_module<St: 'static>(
|
||||
&mut self,
|
||||
module: &Module,
|
||||
extern_vals: &[ExternVal],
|
||||
state: &mut St,
|
||||
) -> Result<Rc<ModuleInstance>, Error> {
|
||||
let mut instance = Rc::new(ModuleInstance::new());
|
||||
|
||||
self.alloc_module_internal(module, extern_vals, &instance)?;
|
||||
|
||||
for element_segment in module
|
||||
.elements_section()
|
||||
.map(|es| es.entries())
|
||||
.unwrap_or(&[])
|
||||
{
|
||||
let offset_val = match eval_init_expr(element_segment.offset(), &instance) {
|
||||
RuntimeValue::I32(v) => v as u32,
|
||||
_ => panic!("Due to validation elem segment offset should evaluate to i32"),
|
||||
};
|
||||
|
||||
let table_inst = instance
|
||||
.table_by_index(DEFAULT_TABLE_INDEX)
|
||||
.expect("Due to validation default table should exists");
|
||||
for (j, func_idx) in element_segment.members().into_iter().enumerate() {
|
||||
let func = instance
|
||||
.func_by_index(*func_idx)
|
||||
.expect("Due to validation funcs from element segments should exists");
|
||||
|
||||
table_inst.set(offset_val + j as u32, func);
|
||||
}
|
||||
}
|
||||
|
||||
for data_segment in module.data_section().map(|ds| ds.entries()).unwrap_or(&[]) {
|
||||
let offset_val = match eval_init_expr(data_segment.offset(), &instance) {
|
||||
RuntimeValue::I32(v) => v as u32,
|
||||
_ => panic!("Due to validation data segment offset should evaluate to i32"),
|
||||
};
|
||||
|
||||
let memory_inst = instance
|
||||
.memory_by_index(DEFAULT_MEMORY_INDEX)
|
||||
.expect("Due to validation default memory should exists");
|
||||
memory_inst.set(offset_val, data_segment.value())?;
|
||||
}
|
||||
|
||||
// And run module's start function, if any
|
||||
if let Some(start_fn_idx) = module.start_section() {
|
||||
let start_func = {
|
||||
instance
|
||||
.func_by_index(start_fn_idx)
|
||||
.expect("Due to validation start function should exists")
|
||||
};
|
||||
self.invoke(start_func, vec![], state)?;
|
||||
}
|
||||
|
||||
Ok(instance)
|
||||
}
|
||||
|
||||
pub fn invoke<St: 'static>(
|
||||
&mut self,
|
||||
func: Rc<FuncInstance>,
|
||||
args: Vec<RuntimeValue>,
|
||||
state: &mut St,
|
||||
) -> Result<Option<RuntimeValue>, Error> {
|
||||
enum InvokeKind {
|
||||
Internal(FunctionContext),
|
||||
Host(Rc<AnyFunc>, Vec<RuntimeValue>),
|
||||
}
|
||||
|
||||
let result = match *func {
|
||||
FuncInstance::Internal { ref func_type, .. } => {
|
||||
let mut args = StackWithLimit::with_data(args, DEFAULT_VALUE_STACK_LIMIT);
|
||||
let args = prepare_function_args(func_type, &mut args)?;
|
||||
let context = FunctionContext::new(
|
||||
Rc::clone(&func),
|
||||
DEFAULT_VALUE_STACK_LIMIT,
|
||||
DEFAULT_FRAME_STACK_LIMIT,
|
||||
func_type,
|
||||
args,
|
||||
);
|
||||
InvokeKind::Internal(context)
|
||||
}
|
||||
FuncInstance::Host { ref host_func, .. } => InvokeKind::Host(Rc::clone(host_func), args),
|
||||
};
|
||||
|
||||
match result {
|
||||
InvokeKind::Internal(ctx) => {
|
||||
let mut interpreter = Interpreter::new(self, state);
|
||||
interpreter.run_function(ctx)
|
||||
}
|
||||
InvokeKind::Host(host_func, args) => {
|
||||
host_func.call_as_any(self, state as &mut Any, &args)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_init_expr(init_expr: &InitExpr, module: &ModuleInstance) -> RuntimeValue {
|
||||
let code = init_expr.code();
|
||||
debug_assert!(
|
||||
|
@ -7,7 +7,6 @@ use elements::{ExportEntry, Internal, ImportEntry, External, GlobalEntry, Global
|
||||
use interpreter::{Error, UserError, ProgramInstance};
|
||||
use interpreter::value::RuntimeValue;
|
||||
use interpreter::host::{HostModuleBuilder, HostModule};
|
||||
use interpreter::store::Store;
|
||||
use interpreter::memory::MemoryInstance;
|
||||
use super::utils::program_with_default_env;
|
||||
|
||||
@ -122,7 +121,7 @@ struct FunctionExecutor {
|
||||
|
||||
fn build_env_module() -> HostModule {
|
||||
let mut builder = HostModuleBuilder::<FunctionExecutor>::new();
|
||||
builder.with_func2("add", |_store: &mut Store, state: &mut FunctionExecutor, arg: i32, unused: i32| {
|
||||
builder.with_func2("add", |state: &mut FunctionExecutor, arg: i32, unused: i32| {
|
||||
let memory_value = state.memory.get(0, 1).unwrap()[0];
|
||||
let fn_argument_unused = unused as u8;
|
||||
let fn_argument = arg as u8;
|
||||
@ -133,7 +132,7 @@ fn build_env_module() -> HostModule {
|
||||
state.values.push(sum as i32);
|
||||
Ok(Some(sum as i32))
|
||||
});
|
||||
builder.with_func2("sub", |_store: &mut Store, state: &mut FunctionExecutor, arg: i32, unused: i32| {
|
||||
builder.with_func2("sub", |state: &mut FunctionExecutor, arg: i32, unused: i32| {
|
||||
let memory_value = state.memory.get(0, 1).unwrap()[0];
|
||||
let fn_argument_unused = unused as u8;
|
||||
let fn_argument = arg as u8;
|
||||
@ -144,7 +143,7 @@ fn build_env_module() -> HostModule {
|
||||
state.values.push(diff as i32);
|
||||
Ok(Some(diff as i32))
|
||||
});
|
||||
builder.with_func2("err", |_: &mut Store, _: &mut FunctionExecutor, _unused1: i32, _unused2: i32| -> Result<Option<i32>, Error> {
|
||||
builder.with_func2("err", |_: &mut FunctionExecutor, _unused1: i32, _unused2: i32| -> Result<Option<i32>, Error> {
|
||||
Err(Error::User(Box::new(UserErrorWithCode { error_code: 777 })))
|
||||
});
|
||||
builder.with_memory("memory", MemoryType::new(256, None));
|
||||
|
Reference in New Issue
Block a user