mirror of
https://github.com/fluencelabs/parity-wasm
synced 2025-06-13 23:11:53 +00:00
Invoke stuff and state.
This commit is contained in:
@ -1,7 +1,8 @@
|
|||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
use std::sync::Arc;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use elements::{FunctionType, ValueType};
|
use elements::{FunctionType, ValueType, GlobalType, MemoryType, TableType};
|
||||||
use interpreter::store::{Store, ExternVal};
|
use interpreter::store::{Store, ExternVal};
|
||||||
use interpreter::value::RuntimeValue;
|
use interpreter::value::RuntimeValue;
|
||||||
use interpreter::Error;
|
use interpreter::Error;
|
||||||
@ -21,7 +22,7 @@ impl<'a, St: 'static> HostModuleBuilder<'a, St> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_func1<
|
pub fn with_func1<
|
||||||
Cl: Fn(&mut St, P1) -> Result<Option<Ret>, Error> + 'static,
|
Cl: Fn(&mut St, P1) -> Result<Option<Ret>, Error> + 'static,
|
||||||
Ret: AsReturn + 'static,
|
Ret: AsReturn + 'static,
|
||||||
P1: FromArg + 'static,
|
P1: FromArg + 'static,
|
||||||
@ -34,12 +35,25 @@ impl<'a, St: 'static> HostModuleBuilder<'a, St> {
|
|||||||
let func_type = Func1::<Cl, St, Ret, P1>::derive_func_type();
|
let func_type = Func1::<Cl, St, Ret, P1>::derive_func_type();
|
||||||
let type_id = self.store.alloc_func_type(func_type);
|
let type_id = self.store.alloc_func_type(func_type);
|
||||||
|
|
||||||
let anyfunc = Box::new(f.into()) as Box<AnyFunc>;
|
let anyfunc = Arc::new(f.into()) as Arc<AnyFunc>;
|
||||||
|
|
||||||
let func_id = self.store.alloc_host_func(type_id, anyfunc);
|
let func_id = self.store.alloc_host_func(type_id, anyfunc);
|
||||||
let extern_val = ExternVal::Func(func_id);
|
self.exports.insert(name.to_owned(), ExternVal::Func(func_id));
|
||||||
|
}
|
||||||
|
|
||||||
self.exports.insert(name.to_owned(), extern_val);
|
pub fn with_global(&mut self, name: &str, global_type: GlobalType, val: RuntimeValue) {
|
||||||
|
let global_id = self.store.alloc_global(global_type, val);
|
||||||
|
self.exports.insert(name.to_owned(), ExternVal::Global(global_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_memory(&mut self, name: &str, memory_type: &MemoryType) -> Result<(), Error> {
|
||||||
|
let memory_id = self.store.alloc_memory(memory_type)?;
|
||||||
|
self.exports.insert(name.to_owned(), ExternVal::Memory(memory_id));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_table(&mut self, name: &str, table_type: &TableType) {
|
||||||
|
let table_id = self.store.alloc_table(table_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,13 +19,9 @@ const DEFAULT_VALUE_STACK_LIMIT: usize = 16384;
|
|||||||
const DEFAULT_FRAME_STACK_LIMIT: usize = 1024;
|
const DEFAULT_FRAME_STACK_LIMIT: usize = 1024;
|
||||||
|
|
||||||
/// Execution context.
|
/// Execution context.
|
||||||
#[derive(Clone)]
|
pub struct ExecutionParams<'a, St: 'static> {
|
||||||
pub struct ExecutionParams<St: 'static> {
|
|
||||||
/// Arguments.
|
|
||||||
pub args: Vec<RuntimeValue>,
|
|
||||||
|
|
||||||
/// State that can be used by host functions,
|
/// State that can be used by host functions,
|
||||||
pub state: St,
|
pub state: &'a mut St,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Export type.
|
/// Export type.
|
||||||
@ -79,32 +75,13 @@ pub struct InternalFunction<'a> {
|
|||||||
pub labels: &'a HashMap<usize, usize>,
|
pub labels: &'a HashMap<usize, usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<St> ExecutionParams<St> {
|
impl<'a, St> ExecutionParams<'a, St> {
|
||||||
/// Add argument.
|
/// Add argument.
|
||||||
pub fn add_argument(mut self, arg: RuntimeValue) -> Self {
|
pub fn add_argument(mut self, arg: RuntimeValue) -> Self {
|
||||||
self.args.push(arg);
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<St: Default> Default for ExecutionParams<St> {
|
|
||||||
fn default() -> Self {
|
|
||||||
ExecutionParams {
|
|
||||||
args: Vec::default(),
|
|
||||||
state: St::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, St: Default> From<Vec<RuntimeValue>> for ExecutionParams<St> {
|
|
||||||
fn from(args: Vec<RuntimeValue>) -> ExecutionParams<St> {
|
|
||||||
ExecutionParams {
|
|
||||||
args: args,
|
|
||||||
state: St::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CallerContext<'a> {
|
impl<'a> CallerContext<'a> {
|
||||||
/// Top most args
|
/// Top most args
|
||||||
pub fn topmost(args: &'a mut StackWithLimit<RuntimeValue>) -> Self {
|
pub fn topmost(args: &'a mut StackWithLimit<RuntimeValue>) -> Self {
|
||||||
|
@ -26,7 +26,7 @@ impl ProgramInstance {
|
|||||||
&mut self,
|
&mut self,
|
||||||
name: &str,
|
name: &str,
|
||||||
module: Module,
|
module: Module,
|
||||||
start_exec_params: ExecutionParams<St>,
|
state: &mut St,
|
||||||
) -> Result<ModuleId, Error> {
|
) -> Result<ModuleId, Error> {
|
||||||
let mut extern_vals = Vec::new();
|
let mut extern_vals = Vec::new();
|
||||||
for import_entry in module.import_section().map(|s| s.entries()).unwrap_or(&[]) {
|
for import_entry in module.import_section().map(|s| s.entries()).unwrap_or(&[]) {
|
||||||
@ -37,7 +37,7 @@ impl ProgramInstance {
|
|||||||
extern_vals.push(extern_val);
|
extern_vals.push(extern_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
let module_id = self.store.instantiate_module(&module, &extern_vals, start_exec_params)?;
|
let module_id = self.store.instantiate_module(&module, &extern_vals, state)?;
|
||||||
self.modules.insert(name.to_string(), module_id);
|
self.modules.insert(name.to_string(), module_id);
|
||||||
|
|
||||||
Ok(module_id)
|
Ok(module_id)
|
||||||
|
@ -8,12 +8,11 @@ use std::collections::{HashMap, VecDeque};
|
|||||||
use elements::{Opcode, BlockType, Local};
|
use elements::{Opcode, BlockType, Local};
|
||||||
use interpreter::Error;
|
use interpreter::Error;
|
||||||
use interpreter::store::{Store, FuncId, ModuleId, FuncInstance};
|
use interpreter::store::{Store, FuncId, ModuleId, FuncInstance};
|
||||||
use interpreter::module::{CallerContext, FunctionSignature};
|
use interpreter::module::{CallerContext, FunctionSignature, ExecutionParams};
|
||||||
use interpreter::value::{
|
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::variable::VariableInstance;
|
|
||||||
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;
|
||||||
|
|
||||||
@ -81,12 +80,10 @@ impl<'store, St: 'static> Interpreter<'store, St> {
|
|||||||
let mut function_context = function_stack.pop_back().expect("on loop entry - not empty; on loop continue - checking for emptiness; qed");
|
let mut function_context = function_stack.pop_back().expect("on loop entry - not empty; on loop continue - checking for emptiness; qed");
|
||||||
let function_ref = function_context.function;
|
let function_ref = function_context.function;
|
||||||
let function_return = {
|
let function_return = {
|
||||||
let func_instance = function_ref.resolve(self.store).clone();
|
let func_body = function_ref.resolve(self.store).body();
|
||||||
|
|
||||||
match func_instance {
|
|
||||||
FuncInstance::Defined { body, .. } => {
|
|
||||||
let function_body = body;
|
|
||||||
|
|
||||||
|
match func_body {
|
||||||
|
Some(function_body) => {
|
||||||
if !function_context.is_initialized() {
|
if !function_context.is_initialized() {
|
||||||
let return_type = function_context.return_type;
|
let return_type = function_context.return_type;
|
||||||
function_context.initialize(&function_body.locals);
|
function_context.initialize(&function_body.locals);
|
||||||
@ -95,9 +92,9 @@ impl<'store, St: 'static> Interpreter<'store, St> {
|
|||||||
|
|
||||||
self.do_run_function(&mut function_context, function_body.opcodes.elements(), &function_body.labels)?
|
self.do_run_function(&mut function_context, function_body.opcodes.elements(), &function_body.labels)?
|
||||||
},
|
},
|
||||||
FuncInstance::Host { host_func, .. } => {
|
None => {
|
||||||
let args: Vec<_> = function_context.locals.drain(..).collect();
|
let args: Vec<_> = function_context.locals.drain(..).collect();
|
||||||
let result = self.store.invoke_host(self.state, host_func, args)?;
|
let result = self.store.invoke(function_ref, args, self.state)?;
|
||||||
RunResult::Return(result)
|
RunResult::Return(result)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -976,7 +973,7 @@ impl<'a> FunctionContext {
|
|||||||
pub fn new<'store>(store: &'store Store, function: FuncId, value_stack_limit: usize, frame_stack_limit: usize, function_type: &FunctionSignature, args: Vec<RuntimeValue>) -> Self {
|
pub fn new<'store>(store: &'store Store, function: FuncId, value_stack_limit: usize, frame_stack_limit: usize, function_type: &FunctionSignature, args: Vec<RuntimeValue>) -> Self {
|
||||||
let func_instance = function.resolve(store);
|
let func_instance = function.resolve(store);
|
||||||
let module = match *func_instance {
|
let module = match *func_instance {
|
||||||
FuncInstance::Defined { module, .. } => module,
|
FuncInstance::Internal { module, .. } => module,
|
||||||
FuncInstance::Host { .. } => panic!("Host functions can't be called as internally defined functions; Thus FunctionContext can be created only with internally defined functions; qed"),
|
FuncInstance::Host { .. } => panic!("Host functions can't be called as internally defined functions; Thus FunctionContext can be created only with internally defined functions; qed"),
|
||||||
};
|
};
|
||||||
FunctionContext {
|
FunctionContext {
|
||||||
@ -995,7 +992,7 @@ impl<'a> FunctionContext {
|
|||||||
let (function_locals, module, function_return_type) = {
|
let (function_locals, module, function_return_type) = {
|
||||||
let func_instance = function.resolve(store);
|
let func_instance = function.resolve(store);
|
||||||
let module = match *func_instance {
|
let module = match *func_instance {
|
||||||
FuncInstance::Defined { module, .. } => module,
|
FuncInstance::Internal { module, .. } => module,
|
||||||
FuncInstance::Host { .. } => panic!("Host functions can't be called as internally defined functions; Thus FunctionContext can be created only with internally defined functions; qed"),
|
FuncInstance::Host { .. } => panic!("Host functions can't be called as internally defined functions; Thus FunctionContext can be created only with internally defined functions; qed"),
|
||||||
};
|
};
|
||||||
let function_type = func_instance.func_type().resolve(store);
|
let function_type = func_instance.func_type().resolve(store);
|
||||||
|
@ -120,27 +120,33 @@ pub enum ExternVal {
|
|||||||
Global(GlobalId),
|
Global(GlobalId),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum FuncInstance {
|
pub enum FuncInstance {
|
||||||
Defined {
|
Internal {
|
||||||
func_type: TypeId,
|
func_type: TypeId,
|
||||||
module: ModuleId,
|
module: ModuleId,
|
||||||
body: Arc<FuncBody>,
|
body: Arc<FuncBody>,
|
||||||
},
|
},
|
||||||
Host {
|
Host {
|
||||||
func_type: TypeId,
|
func_type: TypeId,
|
||||||
host_func: HostFuncId,
|
host_func: Arc<AnyFunc>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FuncInstance {
|
impl FuncInstance {
|
||||||
pub fn func_type(&self) -> TypeId {
|
pub fn func_type(&self) -> TypeId {
|
||||||
match *self {
|
match *self {
|
||||||
FuncInstance::Defined { func_type, .. } | FuncInstance::Host { func_type, .. } => {
|
FuncInstance::Internal { func_type, .. } | FuncInstance::Host { func_type, .. } => {
|
||||||
func_type
|
func_type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn body(&self) -> Option<Arc<FuncBody>> {
|
||||||
|
match *self {
|
||||||
|
FuncInstance::Internal { ref body, .. } => Some(Arc::clone(body)),
|
||||||
|
FuncInstance::Host { .. } => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@ -194,7 +200,6 @@ pub struct Store {
|
|||||||
// However, they can be referenced in several places, so it is handy to have it here.
|
// However, they can be referenced in several places, so it is handy to have it here.
|
||||||
modules: Vec<ModuleInstance>,
|
modules: Vec<ModuleInstance>,
|
||||||
types: Vec<FunctionType>,
|
types: Vec<FunctionType>,
|
||||||
host_funcs: Vec<Box<AnyFunc>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Store {
|
impl Store {
|
||||||
@ -220,8 +225,8 @@ impl Store {
|
|||||||
TypeId(type_id as u32)
|
TypeId(type_id as u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloc_func(&mut self, module: ModuleId, func_type: TypeId, body: FuncBody) -> FuncId {
|
pub fn alloc_func(&mut self, module: ModuleId, func_type: TypeId, body: FuncBody) -> FuncId {
|
||||||
let func = FuncInstance::Defined {
|
let func = FuncInstance::Internal {
|
||||||
func_type,
|
func_type,
|
||||||
module,
|
module,
|
||||||
body: Arc::new(body),
|
body: Arc::new(body),
|
||||||
@ -231,34 +236,31 @@ impl Store {
|
|||||||
FuncId(func_id as u32)
|
FuncId(func_id as u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn alloc_host_func(&mut self, func_type: TypeId, anyfunc: Box<AnyFunc>) -> FuncId {
|
pub fn alloc_host_func(&mut self, func_type: TypeId, host_func: Arc<AnyFunc>) -> FuncId {
|
||||||
self.host_funcs.push(anyfunc);
|
|
||||||
let host_func_id = self.host_funcs.len() - 1;
|
|
||||||
|
|
||||||
let func = FuncInstance::Host {
|
let func = FuncInstance::Host {
|
||||||
func_type,
|
func_type,
|
||||||
host_func: HostFuncId(host_func_id as u32),
|
host_func,
|
||||||
};
|
};
|
||||||
self.funcs.push(func);
|
self.funcs.push(func);
|
||||||
let func_id = self.funcs.len() - 1;
|
let func_id = self.funcs.len() - 1;
|
||||||
FuncId(func_id as u32)
|
FuncId(func_id as u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloc_table(&mut self, table_type: &TableType) -> Result<TableId, Error> {
|
pub fn alloc_table(&mut self, table_type: &TableType) -> Result<TableId, Error> {
|
||||||
let table = TableInstance::new(table_type)?;
|
let table = TableInstance::new(table_type)?;
|
||||||
self.tables.push(table);
|
self.tables.push(table);
|
||||||
let table_id = self.tables.len() - 1;
|
let table_id = self.tables.len() - 1;
|
||||||
Ok(TableId(table_id as u32))
|
Ok(TableId(table_id as u32))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloc_memory(&mut self, mem_type: &MemoryType) -> Result<MemoryId, Error> {
|
pub fn alloc_memory(&mut self, mem_type: &MemoryType) -> Result<MemoryId, Error> {
|
||||||
let mem = MemoryInstance::new(&mem_type)?;
|
let mem = MemoryInstance::new(&mem_type)?;
|
||||||
self.memories.push(mem);
|
self.memories.push(mem);
|
||||||
let mem_id = self.memories.len() - 1;
|
let mem_id = self.memories.len() - 1;
|
||||||
Ok(MemoryId(mem_id as u32))
|
Ok(MemoryId(mem_id as u32))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloc_global(&mut self, global_type: GlobalType, val: RuntimeValue) -> GlobalId {
|
pub fn alloc_global(&mut self, global_type: GlobalType, val: RuntimeValue) -> GlobalId {
|
||||||
let global = GlobalInstance::new(val, global_type.is_mutable());
|
let global = GlobalInstance::new(val, global_type.is_mutable());
|
||||||
self.globals.push(global);
|
self.globals.push(global);
|
||||||
let global_id = self.globals.len() - 1;
|
let global_id = self.globals.len() - 1;
|
||||||
@ -376,7 +378,7 @@ impl Store {
|
|||||||
&mut self,
|
&mut self,
|
||||||
module: &Module,
|
module: &Module,
|
||||||
extern_vals: &[ExternVal],
|
extern_vals: &[ExternVal],
|
||||||
start_exec_params: ExecutionParams<St>,
|
state: &mut St,
|
||||||
) -> Result<ModuleId, Error> {
|
) -> Result<ModuleId, Error> {
|
||||||
let mut instance = ModuleInstance::new();
|
let mut instance = ModuleInstance::new();
|
||||||
// Reserve the index of the module, but not yet push the module.
|
// Reserve the index of the module, but not yet push the module.
|
||||||
@ -442,30 +444,40 @@ impl Store {
|
|||||||
.get(start_fn_idx as usize)
|
.get(start_fn_idx as usize)
|
||||||
.expect("Due to validation start function should exists")
|
.expect("Due to validation start function should exists")
|
||||||
};
|
};
|
||||||
self.invoke(start_func, start_exec_params)?;
|
self.invoke(start_func, vec![], state)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(module_id)
|
Ok(module_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn invoke<St>(&mut self, func: FuncId, params: ExecutionParams<St>) -> Result<Option<RuntimeValue>, Error> {
|
pub fn invoke<St: 'static>(&mut self, func: FuncId, args: Vec<RuntimeValue>, state: &mut St) -> Result<Option<RuntimeValue>, Error> {
|
||||||
let ExecutionParams { args, mut state } = params;
|
enum InvokeKind {
|
||||||
let mut args = StackWithLimit::with_data(args, DEFAULT_VALUE_STACK_LIMIT);
|
Internal(FunctionContext),
|
||||||
let outer = CallerContext::topmost(&mut args);
|
Host(Arc<AnyFunc>),
|
||||||
let inner = {
|
}
|
||||||
let func_type = func.resolve(self).func_type().resolve(self);
|
|
||||||
let func_signature = FunctionSignature::Module(func_type);
|
|
||||||
let args = prepare_function_args(&func_signature, outer.value_stack)?;
|
|
||||||
FunctionContext::new(self, func, outer.value_stack_limit, outer.frame_stack_limit, &func_signature, args)
|
|
||||||
};
|
|
||||||
let mut interpreter = Interpreter::new(self, &mut state);
|
|
||||||
interpreter.run_function(inner)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn invoke_host<St: 'static>(&mut self, state: &mut St, host_func: HostFuncId, args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error> {
|
let result = match *func.resolve(self) {
|
||||||
let host_func_instance = self.host_funcs.get(host_func.0 as usize).expect("ID should be always valid");
|
FuncInstance::Internal { func_type, .. } => {
|
||||||
host_func_instance.call_as_any(state as &mut Any, &args);
|
let mut args = StackWithLimit::with_data(args, DEFAULT_VALUE_STACK_LIMIT);
|
||||||
panic!()
|
let outer = CallerContext::topmost(&mut args);
|
||||||
|
let func_signature = FunctionSignature::Module(func_type.resolve(self));
|
||||||
|
let args = prepare_function_args(&func_signature, outer.value_stack)?;
|
||||||
|
let context = FunctionContext::new(self, func, outer.value_stack_limit, outer.frame_stack_limit, &func_signature, args);
|
||||||
|
InvokeKind::Internal(context)
|
||||||
|
},
|
||||||
|
FuncInstance::Host { ref host_func, .. } => InvokeKind::Host(Arc::clone(host_func)),
|
||||||
|
};
|
||||||
|
|
||||||
|
match result {
|
||||||
|
InvokeKind::Internal(ctx) => {
|
||||||
|
let mut interpreter = Interpreter::new(self, state);
|
||||||
|
interpreter.run_function(ctx)
|
||||||
|
},
|
||||||
|
InvokeKind::Host(host_func) => {
|
||||||
|
// host_func.call_as_any();
|
||||||
|
panic!()
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_global(&mut self, global: GlobalId, val: RuntimeValue) -> Result<(), Error> {
|
pub fn write_global(&mut self, global: GlobalId, val: RuntimeValue) -> Result<(), Error> {
|
||||||
|
Reference in New Issue
Block a user