mirror of
https://github.com/fluencelabs/parity-wasm
synced 2025-06-20 18:26:54 +00:00
call && call_indirect are working
This commit is contained in:
@ -23,8 +23,8 @@ run_test!("br_if", wasm_br_if);
|
|||||||
run_test!("br_table", wasm_br_table);
|
run_test!("br_table", wasm_br_table);
|
||||||
run_test!("br", wasm_br);
|
run_test!("br", wasm_br);
|
||||||
run_test!("break-drop", wasm_break_drop);
|
run_test!("break-drop", wasm_break_drop);
|
||||||
// TODO: run_test!("call_indirect", wasm_call_indirect);
|
run_test!("call_indirect", wasm_call_indirect);
|
||||||
// TODO: run_test!("call", wasm_call);
|
run_test!("call", wasm_call);
|
||||||
run_test!("comments", wasm_comments);
|
run_test!("comments", wasm_comments);
|
||||||
// TODO: run_test!("conversions", wasm_conversions);
|
// TODO: run_test!("conversions", wasm_conversions);
|
||||||
// TODO: run_test!("custom_section", wasm_custom_section);
|
// TODO: run_test!("custom_section", wasm_custom_section);
|
||||||
|
@ -112,6 +112,10 @@ impl ModuleInstanceInterface for EnvModuleInstance {
|
|||||||
self.instance.function_type(function_index, externals)
|
self.instance.function_type(function_index, externals)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn function_type_by_index<'a>(&self, type_index: u32) -> Result<FunctionType, Error> {
|
||||||
|
self.instance.function_type_by_index(type_index)
|
||||||
|
}
|
||||||
|
|
||||||
fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance>, Error> {
|
fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance>, Error> {
|
||||||
self.instance.table(index)
|
self.instance.table(index)
|
||||||
}
|
}
|
||||||
@ -132,8 +136,9 @@ impl ModuleInstanceInterface for EnvModuleInstance {
|
|||||||
self.instance.function_reference_indirect(table_idx, type_idx, func_idx, externals)
|
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> {
|
fn function_body<'a>(&'a self, internal_index: u32, function_type: Option<&FunctionType>) -> Result<Option<InternalFunction<'a>>, Error> {
|
||||||
self.instance.function_body(internal_index)
|
Ok(None)
|
||||||
|
//self.instance.function_body(internal_index, function_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*fn call_function(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result<Option<RuntimeValue>, Error> {
|
/*fn call_function(&self, outer: CallerContext, index: ItemIndex, function_type: Option<&FunctionType>) -> Result<Option<RuntimeValue>, Error> {
|
||||||
|
@ -90,7 +90,7 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> {
|
|||||||
ItemIndex::IndexSpace(index) | ItemIndex::Internal(index) => index,
|
ItemIndex::IndexSpace(index) | ItemIndex::Internal(index) => index,
|
||||||
ItemIndex::External(_) => unreachable!("trying to call function, exported by native env module"),
|
ItemIndex::External(_) => unreachable!("trying to call function, exported by native env module"),
|
||||||
};
|
};
|
||||||
|
println!("=== env_native.function_type({})", index);
|
||||||
if index < NATIVE_INDEX_FUNC_MIN {
|
if index < NATIVE_INDEX_FUNC_MIN {
|
||||||
return self.env.function_type(function_index, externals);
|
return self.env.function_type(function_index, externals);
|
||||||
}
|
}
|
||||||
@ -101,6 +101,10 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> {
|
|||||||
.map(|f| FunctionType::new(f.params.clone(), f.result.clone()))
|
.map(|f| FunctionType::new(f.params.clone(), f.result.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn function_type_by_index<'b>(&self, type_index: u32) -> Result<FunctionType, Error> {
|
||||||
|
self.function_type(ItemIndex::Internal(type_index), None)
|
||||||
|
}
|
||||||
|
|
||||||
fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance>, Error> {
|
fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance>, Error> {
|
||||||
self.env.table(index)
|
self.env.table(index)
|
||||||
}
|
}
|
||||||
@ -121,15 +125,16 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> {
|
|||||||
self.env.function_reference_indirect(table_idx, type_idx, func_idx, externals)
|
self.env.function_reference_indirect(table_idx, type_idx, func_idx, externals)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn function_body<'b>(&'b self, internal_index: u32) -> Result<Option<InternalFunction<'b>>, Error> {
|
fn function_body<'b>(&'b self, internal_index: u32, function_type: Option<&FunctionType>) -> Result<Option<InternalFunction<'b>>, Error> {
|
||||||
self.env.function_body(internal_index)
|
Ok(None)
|
||||||
|
//self.env.function_body(internal_index, function_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_internal_function(&self, outer: CallerContext, index: u32, function_type: Option<&FunctionType>) -> Result<Option<RuntimeValue>, Error> {
|
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);
|
||||||
}
|
}
|
||||||
|
println!("=== env_native.args({:?})", outer.value_stack);
|
||||||
// TODO: check type
|
// TODO: check type
|
||||||
self.functions
|
self.functions
|
||||||
.get((index - NATIVE_INDEX_FUNC_MIN) as usize)
|
.get((index - NATIVE_INDEX_FUNC_MIN) as usize)
|
||||||
|
@ -7,7 +7,7 @@ use interpreter::Error;
|
|||||||
use interpreter::imports::ModuleImports;
|
use interpreter::imports::ModuleImports;
|
||||||
use interpreter::memory::MemoryInstance;
|
use interpreter::memory::MemoryInstance;
|
||||||
use interpreter::program::ProgramInstanceEssence;
|
use interpreter::program::ProgramInstanceEssence;
|
||||||
use interpreter::runner::{Interpreter, FunctionContext};
|
use interpreter::runner::{Interpreter, FunctionContext, prepare_function_args};
|
||||||
use interpreter::stack::StackWithLimit;
|
use interpreter::stack::StackWithLimit;
|
||||||
use interpreter::table::TableInstance;
|
use interpreter::table::TableInstance;
|
||||||
use interpreter::validator::{Validator, FunctionValidationContext};
|
use interpreter::validator::{Validator, FunctionValidationContext};
|
||||||
@ -49,8 +49,10 @@ pub trait ModuleInstanceInterface {
|
|||||||
fn execute_export(&self, name: &str, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error>;
|
fn execute_export(&self, name: &str, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error>;
|
||||||
/// Get export entry.
|
/// Get export entry.
|
||||||
fn export_entry<'a>(&self, name: &str, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>, required_type: &ExportEntryType) -> Result<Internal, Error>;
|
fn export_entry<'a>(&self, name: &str, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>, required_type: &ExportEntryType) -> Result<Internal, Error>;
|
||||||
/// Get function type.
|
/// Get function type for given function index.
|
||||||
fn function_type<'a>(&self, function_index: ItemIndex, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<FunctionType, Error>;
|
fn function_type<'a>(&self, function_index: ItemIndex, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<FunctionType, Error>;
|
||||||
|
/// Get function type for given function index.
|
||||||
|
fn function_type_by_index<'a>(&self, type_index: u32) -> Result<FunctionType, Error>;
|
||||||
/// Get table reference.
|
/// Get table reference.
|
||||||
fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance>, Error>;
|
fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance>, Error>;
|
||||||
/// Get memory reference.
|
/// Get memory reference.
|
||||||
@ -62,7 +64,7 @@ pub trait ModuleInstanceInterface {
|
|||||||
/// Get function indirect reference.
|
/// 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>;
|
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.
|
/// Get internal function for interpretation.
|
||||||
fn function_body<'a>(&'a self, internal_index: u32) -> Result<Option<InternalFunction<'a>>, Error>;
|
fn function_body<'a>(&'a self, internal_index: u32, function_type: Option<&FunctionType>) -> 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<Option<RuntimeValue>, 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.
|
||||||
@ -117,8 +119,6 @@ pub struct InternalFunctionReference<'a> {
|
|||||||
pub module: Arc<ModuleInstanceInterface + 'a>,
|
pub module: Arc<ModuleInstanceInterface + 'a>,
|
||||||
/// Internal function index.
|
/// Internal function index.
|
||||||
pub internal_index: u32,
|
pub internal_index: u32,
|
||||||
// Internal function type.
|
|
||||||
//pub function_type: &'a FunctionType,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> fmt::Debug for InternalFunctionReference<'a> {
|
impl<'a> fmt::Debug for InternalFunctionReference<'a> {
|
||||||
@ -233,15 +233,6 @@ impl ModuleInstance {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn require_function_type(&self, type_index: u32) -> Result<&FunctionType, Error> {
|
|
||||||
self.module.type_section()
|
|
||||||
.ok_or(Error::Validation(format!("type reference {} exists in module without type section", type_index)))
|
|
||||||
.and_then(|s| match s.types().get(type_index as usize) {
|
|
||||||
Some(&Type::Function(ref function_type)) => Ok(function_type),
|
|
||||||
_ => Err(Error::Validation(format!("missing function type with index {}", type_index))),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleInstanceInterface for ModuleInstance {
|
impl ModuleInstanceInterface for ModuleInstance {
|
||||||
@ -250,7 +241,7 @@ impl ModuleInstanceInterface for ModuleInstance {
|
|||||||
if let Some(start_function) = self.module.start_section() {
|
if let Some(start_function) = self.module.start_section() {
|
||||||
let func_type_index = self.require_function(ItemIndex::IndexSpace(start_function))?;
|
let func_type_index = self.require_function(ItemIndex::IndexSpace(start_function))?;
|
||||||
if is_user_module { // tests use non-empty main functions
|
if is_user_module { // tests use non-empty main functions
|
||||||
let func_type = self.require_function_type(func_type_index)?;
|
let func_type = self.function_type_by_index(func_type_index)?;
|
||||||
if func_type.return_type() != None || func_type.params().len() != 0 {
|
if func_type.return_type() != None || func_type.params().len() != 0 {
|
||||||
return Err(Error::Validation("start function expected to have type [] -> []".into()));
|
return Err(Error::Validation("start function expected to have type [] -> []".into()));
|
||||||
}
|
}
|
||||||
@ -287,7 +278,7 @@ impl ModuleInstanceInterface for ModuleInstance {
|
|||||||
// for functions we need to check if function type matches in both modules
|
// for functions we need to check if function type matches in both modules
|
||||||
&External::Function(ref function_type_index) => {
|
&External::Function(ref function_type_index) => {
|
||||||
// External::Function points to function type in type section in this module
|
// External::Function points to function type in type section in this module
|
||||||
let import_function_type = self.require_function_type(*function_type_index)?;
|
let import_function_type = self.function_type_by_index(*function_type_index)?;
|
||||||
|
|
||||||
// get export entry in external module
|
// get export entry in external module
|
||||||
let external_module = self.imports.module(externals, import.module())?;
|
let external_module = self.imports.module(externals, import.module())?;
|
||||||
@ -300,7 +291,7 @@ impl ModuleInstanceInterface for ModuleInstance {
|
|||||||
_ => return Err(Error::Validation(format!("Export with name {} from module {} is not a function", import.field(), import.module()))),
|
_ => return Err(Error::Validation(format!("Export with name {} from module {} is not a function", import.field(), import.module()))),
|
||||||
};
|
};
|
||||||
|
|
||||||
if import_function_type != &export_function_type {
|
if import_function_type != export_function_type {
|
||||||
return Err(Error::Validation(format!("Export function type {} mismatch. Expected function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}",
|
return Err(Error::Validation(format!("Export function type {} mismatch. Expected function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}",
|
||||||
function_type_index, import_function_type.params(), import_function_type.return_type(),
|
function_type_index, import_function_type.params(), import_function_type.return_type(),
|
||||||
export_function_type.params(), export_function_type.return_type())));
|
export_function_type.params(), export_function_type.return_type())));
|
||||||
@ -346,7 +337,7 @@ impl ModuleInstanceInterface for ModuleInstance {
|
|||||||
let code_section = self.module.code_section().expect("function_section_len != 0; function_section_len == code_section_len; qed");
|
let code_section = self.module.code_section().expect("function_section_len != 0; function_section_len == code_section_len; qed");
|
||||||
// check every function body
|
// check every function body
|
||||||
for (index, function) in function_section.entries().iter().enumerate() {
|
for (index, function) in function_section.entries().iter().enumerate() {
|
||||||
let function_type = self.require_function_type(function.type_ref())?;
|
let function_type = self.function_type_by_index(function.type_ref())?;
|
||||||
let function_body = code_section.bodies().get(index as usize).ok_or(Error::Validation(format!("Missing body for function {}", index)))?;
|
let function_body = code_section.bodies().get(index as usize).ok_or(Error::Validation(format!("Missing body for function {}", index)))?;
|
||||||
let mut locals = function_type.params().to_vec();
|
let mut locals = function_type.params().to_vec();
|
||||||
locals.extend(function_body.locals().iter().flat_map(|l| repeat(l.value_type()).take(l.count() as usize)));
|
locals.extend(function_body.locals().iter().flat_map(|l| repeat(l.value_type()).take(l.count() as usize)));
|
||||||
@ -439,19 +430,37 @@ impl ModuleInstanceInterface for ModuleInstance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn function_type<'a>(&self, function_index: ItemIndex, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<FunctionType, Error> {
|
fn function_type<'a>(&self, function_index: ItemIndex, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<FunctionType, Error> {
|
||||||
|
println!("=== getting function_type({}, {:?})", self.name, function_index);
|
||||||
match self.imports.parse_function_index(function_index) {
|
match self.imports.parse_function_index(function_index) {
|
||||||
ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"),
|
ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"),
|
||||||
ItemIndex::Internal(index) => self.require_function(ItemIndex::Internal(index))
|
ItemIndex::Internal(index) => self.require_function(ItemIndex::Internal(index))
|
||||||
.and_then(|ft| self.require_function_type(ft).map(Clone::clone)),
|
.and_then(|ft| self.function_type_by_index(ft)),
|
||||||
ItemIndex::External(index) => self.module.import_section()
|
ItemIndex::External(index) => self.module.import_section()
|
||||||
.ok_or(Error::Function(format!("trying to access external function with index {} in module without import section", index)))
|
.ok_or(Error::Function(format!("trying to access external function with index {} in module without import section", index)))
|
||||||
.and_then(|s| s.entries().get(index as usize)
|
.and_then(|s| s.entries().get(index as usize)
|
||||||
.ok_or(Error::Function(format!("trying to access external function with index {} in module with {}-entries import section", index, s.entries().len()))))
|
.ok_or(Error::Function(format!("trying to access external function with index {} in module with {}-entries import section", index, s.entries().len()))))
|
||||||
.and_then(|e| self.imports.module(externals, e.module()))
|
.and_then(|e| {
|
||||||
.and_then(|m| m.function_type(ItemIndex::IndexSpace(index), externals)),
|
let module = self.imports.module(externals, e.module())?;
|
||||||
|
let function_type = match e.external() {
|
||||||
|
&External::Function(type_index) => self.function_type_by_index(type_index)?,
|
||||||
|
_ => return Err(Error::Function(format!("exported function {} is not a function", index))),
|
||||||
|
};
|
||||||
|
let external_function_index = self.imports.function(externals, e, Some(&function_type))?;
|
||||||
|
module.function_type(ItemIndex::IndexSpace(external_function_index), externals)
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn function_type_by_index<'a>(&self, type_index: u32) -> Result<FunctionType, Error> {
|
||||||
|
self.module.type_section()
|
||||||
|
.ok_or(Error::Validation(format!("type reference {} exists in module without type section", type_index)))
|
||||||
|
.and_then(|s| match s.types().get(type_index as usize) {
|
||||||
|
Some(&Type::Function(ref function_type)) => Ok(function_type),
|
||||||
|
_ => Err(Error::Validation(format!("missing function type with index {}", type_index))),
|
||||||
|
})
|
||||||
|
.map(Clone::clone)
|
||||||
|
}
|
||||||
|
|
||||||
fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance>, Error> {
|
fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance>, Error> {
|
||||||
match self.imports.parse_table_index(index) {
|
match self.imports.parse_table_index(index) {
|
||||||
ItemIndex::IndexSpace(_) => unreachable!("parse_table_index resolves IndexSpace option"),
|
ItemIndex::IndexSpace(_) => unreachable!("parse_table_index resolves IndexSpace option"),
|
||||||
@ -501,9 +510,11 @@ impl ModuleInstanceInterface for ModuleInstance {
|
|||||||
ItemIndex::External(index) => {
|
ItemIndex::External(index) => {
|
||||||
let import_section = self.module.import_section().unwrap();
|
let import_section = self.module.import_section().unwrap();
|
||||||
let import_entry = import_section.entries().get(index as usize).unwrap();
|
let import_entry = import_section.entries().get(index as usize).unwrap();
|
||||||
|
let required_function_type = self.function_type(ItemIndex::External(index), externals)?;
|
||||||
|
let internal_function_index = self.imports.function(externals, import_entry, Some(&required_function_type))?;
|
||||||
Ok(InternalFunctionReference {
|
Ok(InternalFunctionReference {
|
||||||
module: self.imports.module(externals, import_entry.module())?,
|
module: self.imports.module(externals, import_entry.module())?,
|
||||||
internal_index: index
|
internal_index: internal_function_index,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -527,7 +538,7 @@ impl ModuleInstanceInterface for ModuleInstance {
|
|||||||
module.function_reference(ItemIndex::IndexSpace(index), externals)
|
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> {
|
fn function_body<'a>(&'a self, internal_index: u32, function_type: Option<&FunctionType>) -> Result<Option<InternalFunction<'a>>, Error> {
|
||||||
// internal index = index of function in functions section && index of code in code section
|
// internal index = index of function in functions section && index of code in code section
|
||||||
// get function type index
|
// get function type index
|
||||||
let function_type_index = self.module
|
let function_type_index = self.module
|
||||||
@ -637,30 +648,21 @@ impl ModuleInstanceInterface for ModuleInstance {
|
|||||||
}*/
|
}*/
|
||||||
|
|
||||||
fn call_internal_function(&self, mut outer: CallerContext, index: u32, required_function_type: Option<&FunctionType>) -> Result<Option<RuntimeValue>, Error> {
|
fn call_internal_function(&self, mut outer: CallerContext, index: u32, required_function_type: Option<&FunctionType>) -> Result<Option<RuntimeValue>, Error> {
|
||||||
|
println!("=== call_internal_function({})", index);
|
||||||
let function_type_index = self.require_function(ItemIndex::Internal(index))?;
|
let function_type_index = self.require_function(ItemIndex::Internal(index))?;
|
||||||
let function_type = self.require_function_type(function_type_index)?;
|
let function_type = self.function_type_by_index(function_type_index)?;
|
||||||
let function_body = self.function_body(index)?;
|
let function_body = self.function_body(index, required_function_type)?;
|
||||||
|
|
||||||
if let Some(ref required_function_type) = required_function_type {
|
if let Some(ref required_function_type) = required_function_type {
|
||||||
if required_function_type != &function_type {
|
if **required_function_type != 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 ({:?}) -> {:?}",
|
||||||
required_function_type.params(), required_function_type.return_type(), function_type.params(), function_type.return_type())));
|
required_function_type.params(), required_function_type.return_type(), function_type.params(), function_type.return_type())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let args = function_type.params().iter()
|
let mut args = prepare_function_args(&function_type, outer.value_stack)?;
|
||||||
.map(|param_type| {
|
println!("=== call_internal_Function.function_type: {:?}", function_type);
|
||||||
let param_value = outer.value_stack.pop()?;
|
println!("=== call_internal_Function.args: {:?}", args);
|
||||||
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<_>, _>>()?;
|
|
||||||
|
|
||||||
let function_ref = InternalFunctionReference { module: self.self_ref(Some(outer.externals))?, internal_index: index };
|
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);
|
let inner = FunctionContext::new(function_ref, outer.externals, outer.value_stack_limit, outer.frame_stack_limit, &function_type, args);
|
||||||
Interpreter::run_function(inner)
|
Interpreter::run_function(inner)
|
||||||
@ -699,7 +701,7 @@ pub fn check_limits(limits: &ResizableLimits) -> Result<(), Error> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_function_locals(function_type: &FunctionType, function_body: &FuncBody, outer: &mut CallerContext) -> Result<Vec<VariableInstance>, Error> {
|
/*fn prepare_function_locals(function_type: &FunctionType, function_body: &FuncBody, outer: &mut CallerContext) -> Result<Vec<VariableInstance>, Error> {
|
||||||
// locals = function arguments + defined locals
|
// locals = function arguments + defined locals
|
||||||
function_type.params().iter().rev()
|
function_type.params().iter().rev()
|
||||||
.map(|param_type| {
|
.map(|param_type| {
|
||||||
@ -718,7 +720,7 @@ fn prepare_function_locals(function_type: &FunctionType, function_body: &FuncBod
|
|||||||
.flat_map(|l| repeat(l.value_type().into()).take(l.count() as usize))
|
.flat_map(|l| repeat(l.value_type().into()).take(l.count() as usize))
|
||||||
.map(|vt| VariableInstance::new(true, vt, RuntimeValue::default(vt))))
|
.map(|vt| VariableInstance::new(true, vt, RuntimeValue::default(vt))))
|
||||||
.collect::<Result<Vec<_>, _>>()
|
.collect::<Result<Vec<_>, _>>()
|
||||||
}
|
}*/
|
||||||
|
|
||||||
fn get_initializer(expr: &InitExpr, module: &Module, imports: &ModuleImports, expected_type: VariableType) -> Result<RuntimeValue, Error> {
|
fn get_initializer(expr: &InitExpr, module: &Module, imports: &ModuleImports, expected_type: VariableType) -> Result<RuntimeValue, Error> {
|
||||||
let first_opcode = match expr.code().len() {
|
let first_opcode = match expr.code().len() {
|
||||||
|
@ -34,19 +34,29 @@ impl ProgramInstance {
|
|||||||
/// Instantiate module with validation.
|
/// Instantiate module with validation.
|
||||||
pub fn add_module<'a>(&self, name: &str, module: Module, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<Arc<ModuleInstance>, Error> {
|
pub fn add_module<'a>(&self, name: &str, module: Module, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<Arc<ModuleInstance>, Error> {
|
||||||
let module_instance = Arc::new(ModuleInstance::new(Arc::downgrade(&self.essence), name.into(), module)?);
|
let module_instance = Arc::new(ModuleInstance::new(Arc::downgrade(&self.essence), name.into(), module)?);
|
||||||
module_instance.instantiate(true, externals)?;
|
|
||||||
// replace existing module with the same name with new one
|
|
||||||
self.essence.modules.write().insert(name.into(), module_instance.clone());
|
self.essence.modules.write().insert(name.into(), module_instance.clone());
|
||||||
Ok(module_instance)
|
// replace existing module with the same name with new one
|
||||||
|
match module_instance.instantiate(true, externals) {
|
||||||
|
Ok(()) => Ok(module_instance),
|
||||||
|
Err(err) => {
|
||||||
|
self.essence.modules.write().remove(name.into());
|
||||||
|
Err(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Instantiate module without validation.
|
/// Instantiate module without validation.
|
||||||
pub fn add_module_without_validation<'a>(&self, name: &str, module: Module, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<Arc<ModuleInstance>, Error> {
|
pub fn add_module_without_validation<'a>(&self, name: &str, module: Module, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<Arc<ModuleInstance>, Error> {
|
||||||
let module_instance = Arc::new(ModuleInstance::new(Arc::downgrade(&self.essence), name.into(), module)?);
|
let module_instance = Arc::new(ModuleInstance::new(Arc::downgrade(&self.essence), name.into(), module)?);
|
||||||
module_instance.instantiate(false, externals)?;
|
|
||||||
// replace existing module with the same name with new one
|
|
||||||
self.essence.modules.write().insert(name.into(), module_instance.clone());
|
self.essence.modules.write().insert(name.into(), module_instance.clone());
|
||||||
Ok(module_instance)
|
// replace existing module with the same name with new one
|
||||||
|
match module_instance.instantiate(false, externals) {
|
||||||
|
Ok(()) => Ok(module_instance),
|
||||||
|
Err(err) => {
|
||||||
|
self.essence.modules.write().remove(name.into());
|
||||||
|
Err(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert instantiated module.
|
/// Insert instantiated module.
|
||||||
|
@ -38,7 +38,7 @@ 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<'a>>,
|
pub frame_stack: StackWithLimit<BlockFrame>,
|
||||||
/// Current instruction position.
|
/// Current instruction position.
|
||||||
pub position: usize,
|
pub position: usize,
|
||||||
}
|
}
|
||||||
@ -53,7 +53,7 @@ pub enum InstructionOutcome<'a> {
|
|||||||
/// Branch to given frame.
|
/// Branch to given frame.
|
||||||
Branch(usize),
|
Branch(usize),
|
||||||
/// Execute block.
|
/// Execute block.
|
||||||
ExecuteBlock(bool),
|
ExecuteBlock,
|
||||||
/// Execute function call.
|
/// Execute function call.
|
||||||
ExecuteCall(InternalFunctionReference<'a>),
|
ExecuteCall(InternalFunctionReference<'a>),
|
||||||
/// End current frame.
|
/// End current frame.
|
||||||
@ -64,21 +64,29 @@ pub enum InstructionOutcome<'a> {
|
|||||||
|
|
||||||
/// Control stack frame.
|
/// Control stack frame.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct BlockFrame<'a> {
|
pub struct BlockFrame {
|
||||||
/// Is loop frame?
|
/// Frame type.
|
||||||
is_loop: bool,
|
frame_type: BlockFrameType,
|
||||||
|
/// A label for reference to block instruction.
|
||||||
|
begin_position: usize,
|
||||||
/// 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,
|
||||||
/// 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.
|
/// 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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub enum BlockFrameType {
|
||||||
|
Block,
|
||||||
|
Loop,
|
||||||
|
IfTrue,
|
||||||
|
IfElse,
|
||||||
|
}
|
||||||
|
|
||||||
enum RunResult<'a> {
|
enum RunResult<'a> {
|
||||||
Return(Option<RuntimeValue>),
|
Return(Option<RuntimeValue>),
|
||||||
NestedCall(FunctionContext<'a>),
|
NestedCall(FunctionContext<'a>),
|
||||||
@ -92,17 +100,25 @@ impl Interpreter {
|
|||||||
loop {
|
loop {
|
||||||
let mut function_context = function_stack.pop_back().expect("on loop entry - not empty; on loop continue - checking for emptiness; qed");
|
let mut function_context = function_stack.pop_back().expect("on loop entry - not empty; on loop continue - checking for emptiness; qed");
|
||||||
let function_ref = function_context.function.clone();
|
let function_ref = function_context.function.clone();
|
||||||
let function_body = function_ref.module.function_body(function_ref.internal_index)?;
|
let function_body = function_ref.module.function_body(function_ref.internal_index, None)?;
|
||||||
|
|
||||||
let function_return = match function_body {
|
let function_return = match function_body {
|
||||||
Some(function_body) => {
|
Some(function_body) => {
|
||||||
if !function_context.is_initialized() {
|
if !function_context.is_initialized() {
|
||||||
|
let return_type = function_context.return_type;
|
||||||
function_context.initialize(function_body.locals)?;
|
function_context.initialize(function_body.locals)?;
|
||||||
|
function_context.push_frame(BlockFrameType::Block, 0, function_body.body.len() - 1, function_body.body.len() - 1, return_type)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Interpreter::do_run_function(&mut function_context, function_body.body)?
|
Interpreter::do_run_function(&mut function_context, function_body.body)?
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
|
// move locals back to the stack
|
||||||
|
let locals_to_move: Vec<_> = function_context.locals.drain(..).rev().collect();
|
||||||
|
for local in locals_to_move {
|
||||||
|
function_context.value_stack_mut().push(local.get())?;
|
||||||
|
}
|
||||||
|
|
||||||
let nested_context = CallerContext::nested(&mut function_context);
|
let nested_context = CallerContext::nested(&mut function_context);
|
||||||
RunResult::Return(function_ref.module.call_internal_function(nested_context, function_ref.internal_index, None)?)
|
RunResult::Return(function_ref.module.call_internal_function(nested_context, function_ref.internal_index, None)?)
|
||||||
},
|
},
|
||||||
@ -126,20 +142,32 @@ impl Interpreter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn do_run_function<'a>(function_context: &mut FunctionContext<'a>, function_body: &[Opcode]) -> Result<RunResult<'a>, Error> {
|
fn do_run_function<'a>(function_context: &mut FunctionContext<'a>, function_body: &[Opcode]) -> Result<RunResult<'a>, Error> {
|
||||||
loop {
|
// TODO: slow!!! remove this after 'plaining' function instructions
|
||||||
let block_frame = function_context.frame_stack_mut().pop();
|
let mut body_stack = VecDeque::with_capacity(function_context.frame_stack().values().len());
|
||||||
let block_result = Interpreter::run_block_instructions(function_context, block_frame.body)?;
|
body_stack.push_back(function_body);
|
||||||
|
for frame in function_context.frame_stack().values().iter().skip(1) {
|
||||||
|
let instruction = &body_stack.back().unwrap()[frame.begin_position];
|
||||||
|
let instruction_body = Interpreter::into_block(instruction, frame.frame_type)?;
|
||||||
|
body_stack.push_back(instruction_body);
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
//let block_frame = function_context.frame_stack_mut().pop().expect("TODO");
|
||||||
|
//let block_body = body_stack.back().expect("TODO");
|
||||||
|
let block_result = Interpreter::run_block_instructions(function_context, body_stack.back().expect("TODO"))?;
|
||||||
|
println!("=== block_result = {:?}", block_result);
|
||||||
match block_result {
|
match block_result {
|
||||||
InstructionOutcome::RunInstruction | InstructionOutcome::RunNextInstruction => unreachable!("managed by run_block_instructions"),
|
InstructionOutcome::RunInstruction | InstructionOutcome::RunNextInstruction => unreachable!("managed by run_block_instructions"),
|
||||||
InstructionOutcome::Branch(mut index) => {
|
InstructionOutcome::Branch(mut index) => {
|
||||||
// discard index - 2 blocks (-1 since last block is popped && -1 since we have already popped current block)
|
// discard index - 1 blocks
|
||||||
while index >= 2 {
|
while index >= 1 {
|
||||||
function_context.discard_frame()?;
|
function_context.discard_frame()?;
|
||||||
|
assert!(body_stack.pop_back().is_some());
|
||||||
index -= 1;
|
index -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function_context.pop_frame(true)?;
|
function_context.pop_frame(true)?;
|
||||||
|
assert!(body_stack.pop_back().is_some());
|
||||||
if function_context.frame_stack().is_empty() {
|
if function_context.frame_stack().is_empty() {
|
||||||
return Ok(RunResult::Return(match function_context.return_type {
|
return Ok(RunResult::Return(match function_context.return_type {
|
||||||
BlockType::Value(_) => Some(function_context.value_stack_mut().pop()?),
|
BlockType::Value(_) => Some(function_context.value_stack_mut().pop()?),
|
||||||
@ -147,12 +175,20 @@ impl Interpreter {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
InstructionOutcome::ExecuteBlock(branch) => {
|
InstructionOutcome::ExecuteBlock => {
|
||||||
function_context.frame_stack_mut().push_penultimate(block_frame)?;
|
function_context.position = 0;
|
||||||
|
let top_frame = function_context.frame_stack().top().expect("TODO");
|
||||||
|
let instruction = &body_stack.back().expect("TODO")[top_frame.begin_position];
|
||||||
|
let block_body = Interpreter::into_block(instruction, top_frame.frame_type)?;
|
||||||
|
body_stack.push_back(block_body);
|
||||||
|
//body_stack.insert(block_body.len() - 1, block_body);
|
||||||
|
//function_context.frame_stack_mut().push_penultimate(block_frame)?;
|
||||||
},
|
},
|
||||||
InstructionOutcome::ExecuteCall(func_ref) => return Ok(RunResult::NestedCall(function_context.nested(func_ref)?)),
|
InstructionOutcome::ExecuteCall(func_ref) => return Ok(RunResult::NestedCall(function_context.nested(func_ref)?)),
|
||||||
InstructionOutcome::End => (),
|
InstructionOutcome::End if !function_context.frame_stack().is_empty() => {
|
||||||
InstructionOutcome::Return => return Ok(RunResult::Return(match function_context.return_type {
|
assert!(body_stack.pop_back().is_some());
|
||||||
|
},
|
||||||
|
InstructionOutcome::End | InstructionOutcome::Return => return Ok(RunResult::Return(match function_context.return_type {
|
||||||
BlockType::Value(_) => Some(function_context.value_stack_mut().pop()?),
|
BlockType::Value(_) => Some(function_context.value_stack_mut().pop()?),
|
||||||
BlockType::NoResult => None,
|
BlockType::NoResult => None,
|
||||||
})),
|
})),
|
||||||
@ -160,7 +196,7 @@ impl Interpreter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_block_instructions<'a, 'b>(context: &'b mut FunctionContext<'a>, body: &'a [Opcode]) -> Result<InstructionOutcome<'a>, Error> {
|
fn run_block_instructions<'a, 'b>(context: &'b mut FunctionContext<'a>, body: &[Opcode]) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
loop {
|
loop {
|
||||||
let instruction = &body[context.position];
|
let instruction = &body[context.position];
|
||||||
|
|
||||||
@ -168,7 +204,7 @@ impl Interpreter {
|
|||||||
InstructionOutcome::RunInstruction => (),
|
InstructionOutcome::RunInstruction => (),
|
||||||
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 => return Ok(InstructionOutcome::ExecuteBlock),
|
||||||
InstructionOutcome::ExecuteCall(func_ref) => {
|
InstructionOutcome::ExecuteCall(func_ref) => {
|
||||||
context.position += 1;
|
context.position += 1;
|
||||||
return Ok(InstructionOutcome::ExecuteCall(func_ref));
|
return Ok(InstructionOutcome::ExecuteCall(func_ref));
|
||||||
@ -182,7 +218,8 @@ impl Interpreter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_instruction<'a, 'b>(context: &'b mut FunctionContext<'a>, opcode: &'a Opcode) -> Result<InstructionOutcome<'a>, Error> {
|
fn run_instruction<'a, 'b>(context: &'b mut FunctionContext<'a>, opcode: &Opcode) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
|
println!("=== RUNNING {:?}", opcode);
|
||||||
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),
|
||||||
@ -376,19 +413,19 @@ impl Interpreter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_block(opcode: &Opcode, branch: bool) -> Result<&[Opcode], Error> {
|
fn into_block(opcode: &Opcode, frame_type: BlockFrameType) -> Result<&[Opcode], Error> {
|
||||||
match opcode {
|
match opcode {
|
||||||
&Opcode::Block(_, ref ops) if branch => Ok(ops.elements()),
|
&Opcode::Block(_, ref ops) if frame_type != BlockFrameType::IfElse => Ok(ops.elements()),
|
||||||
&Opcode::Loop(_, ref ops) if branch => Ok(ops.elements()),
|
&Opcode::Loop(_, ref ops) if frame_type != BlockFrameType::IfElse => Ok(ops.elements()),
|
||||||
&Opcode::If(_, ref ops) => Ok(Interpreter::separate_if(ops.elements(), branch)),
|
&Opcode::If(_, ref ops) => Ok(Interpreter::separate_if(ops.elements(), frame_type)),
|
||||||
_ => Err(Error::Interpreter("trying to read block from non-bock instruction".into()))
|
_ => Err(Error::Interpreter("trying to read block from non-bock instruction".into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn separate_if(body: &[Opcode], branch: bool) -> &[Opcode] {
|
fn separate_if(body: &[Opcode], frame_type: BlockFrameType) -> &[Opcode] {
|
||||||
let body_len = body.len();
|
let body_len = body.len();
|
||||||
let else_index = body.iter().position(|op| *op == Opcode::Else).unwrap_or(body_len - 1);
|
let else_index = body.iter().position(|op| *op == Opcode::Else).unwrap_or(body_len - 1);
|
||||||
let (begin_index, end_index) = if branch {
|
let (begin_index, end_index) = if frame_type == BlockFrameType::IfTrue {
|
||||||
(0, else_index + 1)
|
(0, else_index + 1)
|
||||||
} else {
|
} else {
|
||||||
(else_index + 1, body_len)
|
(else_index + 1, body_len)
|
||||||
@ -404,26 +441,27 @@ impl Interpreter {
|
|||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_block<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType, body: &'a [Opcode]) -> Result<InstructionOutcome<'a>, Error> {
|
fn run_block<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType, body: &[Opcode]) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
let frame_position = context.position + 1;
|
|
||||||
context.push_frame(false, frame_position, frame_position, body, block_type)?;
|
|
||||||
Ok(InstructionOutcome::ExecuteBlock(true))
|
|
||||||
}
|
|
||||||
|
|
||||||
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, body, block_type)?;
|
context.push_frame(BlockFrameType::Block, frame_position, frame_position + 1, frame_position + 1, block_type)?;
|
||||||
Ok(InstructionOutcome::ExecuteBlock(true))
|
Ok(InstructionOutcome::ExecuteBlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_if<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType, body: &'a [Opcode]) -> Result<InstructionOutcome<'a>, Error> {
|
fn run_loop<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType, body: &[Opcode]) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
|
let frame_position = context.position;
|
||||||
|
context.push_frame(BlockFrameType::Loop, frame_position, frame_position, frame_position + 1, block_type)?;
|
||||||
|
Ok(InstructionOutcome::ExecuteBlock)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_if<'a, 'b>(context: &'b mut FunctionContext<'a>, block_type: BlockType, body: &[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 block_frame_type = if branch { BlockFrameType::IfTrue } else { BlockFrameType::IfElse };
|
||||||
|
let branch_body = Interpreter::separate_if(body, block_frame_type);
|
||||||
|
|
||||||
if branch_body.len() != 0 {
|
if branch_body.len() != 0 {
|
||||||
let frame_position = context.position + 1;
|
let frame_position = context.position;
|
||||||
context.push_frame(false, frame_position, frame_position, branch_body, block_type)?;
|
context.push_frame(block_frame_type, frame_position, frame_position + 1, frame_position + 1, block_type)?;
|
||||||
Ok(InstructionOutcome::ExecuteBlock(branch))
|
Ok(InstructionOutcome::ExecuteBlock)
|
||||||
} else {
|
} else {
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
@ -464,7 +502,15 @@ impl Interpreter {
|
|||||||
|
|
||||||
fn run_call_indirect<'a, 'b>(context: &'b mut FunctionContext<'a>, type_idx: u32) -> Result<InstructionOutcome<'a>, 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::ExecuteCall(context.module().function_reference_indirect(DEFAULT_TABLE_INDEX, type_idx, table_func_idx, Some(context.externals))?))
|
let function_reference = context.module().function_reference_indirect(DEFAULT_TABLE_INDEX, type_idx, table_func_idx, Some(context.externals))?;
|
||||||
|
let required_function_type = context.module().function_type_by_index(type_idx)?;
|
||||||
|
let actual_function_type = function_reference.module.function_type(ItemIndex::Internal(function_reference.internal_index), Some(context.externals))?;
|
||||||
|
if required_function_type != actual_function_type {
|
||||||
|
return Err(Error::Function(format!("expected function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}",
|
||||||
|
required_function_type.params(), required_function_type.return_type(),
|
||||||
|
actual_function_type.params(), actual_function_type.return_type())));
|
||||||
|
}
|
||||||
|
Ok(InstructionOutcome::ExecuteCall(function_reference))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_drop<'a>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
|
fn run_drop<'a>(context: &mut FunctionContext) -> Result<InstructionOutcome<'a>, Error> {
|
||||||
@ -981,17 +1027,9 @@ impl<'a> FunctionContext<'a> {
|
|||||||
pub fn nested(&mut self, function: InternalFunctionReference<'a>) -> Result<Self, Error> {
|
pub fn nested(&mut self, function: InternalFunctionReference<'a>) -> Result<Self, Error> {
|
||||||
let function_type = function.module.function_type(ItemIndex::Internal(function.internal_index), Some(self.externals))?;
|
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_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 function_locals = prepare_function_args(&function_type, &mut self.value_stack)?;
|
||||||
let param_value = self.value_stack.pop()?;
|
println!("=== nested_call.function_type: {:?}", function_type);
|
||||||
let actual_type = param_value.variable_type();
|
println!("=== nested_call.function_locals: {:?}", function_locals);
|
||||||
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 {
|
Ok(FunctionContext {
|
||||||
is_initialized: false,
|
is_initialized: false,
|
||||||
function: function,
|
function: function,
|
||||||
@ -1053,16 +1091,16 @@ impl<'a> FunctionContext<'a> {
|
|||||||
&self.frame_stack
|
&self.frame_stack
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn frame_stack_mut(&mut self) -> &mut StackWithLimit<BlockFrame<'a>> {
|
pub fn frame_stack_mut(&mut self) -> &mut StackWithLimit<BlockFrame> {
|
||||||
&mut self.frame_stack
|
&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> {
|
pub fn push_frame(&mut self, frame_type: BlockFrameType, begin_position: usize, branch_position: usize, end_position: usize, signature: BlockType) -> Result<(), Error> {
|
||||||
self.frame_stack.push(BlockFrame {
|
self.frame_stack.push(BlockFrame {
|
||||||
is_loop: is_loop,
|
frame_type: frame_type,
|
||||||
|
begin_position: begin_position,
|
||||||
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,
|
||||||
})
|
})
|
||||||
@ -1080,7 +1118,7 @@ impl<'a> FunctionContext<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let frame_value = match frame.signature {
|
let frame_value = match frame.signature {
|
||||||
BlockType::Value(_) if !frame.is_loop || !is_branch => Some(self.value_stack.pop()?),
|
BlockType::Value(_) if frame.frame_type != BlockFrameType::Loop || !is_branch => Some(self.value_stack.pop()?),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
self.value_stack.resize(frame.value_limit, RuntimeValue::I32(0));
|
self.value_stack.resize(frame.value_limit, RuntimeValue::I32(0));
|
||||||
@ -1099,19 +1137,6 @@ impl<'a> fmt::Debug for FunctionContext<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> BlockFrame<'a> {
|
|
||||||
/* pub fn invalid() -> Self {
|
|
||||||
BlockFrame {
|
|
||||||
is_loop: false,
|
|
||||||
branch_position: usize::max_value(),
|
|
||||||
end_position: usize::max_value(),
|
|
||||||
branch: true,
|
|
||||||
value_limit: usize::max_value(),
|
|
||||||
signature: BlockType::NoResult,
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
|
|
||||||
fn effective_address(address: u32, offset: u32) -> Result<u32, Error> {
|
fn effective_address(address: u32, offset: u32) -> Result<u32, Error> {
|
||||||
match offset.checked_add(address) {
|
match offset.checked_add(address) {
|
||||||
None => Err(Error::Memory(format!("invalid memory access: {} + {}", offset, address))),
|
None => Err(Error::Memory(format!("invalid memory access: {} + {}", offset, address))),
|
||||||
@ -1119,6 +1144,21 @@ fn effective_address(address: u32, offset: u32) -> Result<u32, Error> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn prepare_function_args(function_type: &FunctionType, caller_stack: &mut StackWithLimit<RuntimeValue>) -> Result<Vec<VariableInstance>, Error> {
|
||||||
|
let mut args = function_type.params().iter().rev().map(|param_type| {
|
||||||
|
let param_value = caller_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<_>, _>>()?;
|
||||||
|
args.reverse();
|
||||||
|
Ok(args)
|
||||||
|
}
|
||||||
|
|
||||||
/*fn prepare_function_locals(function_type: &FunctionType, function_body: &FuncBody, value_stack: &mut StackWithLimit<RuntimeValue>) -> Result<Vec<VariableInstance>, Error> {
|
/*fn prepare_function_locals(function_type: &FunctionType, function_body: &FuncBody, value_stack: &mut StackWithLimit<RuntimeValue>) -> Result<Vec<VariableInstance>, Error> {
|
||||||
// locals = function arguments + defined locals
|
// locals = function arguments + defined locals
|
||||||
function_type.params().iter().rev()
|
function_type.params().iter().rev()
|
||||||
|
Reference in New Issue
Block a user