mirror of
https://github.com/fluencelabs/parity-wasm
synced 2025-06-24 12:12:05 +00:00
function_type returns type reference
This commit is contained in:
@ -1,13 +1,12 @@
|
|||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use builder::module;
|
use builder::module;
|
||||||
use elements::{Module, FunctionType, ExportEntry, Internal, GlobalEntry, GlobalType,
|
use elements::{Module, ExportEntry, Internal, GlobalEntry, GlobalType,
|
||||||
ValueType, InitExpr, Opcode, Opcodes};
|
ValueType, InitExpr, Opcode, Opcodes};
|
||||||
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, ExportEntryType, InternalFunctionReference, InternalFunction};
|
ItemIndex, CallerContext, ExportEntryType, InternalFunctionReference, InternalFunction, FunctionSignature};
|
||||||
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;
|
||||||
@ -116,11 +115,11 @@ impl ModuleInstanceInterface for EnvModuleInstance {
|
|||||||
self.instance.global(index, variable_type)
|
self.instance.global(index, variable_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn function_type(&self, function_index: ItemIndex) -> Result<FunctionType, Error> {
|
fn function_type(&self, function_index: ItemIndex) -> Result<FunctionSignature, Error> {
|
||||||
self.instance.function_type(function_index)
|
self.instance.function_type(function_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn function_type_by_index(&self, type_index: u32) -> Result<FunctionType, Error> {
|
fn function_type_by_index(&self, type_index: u32) -> Result<FunctionSignature, Error> {
|
||||||
self.instance.function_type_by_index(type_index)
|
self.instance.function_type_by_index(type_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,10 +2,10 @@ use std::sync::Arc;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use elements::{FunctionType, Internal, ValueType};
|
use elements::{Internal, ValueType};
|
||||||
use interpreter::Error;
|
use interpreter::Error;
|
||||||
use interpreter::module::{ModuleInstanceInterface, ExecutionParams, ItemIndex,
|
use interpreter::module::{ModuleInstanceInterface, ExecutionParams, ItemIndex,
|
||||||
CallerContext, ExportEntryType, InternalFunctionReference, InternalFunction};
|
CallerContext, ExportEntryType, InternalFunctionReference, InternalFunction, FunctionSignature};
|
||||||
use interpreter::memory::MemoryInstance;
|
use interpreter::memory::MemoryInstance;
|
||||||
use interpreter::table::TableInstance;
|
use interpreter::table::TableInstance;
|
||||||
use interpreter::value::RuntimeValue;
|
use interpreter::value::RuntimeValue;
|
||||||
@ -21,66 +21,54 @@ pub trait UserFunctionExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// User function descriptor
|
/// User function descriptor
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum UserFunctionDescriptor {
|
pub enum UserFunctionDescriptor {
|
||||||
/// Static function definition
|
/// Static function definition
|
||||||
Static(&'static str, &'static [ValueType]),
|
Static(&'static str, &'static [ValueType], Option<ValueType>),
|
||||||
/// Dynamic heap function definition
|
/// Dynamic heap function definition
|
||||||
Heap(String, Vec<ValueType>),
|
Heap(String, Vec<ValueType>, Option<ValueType>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// User function type.
|
impl UserFunctionDescriptor {
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct UserFunction {
|
|
||||||
/// Descriptor with variable-length definitions
|
|
||||||
pub desc: UserFunctionDescriptor,
|
|
||||||
/// Return type of the signature
|
|
||||||
pub result: Option<ValueType>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UserFunction {
|
|
||||||
/// New function with statically known params
|
/// New function with statically known params
|
||||||
pub fn statik(name: &'static str, params: &'static [ValueType], result: Option<ValueType>) -> Self {
|
pub fn statik(name: &'static str, params: &'static [ValueType], result: Option<ValueType>) -> Self {
|
||||||
UserFunction {
|
UserFunctionDescriptor::Static(name, params, result)
|
||||||
desc: UserFunctionDescriptor::Static(name, params),
|
|
||||||
result: result,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// New function with statically unknown params
|
/// New function with statically unknown params
|
||||||
pub fn heap(name: String, params: Vec<ValueType>, result: Option<ValueType>) -> Self {
|
pub fn heap(name: String, params: Vec<ValueType>, result: Option<ValueType>) -> Self {
|
||||||
UserFunction {
|
UserFunctionDescriptor::Heap(name, params, result)
|
||||||
desc: UserFunctionDescriptor::Heap(name, params),
|
|
||||||
result: result,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Name of the function
|
/// Name of the function
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
match self.desc {
|
match self {
|
||||||
UserFunctionDescriptor::Static(name, _) => name,
|
&UserFunctionDescriptor::Static(name, _, _) => name,
|
||||||
UserFunctionDescriptor::Heap(ref name, _) => name,
|
&UserFunctionDescriptor::Heap(ref name, _, _) => name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Arguments of the function
|
/// Arguments of the function
|
||||||
pub fn params(&self) -> &[ValueType] {
|
pub fn params(&self) -> &[ValueType] {
|
||||||
match self.desc {
|
match self {
|
||||||
UserFunctionDescriptor::Static(_, params) => params,
|
&UserFunctionDescriptor::Static(_, params, _) => params,
|
||||||
UserFunctionDescriptor::Heap(_, ref params) => params,
|
&UserFunctionDescriptor::Heap(_, ref params, _) => params,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return type of the function
|
/// Return type of the function
|
||||||
pub fn result(&self) -> Option<ValueType> {
|
pub fn return_type(&self) -> Option<ValueType> {
|
||||||
self.result
|
match self {
|
||||||
|
&UserFunctionDescriptor::Static(_, _, result) => result,
|
||||||
|
&UserFunctionDescriptor::Heap(_, _, result) => result,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set of user-defined functions
|
/// Set of user-defined functions
|
||||||
pub struct UserFunctions<'a> {
|
pub struct UserFunctions<'a> {
|
||||||
/// Functions list.
|
/// Functions list.
|
||||||
pub functions: Cow<'static, [UserFunction]>,
|
pub functions: Cow<'static, [UserFunctionDescriptor]>,
|
||||||
/// Functions executor.
|
/// Functions executor.
|
||||||
pub executor: &'a mut UserFunctionExecutor,
|
pub executor: &'a mut UserFunctionExecutor,
|
||||||
}
|
}
|
||||||
@ -94,7 +82,7 @@ pub struct NativeModuleInstance<'a> {
|
|||||||
/// By-name functions index.
|
/// By-name functions index.
|
||||||
by_name: HashMap<String, u32>,
|
by_name: HashMap<String, u32>,
|
||||||
/// User functions list.
|
/// User functions list.
|
||||||
functions: Cow<'static, [UserFunction]>,
|
functions: Cow<'static, [UserFunctionDescriptor]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> NativeModuleInstance<'a> {
|
impl<'a> NativeModuleInstance<'a> {
|
||||||
@ -123,8 +111,8 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> {
|
|||||||
let composite_index = NATIVE_INDEX_FUNC_MIN + *index;
|
let composite_index = NATIVE_INDEX_FUNC_MIN + *index;
|
||||||
match required_type {
|
match required_type {
|
||||||
&ExportEntryType::Function(ref required_type)
|
&ExportEntryType::Function(ref required_type)
|
||||||
if required_type == &self.function_type(ItemIndex::Internal(composite_index))
|
if self.function_type(ItemIndex::Internal(composite_index))
|
||||||
.expect("by_name contains index; function_type succeeds for all functions from by_name; qed")
|
.expect("by_name contains index; function_type succeeds for all functions from by_name; qed") == *required_type
|
||||||
=> return Ok(Internal::Function(composite_index)),
|
=> return Ok(Internal::Function(composite_index)),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
@ -145,7 +133,7 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> {
|
|||||||
self.env.global(index, variable_type)
|
self.env.global(index, variable_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn function_type(&self, function_index: ItemIndex) -> Result<FunctionType, Error> {
|
fn function_type(&self, function_index: ItemIndex) -> Result<FunctionSignature, Error> {
|
||||||
let index = match function_index {
|
let index = match function_index {
|
||||||
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"),
|
||||||
@ -155,13 +143,12 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> {
|
|||||||
return self.env.function_type(function_index);
|
return self.env.function_type(function_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.functions
|
Ok(FunctionSignature::User(self.functions
|
||||||
.get((index - NATIVE_INDEX_FUNC_MIN) as usize)
|
.get((index - NATIVE_INDEX_FUNC_MIN) as usize)
|
||||||
.ok_or(Error::Native(format!("missing native env function with index {}", index)))
|
.ok_or(Error::Native(format!("missing native env function with index {}", index)))?))
|
||||||
.map(|f| FunctionType::new(f.params().to_vec(), f.result().clone()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn function_type_by_index(&self, type_index: u32) -> Result<FunctionType, Error> {
|
fn function_type_by_index(&self, type_index: u32) -> Result<FunctionSignature, Error> {
|
||||||
self.function_type(ItemIndex::Internal(type_index))
|
self.function_type(ItemIndex::Internal(type_index))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,3 +180,10 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> {
|
|||||||
pub fn env_native_module<'a>(env: Arc<ModuleInstanceInterface>, user_functions: UserFunctions<'a>) -> Result<NativeModuleInstance, Error> {
|
pub fn env_native_module<'a>(env: Arc<ModuleInstanceInterface>, user_functions: UserFunctions<'a>) -> Result<NativeModuleInstance, Error> {
|
||||||
NativeModuleInstance::new(env, user_functions)
|
NativeModuleInstance::new(env, user_functions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> PartialEq for UserFunctionDescriptor {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.params() == other.params()
|
||||||
|
&& self.return_type() == other.return_type()
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,9 @@
|
|||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use elements::{ImportSection, ImportEntry, External, Internal, FunctionType};
|
use elements::{ImportSection, ImportEntry, External, Internal};
|
||||||
use interpreter::Error;
|
use interpreter::Error;
|
||||||
use interpreter::memory::MemoryInstance;
|
use interpreter::memory::MemoryInstance;
|
||||||
use interpreter::module::{ModuleInstanceInterface, ItemIndex, ExportEntryType};
|
use interpreter::module::{ModuleInstanceInterface, ItemIndex, ExportEntryType, FunctionSignature};
|
||||||
use interpreter::program::ProgramInstanceEssence;
|
use interpreter::program::ProgramInstanceEssence;
|
||||||
use interpreter::table::TableInstance;
|
use interpreter::table::TableInstance;
|
||||||
use interpreter::variable::{VariableInstance, VariableType};
|
use interpreter::variable::{VariableInstance, VariableType};
|
||||||
@ -119,8 +119,8 @@ impl ModuleImports {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get function index.
|
/// Get function index.
|
||||||
pub fn function<'a>(&self, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>, import: &ImportEntry, required_type: Option<&FunctionType>) -> Result<u32, Error> {
|
pub fn function<'a>(&self, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>, import: &ImportEntry, required_type: Option<FunctionSignature>) -> Result<u32, Error> {
|
||||||
let (_, export) = self.external_export(externals, import, &required_type.map(|ft| ExportEntryType::Function(ft.clone())).unwrap_or(ExportEntryType::Any))?;
|
let (_, export) = self.external_export(externals, import, &required_type.map(|ft| ExportEntryType::Function(ft)).unwrap_or(ExportEntryType::Any))?;
|
||||||
if let Internal::Function(external_index) = export {
|
if let Internal::Function(external_index) = export {
|
||||||
return Ok(external_index);
|
return Ok(external_index);
|
||||||
}
|
}
|
||||||
|
@ -79,5 +79,5 @@ pub use self::table::TableInstance;
|
|||||||
pub use self::program::ProgramInstance;
|
pub use self::program::ProgramInstance;
|
||||||
pub use self::value::RuntimeValue;
|
pub use self::value::RuntimeValue;
|
||||||
pub use self::variable::VariableInstance;
|
pub use self::variable::VariableInstance;
|
||||||
pub use self::env_native::{env_native_module, UserFunctions, UserFunction, UserFunctionExecutor, UserFunctionDescriptor};
|
pub use self::env_native::{env_native_module, UserFunctions, UserFunctionExecutor, UserFunctionDescriptor};
|
||||||
pub use self::env::EnvParams;
|
pub use self::env::EnvParams;
|
@ -2,8 +2,9 @@ use std::collections::HashMap;
|
|||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use elements::{Module, InitExpr, Opcode, Type, FunctionType, Internal, External, BlockType, ResizableLimits, Local};
|
use elements::{Module, InitExpr, Opcode, Type, FunctionType, Internal, External, BlockType, ResizableLimits, Local, ValueType};
|
||||||
use interpreter::Error;
|
use interpreter::Error;
|
||||||
|
use interpreter::env_native::UserFunctionDescriptor;
|
||||||
use interpreter::imports::ModuleImports;
|
use interpreter::imports::ModuleImports;
|
||||||
use interpreter::memory::MemoryInstance;
|
use interpreter::memory::MemoryInstance;
|
||||||
use interpreter::program::ProgramInstanceEssence;
|
use interpreter::program::ProgramInstanceEssence;
|
||||||
@ -30,15 +31,24 @@ pub struct ExecutionParams<'a> {
|
|||||||
|
|
||||||
/// Export type.
|
/// Export type.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ExportEntryType {
|
pub enum ExportEntryType<'a> {
|
||||||
/// Any type.
|
/// Any type.
|
||||||
Any,
|
Any,
|
||||||
/// Type of function.
|
/// Type of function.
|
||||||
Function(FunctionType),
|
Function(FunctionSignature<'a>),
|
||||||
/// Type of global.
|
/// Type of global.
|
||||||
Global(VariableType),
|
Global(VariableType),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Function signature.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum FunctionSignature<'a> {
|
||||||
|
/// Module function reference.
|
||||||
|
Module(&'a FunctionType),
|
||||||
|
/// Native user function refrence.
|
||||||
|
User(&'a UserFunctionDescriptor),
|
||||||
|
}
|
||||||
|
|
||||||
/// Module instance API.
|
/// Module instance API.
|
||||||
pub trait ModuleInstanceInterface {
|
pub trait ModuleInstanceInterface {
|
||||||
/// Execute function with the given index.
|
/// Execute function with the given index.
|
||||||
@ -54,9 +64,9 @@ pub trait ModuleInstanceInterface {
|
|||||||
/// 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 type for given function index.
|
/// Get function type for given function index.
|
||||||
fn function_type(&self, function_index: ItemIndex) -> Result<FunctionType, Error>;
|
fn function_type(&self, function_index: ItemIndex) -> Result<FunctionSignature, Error>;
|
||||||
/// Get function type for given function index.
|
/// Get function type for given function index.
|
||||||
fn function_type_by_index(&self, type_index: u32) -> Result<FunctionType, Error>;
|
fn function_type_by_index(&self, type_index: u32) -> Result<FunctionSignature, Error>;
|
||||||
/// Get function reference.
|
/// Get function reference.
|
||||||
fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<InternalFunctionReference<'a>, Error>;
|
fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<InternalFunctionReference<'a>, Error>;
|
||||||
/// Get function indirect reference.
|
/// Get function indirect reference.
|
||||||
@ -259,16 +269,18 @@ impl ModuleInstance {
|
|||||||
|
|
||||||
// export entry points to function in function index space
|
// export entry points to function in function index space
|
||||||
// and Internal::Function points to type in type section
|
// and Internal::Function points to type in type section
|
||||||
|
{
|
||||||
let export_function_type = match export_entry {
|
let export_function_type = match export_entry {
|
||||||
Internal::Function(function_index) => external_module.function_type(ItemIndex::IndexSpace(function_index))?,
|
Internal::Function(function_index) => external_module.function_type(ItemIndex::IndexSpace(function_index))?,
|
||||||
_ => 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 export_function_type != import_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())));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
&External::Global(ref global_type) => if global_type.is_mutable() {
|
&External::Global(ref global_type) => if global_type.is_mutable() {
|
||||||
return Err(Error::Validation(format!("trying to import mutable global {}", import.field())));
|
return Err(Error::Validation(format!("trying to import mutable global {}", import.field())));
|
||||||
@ -310,18 +322,18 @@ impl 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_labels = {
|
||||||
let function_type = self.function_type_by_index(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)));
|
||||||
|
|
||||||
let function_labels = {
|
|
||||||
let mut context = FunctionValidationContext::new(
|
let mut context = FunctionValidationContext::new(
|
||||||
self,
|
self,
|
||||||
&locals,
|
&locals,
|
||||||
DEFAULT_VALUE_STACK_LIMIT,
|
DEFAULT_VALUE_STACK_LIMIT,
|
||||||
DEFAULT_FRAME_STACK_LIMIT,
|
DEFAULT_FRAME_STACK_LIMIT,
|
||||||
&function_type);
|
function_type.clone());
|
||||||
|
|
||||||
let block_type = function_type.return_type().map(BlockType::Value).unwrap_or(BlockType::NoResult);
|
let block_type = function_type.return_type().map(BlockType::Value).unwrap_or(BlockType::NoResult);
|
||||||
Validator::validate_function(&mut context, block_type, function_body.code().elements())
|
Validator::validate_function(&mut context, block_type, function_body.code().elements())
|
||||||
@ -439,7 +451,7 @@ impl ModuleInstanceInterface for ModuleInstance {
|
|||||||
&ExportEntryType::Function(ref required_type) => match e.internal() {
|
&ExportEntryType::Function(ref required_type) => match e.internal() {
|
||||||
&Internal::Function(function_index) =>
|
&Internal::Function(function_index) =>
|
||||||
self.function_type(ItemIndex::IndexSpace(function_index))
|
self.function_type(ItemIndex::IndexSpace(function_index))
|
||||||
.map(|ft| &ft == required_type)
|
.map(|ft| ft == *required_type)
|
||||||
.unwrap_or(false),
|
.unwrap_or(false),
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
@ -487,7 +499,7 @@ impl ModuleInstanceInterface for ModuleInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn function_type(&self, function_index: ItemIndex) -> Result<FunctionType, Error> {
|
fn function_type(&self, function_index: ItemIndex) -> Result<FunctionSignature, Error> {
|
||||||
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))
|
||||||
@ -503,14 +515,14 @@ impl ModuleInstanceInterface for ModuleInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn function_type_by_index(&self, type_index: u32) -> Result<FunctionType, Error> {
|
fn function_type_by_index(&self, type_index: u32) -> Result<FunctionSignature, Error> {
|
||||||
self.module.type_section()
|
self.module.type_section()
|
||||||
.ok_or(Error::Validation(format!("type reference {} exists in module without type section", type_index)))
|
.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) {
|
.and_then(|s| match s.types().get(type_index as usize) {
|
||||||
Some(&Type::Function(ref function_type)) => Ok(function_type),
|
Some(&Type::Function(ref function_type)) => Ok(function_type),
|
||||||
_ => Err(Error::Validation(format!("missing function type with index {}", type_index))),
|
_ => Err(Error::Validation(format!("missing function type with index {}", type_index))),
|
||||||
})
|
})
|
||||||
.map(Clone::clone)
|
.map(FunctionSignature::Module)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<InternalFunctionReference<'a>, Error> {
|
fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<InternalFunctionReference<'a>, Error> {
|
||||||
@ -526,7 +538,7 @@ impl ModuleInstanceInterface for ModuleInstance {
|
|||||||
.entries().get(index as usize)
|
.entries().get(index as usize)
|
||||||
.expect("parse_function_index has returned External(index); it is only returned when entry with index exists in import section exists; qed");
|
.expect("parse_function_index has returned External(index); it is only returned when entry with index exists in import section exists; qed");
|
||||||
let required_function_type = self.function_type(ItemIndex::External(index))?;
|
let required_function_type = self.function_type(ItemIndex::External(index))?;
|
||||||
let internal_function_index = self.imports.function(externals, import_entry, Some(&required_function_type))?;
|
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: internal_function_index,
|
internal_index: internal_function_index,
|
||||||
@ -640,3 +652,39 @@ fn get_initializer(expr: &InitExpr, module: &Module, imports: &ModuleImports, ex
|
|||||||
_ => Err(Error::Initialization(format!("not-supported {:?} instruction in instantiation-time initializer", first_opcode))),
|
_ => Err(Error::Initialization(format!("not-supported {:?} instruction in instantiation-time initializer", first_opcode))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> FunctionSignature<'a> {
|
||||||
|
pub fn return_type(&self) -> Option<ValueType> {
|
||||||
|
match self {
|
||||||
|
&FunctionSignature::Module(ft) => ft.return_type(),
|
||||||
|
&FunctionSignature::User(fd) => fd.return_type(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn params(&self) -> &[ValueType] {
|
||||||
|
match self {
|
||||||
|
&FunctionSignature::Module(ft) => ft.params(),
|
||||||
|
&FunctionSignature::User(fd) => fd.params(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PartialEq for FunctionSignature<'a> {
|
||||||
|
fn eq<'b>(&self, other: &FunctionSignature<'b>) -> bool {
|
||||||
|
match self {
|
||||||
|
&FunctionSignature::Module(ft1) => match other {
|
||||||
|
&FunctionSignature::Module(ft2) => ft1 == ft2,
|
||||||
|
&FunctionSignature::User(ft2) => ft1.params() == ft2.params() && ft1.return_type() == ft2.return_type(),
|
||||||
|
},
|
||||||
|
&FunctionSignature::User(ft1) => match other {
|
||||||
|
&FunctionSignature::User(ft2) => ft1 == ft2,
|
||||||
|
&FunctionSignature::Module(ft2) => ft1.params() == ft2.params() && ft1.return_type() == ft2.return_type(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a> From<&'a FunctionType> for FunctionSignature<'a> {
|
||||||
|
fn from(other: &'a FunctionType) -> Self {
|
||||||
|
FunctionSignature::Module(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,9 +5,9 @@ use std::sync::Arc;
|
|||||||
use std::fmt::{self, Display};
|
use std::fmt::{self, Display};
|
||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
use elements::{Opcode, BlockType, FunctionType, Local};
|
use elements::{Opcode, BlockType, Local};
|
||||||
use interpreter::Error;
|
use interpreter::Error;
|
||||||
use interpreter::module::{ModuleInstanceInterface, CallerContext, ItemIndex, InternalFunctionReference};
|
use interpreter::module::{ModuleInstanceInterface, CallerContext, ItemIndex, InternalFunctionReference, FunctionSignature};
|
||||||
use interpreter::stack::StackWithLimit;
|
use interpreter::stack::StackWithLimit;
|
||||||
use interpreter::value::{
|
use interpreter::value::{
|
||||||
RuntimeValue, TryInto, WrapInto, TryTruncateInto, ExtendInto,
|
RuntimeValue, TryInto, WrapInto, TryTruncateInto, ExtendInto,
|
||||||
@ -423,6 +423,7 @@ impl Interpreter {
|
|||||||
fn run_call_indirect<'a>(context: &mut FunctionContext<'a>, type_idx: u32) -> Result<InstructionOutcome<'a>, Error> {
|
fn run_call_indirect<'a>(context: &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()?;
|
||||||
let function_reference = 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 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))?;
|
let actual_function_type = function_reference.module.function_type(ItemIndex::Internal(function_reference.internal_index))?;
|
||||||
if required_function_type != actual_function_type {
|
if required_function_type != actual_function_type {
|
||||||
@ -430,6 +431,7 @@ impl Interpreter {
|
|||||||
required_function_type.params(), required_function_type.return_type(),
|
required_function_type.params(), required_function_type.return_type(),
|
||||||
actual_function_type.params(), actual_function_type.return_type())));
|
actual_function_type.params(), actual_function_type.return_type())));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Ok(InstructionOutcome::ExecuteCall(function_reference))
|
Ok(InstructionOutcome::ExecuteCall(function_reference))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -931,7 +933,7 @@ impl Interpreter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FunctionContext<'a> {
|
impl<'a> FunctionContext<'a> {
|
||||||
pub fn new(function: InternalFunctionReference<'a>, externals: &'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>, function_labels: HashMap<usize, usize>, value_stack_limit: usize, frame_stack_limit: usize, function_type: &FunctionType, args: Vec<VariableInstance>) -> Self {
|
pub fn new(function: InternalFunctionReference<'a>, externals: &'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>, function_labels: HashMap<usize, usize>, value_stack_limit: usize, frame_stack_limit: usize, function_type: &FunctionSignature, args: Vec<VariableInstance>) -> Self {
|
||||||
FunctionContext {
|
FunctionContext {
|
||||||
is_initialized: false,
|
is_initialized: false,
|
||||||
function: function,
|
function: function,
|
||||||
@ -946,9 +948,12 @@ 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_locals, function_return_type) = {
|
||||||
let function_type = function.module.function_type(ItemIndex::Internal(function.internal_index))?;
|
let function_type = function.module.function_type(ItemIndex::Internal(function.internal_index))?;
|
||||||
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 = prepare_function_args(&function_type, &mut self.value_stack)?;
|
let function_locals = prepare_function_args(&function_type, &mut self.value_stack)?;
|
||||||
|
(function_locals, function_return_type)
|
||||||
|
};
|
||||||
|
|
||||||
Ok(FunctionContext {
|
Ok(FunctionContext {
|
||||||
is_initialized: false,
|
is_initialized: false,
|
||||||
@ -1083,7 +1088,7 @@ 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> {
|
pub fn prepare_function_args(function_type: &FunctionSignature, caller_stack: &mut StackWithLimit<RuntimeValue>) -> Result<Vec<VariableInstance>, Error> {
|
||||||
let mut args = function_type.params().iter().rev().map(|param_type| {
|
let mut args = function_type.params().iter().rev().map(|param_type| {
|
||||||
let param_value = caller_stack.pop()?;
|
let param_value = caller_stack.pop()?;
|
||||||
let actual_type = param_value.variable_type();
|
let actual_type = param_value.variable_type();
|
||||||
|
@ -5,9 +5,9 @@ use builder::module;
|
|||||||
use elements::{ExportEntry, Internal, ImportEntry, External, GlobalEntry, GlobalType,
|
use elements::{ExportEntry, Internal, ImportEntry, External, GlobalEntry, GlobalType,
|
||||||
InitExpr, ValueType, BlockType, Opcodes, Opcode, FunctionType};
|
InitExpr, ValueType, BlockType, Opcodes, Opcode, FunctionType};
|
||||||
use interpreter::Error;
|
use interpreter::Error;
|
||||||
use interpreter::env_native::{env_native_module, UserFunction, UserFunctions, UserFunctionExecutor, UserFunctionDescriptor};
|
use interpreter::env_native::{env_native_module, UserFunctions, UserFunctionExecutor, UserFunctionDescriptor};
|
||||||
use interpreter::memory::MemoryInstance;
|
use interpreter::memory::MemoryInstance;
|
||||||
use interpreter::module::{ModuleInstance, ModuleInstanceInterface, CallerContext, ItemIndex, ExecutionParams, ExportEntryType};
|
use interpreter::module::{ModuleInstance, ModuleInstanceInterface, CallerContext, ItemIndex, ExecutionParams, ExportEntryType, FunctionSignature};
|
||||||
use interpreter::program::ProgramInstance;
|
use interpreter::program::ProgramInstance;
|
||||||
use interpreter::validator::{FunctionValidationContext, Validator};
|
use interpreter::validator::{FunctionValidationContext, Validator};
|
||||||
use interpreter::value::RuntimeValue;
|
use interpreter::value::RuntimeValue;
|
||||||
@ -101,21 +101,17 @@ fn global_get_set() {
|
|||||||
|
|
||||||
const SIGNATURE_I32: &'static [ValueType] = &[ValueType::I32];
|
const SIGNATURE_I32: &'static [ValueType] = &[ValueType::I32];
|
||||||
|
|
||||||
const SIGNATURES: &'static [UserFunction] = &[
|
const SIGNATURES: &'static [UserFunctionDescriptor] = &[
|
||||||
UserFunction {
|
UserFunctionDescriptor::Static(
|
||||||
desc: UserFunctionDescriptor::Static(
|
|
||||||
"add",
|
"add",
|
||||||
SIGNATURE_I32,
|
SIGNATURE_I32,
|
||||||
|
Some(ValueType::I32),
|
||||||
),
|
),
|
||||||
result: Some(ValueType::I32),
|
UserFunctionDescriptor::Static(
|
||||||
},
|
|
||||||
UserFunction {
|
|
||||||
desc: UserFunctionDescriptor::Static(
|
|
||||||
"sub",
|
"sub",
|
||||||
SIGNATURE_I32,
|
SIGNATURE_I32,
|
||||||
|
Some(ValueType::I32),
|
||||||
),
|
),
|
||||||
result: Some(ValueType::I32),
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// user function executor
|
// user function executor
|
||||||
@ -217,16 +213,16 @@ fn env_native_export_entry_type_check() {
|
|||||||
functions: ::std::borrow::Cow::from(SIGNATURES),
|
functions: ::std::borrow::Cow::from(SIGNATURES),
|
||||||
}).unwrap());
|
}).unwrap());
|
||||||
|
|
||||||
assert!(native_env_instance.export_entry("add", &ExportEntryType::Function(FunctionType::new(vec![ValueType::I32], Some(ValueType::I32)))).is_ok());
|
assert!(native_env_instance.export_entry("add", &ExportEntryType::Function(FunctionSignature::Module(&FunctionType::new(vec![ValueType::I32], Some(ValueType::I32))))).is_ok());
|
||||||
assert!(native_env_instance.export_entry("add", &ExportEntryType::Function(FunctionType::new(vec![], Some(ValueType::I32)))).is_err());
|
assert!(native_env_instance.export_entry("add", &ExportEntryType::Function(FunctionSignature::Module(&FunctionType::new(vec![], Some(ValueType::I32))))).is_err());
|
||||||
assert!(native_env_instance.export_entry("add", &ExportEntryType::Function(FunctionType::new(vec![ValueType::I32], None))).is_err());
|
assert!(native_env_instance.export_entry("add", &ExportEntryType::Function(FunctionSignature::Module(&FunctionType::new(vec![ValueType::I32], None)))).is_err());
|
||||||
assert!(native_env_instance.export_entry("add", &ExportEntryType::Function(FunctionType::new(vec![ValueType::I32], Some(ValueType::I64)))).is_err());
|
assert!(native_env_instance.export_entry("add", &ExportEntryType::Function(FunctionSignature::Module(&FunctionType::new(vec![ValueType::I32], Some(ValueType::I64))))).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn if_else_with_return_type_validation() {
|
fn if_else_with_return_type_validation() {
|
||||||
let module_instance = ModuleInstance::new(Weak::default(), "test".into(), module().build()).unwrap();
|
let module_instance = ModuleInstance::new(Weak::default(), "test".into(), module().build()).unwrap();
|
||||||
let mut context = FunctionValidationContext::new(&module_instance, &[], 1024, 1024, &FunctionType::default());
|
let mut context = FunctionValidationContext::new(&module_instance, &[], 1024, 1024, FunctionSignature::Module(&FunctionType::default()));
|
||||||
|
|
||||||
Validator::validate_function(&mut context, BlockType::NoResult, &[
|
Validator::validate_function(&mut context, BlockType::NoResult, &[
|
||||||
Opcode::I32Const(1),
|
Opcode::I32Const(1),
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use std::u32;
|
use std::u32;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use elements::{Opcode, BlockType, FunctionType, ValueType};
|
use elements::{Opcode, BlockType, ValueType};
|
||||||
use interpreter::Error;
|
use interpreter::Error;
|
||||||
use interpreter::runner::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX};
|
use interpreter::runner::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX};
|
||||||
use interpreter::module::{ModuleInstance, ModuleInstanceInterface, ItemIndex};
|
use interpreter::module::{ModuleInstance, ModuleInstanceInterface, ItemIndex, FunctionSignature};
|
||||||
use interpreter::stack::StackWithLimit;
|
use interpreter::stack::StackWithLimit;
|
||||||
use interpreter::variable::VariableType;
|
use interpreter::variable::VariableType;
|
||||||
|
|
||||||
@ -572,7 +572,7 @@ impl<'a> FunctionValidationContext<'a> {
|
|||||||
locals: &'a [ValueType],
|
locals: &'a [ValueType],
|
||||||
value_stack_limit: usize,
|
value_stack_limit: usize,
|
||||||
frame_stack_limit: usize,
|
frame_stack_limit: usize,
|
||||||
function: &FunctionType,
|
function: FunctionSignature,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
FunctionValidationContext {
|
FunctionValidationContext {
|
||||||
module_instance: module_instance,
|
module_instance: module_instance,
|
||||||
|
Reference in New Issue
Block a user