mirror of
https://github.com/fluencelabs/parity-wasm
synced 2025-06-14 23:41:43 +00:00
flush
This commit is contained in:
@ -7,7 +7,7 @@ use elements::{Module, FunctionType, ExportEntry, Internal, GlobalEntry, GlobalT
|
|||||||
use interpreter::Error;
|
use interpreter::Error;
|
||||||
use interpreter::env_native::NATIVE_INDEX_FUNC_MIN;
|
use interpreter::env_native::NATIVE_INDEX_FUNC_MIN;
|
||||||
use interpreter::module::{ModuleInstanceInterface, ModuleInstance, ExecutionParams,
|
use interpreter::module::{ModuleInstanceInterface, ModuleInstance, ExecutionParams,
|
||||||
ItemIndex, CallerContext, CallResult, ExportEntryType};
|
ItemIndex, CallerContext, ExportEntryType, InternalFunctionReference, InternalFunction};
|
||||||
use interpreter::memory::{MemoryInstance, LINEAR_MEMORY_PAGE_SIZE};
|
use interpreter::memory::{MemoryInstance, LINEAR_MEMORY_PAGE_SIZE};
|
||||||
use interpreter::table::TableInstance;
|
use interpreter::table::TableInstance;
|
||||||
use interpreter::value::RuntimeValue;
|
use interpreter::value::RuntimeValue;
|
||||||
@ -124,15 +124,27 @@ impl ModuleInstanceInterface for EnvModuleInstance {
|
|||||||
self.instance.global(index, variable_type)
|
self.instance.global(index, variable_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_function<'a>(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result<CallResult<'a>, Error> {
|
fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<InternalFunctionReference<'a>, Error> {
|
||||||
|
self.instance.function_reference(index, externals)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn function_reference_indirect<'a>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<InternalFunctionReference<'a>, Error> {
|
||||||
|
self.instance.function_reference_indirect(table_idx, type_idx, func_idx, externals)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn function_body<'a>(&'a self, internal_index: u32) -> Result<Option<InternalFunction<'a>>, Error> {
|
||||||
|
self.instance.function_body(internal_index)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*fn call_function(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result<Option<RuntimeValue>, Error> {
|
||||||
self.instance.call_function(outer, index, function_type)
|
self.instance.call_function(outer, index, function_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_function_indirect<'a>(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result<CallResult<'a>, Error> {
|
fn call_function_indirect(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result<Option<RuntimeValue>, Error> {
|
||||||
self.instance.call_function_indirect(outer, table_index, type_index, func_index)
|
self.instance.call_function_indirect(outer, table_index, type_index, func_index)
|
||||||
}
|
}*/
|
||||||
|
|
||||||
fn call_internal_function<'a>(&self, outer: CallerContext, index: u32, _function_type: Option<&FunctionType>) -> Result<CallResult<'a>, Error> {
|
fn call_internal_function(&self, outer: CallerContext, index: u32, _function_type: Option<&FunctionType>) -> Result<Option<RuntimeValue>, Error> {
|
||||||
// TODO: check function type
|
// TODO: check function type
|
||||||
// to make interpreter independent of *SCRIPTEN runtime, just make abort/assert = interpreter Error
|
// to make interpreter independent of *SCRIPTEN runtime, just make abort/assert = interpreter Error
|
||||||
match index {
|
match index {
|
||||||
@ -145,12 +157,12 @@ impl ModuleInstanceInterface for EnvModuleInstance {
|
|||||||
.and_then(|g| g.set(RuntimeValue::I32(1)))
|
.and_then(|g| g.set(RuntimeValue::I32(1)))
|
||||||
.and_then(|_| Err(Error::Trap("assertion failed".into())))
|
.and_then(|_| Err(Error::Trap("assertion failed".into())))
|
||||||
} else {
|
} else {
|
||||||
Ok(CallResult::Executed(None))
|
Ok(None)
|
||||||
}),
|
}),
|
||||||
INDEX_FUNC_ENLARGE_MEMORY => Ok(CallResult::Executed(Some(RuntimeValue::I32(0)))), // TODO: support memory enlarge
|
INDEX_FUNC_ENLARGE_MEMORY => Ok(Some(RuntimeValue::I32(0))), // TODO: support memory enlarge
|
||||||
INDEX_FUNC_GET_TOTAL_MEMORY => self.global(ItemIndex::IndexSpace(INDEX_GLOBAL_TOTAL_MEMORY), Some(VariableType::I32))
|
INDEX_FUNC_GET_TOTAL_MEMORY => self.global(ItemIndex::IndexSpace(INDEX_GLOBAL_TOTAL_MEMORY), Some(VariableType::I32))
|
||||||
.map(|g| g.get())
|
.map(|g| g.get())
|
||||||
.map(|v| CallResult::Executed(Some(v))),
|
.map(Some),
|
||||||
INDEX_FUNC_MIN_NONUSED ... INDEX_FUNC_MAX => Err(Error::Trap("unimplemented".into())),
|
INDEX_FUNC_MIN_NONUSED ... INDEX_FUNC_MAX => Err(Error::Trap("unimplemented".into())),
|
||||||
_ => Err(Error::Trap(format!("trying to call function with index {} in env module", index))),
|
_ => Err(Error::Trap(format!("trying to call function with index {} in env module", index))),
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use elements::{FunctionType, Internal, ValueType};
|
use elements::{FunctionType, Internal, ValueType, Opcode};
|
||||||
use interpreter::Error;
|
use interpreter::Error;
|
||||||
use interpreter::module::{ModuleInstanceInterface, ExecutionParams, ItemIndex,
|
use interpreter::module::{ModuleInstanceInterface, ExecutionParams, ItemIndex,
|
||||||
CallerContext, CallResult, ExportEntryType};
|
CallerContext, ExportEntryType, InternalFunctionReference, InternalFunction};
|
||||||
use interpreter::memory::MemoryInstance;
|
use interpreter::memory::MemoryInstance;
|
||||||
use interpreter::table::TableInstance;
|
use interpreter::table::TableInstance;
|
||||||
use interpreter::value::RuntimeValue;
|
use interpreter::value::RuntimeValue;
|
||||||
@ -113,15 +113,19 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> {
|
|||||||
self.env.global(index, variable_type)
|
self.env.global(index, variable_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_function<'b>(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result<CallResult<'b>, Error> {
|
fn function_reference<'b>(&self, index: ItemIndex, externals: Option<&'b HashMap<String, Arc<ModuleInstanceInterface + 'b>>>) -> Result<InternalFunctionReference<'b>, Error> {
|
||||||
self.env.call_function(outer, index, function_type)
|
self.env.function_reference(index, externals)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_function_indirect<'b>(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result<CallResult<'b>, Error> {
|
fn function_reference_indirect<'b>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'b HashMap<String, Arc<ModuleInstanceInterface + 'b>>>) -> Result<InternalFunctionReference<'b>, Error> {
|
||||||
self.env.call_function_indirect(outer, table_index, type_index, func_index)
|
self.env.function_reference_indirect(table_idx, type_idx, func_idx, externals)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_internal_function<'b>(&self, outer: CallerContext, index: u32, function_type: Option<&FunctionType>) -> Result<CallResult<'b>, Error> {
|
fn function_body<'b>(&'b self, internal_index: u32) -> Result<Option<InternalFunction<'b>>, Error> {
|
||||||
|
self.env.function_body(internal_index)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_internal_function(&self, outer: CallerContext, index: u32, function_type: Option<&FunctionType>) -> Result<Option<RuntimeValue>, Error> {
|
||||||
if index < NATIVE_INDEX_FUNC_MIN {
|
if index < NATIVE_INDEX_FUNC_MIN {
|
||||||
return self.env.call_internal_function(outer, index, function_type);
|
return self.env.call_internal_function(outer, index, function_type);
|
||||||
}
|
}
|
||||||
@ -131,7 +135,6 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> {
|
|||||||
.get((index - NATIVE_INDEX_FUNC_MIN) as usize)
|
.get((index - NATIVE_INDEX_FUNC_MIN) as usize)
|
||||||
.ok_or(Error::Native(format!("trying to call native function with index {}", index)))
|
.ok_or(Error::Native(format!("trying to call native function with index {}", index)))
|
||||||
.and_then(|f| self.executor.write().execute(&f.name, outer))
|
.and_then(|f| self.executor.write().execute(&f.name, outer))
|
||||||
.map(CallResult::Executed)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
use elements::{Module, InitExpr, Opcode, Type, FunctionType, FuncBody, Internal, External, BlockType, ResizableLimits};
|
use std::fmt;
|
||||||
|
use elements::{Module, InitExpr, Opcode, Type, FunctionType, FuncBody, Internal, External, BlockType, ResizableLimits, Local};
|
||||||
use interpreter::Error;
|
use interpreter::Error;
|
||||||
use interpreter::imports::ModuleImports;
|
use interpreter::imports::ModuleImports;
|
||||||
use interpreter::memory::MemoryInstance;
|
use interpreter::memory::MemoryInstance;
|
||||||
@ -16,7 +17,7 @@ use interpreter::variable::{VariableInstance, VariableType};
|
|||||||
/// Maximum number of entries in value stack.
|
/// Maximum number of entries in value stack.
|
||||||
const DEFAULT_VALUE_STACK_LIMIT: usize = 16384;
|
const DEFAULT_VALUE_STACK_LIMIT: usize = 16384;
|
||||||
/// Maximum number of entries in frame stack.
|
/// Maximum number of entries in frame stack.
|
||||||
const DEFAULT_FRAME_STACK_LIMIT: usize = 128; // TODO: fix runner to support bigger depth
|
const DEFAULT_FRAME_STACK_LIMIT: usize = 1024;
|
||||||
|
|
||||||
/// Execution context.
|
/// Execution context.
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
@ -38,14 +39,6 @@ pub enum ExportEntryType {
|
|||||||
Global(VariableType),
|
Global(VariableType),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call result. To eliminate recursion, module must return function body to interpreter or execute function itself if no body available.
|
|
||||||
pub enum CallResult<'a> {
|
|
||||||
/// Function is executed with given result.
|
|
||||||
Executed(Option<RuntimeValue>),
|
|
||||||
/// Function execution is scheduled.
|
|
||||||
Scheduled(FunctionContext<'a>, &'a [Opcode]),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Module instance API.
|
/// Module instance API.
|
||||||
pub trait ModuleInstanceInterface {
|
pub trait ModuleInstanceInterface {
|
||||||
/// Run instantiation-time procedures (validation and start function call). Module is not completely validated until this call.
|
/// Run instantiation-time procedures (validation and start function call). Module is not completely validated until this call.
|
||||||
@ -64,12 +57,18 @@ pub trait ModuleInstanceInterface {
|
|||||||
fn memory(&self, index: ItemIndex) -> Result<Arc<MemoryInstance>, Error>;
|
fn memory(&self, index: ItemIndex) -> Result<Arc<MemoryInstance>, Error>;
|
||||||
/// Get global reference.
|
/// Get global reference.
|
||||||
fn global(&self, index: ItemIndex, variable_type: Option<VariableType>) -> Result<Arc<VariableInstance>, Error>;
|
fn global(&self, index: ItemIndex, variable_type: Option<VariableType>) -> Result<Arc<VariableInstance>, Error>;
|
||||||
|
/// Get function reference.
|
||||||
|
fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<InternalFunctionReference<'a>, Error>;
|
||||||
|
/// Get function indirect reference.
|
||||||
|
fn function_reference_indirect<'a>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<InternalFunctionReference<'a>, Error>;
|
||||||
|
/// Get internal function for interpretation.
|
||||||
|
fn function_body<'a>(&'a self, internal_index: u32) -> Result<Option<InternalFunction<'a>>, Error>;
|
||||||
/// Call function with given index in functions index space.
|
/// Call function with given index in functions index space.
|
||||||
fn call_function<'a>(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result<CallResult<'a>, Error>;
|
//fn call_function<'a>(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result<Option<RuntimeValue>, Error>;
|
||||||
/// Call function with given index in the given table.
|
/// Call function with given index in the given table.
|
||||||
fn call_function_indirect<'a>(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result<CallResult<'a>, Error>;
|
//fn call_function_indirect<'a>(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result<Option<RuntimeValue>, Error>;
|
||||||
/// Call function with internal index.
|
/// Call function with internal index.
|
||||||
fn call_internal_function<'a>(&self, outer: CallerContext, index: u32, function_type: Option<&FunctionType>) -> Result<CallResult<'a>, Error>;
|
fn call_internal_function<'a>(&self, outer: CallerContext, index: u32, function_type: Option<&FunctionType>) -> Result<Option<RuntimeValue>, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Item index in items index space.
|
/// Item index in items index space.
|
||||||
@ -111,6 +110,33 @@ pub struct CallerContext<'a> {
|
|||||||
pub externals: &'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>,
|
pub externals: &'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Internal function reference.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct InternalFunctionReference<'a> {
|
||||||
|
/// Module reference.
|
||||||
|
pub module: Arc<ModuleInstanceInterface + 'a>,
|
||||||
|
/// Internal function index.
|
||||||
|
pub internal_index: u32,
|
||||||
|
// Internal function type.
|
||||||
|
//pub function_type: &'a FunctionType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> fmt::Debug for InternalFunctionReference<'a> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "InternalFunctionReference")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Internal function ready for interpretation.
|
||||||
|
pub struct InternalFunction<'a> {
|
||||||
|
/// Function type.
|
||||||
|
pub func_type: &'a FunctionType,
|
||||||
|
/// Function locals.
|
||||||
|
pub locals: &'a [Local],
|
||||||
|
/// Function body.
|
||||||
|
pub body: &'a [Opcode],
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> ExecutionParams<'a> {
|
impl<'a> ExecutionParams<'a> {
|
||||||
/// Create new execution params with given externa; module override.
|
/// Create new execution params with given externa; module override.
|
||||||
pub fn with_external(name: String, module: Arc<ModuleInstanceInterface + 'a>) -> Self {
|
pub fn with_external(name: String, module: Arc<ModuleInstanceInterface + 'a>) -> Self {
|
||||||
@ -185,6 +211,10 @@ impl ModuleInstance {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn self_ref<'a>(&self, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<Arc<ModuleInstanceInterface + 'a>, Error> {
|
||||||
|
self.imports.module(externals, &self.name)
|
||||||
|
}
|
||||||
|
|
||||||
fn require_function(&self, index: ItemIndex) -> Result<u32, Error> {
|
fn require_function(&self, index: ItemIndex) -> Result<u32, Error> {
|
||||||
match self.imports.parse_function_index(index) {
|
match self.imports.parse_function_index(index) {
|
||||||
ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"),
|
ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"),
|
||||||
@ -212,13 +242,6 @@ impl ModuleInstance {
|
|||||||
_ => Err(Error::Validation(format!("missing function type with index {}", type_index))),
|
_ => Err(Error::Validation(format!("missing function type with index {}", type_index))),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unwrap_call_result(&self, call_result: CallResult) -> Result<Option<RuntimeValue>, Error> {
|
|
||||||
match call_result {
|
|
||||||
CallResult::Executed(v) => Ok(v),
|
|
||||||
CallResult::Scheduled(context, body) => Interpreter::run_function(context, body)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleInstanceInterface for ModuleInstance {
|
impl ModuleInstanceInterface for ModuleInstance {
|
||||||
@ -368,10 +391,12 @@ impl ModuleInstanceInterface for ModuleInstance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn execute_index(&self, index: u32, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
|
fn execute_index(&self, index: u32, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
|
||||||
let args_len = params.args.len();
|
let ExecutionParams { args, externals } = params;
|
||||||
let mut args = StackWithLimit::with_data(params.args, args_len);
|
let mut args = StackWithLimit::with_data(args, DEFAULT_VALUE_STACK_LIMIT);
|
||||||
let caller_context = CallerContext::topmost(&mut args, ¶ms.externals);
|
let function_reference = self.function_reference(ItemIndex::IndexSpace(index), Some(&externals))?;
|
||||||
self.unwrap_call_result(self.call_function(caller_context, ItemIndex::IndexSpace(index), None)?)
|
let function_type = self.function_type(ItemIndex::IndexSpace(index), Some(&externals))?;
|
||||||
|
let function_context = CallerContext::topmost(&mut args, &externals);
|
||||||
|
function_reference.module.call_internal_function(function_context, function_reference.internal_index, Some(&function_type))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute_export(&self, name: &str, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
|
fn execute_export(&self, name: &str, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
|
||||||
@ -466,7 +491,120 @@ impl ModuleInstanceInterface for ModuleInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_function<'a>(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result<CallResult<'a>, Error> {
|
fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<InternalFunctionReference<'a>, Error> {
|
||||||
|
match self.imports.parse_function_index(index) {
|
||||||
|
ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"),
|
||||||
|
ItemIndex::Internal(index) => Ok(InternalFunctionReference {
|
||||||
|
module: self.self_ref(externals)?,
|
||||||
|
internal_index: index,
|
||||||
|
}),
|
||||||
|
ItemIndex::External(index) => {
|
||||||
|
let import_section = self.module.import_section().unwrap();
|
||||||
|
let import_entry = import_section.entries().get(index as usize).unwrap();
|
||||||
|
Ok(InternalFunctionReference {
|
||||||
|
module: self.imports.module(externals, import_entry.module())?,
|
||||||
|
internal_index: index
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn function_reference_indirect<'a>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<InternalFunctionReference<'a>, Error> {
|
||||||
|
let function_type = match self.module.type_section()
|
||||||
|
.ok_or(Error::Function(format!("trying to indirect call function {} with non-existent function section", func_idx)))
|
||||||
|
.and_then(|s| s.types().get(type_idx as usize)
|
||||||
|
.ok_or(Error::Function(format!("trying to indirect call function {} with non-existent type index {}", func_idx, type_idx))))? {
|
||||||
|
&Type::Function(ref function_type) => function_type,
|
||||||
|
};
|
||||||
|
|
||||||
|
let table = self.table(ItemIndex::IndexSpace(table_idx))?;
|
||||||
|
let (module, index) = match table.get(func_idx)? {
|
||||||
|
RuntimeValue::AnyFunc(module, index) => (module.clone(), index),
|
||||||
|
_ => return Err(Error::Function(format!("trying to indirect call function {} via non-anyfunc table {:?}", func_idx, table_idx))),
|
||||||
|
};
|
||||||
|
|
||||||
|
let module = self.imports.module(externals, &module)?;
|
||||||
|
module.function_reference(ItemIndex::IndexSpace(index), externals)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn function_body<'a>(&'a self, internal_index: u32/*, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>*/) -> Result<Option<InternalFunction<'a>>, Error> {
|
||||||
|
// internal index = index of function in functions section && index of code in code section
|
||||||
|
// get function type index
|
||||||
|
let function_type_index = self.module
|
||||||
|
.function_section()
|
||||||
|
.ok_or(Error::Function(format!("trying to call function with index {} in module without function section", internal_index)))
|
||||||
|
.and_then(|s| s.entries()
|
||||||
|
.get(internal_index as usize)
|
||||||
|
.ok_or(Error::Function(format!("trying to call function with index {} in module with {} functions", internal_index, s.entries().len()))))?
|
||||||
|
.type_ref();
|
||||||
|
// function type index = index of function type in types index
|
||||||
|
// get function type
|
||||||
|
let item_type = self.module
|
||||||
|
.type_section()
|
||||||
|
.ok_or(Error::Function(format!("trying to call function with index {} in module without types section", internal_index)))
|
||||||
|
.and_then(|s| s.types()
|
||||||
|
.get(function_type_index as usize)
|
||||||
|
.ok_or(Error::Function(format!("trying to call function with type index {} in module with {} types", function_type_index, s.types().len()))))?;
|
||||||
|
let actual_function_type = match item_type {
|
||||||
|
&Type::Function(ref function_type) => function_type,
|
||||||
|
};
|
||||||
|
|
||||||
|
// get function body
|
||||||
|
let function_body = self.module
|
||||||
|
.code_section()
|
||||||
|
.ok_or(Error::Function(format!("trying to call function with index {} in module without code section", internal_index)))
|
||||||
|
.and_then(|s| s.bodies()
|
||||||
|
.get(internal_index as usize)
|
||||||
|
.ok_or(Error::Function(format!("trying to call function with index {} in module with {} functions codes", internal_index, s.bodies().len()))))?;
|
||||||
|
|
||||||
|
Ok(Some(InternalFunction {
|
||||||
|
func_type: actual_function_type,
|
||||||
|
locals: function_body.locals(),
|
||||||
|
body: function_body.code().elements(),
|
||||||
|
}))
|
||||||
|
/*match self.imports.parse_function_index(index) {
|
||||||
|
ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"),
|
||||||
|
ItemIndex::Internal(index) => {
|
||||||
|
// internal index = index of function in functions section && index of code in code section
|
||||||
|
// get function type index
|
||||||
|
let function_type_index = self.module
|
||||||
|
.function_section()
|
||||||
|
.ok_or(Error::Function(format!("trying to call function with index {} in module without function section", index)))
|
||||||
|
.and_then(|s| s.entries()
|
||||||
|
.get(index as usize)
|
||||||
|
.ok_or(Error::Function(format!("trying to call function with index {} in module with {} functions", index, s.entries().len()))))?
|
||||||
|
.type_ref();
|
||||||
|
// function type index = index of function type in types index
|
||||||
|
// get function type
|
||||||
|
let item_type = self.module
|
||||||
|
.type_section()
|
||||||
|
.ok_or(Error::Function(format!("trying to call function with index {} in module without types section", index)))
|
||||||
|
.and_then(|s| s.types()
|
||||||
|
.get(function_type_index as usize)
|
||||||
|
.ok_or(Error::Function(format!("trying to call function with type index {} in module with {} types", function_type_index, s.types().len()))))?;
|
||||||
|
let actual_function_type = match item_type {
|
||||||
|
&Type::Function(ref function_type) => function_type,
|
||||||
|
};
|
||||||
|
|
||||||
|
// get function body
|
||||||
|
let function_body = self.module
|
||||||
|
.code_section()
|
||||||
|
.ok_or(Error::Function(format!("trying to call function with index {} in module without code section", index)))
|
||||||
|
.and_then(|s| s.bodies()
|
||||||
|
.get(index as usize)
|
||||||
|
.ok_or(Error::Function(format!("trying to call function with index {} in module with {} functions codes", index, s.bodies().len()))))?;
|
||||||
|
|
||||||
|
Ok(Some(Function {
|
||||||
|
func_type: actual_function_type,
|
||||||
|
body: function_body.code().elements(),
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
ItemIndex::External(index) => {
|
||||||
|
},
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*fn call_function(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result<Option<RuntimeValue>, Error> {
|
||||||
match self.imports.parse_function_index(index) {
|
match self.imports.parse_function_index(index) {
|
||||||
ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"),
|
ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"),
|
||||||
ItemIndex::Internal(index) => self.call_internal_function(outer, index, function_type),
|
ItemIndex::Internal(index) => self.call_internal_function(outer, index, function_type),
|
||||||
@ -480,7 +618,7 @@ impl ModuleInstanceInterface for ModuleInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_function_indirect<'a>(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result<CallResult<'a>, Error> {
|
fn call_function_indirect(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result<Option<RuntimeValue>, Error> {
|
||||||
let function_type = match self.module.type_section()
|
let function_type = match self.module.type_section()
|
||||||
.ok_or(Error::Function(format!("trying to indirect call function {} with non-existent function section", func_index)))
|
.ok_or(Error::Function(format!("trying to indirect call function {} with non-existent function section", func_index)))
|
||||||
.and_then(|s| s.types().get(type_index as usize)
|
.and_then(|s| s.types().get(type_index as usize)
|
||||||
@ -496,53 +634,36 @@ impl ModuleInstanceInterface for ModuleInstance {
|
|||||||
|
|
||||||
let module = self.imports.module(Some(outer.externals), &module)?;
|
let module = self.imports.module(Some(outer.externals), &module)?;
|
||||||
module.call_function(outer, ItemIndex::IndexSpace(index), Some(function_type))
|
module.call_function(outer, ItemIndex::IndexSpace(index), Some(function_type))
|
||||||
}
|
}*/
|
||||||
|
|
||||||
fn call_internal_function<'a>(&self, mut outer: CallerContext, index: u32, function_type: Option<&FunctionType>) -> Result<CallResult<'a>, Error> {
|
fn call_internal_function(&self, mut outer: CallerContext, index: u32, required_function_type: Option<&FunctionType>) -> Result<Option<RuntimeValue>, Error> {
|
||||||
// TODO: cache
|
let function_type_index = self.require_function(ItemIndex::Internal(index))?;
|
||||||
// internal index = index of function in functions section && index of code in code section
|
let function_type = self.require_function_type(function_type_index)?;
|
||||||
// get function type index
|
let function_body = self.function_body(index)?;
|
||||||
let function_type_index = self.module
|
|
||||||
.function_section()
|
if let Some(ref required_function_type) = required_function_type {
|
||||||
.ok_or(Error::Function(format!("trying to call function with index {} in module without function section", index)))
|
if required_function_type != &function_type {
|
||||||
.and_then(|s| s.entries()
|
|
||||||
.get(index as usize)
|
|
||||||
.ok_or(Error::Function(format!("trying to call function with index {} in module with {} functions", index, s.entries().len()))))?
|
|
||||||
.type_ref();
|
|
||||||
// function type index = index of function type in types index
|
|
||||||
// get function type
|
|
||||||
let item_type = self.module
|
|
||||||
.type_section()
|
|
||||||
.ok_or(Error::Function(format!("trying to call function with index {} in module without types section", index)))
|
|
||||||
.and_then(|s| s.types()
|
|
||||||
.get(function_type_index as usize)
|
|
||||||
.ok_or(Error::Function(format!("trying to call function with type index {} in module with {} types", function_type_index, s.types().len()))))?;
|
|
||||||
let actual_function_type = match item_type {
|
|
||||||
&Type::Function(ref function_type) => function_type,
|
|
||||||
};
|
|
||||||
if let Some(ref function_type) = function_type {
|
|
||||||
if function_type != &actual_function_type {
|
|
||||||
return Err(Error::Function(format!("expected function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}",
|
return Err(Error::Function(format!("expected function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}",
|
||||||
function_type.params(), function_type.return_type(), actual_function_type.params(), actual_function_type.return_type())));
|
required_function_type.params(), required_function_type.return_type(), function_type.params(), function_type.return_type())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// get function body
|
|
||||||
let function_body = self.module
|
|
||||||
.code_section()
|
|
||||||
.ok_or(Error::Function(format!("trying to call function with index {} in module without code section", index)))
|
|
||||||
.and_then(|s| s.bodies()
|
|
||||||
.get(index as usize)
|
|
||||||
.ok_or(Error::Function(format!("trying to call function with index {} in module with {} functions codes", index, s.bodies().len()))))?;
|
|
||||||
|
|
||||||
// each functions has its own value stack
|
let args = function_type.params().iter()
|
||||||
// but there's global stack limit
|
.map(|param_type| {
|
||||||
// args, locals
|
let param_value = outer.value_stack.pop()?;
|
||||||
let function_code = function_body.code().elements();
|
let actual_type = param_value.variable_type();
|
||||||
let value_stack_limit = outer.value_stack_limit;
|
let expected_type = (*param_type).into();
|
||||||
let frame_stack_limit = outer.frame_stack_limit;
|
if actual_type != Some(expected_type) {
|
||||||
let locals = prepare_function_locals(actual_function_type, function_body, &mut outer)?;
|
return Err(Error::Function(format!("invalid parameter type {:?} when expected {:?}", actual_type, expected_type)));
|
||||||
let mut innner = FunctionContext::new(self, outer.externals, value_stack_limit, frame_stack_limit, actual_function_type, locals);
|
}
|
||||||
Interpreter::run_function(innner, function_code).map(CallResult::Executed)
|
|
||||||
|
VariableInstance::new(true, expected_type, param_value)
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
|
let function_ref = InternalFunctionReference { module: self.self_ref(Some(outer.externals))?, internal_index: index };
|
||||||
|
let inner = FunctionContext::new(function_ref, outer.externals, outer.value_stack_limit, outer.frame_stack_limit, &function_type, args);
|
||||||
|
Interpreter::run_function(inner)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,10 +3,11 @@ use std::ops;
|
|||||||
use std::u32;
|
use std::u32;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::fmt::{self, Display};
|
use std::fmt::{self, Display};
|
||||||
|
use std::iter::repeat;
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
use elements::{Opcode, BlockType, FunctionType};
|
use elements::{Opcode, BlockType, FunctionType, Local};
|
||||||
use interpreter::Error;
|
use interpreter::Error;
|
||||||
use interpreter::module::{ModuleInstance, ModuleInstanceInterface, CallerContext, CallResult, ItemIndex};
|
use interpreter::module::{ModuleInstance, ModuleInstanceInterface, CallerContext, ItemIndex, InternalFunctionReference};
|
||||||
use interpreter::stack::StackWithLimit;
|
use interpreter::stack::StackWithLimit;
|
||||||
use interpreter::value::{
|
use interpreter::value::{
|
||||||
RuntimeValue, TryInto, WrapInto, TryTruncateInto, ExtendInto,
|
RuntimeValue, TryInto, WrapInto, TryTruncateInto, ExtendInto,
|
||||||
@ -24,8 +25,10 @@ pub struct Interpreter;
|
|||||||
|
|
||||||
/// Function execution context.
|
/// Function execution context.
|
||||||
pub struct FunctionContext<'a> {
|
pub struct FunctionContext<'a> {
|
||||||
/// Module instance.
|
/// Is context initialized.
|
||||||
pub module: &'a ModuleInstance,
|
pub is_initialized: bool,
|
||||||
|
/// Internal function reference.
|
||||||
|
pub function: InternalFunctionReference<'a>,
|
||||||
/// Execution-local external modules.
|
/// Execution-local external modules.
|
||||||
pub externals: &'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>,
|
pub externals: &'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>,
|
||||||
/// Function return type.
|
/// Function return type.
|
||||||
@ -35,14 +38,14 @@ pub struct FunctionContext<'a> {
|
|||||||
/// Values stack.
|
/// Values stack.
|
||||||
pub value_stack: StackWithLimit<RuntimeValue>,
|
pub value_stack: StackWithLimit<RuntimeValue>,
|
||||||
/// Blocks frames stack.
|
/// Blocks frames stack.
|
||||||
pub frame_stack: StackWithLimit<BlockFrame>,
|
pub frame_stack: StackWithLimit<BlockFrame<'a>>,
|
||||||
/// Current instruction position.
|
/// Current instruction position.
|
||||||
pub position: usize,
|
pub position: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Interpreter action to execute after executing instruction.
|
/// Interpreter action to execute after executing instruction.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum InstructionOutcome {
|
pub enum InstructionOutcome<'a> {
|
||||||
/// Continue with current instruction.
|
/// Continue with current instruction.
|
||||||
RunInstruction,
|
RunInstruction,
|
||||||
/// Continue with next instruction.
|
/// Continue with next instruction.
|
||||||
@ -52,9 +55,7 @@ pub enum InstructionOutcome {
|
|||||||
/// Execute block.
|
/// Execute block.
|
||||||
ExecuteBlock(bool),
|
ExecuteBlock(bool),
|
||||||
/// Execute function call.
|
/// Execute function call.
|
||||||
ExecuteCall(u32),
|
ExecuteCall(InternalFunctionReference<'a>),
|
||||||
/// Execute indirect function call.
|
|
||||||
ExecuteIndirectCall(u32, u32, u32),
|
|
||||||
/// End current frame.
|
/// End current frame.
|
||||||
End,
|
End,
|
||||||
/// Return from current function block.
|
/// Return from current function block.
|
||||||
@ -63,155 +64,103 @@ pub enum InstructionOutcome {
|
|||||||
|
|
||||||
/// Control stack frame.
|
/// Control stack frame.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct BlockFrame {
|
pub struct BlockFrame<'a> {
|
||||||
/// Is loop frame?
|
/// Is loop frame?
|
||||||
is_loop: bool,
|
is_loop: bool,
|
||||||
// A label for reference from branch instructions.
|
/// A label for reference from branch instructions.
|
||||||
branch_position: usize,
|
branch_position: usize,
|
||||||
// A label for reference from end instructions.
|
/// A label for reference from end instructions.
|
||||||
end_position: usize,
|
end_position: usize,
|
||||||
// A limit integer value, which is an index into the value stack indicating where to reset it to on a branch to that label.
|
/// Block body.
|
||||||
|
body: &'a [Opcode],
|
||||||
|
/// A limit integer value, which is an index into the value stack indicating where to reset it to on a branch to that label.
|
||||||
value_limit: usize,
|
value_limit: usize,
|
||||||
// A signature, which is a block signature type indicating the number and types of result values of the region.
|
/// A signature, which is a block signature type indicating the number and types of result values of the region.
|
||||||
signature: BlockType,
|
signature: BlockType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum RunResult<'a> {
|
||||||
|
Return(Option<RuntimeValue>),
|
||||||
|
NestedCall(FunctionContext<'a>),
|
||||||
|
}
|
||||||
|
|
||||||
impl Interpreter {
|
impl Interpreter {
|
||||||
pub fn run_function(mut context: FunctionContext, body: &[Opcode]) -> Result<Option<RuntimeValue>, Error> {
|
pub fn run_function(function_context: FunctionContext) -> Result<Option<RuntimeValue>, Error> {
|
||||||
let mut context_depth = 0usize;
|
let mut function_stack = VecDeque::new();
|
||||||
let mut context_stack = VecDeque::new();
|
function_stack.push_back(function_context);
|
||||||
let mut blocks_stack = VecDeque::new();
|
|
||||||
|
|
||||||
{
|
loop {
|
||||||
let return_type = context.return_type;
|
let mut function_context = function_stack.pop_back().expect("on loop entry - not empty; on loop continue - checking for emptiness; qed");
|
||||||
context.push_frame(false, body.len() - 1, body.len() - 1, return_type)?;
|
let function_ref = function_context.function.clone();
|
||||||
context.position = 0;
|
let function_body = function_ref.module.function_body(function_ref.internal_index)?;
|
||||||
|
|
||||||
context_stack.push_back(context);
|
let function_return = match function_body {
|
||||||
blocks_stack.push_back((1, body));
|
Some(function_body) => {
|
||||||
}
|
if !function_context.is_initialized() {
|
||||||
|
function_context.initialize(function_body.locals)?;
|
||||||
|
}
|
||||||
|
|
||||||
loop { // functions loop
|
Interpreter::do_run_function(&mut function_context, function_body.body)?
|
||||||
let function_return = {
|
},
|
||||||
let context = context_stack.back_mut().unwrap();
|
None => {
|
||||||
Interpreter::run_function_blocks(context_depth, &mut blocks_stack, context)?
|
let nested_context = CallerContext::nested(&mut function_context);
|
||||||
|
RunResult::Return(function_ref.module.call_internal_function(nested_context, function_ref.internal_index, None)?)
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
match function_return {
|
match function_return {
|
||||||
InstructionOutcome::ExecuteCall(func_idx) => {
|
RunResult::Return(return_value) => {
|
||||||
let context = context_stack.back_mut().unwrap();
|
match function_stack.back_mut() {
|
||||||
match context.call_function(func_idx)? {
|
Some(caller_context) => if let Some(return_value) = return_value {
|
||||||
CallResult::Executed(result) => if let Some(result) = result {
|
caller_context.value_stack_mut().push(return_value)?;
|
||||||
context.value_stack_mut().push(result)?;
|
|
||||||
},
|
},
|
||||||
CallResult::Scheduled(new_context, body) => {
|
|
||||||
unimplemented!()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
InstructionOutcome::ExecuteIndirectCall(table_idx, type_idx, func_idx) => {
|
|
||||||
let context = context_stack.back_mut().unwrap();
|
|
||||||
match context.call_function_indirect(table_idx, type_idx, func_idx)? {
|
|
||||||
CallResult::Executed(result) => if let Some(result) = result {
|
|
||||||
context.value_stack_mut().push(result)?;
|
|
||||||
},
|
|
||||||
CallResult::Scheduled(new_context, body) => {
|
|
||||||
unimplemented!()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
InstructionOutcome::Return => {
|
|
||||||
// return function value
|
|
||||||
let mut context = context_stack.pop_back().unwrap();
|
|
||||||
let return_value = match context.return_type {
|
|
||||||
BlockType::Value(_) => Some(context.value_stack_mut().pop()?),
|
|
||||||
BlockType::NoResult => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
match context_stack.back_mut() {
|
|
||||||
None => return Ok(return_value),
|
None => return Ok(return_value),
|
||||||
Some(context) => if let Some(return_value) = return_value {
|
|
||||||
context.value_stack_mut().push(return_value)?;
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
InstructionOutcome::RunInstruction | InstructionOutcome::RunNextInstruction | InstructionOutcome::Branch(_)
|
RunResult::NestedCall(nested_context) => {
|
||||||
| InstructionOutcome::ExecuteBlock(_) | InstructionOutcome::End => unreachable!("managed by run_function_blocks"),
|
function_stack.push_back(function_context);
|
||||||
/*CallResult::Executed(result) => {
|
function_stack.push_back(nested_context);
|
||||||
context_stack.pop_back();
|
|
||||||
match context_stack.back_mut() {
|
|
||||||
None => return Ok(result),
|
|
||||||
Some(context) => match result {
|
|
||||||
Some(result) => context.value_stack_mut().push(result)?,
|
|
||||||
None => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
context_depth -= 1;
|
|
||||||
},
|
},
|
||||||
CallResult::Scheduled(context, body) => {
|
|
||||||
context_depth += 1;
|
|
||||||
|
|
||||||
context_stack.push_back(context);
|
|
||||||
blocks_stack.push_back((context_depth, body));
|
|
||||||
},*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_function_blocks<'a, 'b, 'c>(current_depth: usize, blocks_stack: &'b mut VecDeque<(usize, &'a [Opcode])>, context: &'c mut FunctionContext<'a>) -> Result<InstructionOutcome, Error> where 'a: 'b {
|
fn do_run_function<'a>(function_context: &mut FunctionContext<'a>, function_body: &[Opcode]) -> Result<RunResult<'a>, Error> {
|
||||||
loop { // blocks loop
|
loop {
|
||||||
let block_return = {
|
let block_frame = function_context.frame_stack_mut().pop();
|
||||||
let block = match blocks_stack.back() {
|
let block_result = Interpreter::run_block_instructions(function_context, block_frame.body)?;
|
||||||
Some(block) => block,
|
|
||||||
None => return Ok(InstructionOutcome::Return),
|
|
||||||
};
|
|
||||||
|
|
||||||
assert!(block.0 >= current_depth);
|
match block_result {
|
||||||
if block.0 < current_depth {
|
InstructionOutcome::RunInstruction | InstructionOutcome::RunNextInstruction => unreachable!("managed by run_block_instructions"),
|
||||||
return Ok(InstructionOutcome::Return);
|
|
||||||
}
|
|
||||||
|
|
||||||
let block_body = block.1;
|
|
||||||
Interpreter::run_block_instructions(context, block_body)?
|
|
||||||
};
|
|
||||||
|
|
||||||
match block_return {
|
|
||||||
InstructionOutcome::RunInstruction | InstructionOutcome::RunNextInstruction => unreachable!("resolved by run_block_instructions"),
|
|
||||||
InstructionOutcome::ExecuteCall(func_idx) => return Ok(InstructionOutcome::ExecuteCall(func_idx)),
|
|
||||||
InstructionOutcome::ExecuteIndirectCall(table_idx, type_idx, func_idx) => return Ok(InstructionOutcome::ExecuteIndirectCall(table_idx, type_idx, func_idx)),
|
|
||||||
InstructionOutcome::ExecuteBlock(branch) => {
|
|
||||||
let nested_block = Interpreter::into_block(&blocks_stack.back().unwrap().1[context.position], branch)?;
|
|
||||||
blocks_stack.push_back((current_depth, nested_block));
|
|
||||||
context.position = 0;
|
|
||||||
},
|
|
||||||
InstructionOutcome::Branch(mut index) => {
|
InstructionOutcome::Branch(mut index) => {
|
||||||
// discard index - 1 blocks
|
// discard index - 2 blocks (-1 since last block is popped && -1 since we have already popped current block)
|
||||||
while index >= 1 {
|
while index >= 2 {
|
||||||
context.discard_frame()?;
|
function_context.discard_frame()?;
|
||||||
assert!(blocks_stack.pop_back().is_some());
|
|
||||||
index -= 1;
|
index -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
context.pop_frame(true)?;
|
function_context.pop_frame(true)?;
|
||||||
assert!(blocks_stack.pop_back().is_some());
|
if function_context.frame_stack().is_empty() {
|
||||||
}
|
return Ok(RunResult::Return(match function_context.return_type {
|
||||||
InstructionOutcome::End => {
|
BlockType::Value(_) => Some(function_context.value_stack_mut().pop()?),
|
||||||
// pop single block
|
BlockType::NoResult => None,
|
||||||
context.pop_frame(false)?;
|
}));
|
||||||
assert!(blocks_stack.pop_back().is_some());
|
|
||||||
},
|
|
||||||
InstructionOutcome::Return => {
|
|
||||||
// discard all function blocks
|
|
||||||
while context.frame_stack.len() > 0 {
|
|
||||||
context.discard_frame()?;
|
|
||||||
assert!(blocks_stack.pop_back().is_some());
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
InstructionOutcome::ExecuteBlock(branch) => {
|
||||||
|
function_context.frame_stack_mut().push_penultimate(block_frame)?;
|
||||||
|
},
|
||||||
|
InstructionOutcome::ExecuteCall(func_ref) => return Ok(RunResult::NestedCall(function_context.nested(func_ref)?)),
|
||||||
|
InstructionOutcome::End => (),
|
||||||
|
InstructionOutcome::Return => return Ok(RunResult::Return(match function_context.return_type {
|
||||||
|
BlockType::Value(_) => Some(function_context.value_stack_mut().pop()?),
|
||||||
|
BlockType::NoResult => None,
|
||||||
|
})),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_block_instructions<'a>(context: &mut FunctionContext<'a>, body: &'a [Opcode]) -> Result<InstructionOutcome, Error> {
|
fn run_block_instructions<'a, 'b>(context: &'b mut FunctionContext<'a>, body: &'a [Opcode]) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
loop {
|
loop {
|
||||||
let instruction = &body[context.position];
|
let instruction = &body[context.position];
|
||||||
|
|
||||||
@ -220,26 +169,25 @@ impl Interpreter {
|
|||||||
InstructionOutcome::RunNextInstruction => context.position += 1,
|
InstructionOutcome::RunNextInstruction => context.position += 1,
|
||||||
InstructionOutcome::Branch(index) => return Ok(InstructionOutcome::Branch(index)),
|
InstructionOutcome::Branch(index) => return Ok(InstructionOutcome::Branch(index)),
|
||||||
InstructionOutcome::ExecuteBlock(branch) => return Ok(InstructionOutcome::ExecuteBlock(branch)),
|
InstructionOutcome::ExecuteBlock(branch) => return Ok(InstructionOutcome::ExecuteBlock(branch)),
|
||||||
InstructionOutcome::ExecuteCall(func_idx) => {
|
InstructionOutcome::ExecuteCall(func_ref) => {
|
||||||
context.position += 1;
|
context.position += 1;
|
||||||
return Ok(InstructionOutcome::ExecuteCall(func_idx));
|
return Ok(InstructionOutcome::ExecuteCall(func_ref));
|
||||||
},
|
},
|
||||||
InstructionOutcome::ExecuteIndirectCall(table_idx, type_idx, func_idx) => {
|
InstructionOutcome::End => {
|
||||||
context.position += 1;
|
context.pop_frame(false)?;
|
||||||
return Ok(InstructionOutcome::ExecuteIndirectCall(table_idx, type_idx, func_idx));
|
return Ok(InstructionOutcome::End);
|
||||||
},
|
},
|
||||||
InstructionOutcome::End => return Ok(InstructionOutcome::End),
|
|
||||||
InstructionOutcome::Return => return Ok(InstructionOutcome::Return),
|
InstructionOutcome::Return => return Ok(InstructionOutcome::Return),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_instruction<'a>(context: &mut FunctionContext, opcode: &'a Opcode) -> Result<InstructionOutcome, Error> {
|
fn run_instruction<'a, 'b>(context: &'b mut FunctionContext<'a>, opcode: &'a Opcode) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
match opcode {
|
match opcode {
|
||||||
&Opcode::Unreachable => Interpreter::run_unreachable(context),
|
&Opcode::Unreachable => Interpreter::run_unreachable(context),
|
||||||
&Opcode::Nop => Interpreter::run_nop(context),
|
&Opcode::Nop => Interpreter::run_nop(context),
|
||||||
&Opcode::Block(block_type, _) => Interpreter::run_block(context, block_type),
|
&Opcode::Block(block_type, ref ops) => Interpreter::run_block(context, block_type, ops.elements()),
|
||||||
&Opcode::Loop(block_type, ref ops) => Interpreter::run_loop(context, block_type),
|
&Opcode::Loop(block_type, ref ops) => Interpreter::run_loop(context, block_type, ops.elements()),
|
||||||
&Opcode::If(block_type, ref ops) => Interpreter::run_if(context, block_type, ops.elements()),
|
&Opcode::If(block_type, ref ops) => Interpreter::run_if(context, block_type, ops.elements()),
|
||||||
&Opcode::Else => Interpreter::run_else(context),
|
&Opcode::Else => Interpreter::run_else(context),
|
||||||
&Opcode::End => Interpreter::run_end(context),
|
&Opcode::End => Interpreter::run_end(context),
|
||||||
@ -448,52 +396,52 @@ impl Interpreter {
|
|||||||
&body[begin_index..end_index]
|
&body[begin_index..end_index]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_unreachable<'a>(_context: &mut FunctionContext) -> Result<InstructionOutcome, Error> {
|
fn run_unreachable<'a>(_context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
Err(Error::Trap("programmatic".into()))
|
Err(Error::Trap("programmatic".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_nop<'a>(_context: &mut FunctionContext) -> Result<InstructionOutcome, Error> {
|
fn run_nop<'a>(_context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_block<'a>(context: &mut FunctionContext, block_type: BlockType) -> Result<InstructionOutcome, Error> {
|
fn run_block<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType, body: &'a [Opcode]) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
let frame_position = context.position + 1;
|
let frame_position = context.position + 1;
|
||||||
context.push_frame(false, frame_position, frame_position, block_type)?;
|
context.push_frame(false, frame_position, frame_position, body, block_type)?;
|
||||||
Ok(InstructionOutcome::ExecuteBlock(true))
|
Ok(InstructionOutcome::ExecuteBlock(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_loop<'a>(context: &mut FunctionContext, block_type: BlockType) -> Result<InstructionOutcome, Error> {
|
fn run_loop<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType, body: &'a [Opcode]) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
let frame_position = context.position;
|
let frame_position = context.position;
|
||||||
context.push_frame(true, frame_position, frame_position + 1, block_type.clone())?;
|
context.push_frame(true, frame_position, frame_position + 1, body, block_type)?;
|
||||||
Ok(InstructionOutcome::ExecuteBlock(true))
|
Ok(InstructionOutcome::ExecuteBlock(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_if<'a>(context: &mut FunctionContext, block_type: BlockType, body: &'a [Opcode]) -> Result<InstructionOutcome, Error> {
|
fn run_if<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType, body: &'a [Opcode]) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
let branch = context.value_stack_mut().pop_as()?;
|
let branch = context.value_stack_mut().pop_as()?;
|
||||||
let branch_body = Interpreter::separate_if(body, branch);
|
let branch_body = Interpreter::separate_if(body, branch);
|
||||||
|
|
||||||
if branch_body.len() != 0 {
|
if branch_body.len() != 0 {
|
||||||
let frame_position = context.position + 1;
|
let frame_position = context.position + 1;
|
||||||
context.push_frame(false, frame_position, frame_position, block_type.clone())?;
|
context.push_frame(false, frame_position, frame_position, branch_body, block_type)?;
|
||||||
Ok(InstructionOutcome::ExecuteBlock(branch))
|
Ok(InstructionOutcome::ExecuteBlock(branch))
|
||||||
} else {
|
} else {
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_else<'a>(_context: &mut FunctionContext) -> Result<InstructionOutcome, Error> {
|
fn run_else<'a>(_context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
Ok(InstructionOutcome::End)
|
Ok(InstructionOutcome::End)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_end<'a>(_context: &mut FunctionContext) -> Result<InstructionOutcome, Error> {
|
fn run_end<'a>(_context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
Ok(InstructionOutcome::End)
|
Ok(InstructionOutcome::End)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_br<'a>(_context: &mut FunctionContext, label_idx: u32) -> Result<InstructionOutcome, Error> {
|
fn run_br<'a>(_context: &mut FunctionContext, label_idx: u32) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
Ok(InstructionOutcome::Branch(label_idx as usize))
|
Ok(InstructionOutcome::Branch(label_idx as usize))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_br_if<'a>(context: &mut FunctionContext, label_idx: u32) -> Result<InstructionOutcome, Error> {
|
fn run_br_if<'a>(context: &mut FunctionContext, label_idx: u32) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
if context.value_stack_mut().pop_as()? {
|
if context.value_stack_mut().pop_as()? {
|
||||||
Ok(InstructionOutcome::Branch(label_idx as usize))
|
Ok(InstructionOutcome::Branch(label_idx as usize))
|
||||||
} else {
|
} else {
|
||||||
@ -501,38 +449,32 @@ impl Interpreter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_br_table<'a>(context: &mut FunctionContext, table: &Vec<u32>, default: u32) -> Result<InstructionOutcome, Error> {
|
fn run_br_table<'a>(context: &mut FunctionContext, table: &Vec<u32>, default: u32) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
let index: u32 = context.value_stack_mut().pop_as()?;
|
let index: u32 = context.value_stack_mut().pop_as()?;
|
||||||
Ok(InstructionOutcome::Branch(table.get(index as usize).cloned().unwrap_or(default) as usize))
|
Ok(InstructionOutcome::Branch(table.get(index as usize).cloned().unwrap_or(default) as usize))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_return<'a>(_context: &mut FunctionContext) -> Result<InstructionOutcome, Error> {
|
fn run_return<'a>(_context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
Ok(InstructionOutcome::Return)
|
Ok(InstructionOutcome::Return)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_call<'a>(context: &mut FunctionContext, func_idx: u32) -> Result<InstructionOutcome, Error> {
|
fn run_call<'a, 'b>(context: &'b mut FunctionContext<'a>, func_idx: u32) -> Result<InstructionOutcome<'a>, Error> where 'a: 'b {
|
||||||
Ok(InstructionOutcome::ExecuteCall(func_idx))
|
Ok(InstructionOutcome::ExecuteCall(context.module().function_reference(ItemIndex::IndexSpace(func_idx), Some(context.externals))?))
|
||||||
/*context.call_function(func_idx)
|
|
||||||
.and_then(|r| r.map(|r| context.value_stack_mut().push(r)).unwrap_or(Ok(())))
|
|
||||||
.map(|_| InstructionOutcome::RunNextInstruction)*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_call_indirect<'a>(context: &mut FunctionContext, type_idx: u32) -> Result<InstructionOutcome, Error> {
|
fn run_call_indirect<'a, 'b>(context: &'b mut FunctionContext<'a>, type_idx: u32) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
let table_func_idx: u32 = context.value_stack_mut().pop_as()?;
|
let table_func_idx: u32 = context.value_stack_mut().pop_as()?;
|
||||||
Ok(InstructionOutcome::ExecuteIndirectCall(DEFAULT_TABLE_INDEX, type_idx, table_func_idx))
|
Ok(InstructionOutcome::ExecuteCall(context.module().function_reference_indirect(DEFAULT_TABLE_INDEX, type_idx, table_func_idx, Some(context.externals))?))
|
||||||
/*context.call_function_indirect(DEFAULT_TABLE_INDEX, type_idx, table_func_idx)
|
|
||||||
.and_then(|r| r.map(|r| context.value_stack_mut().push(r)).unwrap_or(Ok(())))
|
|
||||||
.map(|_| InstructionOutcome::RunNextInstruction)*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_drop<'a>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> {
|
fn run_drop<'a>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
.pop()
|
.pop()
|
||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_select<'a>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> {
|
fn run_select<'a>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
.pop_triple()
|
.pop_triple()
|
||||||
@ -547,32 +489,32 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_get_local<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Error> {
|
fn run_get_local<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
context.get_local(index as usize)
|
context.get_local(index as usize)
|
||||||
.map(|value| context.value_stack_mut().push(value))
|
.map(|value| context.value_stack_mut().push(value))
|
||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_set_local<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Error> {
|
fn run_set_local<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
let arg = context.value_stack_mut().pop()?;
|
let arg = context.value_stack_mut().pop()?;
|
||||||
context.set_local(index as usize, arg)
|
context.set_local(index as usize, arg)
|
||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_tee_local<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Error> {
|
fn run_tee_local<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
let arg = context.value_stack().top()?.clone();
|
let arg = context.value_stack().top()?.clone();
|
||||||
context.set_local(index as usize, arg)
|
context.set_local(index as usize, arg)
|
||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_get_global<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Error> {
|
fn run_get_global<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
context.module()
|
context.module()
|
||||||
.global(ItemIndex::IndexSpace(index), None)
|
.global(ItemIndex::IndexSpace(index), None)
|
||||||
.and_then(|g| context.value_stack_mut().push(g.get()))
|
.and_then(|g| context.value_stack_mut().push(g.get()))
|
||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_set_global<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, Error> {
|
fn run_set_global<'a>(context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
.pop()
|
.pop()
|
||||||
@ -580,7 +522,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_load<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome, Error>
|
fn run_load<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<T>, T: LittleEndianConvert {
|
where RuntimeValue: From<T>, T: LittleEndianConvert {
|
||||||
let address = effective_address(offset, context.value_stack_mut().pop_as()?)?;
|
let address = effective_address(offset, context.value_stack_mut().pop_as()?)?;
|
||||||
context.module()
|
context.module()
|
||||||
@ -591,7 +533,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_load_extend<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome, Error>
|
fn run_load_extend<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where T: ExtendInto<U>, RuntimeValue: From<U>, T: LittleEndianConvert {
|
where T: ExtendInto<U>, RuntimeValue: From<U>, T: LittleEndianConvert {
|
||||||
let address = effective_address(offset, context.value_stack_mut().pop_as()?)?;
|
let address = effective_address(offset, context.value_stack_mut().pop_as()?)?;
|
||||||
let stack_value: U = context.module()
|
let stack_value: U = context.module()
|
||||||
@ -605,7 +547,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_store<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome, Error>
|
fn run_store<'a, T>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: TryInto<T, Error>, T: LittleEndianConvert {
|
where RuntimeValue: TryInto<T, Error>, T: LittleEndianConvert {
|
||||||
let stack_value = context
|
let stack_value = context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -618,7 +560,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_store_wrap<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome, Error>
|
fn run_store_wrap<'a, T, U>(context: &mut FunctionContext, _align: u32, offset: u32) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: TryInto<T, Error>, T: WrapInto<U>, U: LittleEndianConvert {
|
where RuntimeValue: TryInto<T, Error>, T: WrapInto<U>, U: LittleEndianConvert {
|
||||||
let stack_value: T = context.value_stack_mut().pop().and_then(|v| v.try_into())?;
|
let stack_value: T = context.value_stack_mut().pop().and_then(|v| v.try_into())?;
|
||||||
let stack_value = stack_value.wrap_into().into_little_endian();
|
let stack_value = stack_value.wrap_into().into_little_endian();
|
||||||
@ -629,7 +571,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_current_memory<'a>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> {
|
fn run_current_memory<'a>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
context.module()
|
context.module()
|
||||||
.memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX))
|
.memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX))
|
||||||
.map(|m| m.size())
|
.map(|m| m.size())
|
||||||
@ -637,7 +579,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_grow_memory<'a>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error> {
|
fn run_grow_memory<'a>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
let pages: u32 = context.value_stack_mut().pop_as()?;
|
let pages: u32 = context.value_stack_mut().pop_as()?;
|
||||||
context.module()
|
context.module()
|
||||||
.memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX))
|
.memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX))
|
||||||
@ -646,14 +588,14 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_const<'a>(context: &mut FunctionContext, val: RuntimeValue) -> Result<InstructionOutcome, Error> {
|
fn run_const<'a>(context: &mut FunctionContext, val: RuntimeValue) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
.push(val)
|
.push(val)
|
||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_eqz<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_eqz<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> + Default {
|
where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> + Default {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -663,7 +605,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_eq<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_eq<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> {
|
where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -673,7 +615,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_ne<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_ne<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> {
|
where RuntimeValue: TryInto<T, Error>, T: PartialEq<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -683,7 +625,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_lt<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_lt<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> + Display {
|
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> + Display {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -693,7 +635,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_gt<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_gt<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> {
|
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -703,7 +645,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_lte<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_lte<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> {
|
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -713,7 +655,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_gte<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_gte<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> {
|
where RuntimeValue: TryInto<T, Error>, T: PartialOrd<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -723,7 +665,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_clz<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_clz<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -733,7 +675,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_ctz<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_ctz<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -743,7 +685,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_popcnt<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_popcnt<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -753,7 +695,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_add<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_add<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> {
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -763,7 +705,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_sub<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_sub<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> {
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -773,7 +715,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_mul<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_mul<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> {
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: ArithmeticOps<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -783,7 +725,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_div<'a, T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_div<'a, T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U> + Display, U: ArithmeticOps<U> + TransmuteInto<T> {
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U> + Display, U: ArithmeticOps<U> + TransmuteInto<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -795,7 +737,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_rem<'a, T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_rem<'a, T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U>, U: Integer<U> + TransmuteInto<T> {
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U>, U: Integer<U> + TransmuteInto<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -807,7 +749,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_and<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_and<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<<T as ops::BitAnd>::Output> + TryInto<T, Error>, T: ops::BitAnd<T> {
|
where RuntimeValue: From<<T as ops::BitAnd>::Output> + TryInto<T, Error>, T: ops::BitAnd<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -817,7 +759,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_or<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_or<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<<T as ops::BitOr>::Output> + TryInto<T, Error>, T: ops::BitOr<T> {
|
where RuntimeValue: From<<T as ops::BitOr>::Output> + TryInto<T, Error>, T: ops::BitOr<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -827,7 +769,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_xor<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_xor<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<<T as ops::BitXor>::Output> + TryInto<T, Error>, T: ops::BitXor<T> {
|
where RuntimeValue: From<<T as ops::BitXor>::Output> + TryInto<T, Error>, T: ops::BitXor<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -837,7 +779,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_shl<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_shl<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<<T as ops::Shl<T>>::Output> + TryInto<T, Error>, T: ops::Shl<T> {
|
where RuntimeValue: From<<T as ops::Shl<T>>::Output> + TryInto<T, Error>, T: ops::Shl<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -847,7 +789,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_shr<'a, T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_shr<'a, T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U>, U: ops::Shr<U>, <U as ops::Shr<U>>::Output: TransmuteInto<T> {
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: TransmuteInto<U>, U: ops::Shr<U>, <U as ops::Shr<U>>::Output: TransmuteInto<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -859,7 +801,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_rotl<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_rotl<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -869,7 +811,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_rotr<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_rotr<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Integer<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -879,7 +821,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_abs<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_abs<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -889,7 +831,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_neg<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_neg<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<<T as ops::Neg>::Output> + TryInto<T, Error>, T: ops::Neg {
|
where RuntimeValue: From<<T as ops::Neg>::Output> + TryInto<T, Error>, T: ops::Neg {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -899,7 +841,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_ceil<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_ceil<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -909,7 +851,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_floor<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_floor<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -919,7 +861,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_trunc<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_trunc<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -929,7 +871,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_nearest<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_nearest<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -939,7 +881,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_sqrt<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_sqrt<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -949,7 +891,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_min<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_min<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -959,7 +901,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_max<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_max<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -969,7 +911,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_copysign<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_copysign<'a, T>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
where RuntimeValue: From<T> + TryInto<T, Error>, T: Float<T> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -979,7 +921,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_wrap<'a, T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_wrap<'a, T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<U> + TryInto<T, Error>, T: WrapInto<U> {
|
where RuntimeValue: From<U> + TryInto<T, Error>, T: WrapInto<U> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -989,7 +931,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_trunc_to_int<'a, T, U, V>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_trunc_to_int<'a, T, U, V>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<V> + TryInto<T, Error>, T: TryTruncateInto<U, Error>, U: TransmuteInto<V>, {
|
where RuntimeValue: From<V> + TryInto<T, Error>, T: TryTruncateInto<U, Error>, U: TransmuteInto<V>, {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -1000,7 +942,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_extend<'a, T, U, V>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_extend<'a, T, U, V>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<V> + TryInto<T, Error>, T: ExtendInto<U>, U: TransmuteInto<V> {
|
where RuntimeValue: From<V> + TryInto<T, Error>, T: ExtendInto<U>, U: TransmuteInto<V> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -1011,7 +953,7 @@ impl Interpreter {
|
|||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_reinterpret<'a, T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome, Error>
|
fn run_reinterpret<'a, T, U>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error>
|
||||||
where RuntimeValue: From<U>, RuntimeValue: TryInto<T, Error>, T: TransmuteInto<U> {
|
where RuntimeValue: From<U>, RuntimeValue: TryInto<T, Error>, T: TransmuteInto<U> {
|
||||||
context
|
context
|
||||||
.value_stack_mut()
|
.value_stack_mut()
|
||||||
@ -1023,11 +965,12 @@ impl Interpreter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FunctionContext<'a> {
|
impl<'a> FunctionContext<'a> {
|
||||||
pub fn new(module: &'a ModuleInstance, externals: &'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>, value_stack_limit: usize, frame_stack_limit: usize, function: &FunctionType, args: Vec<VariableInstance>) -> Self {
|
pub fn new(function: InternalFunctionReference<'a>, externals: &'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>, value_stack_limit: usize, frame_stack_limit: usize, function_type: &FunctionType, args: Vec<VariableInstance>) -> Self {
|
||||||
FunctionContext {
|
FunctionContext {
|
||||||
module: module,
|
is_initialized: false,
|
||||||
|
function: function,
|
||||||
externals: externals,
|
externals: externals,
|
||||||
return_type: function.return_type().map(|vt| BlockType::Value(vt)).unwrap_or(BlockType::NoResult),
|
return_type: function_type.return_type().map(|vt| BlockType::Value(vt)).unwrap_or(BlockType::NoResult),
|
||||||
value_stack: StackWithLimit::with_limit(value_stack_limit),
|
value_stack: StackWithLimit::with_limit(value_stack_limit),
|
||||||
frame_stack: StackWithLimit::with_limit(frame_stack_limit),
|
frame_stack: StackWithLimit::with_limit(frame_stack_limit),
|
||||||
locals: args,
|
locals: args,
|
||||||
@ -1035,23 +978,57 @@ impl<'a> FunctionContext<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn module(&self) -> &ModuleInstance {
|
pub fn nested(&mut self, function: InternalFunctionReference<'a>) -> Result<Self, Error> {
|
||||||
self.module
|
let function_type = function.module.function_type(ItemIndex::Internal(function.internal_index), Some(self.externals))?;
|
||||||
|
let function_return_type = function_type.return_type().map(|vt| BlockType::Value(vt)).unwrap_or(BlockType::NoResult);
|
||||||
|
let function_locals = function_type.params().iter().rev().map(|param_type| {
|
||||||
|
let param_value = self.value_stack.pop()?;
|
||||||
|
let actual_type = param_value.variable_type();
|
||||||
|
let expected_type = (*param_type).into();
|
||||||
|
if actual_type != Some(expected_type) {
|
||||||
|
return Err(Error::Function(format!("invalid parameter type {:?} when expected {:?}", actual_type, expected_type)));
|
||||||
|
}
|
||||||
|
|
||||||
|
VariableInstance::new(true, expected_type, param_value)
|
||||||
|
}).collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
|
Ok(FunctionContext {
|
||||||
|
is_initialized: false,
|
||||||
|
function: function,
|
||||||
|
externals: self.externals,
|
||||||
|
return_type: function_return_type,
|
||||||
|
value_stack: StackWithLimit::with_limit(self.value_stack.limit() - self.value_stack.len()),
|
||||||
|
frame_stack: StackWithLimit::with_limit(self.frame_stack.limit() - self.frame_stack.len()),
|
||||||
|
locals: function_locals,
|
||||||
|
position: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_initialized(&self) -> bool {
|
||||||
|
self.is_initialized
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initialize(&mut self, locals: &[Local]) -> Result<(), Error> {
|
||||||
|
debug_assert!(!self.is_initialized);
|
||||||
|
self.is_initialized = true;
|
||||||
|
|
||||||
|
let locals = locals.iter()
|
||||||
|
.flat_map(|l| repeat(l.value_type().into()).take(l.count() as usize))
|
||||||
|
.map(|vt| VariableInstance::new(true, vt, RuntimeValue::default(vt)))
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
self.locals.extend(locals);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn module(&self) -> &Arc<ModuleInstanceInterface + 'a> {
|
||||||
|
&self.function.module
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn externals(&self) -> &HashMap<String, Arc<ModuleInstanceInterface + 'a>> {
|
pub fn externals(&self) -> &HashMap<String, Arc<ModuleInstanceInterface + 'a>> {
|
||||||
&self.externals
|
&self.externals
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call_function<'b>(&mut self, index: u32) -> Result<CallResult<'b>, Error> {
|
pub fn set_local(&mut self, index: usize, value: RuntimeValue) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
self.module.call_function(CallerContext::nested(self), ItemIndex::IndexSpace(index), None)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn call_function_indirect<'b>(&mut self, table_index: u32, type_index: u32, func_index: u32) -> Result<CallResult<'b>, Error> {
|
|
||||||
self.module.call_function_indirect(CallerContext::nested(self), ItemIndex::IndexSpace(table_index), type_index, func_index)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_local(&mut self, index: usize, value: RuntimeValue) -> Result<InstructionOutcome, Error> {
|
|
||||||
self.locals.get_mut(index)
|
self.locals.get_mut(index)
|
||||||
.ok_or(Error::Local(format!("expected to have local with index {}", index)))
|
.ok_or(Error::Local(format!("expected to have local with index {}", index)))
|
||||||
.and_then(|l| l.set(value))
|
.and_then(|l| l.set(value))
|
||||||
@ -1076,11 +1053,16 @@ impl<'a> FunctionContext<'a> {
|
|||||||
&self.frame_stack
|
&self.frame_stack
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_frame(&mut self, is_loop: bool, branch_position: usize, end_position: usize, signature: BlockType) -> Result<(), Error> {
|
pub fn frame_stack_mut(&mut self) -> &mut StackWithLimit<BlockFrame<'a>> {
|
||||||
|
&mut self.frame_stack
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_frame(&mut self, is_loop: bool, branch_position: usize, end_position: usize, body: &'a [Opcode], signature: BlockType) -> Result<(), Error> {
|
||||||
self.frame_stack.push(BlockFrame {
|
self.frame_stack.push(BlockFrame {
|
||||||
is_loop: is_loop,
|
is_loop: is_loop,
|
||||||
branch_position: branch_position,
|
branch_position: branch_position,
|
||||||
end_position: end_position,
|
end_position: end_position,
|
||||||
|
body: body,
|
||||||
value_limit: self.value_stack.len(),
|
value_limit: self.value_stack.len(),
|
||||||
signature: signature,
|
signature: signature,
|
||||||
})
|
})
|
||||||
@ -1117,16 +1099,17 @@ impl<'a> fmt::Debug for FunctionContext<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BlockFrame {
|
impl<'a> BlockFrame<'a> {
|
||||||
pub fn invalid() -> Self {
|
/* pub fn invalid() -> Self {
|
||||||
BlockFrame {
|
BlockFrame {
|
||||||
is_loop: false,
|
is_loop: false,
|
||||||
branch_position: usize::max_value(),
|
branch_position: usize::max_value(),
|
||||||
end_position: usize::max_value(),
|
end_position: usize::max_value(),
|
||||||
|
branch: true,
|
||||||
value_limit: usize::max_value(),
|
value_limit: usize::max_value(),
|
||||||
signature: BlockType::NoResult,
|
signature: BlockType::NoResult,
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
fn effective_address(address: u32, offset: u32) -> Result<u32, Error> {
|
fn effective_address(address: u32, offset: u32) -> Result<u32, Error> {
|
||||||
@ -1135,3 +1118,25 @@ fn effective_address(address: u32, offset: u32) -> Result<u32, Error> {
|
|||||||
Some(address) => Ok(address),
|
Some(address) => Ok(address),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*fn prepare_function_locals(function_type: &FunctionType, function_body: &FuncBody, value_stack: &mut StackWithLimit<RuntimeValue>) -> Result<Vec<VariableInstance>, Error> {
|
||||||
|
// locals = function arguments + defined locals
|
||||||
|
function_type.params().iter().rev()
|
||||||
|
.map(|param_type| {
|
||||||
|
let param_value = outer.value_stack.pop()?;
|
||||||
|
let actual_type = param_value.variable_type();
|
||||||
|
let expected_type = (*param_type).into();
|
||||||
|
if actual_type != Some(expected_type) {
|
||||||
|
return Err(Error::Function(format!("invalid parameter type {:?} when expected {:?}", actual_type, expected_type)));
|
||||||
|
}
|
||||||
|
|
||||||
|
VariableInstance::new(true, expected_type, param_value)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>().into_iter().rev()
|
||||||
|
.chain(function_body.locals()
|
||||||
|
.iter()
|
||||||
|
.flat_map(|l| repeat(l.value_type().into()).take(l.count() as usize))
|
||||||
|
.map(|vt| VariableInstance::new(true, vt, RuntimeValue::default(vt))))
|
||||||
|
.collect::<Result<Vec<_>, _>>()
|
||||||
|
}
|
||||||
|
*/
|
@ -38,16 +38,22 @@ impl<T> StackWithLimit<T> where T: Clone {
|
|||||||
self.limit
|
self.limit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn values(&self) -> &VecDeque<T> {
|
||||||
|
&self.values
|
||||||
|
}
|
||||||
|
|
||||||
pub fn top(&self) -> Result<&T, Error> {
|
pub fn top(&self) -> Result<&T, Error> {
|
||||||
self.values
|
self.values
|
||||||
.back()
|
.back()
|
||||||
.ok_or(Error::Stack("non-empty stack expected".into()))
|
.ok_or(Error::Stack("non-empty stack expected".into()))
|
||||||
|
.map_err(|e| { panic!("1") })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn top_mut(&mut self) -> Result<&mut T, Error> {
|
pub fn top_mut(&mut self) -> Result<&mut T, Error> {
|
||||||
self.values
|
self.values
|
||||||
.back_mut()
|
.back_mut()
|
||||||
.ok_or(Error::Stack("non-empty stack expected".into()))
|
.ok_or(Error::Stack("non-empty stack expected".into()))
|
||||||
|
.map_err(|e| { panic!("2") })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, index: usize) -> Result<&T, Error> {
|
pub fn get(&self, index: usize) -> Result<&T, Error> {
|
||||||
@ -67,10 +73,24 @@ impl<T> StackWithLimit<T> where T: Clone {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn push_penultimate(&mut self, value: T) -> Result<(), Error> {
|
||||||
|
if self.values.is_empty() {
|
||||||
|
return Err(Error::Stack("trying to insert penultimate element into empty stack".into()));
|
||||||
|
}
|
||||||
|
self.push(value)?;
|
||||||
|
|
||||||
|
let last_index = self.values.len() - 1;
|
||||||
|
let penultimate_index = last_index - 1;
|
||||||
|
self.values.swap(last_index, penultimate_index);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn pop(&mut self) -> Result<T, Error> {
|
pub fn pop(&mut self) -> Result<T, Error> {
|
||||||
self.values
|
self.values
|
||||||
.pop_back()
|
.pop_back()
|
||||||
.ok_or(Error::Stack("non-empty stack expected".into()))
|
.ok_or(Error::Stack("non-empty stack expected".into()))
|
||||||
|
.map_err(|e| { panic!("3") })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resize(&mut self, new_size: usize, dummy: T) {
|
pub fn resize(&mut self, new_size: usize, dummy: T) {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
///! Tests from https://github.com/WebAssembly/wabt/tree/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp
|
///! Tests from https://github.com/WebAssembly/wabt/tree/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp
|
||||||
|
|
||||||
use std::sync::Weak;
|
use std::sync::{Arc, Weak};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use builder::module;
|
use builder::module;
|
||||||
use elements::{Module, ValueType, Opcodes, Opcode, BlockType, FunctionType};
|
use elements::{Module, ValueType, Opcodes, Opcode, BlockType, FunctionType, Local};
|
||||||
use interpreter::Error;
|
use interpreter::Error;
|
||||||
use interpreter::module::{ModuleInstance, ModuleInstanceInterface, ItemIndex};
|
use interpreter::module::{ModuleInstance, ModuleInstanceInterface, ItemIndex};
|
||||||
use interpreter::program::ProgramInstance;
|
use interpreter::program::ProgramInstance;
|
||||||
@ -11,44 +11,53 @@ use interpreter::runner::{Interpreter, FunctionContext};
|
|||||||
use interpreter::value::{RuntimeValue, TryInto};
|
use interpreter::value::{RuntimeValue, TryInto};
|
||||||
use interpreter::variable::{VariableInstance, VariableType};
|
use interpreter::variable::{VariableInstance, VariableType};
|
||||||
|
|
||||||
fn run_function_i32(body: &Opcodes, arg: i32) -> Result<i32, Error> {
|
fn make_function_i32(body: Opcodes) -> (ProgramInstance, Arc<ModuleInstanceInterface>) {
|
||||||
let ftype = FunctionType::new(vec![ValueType::I32], Some(ValueType::I32));
|
let module = module()
|
||||||
let module = ModuleInstance::new(Weak::default(), "test".into(), Module::default()).unwrap();
|
.function()
|
||||||
let externals = HashMap::new();
|
.signature().param().i32().return_type().i32().build()
|
||||||
let mut context = FunctionContext::new(&module, &externals, 1024, 1024, &ftype, vec![
|
.body()
|
||||||
VariableInstance::new(true, VariableType::I32, RuntimeValue::I32(arg)).unwrap(), // arg
|
.with_locals(vec![Local::new(2, ValueType::I32)])
|
||||||
VariableInstance::new(true, VariableType::I32, RuntimeValue::I32(0)).unwrap(), // local1
|
.with_opcodes(body)
|
||||||
VariableInstance::new(true, VariableType::I32, RuntimeValue::I32(0)).unwrap(), // local2
|
.build()
|
||||||
]);
|
.build()
|
||||||
Interpreter::run_function(context, body.elements())
|
.build();
|
||||||
.map(|v| v.unwrap().try_into().unwrap())
|
|
||||||
|
let program = ProgramInstance::new().unwrap();
|
||||||
|
let module = program.add_module("main", module, None).unwrap();
|
||||||
|
(program, module)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_function_i32(module: &Arc<ModuleInstanceInterface>, arg: i32) -> Result<i32, Error> {
|
||||||
|
module
|
||||||
|
.execute_index(0, vec![RuntimeValue::I32(arg)].into())
|
||||||
|
.map(|r| r.unwrap().try_into().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/unreachable.txt
|
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/unreachable.txt
|
||||||
#[test]
|
#[test]
|
||||||
fn unreachable() {
|
fn unreachable() {
|
||||||
let body = Opcodes::new(vec![
|
let (_program, module) = make_function_i32(Opcodes::new(vec![
|
||||||
Opcode::Unreachable, // trap
|
Opcode::Unreachable, // trap
|
||||||
Opcode::End]);
|
Opcode::End]));
|
||||||
|
|
||||||
assert_eq!(run_function_i32(&body, 0).unwrap_err(), Error::Trap("programmatic".into()));
|
assert_eq!(run_function_i32(&module, 0).unwrap_err(), Error::Trap("programmatic".into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn nop() {
|
fn nop() {
|
||||||
let body = Opcodes::new(vec![
|
let (_program, module) = make_function_i32(Opcodes::new(vec![
|
||||||
Opcode::Nop, // nop
|
Opcode::Nop, // nop
|
||||||
Opcode::I32Const(1), // [1]
|
Opcode::I32Const(1), // [1]
|
||||||
Opcode::Nop, // nop
|
Opcode::Nop, // nop
|
||||||
Opcode::End]);
|
Opcode::End]));
|
||||||
|
|
||||||
assert_eq!(run_function_i32(&body, 0).unwrap(), 1);
|
assert_eq!(run_function_i32(&module, 0).unwrap(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/expr-block.txt
|
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/expr-block.txt
|
||||||
#[test]
|
#[test]
|
||||||
fn expr_block() {
|
fn expr_block() {
|
||||||
let body = Opcodes::new(vec![
|
let (_program, module) = make_function_i32(Opcodes::new(vec![
|
||||||
Opcode::Block(BlockType::Value(ValueType::I32), // mark block
|
Opcode::Block(BlockType::Value(ValueType::I32), // mark block
|
||||||
Opcodes::new(vec![
|
Opcodes::new(vec![
|
||||||
Opcode::I32Const(10), // [10]
|
Opcode::I32Const(10), // [10]
|
||||||
@ -56,15 +65,15 @@ fn expr_block() {
|
|||||||
Opcode::I32Const(1), // [1]
|
Opcode::I32Const(1), // [1]
|
||||||
Opcode::End,
|
Opcode::End,
|
||||||
])),
|
])),
|
||||||
Opcode::End]);
|
Opcode::End]));
|
||||||
|
|
||||||
assert_eq!(run_function_i32(&body, 0).unwrap(), 1);
|
assert_eq!(run_function_i32(&module, 0).unwrap(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/loop.txt
|
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/loop.txt
|
||||||
#[test]
|
#[test]
|
||||||
fn loop_test() {
|
fn loop_test() {
|
||||||
let body = Opcodes::new(vec![
|
let (_program, module) = make_function_i32(Opcodes::new(vec![
|
||||||
Opcode::Loop(BlockType::NoResult, // loop
|
Opcode::Loop(BlockType::NoResult, // loop
|
||||||
Opcodes::new(vec![
|
Opcodes::new(vec![
|
||||||
Opcode::GetLocal(1), // [local1]
|
Opcode::GetLocal(1), // [local1]
|
||||||
@ -85,15 +94,15 @@ fn loop_test() {
|
|||||||
])),
|
])),
|
||||||
Opcode::End])), // end loop
|
Opcode::End])), // end loop
|
||||||
Opcode::GetLocal(1), // [local1]
|
Opcode::GetLocal(1), // [local1]
|
||||||
Opcode::End]);
|
Opcode::End]));
|
||||||
|
|
||||||
assert_eq!(run_function_i32(&body, 0).unwrap(), 10);
|
assert_eq!(run_function_i32(&module, 0).unwrap(), 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/if.txt#L3
|
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/if.txt#L3
|
||||||
#[test]
|
#[test]
|
||||||
fn if_1() {
|
fn if_1() {
|
||||||
let body = Opcodes::new(vec![
|
let (_program, module) = make_function_i32(Opcodes::new(vec![
|
||||||
Opcode::I32Const(0), // [0]
|
Opcode::I32Const(0), // [0]
|
||||||
Opcode::SetLocal(0), // [] + arg = 0
|
Opcode::SetLocal(0), // [] + arg = 0
|
||||||
Opcode::I32Const(1), // [1]
|
Opcode::I32Const(1), // [1]
|
||||||
@ -115,15 +124,15 @@ fn if_1() {
|
|||||||
Opcode::End, // end if
|
Opcode::End, // end if
|
||||||
])),
|
])),
|
||||||
Opcode::GetLocal(0), // [arg]
|
Opcode::GetLocal(0), // [arg]
|
||||||
Opcode::End]);
|
Opcode::End]));
|
||||||
|
|
||||||
assert_eq!(run_function_i32(&body, 0).unwrap(), 1);
|
assert_eq!(run_function_i32(&module, 0).unwrap(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/if.txt#L23
|
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/if.txt#L23
|
||||||
#[test]
|
#[test]
|
||||||
fn if_2() {
|
fn if_2() {
|
||||||
let body = Opcodes::new(vec![
|
let (_program, module) = make_function_i32(Opcodes::new(vec![
|
||||||
Opcode::I32Const(1), // [1]
|
Opcode::I32Const(1), // [1]
|
||||||
Opcode::If(BlockType::NoResult, // if 1
|
Opcode::If(BlockType::NoResult, // if 1
|
||||||
Opcodes::new(vec![
|
Opcodes::new(vec![
|
||||||
@ -147,15 +156,15 @@ fn if_2() {
|
|||||||
Opcode::GetLocal(0), // [arg]
|
Opcode::GetLocal(0), // [arg]
|
||||||
Opcode::GetLocal(1), // [arg, local1]
|
Opcode::GetLocal(1), // [arg, local1]
|
||||||
Opcode::I32Add, // [arg + local1]
|
Opcode::I32Add, // [arg + local1]
|
||||||
Opcode::End]);
|
Opcode::End]));
|
||||||
|
|
||||||
assert_eq!(run_function_i32(&body, 0).unwrap(), 9);
|
assert_eq!(run_function_i32(&module, 0).unwrap(), 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/expr-if.txt
|
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/expr-if.txt
|
||||||
#[test]
|
#[test]
|
||||||
fn expr_if() {
|
fn expr_if() {
|
||||||
let body = Opcodes::new(vec![
|
let (_program, module) = make_function_i32(Opcodes::new(vec![
|
||||||
Opcode::GetLocal(0), // [arg]
|
Opcode::GetLocal(0), // [arg]
|
||||||
Opcode::I32Const(0), // [arg, 0]
|
Opcode::I32Const(0), // [arg, 0]
|
||||||
Opcode::I32Eq, // [arg == 0]
|
Opcode::I32Eq, // [arg == 0]
|
||||||
@ -166,16 +175,16 @@ fn expr_if() {
|
|||||||
Opcode::I32Const(2), // [2]
|
Opcode::I32Const(2), // [2]
|
||||||
Opcode::End, // end if
|
Opcode::End, // end if
|
||||||
])),
|
])),
|
||||||
Opcode::End]);
|
Opcode::End]));
|
||||||
|
|
||||||
assert_eq!(run_function_i32(&body, 0).unwrap(), 1);
|
assert_eq!(run_function_i32(&module, 0).unwrap(), 1);
|
||||||
assert_eq!(run_function_i32(&body, 1).unwrap(), 2);
|
assert_eq!(run_function_i32(&module, 1).unwrap(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/nested-if.txt
|
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/nested-if.txt
|
||||||
#[test]
|
#[test]
|
||||||
fn nested_if() {
|
fn nested_if() {
|
||||||
let body = Opcodes::new(vec![
|
let (_program, module) = make_function_i32(Opcodes::new(vec![
|
||||||
Opcode::Block(BlockType::NoResult,
|
Opcode::Block(BlockType::NoResult,
|
||||||
Opcodes::new(vec![
|
Opcodes::new(vec![
|
||||||
Opcode::I32Const(1),
|
Opcode::I32Const(1),
|
||||||
@ -194,15 +203,15 @@ fn nested_if() {
|
|||||||
Opcode::End,
|
Opcode::End,
|
||||||
])),
|
])),
|
||||||
Opcode::I32Const(4),
|
Opcode::I32Const(4),
|
||||||
Opcode::End]);
|
Opcode::End]));
|
||||||
|
|
||||||
assert_eq!(run_function_i32(&body, 0).unwrap(), 4);
|
assert_eq!(run_function_i32(&module, 0).unwrap(), 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/br.txt#L4
|
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/br.txt#L4
|
||||||
#[test]
|
#[test]
|
||||||
fn br_0() {
|
fn br_0() {
|
||||||
let body = Opcodes::new(vec![
|
let (_program, module) = make_function_i32(Opcodes::new(vec![
|
||||||
Opcode::Block(BlockType::NoResult, // mark block
|
Opcode::Block(BlockType::NoResult, // mark block
|
||||||
Opcodes::new(vec![
|
Opcodes::new(vec![
|
||||||
Opcode::I32Const(1), // [1]
|
Opcode::I32Const(1), // [1]
|
||||||
@ -224,15 +233,15 @@ fn br_0() {
|
|||||||
Opcode::I32Const(1), // [arg == 0, local1, 1]
|
Opcode::I32Const(1), // [arg == 0, local1, 1]
|
||||||
Opcode::I32Eq, // [arg == 0, local1 == 1]
|
Opcode::I32Eq, // [arg == 0, local1 == 1]
|
||||||
Opcode::I32Add, // [arg == 0 + local1 == 1]
|
Opcode::I32Add, // [arg == 0 + local1 == 1]
|
||||||
Opcode::End]);
|
Opcode::End]));
|
||||||
|
|
||||||
assert_eq!(run_function_i32(&body, 0).unwrap(), 2);
|
assert_eq!(run_function_i32(&module, 0).unwrap(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/br.txt#L26
|
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/br.txt#L26
|
||||||
#[test]
|
#[test]
|
||||||
fn br_1() {
|
fn br_1() {
|
||||||
let body = Opcodes::new(vec![
|
let (_program, module) = make_function_i32(Opcodes::new(vec![
|
||||||
Opcode::Block(BlockType::NoResult, // block1
|
Opcode::Block(BlockType::NoResult, // block1
|
||||||
Opcodes::new(vec![
|
Opcodes::new(vec![
|
||||||
Opcode::Block(BlockType::NoResult, // block2
|
Opcode::Block(BlockType::NoResult, // block2
|
||||||
@ -264,15 +273,15 @@ fn br_1() {
|
|||||||
Opcode::I32Const(1), // [arg == 0 + local1 == 0, local2, 1]
|
Opcode::I32Const(1), // [arg == 0 + local1 == 0, local2, 1]
|
||||||
Opcode::I32Eq, // [arg == 0 + local1 == 0, local2 == 1]
|
Opcode::I32Eq, // [arg == 0 + local1 == 0, local2 == 1]
|
||||||
Opcode::I32Add, // [arg == 0 + local1 == 0 + local2 == 1]
|
Opcode::I32Add, // [arg == 0 + local1 == 0 + local2 == 1]
|
||||||
Opcode::End]);
|
Opcode::End]));
|
||||||
|
|
||||||
assert_eq!(run_function_i32(&body, 0).unwrap(), 3);
|
assert_eq!(run_function_i32(&module, 0).unwrap(), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/br.txt#L56
|
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/br.txt#L56
|
||||||
#[test]
|
#[test]
|
||||||
fn br_2() {
|
fn br_2() {
|
||||||
let body = Opcodes::new(vec![
|
let (_program, module) = make_function_i32(Opcodes::new(vec![
|
||||||
Opcode::Block(BlockType::NoResult, // block1
|
Opcode::Block(BlockType::NoResult, // block1
|
||||||
Opcodes::new(vec![
|
Opcodes::new(vec![
|
||||||
Opcode::Block(BlockType::NoResult, // block2
|
Opcode::Block(BlockType::NoResult, // block2
|
||||||
@ -291,15 +300,15 @@ fn br_2() {
|
|||||||
])),
|
])),
|
||||||
Opcode::I32Const(2), // [2]
|
Opcode::I32Const(2), // [2]
|
||||||
Opcode::Return, // return 2
|
Opcode::Return, // return 2
|
||||||
Opcode::End]);
|
Opcode::End]));
|
||||||
|
|
||||||
assert_eq!(run_function_i32(&body, 0).unwrap(), 2);
|
assert_eq!(run_function_i32(&module, 0).unwrap(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/br.txt#L71
|
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/br.txt#L71
|
||||||
#[test]
|
#[test]
|
||||||
fn br_3() {
|
fn br_3() {
|
||||||
let body = Opcodes::new(vec![
|
let (_program, module) = make_function_i32(Opcodes::new(vec![
|
||||||
Opcode::Block(BlockType::NoResult, // block1
|
Opcode::Block(BlockType::NoResult, // block1
|
||||||
Opcodes::new(vec![
|
Opcodes::new(vec![
|
||||||
Opcode::Loop(BlockType::NoResult, // loop
|
Opcode::Loop(BlockType::NoResult, // loop
|
||||||
@ -333,15 +342,15 @@ fn br_3() {
|
|||||||
])),
|
])),
|
||||||
Opcode::GetLocal(1), // [local1]
|
Opcode::GetLocal(1), // [local1]
|
||||||
Opcode::Return, // return local1
|
Opcode::Return, // return local1
|
||||||
Opcode::End]);
|
Opcode::End]));
|
||||||
|
|
||||||
assert_eq!(run_function_i32(&body, 0).unwrap(), 3);
|
assert_eq!(run_function_i32(&module, 0).unwrap(), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/expr-br.txt
|
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/expr-br.txt
|
||||||
#[test]
|
#[test]
|
||||||
fn expr_br() {
|
fn expr_br() {
|
||||||
let body = Opcodes::new(vec![
|
let (_program, module) = make_function_i32(Opcodes::new(vec![
|
||||||
Opcode::Block(BlockType::Value(ValueType::I32), // block1
|
Opcode::Block(BlockType::Value(ValueType::I32), // block1
|
||||||
Opcodes::new(vec![
|
Opcodes::new(vec![
|
||||||
Opcode::GetLocal(0), // [arg]
|
Opcode::GetLocal(0), // [arg]
|
||||||
@ -356,16 +365,16 @@ fn expr_br() {
|
|||||||
Opcode::I32Const(2), // [2]
|
Opcode::I32Const(2), // [2]
|
||||||
Opcode::End, // end (block1)
|
Opcode::End, // end (block1)
|
||||||
])),
|
])),
|
||||||
Opcode::End]);
|
Opcode::End]));
|
||||||
|
|
||||||
assert_eq!(run_function_i32(&body, 0).unwrap(), 1);
|
assert_eq!(run_function_i32(&module, 0).unwrap(), 1);
|
||||||
assert_eq!(run_function_i32(&body, 1).unwrap(), 2);
|
assert_eq!(run_function_i32(&module, 1).unwrap(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/brif.txt
|
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/brif.txt
|
||||||
#[test]
|
#[test]
|
||||||
fn brif() {
|
fn brif() {
|
||||||
let body = Opcodes::new(vec![
|
let (_program, module) = make_function_i32(Opcodes::new(vec![
|
||||||
Opcode::Block(BlockType::NoResult, // block1
|
Opcode::Block(BlockType::NoResult, // block1
|
||||||
Opcodes::new(vec![
|
Opcodes::new(vec![
|
||||||
Opcode::GetLocal(0), // [arg]
|
Opcode::GetLocal(0), // [arg]
|
||||||
@ -376,16 +385,16 @@ fn brif() {
|
|||||||
])),
|
])),
|
||||||
Opcode::I32Const(2), // [2]
|
Opcode::I32Const(2), // [2]
|
||||||
Opcode::Return, // return 2
|
Opcode::Return, // return 2
|
||||||
Opcode::End]);
|
Opcode::End]));
|
||||||
|
|
||||||
assert_eq!(run_function_i32(&body, 0).unwrap(), 1);
|
assert_eq!(run_function_i32(&module, 0).unwrap(), 1);
|
||||||
assert_eq!(run_function_i32(&body, 1).unwrap(), 2);
|
assert_eq!(run_function_i32(&module, 1).unwrap(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/brif-loop.txt
|
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/brif-loop.txt
|
||||||
#[test]
|
#[test]
|
||||||
fn brif_loop() {
|
fn brif_loop() {
|
||||||
let body = Opcodes::new(vec![
|
let (_program, module) = make_function_i32(Opcodes::new(vec![
|
||||||
Opcode::Loop(BlockType::NoResult, // loop
|
Opcode::Loop(BlockType::NoResult, // loop
|
||||||
Opcodes::new(vec![
|
Opcodes::new(vec![
|
||||||
Opcode::GetLocal(1), // [local1]
|
Opcode::GetLocal(1), // [local1]
|
||||||
@ -400,16 +409,16 @@ fn brif_loop() {
|
|||||||
])),
|
])),
|
||||||
Opcode::GetLocal(1), // [local1]
|
Opcode::GetLocal(1), // [local1]
|
||||||
Opcode::Return, // return
|
Opcode::Return, // return
|
||||||
Opcode::End]);
|
Opcode::End]));
|
||||||
|
|
||||||
assert_eq!(run_function_i32(&body, 3).unwrap(), 3);
|
assert_eq!(run_function_i32(&module, 3).unwrap(), 3);
|
||||||
assert_eq!(run_function_i32(&body, 10).unwrap(), 10);
|
assert_eq!(run_function_i32(&module, 10).unwrap(), 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/expr-brif.txt
|
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/expr-brif.txt
|
||||||
#[test]
|
#[test]
|
||||||
fn expr_brif() {
|
fn expr_brif() {
|
||||||
let body = Opcodes::new(vec![
|
let (_program, module) = make_function_i32(Opcodes::new(vec![
|
||||||
Opcode::Loop(BlockType::NoResult, // loop
|
Opcode::Loop(BlockType::NoResult, // loop
|
||||||
Opcodes::new(vec![
|
Opcodes::new(vec![
|
||||||
Opcode::GetLocal(1), // [local1]
|
Opcode::GetLocal(1), // [local1]
|
||||||
@ -423,16 +432,16 @@ fn expr_brif() {
|
|||||||
Opcode::End, // end (loop)
|
Opcode::End, // end (loop)
|
||||||
])),
|
])),
|
||||||
Opcode::GetLocal(1), // [local1]
|
Opcode::GetLocal(1), // [local1]
|
||||||
Opcode::End]);
|
Opcode::End]));
|
||||||
|
|
||||||
assert_eq!(run_function_i32(&body, 3).unwrap(), 3);
|
assert_eq!(run_function_i32(&module, 3).unwrap(), 3);
|
||||||
assert_eq!(run_function_i32(&body, 10).unwrap(), 10);
|
assert_eq!(run_function_i32(&module, 10).unwrap(), 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/brtable.txt
|
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/brtable.txt
|
||||||
#[test]
|
#[test]
|
||||||
fn brtable() {
|
fn brtable() {
|
||||||
let body = Opcodes::new(vec![
|
let (_program, module) = make_function_i32(Opcodes::new(vec![
|
||||||
Opcode::Block(BlockType::NoResult, // block3
|
Opcode::Block(BlockType::NoResult, // block3
|
||||||
Opcodes::new(vec![
|
Opcodes::new(vec![
|
||||||
Opcode::Block(BlockType::NoResult, // block2
|
Opcode::Block(BlockType::NoResult, // block2
|
||||||
@ -457,18 +466,18 @@ fn brtable() {
|
|||||||
])),
|
])),
|
||||||
Opcode::I32Const(2), // [2]
|
Opcode::I32Const(2), // [2]
|
||||||
Opcode::Return, // return 2
|
Opcode::Return, // return 2
|
||||||
Opcode::End]);
|
Opcode::End]));
|
||||||
|
|
||||||
assert_eq!(run_function_i32(&body, 0).unwrap(), 0);
|
assert_eq!(run_function_i32(&module, 0).unwrap(), 0);
|
||||||
assert_eq!(run_function_i32(&body, 1).unwrap(), 1);
|
assert_eq!(run_function_i32(&module, 1).unwrap(), 1);
|
||||||
assert_eq!(run_function_i32(&body, 2).unwrap(), 2);
|
assert_eq!(run_function_i32(&module, 2).unwrap(), 2);
|
||||||
assert_eq!(run_function_i32(&body, 3).unwrap(), 2);
|
assert_eq!(run_function_i32(&module, 3).unwrap(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/return.txt
|
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/return.txt
|
||||||
#[test]
|
#[test]
|
||||||
fn return_test() {
|
fn return_test() {
|
||||||
let body = Opcodes::new(vec![
|
let (_program, module) = make_function_i32(Opcodes::new(vec![
|
||||||
Opcode::GetLocal(0),
|
Opcode::GetLocal(0),
|
||||||
Opcode::I32Const(0),
|
Opcode::I32Const(0),
|
||||||
Opcode::I32Eq,
|
Opcode::I32Eq,
|
||||||
@ -489,11 +498,11 @@ fn return_test() {
|
|||||||
])),
|
])),
|
||||||
Opcode::I32Const(3),
|
Opcode::I32Const(3),
|
||||||
Opcode::Return,
|
Opcode::Return,
|
||||||
Opcode::End]);
|
Opcode::End]));
|
||||||
|
|
||||||
assert_eq!(run_function_i32(&body, 0).unwrap(), 1);
|
assert_eq!(run_function_i32(&module, 0).unwrap(), 1);
|
||||||
assert_eq!(run_function_i32(&body, 1).unwrap(), 2);
|
assert_eq!(run_function_i32(&module, 1).unwrap(), 2);
|
||||||
assert_eq!(run_function_i32(&body, 5).unwrap(), 3);
|
assert_eq!(run_function_i32(&module, 5).unwrap(), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/return-void.txt
|
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/return-void.txt
|
||||||
|
Reference in New Issue
Block a user