2017-06-13 12:01:59 +03:00
use std ::collections ::HashMap ;
2017-05-04 19:50:48 +03:00
use std ::iter ::repeat ;
2017-04-21 14:35:12 +03:00
use std ::sync ::{ Arc , Weak } ;
2017-06-16 12:23:49 +03:00
use std ::fmt ;
2017-06-26 11:54:17 +03:00
use elements ::{ Module , InitExpr , Opcode , Type , FunctionType , Internal , External , BlockType , ResizableLimits , Local , ValueType } ;
2017-04-21 14:35:12 +03:00
use interpreter ::Error ;
2017-06-26 11:54:17 +03:00
use interpreter ::env_native ::UserFunctionDescriptor ;
2017-04-21 14:35:12 +03:00
use interpreter ::imports ::ModuleImports ;
use interpreter ::memory ::MemoryInstance ;
use interpreter ::program ::ProgramInstanceEssence ;
2017-06-19 11:01:59 +03:00
use interpreter ::runner ::{ Interpreter , FunctionContext , prepare_function_args } ;
2017-04-28 13:34:58 +03:00
use interpreter ::stack ::StackWithLimit ;
2017-04-21 14:35:12 +03:00
use interpreter ::table ::TableInstance ;
2017-06-07 14:48:02 +03:00
use interpreter ::validator ::{ Validator , FunctionValidationContext } ;
2017-05-31 18:43:09 +02:00
use interpreter ::value ::{ RuntimeValue , TryInto } ;
2017-04-26 15:41:22 +03:00
use interpreter ::variable ::{ VariableInstance , VariableType } ;
2017-04-21 14:35:12 +03:00
2017-06-07 14:48:02 +03:00
/// Maximum number of entries in value stack.
const DEFAULT_VALUE_STACK_LIMIT : usize = 16384 ;
/// Maximum number of entries in frame stack.
2017-06-16 12:23:49 +03:00
const DEFAULT_FRAME_STACK_LIMIT : usize = 1024 ;
2017-06-07 14:48:02 +03:00
2017-05-18 15:08:55 +03:00
/// Execution context.
2017-06-13 12:01:59 +03:00
#[ derive(Default, Clone) ]
2017-05-19 09:36:50 +03:00
pub struct ExecutionParams < ' a > {
2017-05-18 15:08:55 +03:00
/// Arguments.
pub args : Vec < RuntimeValue > ,
/// Execution-local external modules.
2017-05-19 09:36:50 +03:00
pub externals : HashMap < String , Arc < ModuleInstanceInterface + ' a > > ,
2017-05-18 15:08:55 +03:00
}
2017-06-13 12:01:59 +03:00
/// Export type.
#[ derive(Debug, Clone) ]
2017-06-26 11:54:17 +03:00
pub enum ExportEntryType < ' a > {
2017-06-13 12:01:59 +03:00
/// Any type.
Any ,
/// Type of function.
2017-06-26 11:54:17 +03:00
Function ( FunctionSignature < ' a > ) ,
2017-06-13 12:01:59 +03:00
/// Type of global.
Global ( VariableType ) ,
}
2017-06-26 11:54:17 +03:00
/// Function signature.
#[ derive(Debug, Clone) ]
pub enum FunctionSignature < ' a > {
/// Module function reference.
Module ( & ' a FunctionType ) ,
/// Native user function refrence.
User ( & ' a UserFunctionDescriptor ) ,
}
2017-05-04 11:25:25 +03:00
/// Module instance API.
pub trait ModuleInstanceInterface {
/// Execute function with the given index.
2017-05-18 15:08:55 +03:00
fn execute_index ( & self , index : u32 , params : ExecutionParams ) -> Result < Option < RuntimeValue > , Error > ;
2017-05-04 19:09:43 +03:00
/// Execute function with the given export name.
2017-05-18 15:08:55 +03:00
fn execute_export ( & self , name : & str , params : ExecutionParams ) -> Result < Option < RuntimeValue > , Error > ;
/// Get export entry.
2017-06-19 12:35:17 +03:00
fn export_entry < ' a > ( & self , name : & str , required_type : & ExportEntryType ) -> Result < Internal , Error > ;
2017-05-04 11:25:25 +03:00
/// Get table reference.
fn table ( & self , index : ItemIndex ) -> Result < Arc < TableInstance > , Error > ;
/// Get memory reference.
fn memory ( & self , index : ItemIndex ) -> Result < Arc < MemoryInstance > , Error > ;
/// Get global reference.
2017-06-13 12:01:59 +03:00
fn global ( & self , index : ItemIndex , variable_type : Option < VariableType > ) -> Result < Arc < VariableInstance > , Error > ;
2017-06-19 12:04:16 +03:00
/// Get function type for given function index.
2017-06-26 11:54:17 +03:00
fn function_type ( & self , function_index : ItemIndex ) -> Result < FunctionSignature , Error > ;
2017-06-19 12:04:16 +03:00
/// Get function type for given function index.
2017-06-26 11:54:17 +03:00
fn function_type_by_index ( & self , type_index : u32 ) -> Result < FunctionSignature , Error > ;
2017-06-16 12:23:49 +03:00
/// 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.
2017-06-19 12:04:16 +03:00
fn function_body < ' a > ( & ' a self , internal_index : u32 ) -> Result < Option < InternalFunction < ' a > > , Error > ;
/// Call function with given internal index.
2017-06-19 12:35:17 +03:00
fn call_internal_function ( & self , outer : CallerContext , index : u32 ) -> Result < Option < RuntimeValue > , Error > ;
2017-05-04 11:25:25 +03:00
}
2017-04-21 14:35:12 +03:00
/// Item index in items index space.
#[ derive(Debug, Clone, Copy) ]
pub enum ItemIndex {
/// Index in index space.
IndexSpace ( u32 ) ,
/// Internal item index (i.e. index of item in items section).
Internal ( u32 ) ,
2017-05-18 15:08:55 +03:00
/// External module item index (i.e. index of item in the import section).
2017-04-21 14:35:12 +03:00
External ( u32 ) ,
}
/// Module instance.
pub struct ModuleInstance {
2017-06-13 12:01:59 +03:00
/// Module name.
name : String ,
2017-04-21 14:35:12 +03:00
/// Module.
module : Module ,
2017-06-22 17:52:05 +03:00
/// Function labels.
functions_labels : HashMap < u32 , HashMap < usize , usize > > ,
2017-04-21 14:35:12 +03:00
/// Module imports.
imports : ModuleImports ,
/// Tables.
tables : Vec < Arc < TableInstance > > ,
/// Linear memory regions.
memory : Vec < Arc < MemoryInstance > > ,
/// Globals.
globals : Vec < Arc < VariableInstance > > ,
}
2017-04-28 13:34:58 +03:00
/// Caller context.
pub struct CallerContext < ' a > {
2017-05-15 15:40:08 +03:00
/// Value stack limit
2017-04-28 13:34:58 +03:00
pub value_stack_limit : usize ,
2017-05-15 15:40:08 +03:00
/// Frame stack limit
2017-04-28 13:34:58 +03:00
pub frame_stack_limit : usize ,
2017-05-15 15:40:08 +03:00
/// Stack of the input parameters
2017-04-28 13:34:58 +03:00
pub value_stack : & ' a mut StackWithLimit < RuntimeValue > ,
2017-05-18 15:08:55 +03:00
/// Execution-local external modules.
2017-05-19 09:36:50 +03:00
pub externals : & ' a HashMap < String , Arc < ModuleInstanceInterface + ' a > > ,
2017-05-18 15:08:55 +03:00
}
2017-06-16 12:23:49 +03:00
/// Internal function reference.
#[ derive(Clone) ]
pub struct InternalFunctionReference < ' a > {
/// Module reference.
pub module : Arc < ModuleInstanceInterface + ' a > ,
/// Internal function index.
pub internal_index : u32 ,
}
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 locals.
pub locals : & ' a [ Local ] ,
/// Function body.
pub body : & ' a [ Opcode ] ,
2017-06-22 17:52:05 +03:00
/// Function labels.
pub labels : & ' a HashMap < usize , usize > ,
2017-06-16 12:23:49 +03:00
}
2017-05-19 09:36:50 +03:00
impl < ' a > ExecutionParams < ' a > {
2017-05-18 15:08:55 +03:00
/// Create new execution params with given externa; module override.
2017-05-19 09:36:50 +03:00
pub fn with_external ( name : String , module : Arc < ModuleInstanceInterface + ' a > ) -> Self {
2017-05-18 15:08:55 +03:00
let mut externals = HashMap ::new ( ) ;
externals . insert ( name , module ) ;
ExecutionParams {
args : Vec ::new ( ) ,
externals : externals ,
}
}
2017-05-19 09:36:50 +03:00
/// Add argument.
pub fn add_argument ( mut self , arg : RuntimeValue ) -> Self {
self . args . push ( arg ) ;
self
}
2017-05-18 15:08:55 +03:00
}
2017-05-19 09:36:50 +03:00
impl < ' a > From < Vec < RuntimeValue > > for ExecutionParams < ' a > {
fn from ( args : Vec < RuntimeValue > ) -> ExecutionParams < ' a > {
2017-05-18 15:08:55 +03:00
ExecutionParams {
args : args ,
externals : HashMap ::new ( ) ,
}
}
2017-04-28 13:34:58 +03:00
}
2017-04-21 14:35:12 +03:00
impl ModuleInstance {
/// Instantiate given module within program context.
2017-06-13 12:01:59 +03:00
pub fn new < ' a > ( program : Weak < ProgramInstanceEssence > , name : String , module : Module ) -> Result < Self , Error > {
2017-04-21 14:35:12 +03:00
// load entries from import section
let imports = ModuleImports ::new ( program , module . import_section ( ) ) ;
// instantiate linear memory regions, if any
2017-05-04 10:58:16 +03:00
let memory = match module . memory_section ( ) {
2017-04-21 14:35:12 +03:00
Some ( memory_section ) = > memory_section . entries ( )
2017-06-21 11:35:09 +03:00
. iter ( )
. map ( MemoryInstance ::new )
. collect ::< Result < Vec < _ > , _ > > ( ) ? ,
2017-04-21 14:35:12 +03:00
None = > Vec ::new ( ) ,
} ;
// instantiate tables, if any
2017-05-04 10:58:16 +03:00
let tables = match module . table_section ( ) {
2017-04-21 14:35:12 +03:00
Some ( table_section ) = > table_section . entries ( )
2017-06-21 11:35:09 +03:00
. iter ( )
. map ( | tt | TableInstance ::new ( tt ) )
. collect ::< Result < Vec < _ > , _ > > ( ) ? ,
2017-04-21 14:35:12 +03:00
None = > Vec ::new ( ) ,
} ;
// instantiate globals, if any
let globals = match module . global_section ( ) {
Some ( global_section ) = > global_section . entries ( )
2017-06-21 11:35:09 +03:00
. iter ( )
. map ( | g | {
get_initializer ( g . init_expr ( ) , & module , & imports , g . global_type ( ) . content_type ( ) . into ( ) )
. map_err ( | e | Error ::Initialization ( e . into ( ) ) )
. and_then ( | v | VariableInstance ::new_global ( g . global_type ( ) , v ) . map ( Arc ::new ) )
} )
. collect ::< Result < Vec < _ > , _ > > ( ) ? ,
2017-04-21 14:35:12 +03:00
None = > Vec ::new ( ) ,
} ;
2017-06-13 12:01:59 +03:00
Ok ( ModuleInstance {
name : name ,
2017-04-21 14:35:12 +03:00
module : module ,
imports : imports ,
2017-06-22 17:52:05 +03:00
functions_labels : HashMap ::new ( ) ,
2017-04-21 14:35:12 +03:00
memory : memory ,
tables : tables ,
globals : globals ,
2017-06-13 12:01:59 +03:00
} )
}
2017-06-23 10:39:31 +03:00
/// Run instantiation-time procedures (validation). Module is not completely validated until this call.
2017-06-22 17:52:05 +03:00
pub fn instantiate < ' a > ( & mut self , is_user_module : bool , externals : Option < & ' a HashMap < String , Arc < ModuleInstanceInterface + ' a > > > ) -> Result < ( ) , Error > {
2017-06-08 10:49:32 +03:00
// validate start section
if let Some ( start_function ) = self . module . start_section ( ) {
2017-06-09 12:13:35 +03:00
let func_type_index = self . require_function ( ItemIndex ::IndexSpace ( start_function ) ) ? ;
if is_user_module { // tests use non-empty main functions
2017-06-19 11:01:59 +03:00
let func_type = self . function_type_by_index ( func_type_index ) ? ;
2017-06-09 12:13:35 +03:00
if func_type . return_type ( ) ! = None | | func_type . params ( ) . len ( ) ! = 0 {
return Err ( Error ::Validation ( " start function expected to have type [] -> [] " . into ( ) ) ) ;
}
}
2017-06-08 10:49:32 +03:00
}
// validate export section
if is_user_module { // TODO: env module exports STACKTOP global, which is mutable => check is failed
if let Some ( export_section ) = self . module . export_section ( ) {
for export in export_section . entries ( ) {
match export . internal ( ) {
& Internal ::Function ( function_index ) = >
2017-06-09 12:13:35 +03:00
self . require_function ( ItemIndex ::IndexSpace ( function_index ) ) . map ( | _ | ( ) ) ? ,
2017-06-08 10:49:32 +03:00
& Internal ::Global ( global_index ) = >
2017-06-13 12:01:59 +03:00
self . global ( ItemIndex ::IndexSpace ( global_index ) , None )
2017-06-08 10:49:32 +03:00
. and_then ( | g | if g . is_mutable ( ) {
Err ( Error ::Validation ( format! ( " trying to export mutable global {} " , export . field ( ) ) ) )
} else {
Ok ( ( ) )
} ) ? ,
& Internal ::Memory ( memory_index ) = >
self . memory ( ItemIndex ::IndexSpace ( memory_index ) ) . map ( | _ | ( ) ) ? ,
& Internal ::Table ( table_index ) = >
self . table ( ItemIndex ::IndexSpace ( table_index ) ) . map ( | _ | ( ) ) ? ,
2017-06-07 14:48:02 +03:00
}
2017-06-08 10:49:32 +03:00
}
}
}
// validate import section
if let Some ( import_section ) = self . module . import_section ( ) {
for import in import_section . entries ( ) {
match import . external ( ) {
2017-06-13 12:01:59 +03:00
// for functions we need to check if function type matches in both modules
& External ::Function ( ref function_type_index ) = > {
// External::Function points to function type in type section in this module
2017-06-19 11:01:59 +03:00
let import_function_type = self . function_type_by_index ( * function_type_index ) ? ;
2017-06-13 12:01:59 +03:00
// get export entry in external module
let external_module = self . imports . module ( externals , import . module ( ) ) ? ;
2017-06-19 12:35:17 +03:00
let export_entry = external_module . export_entry ( import . field ( ) , & ExportEntryType ::Function ( import_function_type . clone ( ) ) ) ? ;
2017-06-13 12:01:59 +03:00
// export entry points to function in function index space
// and Internal::Function points to type in type section
2017-06-26 11:54:17 +03:00
{
let export_function_type = match export_entry {
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 ( ) ) ) ) ,
} ;
if export_function_type ! = import_function_type {
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 ( ) ,
export_function_type . params ( ) , export_function_type . return_type ( ) ) ) ) ;
}
2017-06-13 12:01:59 +03:00
}
} ,
2017-06-08 10:49:32 +03:00
& External ::Global ( ref global_type ) = > if global_type . is_mutable ( ) {
2017-06-13 12:01:59 +03:00
return Err ( Error ::Validation ( format! ( " trying to import mutable global {} " , import . field ( ) ) ) ) ;
} else {
self . imports . global ( externals , import , Some ( global_type . content_type ( ) . into ( ) ) ) ? ;
} ,
& External ::Memory ( ref memory_type ) = > {
check_limits ( memory_type . limits ( ) ) ? ;
self . imports . memory ( externals , import ) ? ;
} ,
& External ::Table ( ref table_type ) = > {
check_limits ( table_type . limits ( ) ) ? ;
self . imports . table ( externals , import ) ? ;
2017-06-08 10:49:32 +03:00
} ,
}
}
}
// there must be no greater than 1 table in tables index space
if self . imports . tables_len ( ) + self . tables . len ( ) > 1 {
return Err ( Error ::Validation ( format! ( " too many tables in index space: {} " , self . imports . tables_len ( ) + self . tables . len ( ) ) ) ) ;
}
// there must be no greater than 1 memory region in memory regions index space
if self . imports . memory_regions_len ( ) + self . memory . len ( ) > 1 {
return Err ( Error ::Validation ( format! ( " too many memory regions in index space: {} " , self . imports . memory_regions_len ( ) + self . memory . len ( ) ) ) ) ;
}
// for every function section entry there must be corresponding entry in code section and type && vice versa
let function_section_len = self . module . function_section ( ) . map ( | s | s . entries ( ) . len ( ) ) . unwrap_or ( 0 ) ;
let code_section_len = self . module . code_section ( ) . map ( | s | s . bodies ( ) . len ( ) ) . unwrap_or ( 0 ) ;
if function_section_len ! = code_section_len {
return Err ( Error ::Validation ( format! ( " length of function section is {} , while len of code section is {} " , function_section_len , code_section_len ) ) ) ;
}
// validate every function body in user modules
2017-06-09 12:13:35 +03:00
if is_user_module & & function_section_len ! = 0 { // tests use invalid code
2017-06-08 10:49:32 +03:00
let function_section = self . module . function_section ( ) . expect ( " function_section_len != 0; qed " ) ;
let code_section = self . module . code_section ( ) . expect ( " function_section_len != 0; function_section_len == code_section_len; qed " ) ;
// check every function body
for ( index , function ) in function_section . entries ( ) . iter ( ) . enumerate ( ) {
2017-06-23 10:39:31 +03:00
let function_labels = {
2017-06-26 11:54:17 +03:00
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 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 ) ) ) ;
2017-06-23 10:39:31 +03:00
let mut context = FunctionValidationContext ::new (
self ,
& locals ,
DEFAULT_VALUE_STACK_LIMIT ,
DEFAULT_FRAME_STACK_LIMIT ,
2017-06-26 11:54:17 +03:00
function_type . clone ( ) ) ;
2017-06-23 10:39:31 +03:00
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 ( ) )
. map_err ( | e | {
if let Error ::Validation ( msg ) = e {
Error ::Validation ( format! ( " Function # {} validation error: {} " , index , msg ) )
} else {
e
}
} ) ? ;
context . function_labels ( )
} ;
self . functions_labels . insert ( index as u32 , function_labels ) ;
2017-06-07 14:48:02 +03:00
}
}
2017-05-04 11:25:25 +03:00
// use data section to initialize linear memory regions
if let Some ( data_section ) = self . module . data_section ( ) {
for ( data_segment_index , data_segment ) in data_section . entries ( ) . iter ( ) . enumerate ( ) {
2017-06-13 12:01:59 +03:00
let offset : u32 = get_initializer ( data_segment . offset ( ) , & self . module , & self . imports , VariableType ::I32 ) ? . try_into ( ) ? ;
2017-05-04 11:25:25 +03:00
self . memory ( ItemIndex ::IndexSpace ( data_segment . index ( ) ) )
. map_err ( | e | Error ::Initialization ( format! ( " DataSegment {} initializes non-existant MemoryInstance {} : {:?} " , data_segment_index , data_segment . index ( ) , e ) ) )
. and_then ( | m | m . set ( offset , data_segment . value ( ) ) )
. map_err ( | e | Error ::Initialization ( e . into ( ) ) ) ? ;
}
}
// use element section to fill tables
if let Some ( element_section ) = self . module . elements_section ( ) {
for ( element_segment_index , element_segment ) in element_section . entries ( ) . iter ( ) . enumerate ( ) {
2017-06-13 12:01:59 +03:00
let offset : u32 = get_initializer ( element_segment . offset ( ) , & self . module , & self . imports , VariableType ::I32 ) ? . try_into ( ) ? ;
2017-06-08 10:49:32 +03:00
for function_index in element_segment . members ( ) {
self . require_function ( ItemIndex ::IndexSpace ( * function_index ) ) ? ;
}
2017-05-04 11:25:25 +03:00
self . table ( ItemIndex ::IndexSpace ( element_segment . index ( ) ) )
. map_err ( | e | Error ::Initialization ( format! ( " ElementSegment {} initializes non-existant Table {} : {:?} " , element_segment_index , element_segment . index ( ) , e ) ) )
2017-06-13 12:01:59 +03:00
. and_then ( | m | m . set_raw ( offset , self . name . clone ( ) , element_segment . members ( ) ) )
2017-05-04 11:25:25 +03:00
. map_err ( | e | Error ::Initialization ( e . into ( ) ) ) ? ;
}
}
2017-06-22 17:52:05 +03:00
Ok ( ( ) )
}
2017-06-23 10:39:31 +03:00
/// Run start function [if any].
2017-06-22 17:52:05 +03:00
pub fn run_start_function ( & self ) -> Result < ( ) , Error > {
2017-06-09 12:13:35 +03:00
// execute start function (if any)
if let Some ( start_function ) = self . module . start_section ( ) {
self . execute_index ( start_function , ExecutionParams ::default ( ) ) ? ;
}
2017-05-04 11:25:25 +03:00
Ok ( ( ) )
}
2017-06-08 10:49:32 +03:00
2017-06-22 17:52:05 +03:00
fn self_ref < ' a > ( & self , externals : Option < & ' a HashMap < String , Arc < ModuleInstanceInterface + ' a > > > ) -> Result < Arc < ModuleInstanceInterface + ' a > , Error > {
2017-06-23 14:11:09 +03:00
self . imports . module ( externals , & self . name )
2017-06-22 17:52:05 +03:00
}
fn require_function ( & self , index : ItemIndex ) -> Result < u32 , Error > {
match self . imports . parse_function_index ( index ) {
ItemIndex ::IndexSpace ( _ ) = > unreachable! ( " parse_function_index resolves IndexSpace option " ) ,
ItemIndex ::Internal ( index ) = > self . module . function_section ( )
. ok_or ( Error ::Function ( format! ( " missing internal function {} " , index ) ) )
. and_then ( | s | s . entries ( ) . get ( index as usize )
. ok_or ( Error ::Function ( format! ( " missing internal function {} " , index ) ) ) )
. map ( | f | f . type_ref ( ) ) ,
ItemIndex ::External ( index ) = > self . module . import_section ( )
. ok_or ( Error ::Function ( format! ( " missing external function {} " , index ) ) )
. and_then ( | s | s . entries ( ) . get ( index as usize )
. ok_or ( Error ::Function ( format! ( " missing external function {} " , index ) ) ) )
. and_then ( | import | match import . external ( ) {
& External ::Function ( type_idx ) = > Ok ( type_idx ) ,
_ = > Err ( Error ::Function ( format! ( " external function {} is pointing to non-function import " , index ) ) ) ,
} ) ,
}
}
}
impl ModuleInstanceInterface for ModuleInstance {
2017-05-18 15:08:55 +03:00
fn execute_index ( & self , index : u32 , params : ExecutionParams ) -> Result < Option < RuntimeValue > , Error > {
2017-06-16 12:23:49 +03:00
let ExecutionParams { args , externals } = params ;
let mut args = StackWithLimit ::with_data ( args , DEFAULT_VALUE_STACK_LIMIT ) ;
let function_reference = self . function_reference ( ItemIndex ::IndexSpace ( index ) , Some ( & externals ) ) ? ;
let function_context = CallerContext ::topmost ( & mut args , & externals ) ;
2017-06-19 12:04:16 +03:00
function_reference . module . call_internal_function ( function_context , function_reference . internal_index )
2017-04-27 14:44:03 +03:00
}
2017-05-18 15:08:55 +03:00
fn execute_export ( & self , name : & str , params : ExecutionParams ) -> Result < Option < RuntimeValue > , Error > {
2017-05-04 19:09:43 +03:00
let index = self . module . export_section ( )
. ok_or ( Error ::Function ( " missing export section " . into ( ) ) )
. and_then ( | s | s . entries ( ) . iter ( )
. find ( | e | e . field ( ) = = name & & match e . internal ( ) {
& Internal ::Function ( _ ) = > true ,
_ = > false ,
} )
. ok_or ( Error ::Function ( format! ( " missing export section exported function with name {} " , name ) ) )
. map ( | e | match e . internal ( ) {
& Internal ::Function ( index ) = > index ,
_ = > unreachable! ( ) , // checked couple of lines above
} )
) ? ;
2017-05-18 15:08:55 +03:00
self . execute_index ( index , params )
2017-05-04 19:09:43 +03:00
}
2017-06-19 12:35:17 +03:00
fn export_entry < ' a > ( & self , name : & str , required_type : & ExportEntryType ) -> Result < Internal , Error > {
2017-05-18 15:08:55 +03:00
self . module . export_section ( )
. ok_or ( Error ::Program ( format! ( " trying to import {} from module without export section " , name ) ) )
. and_then ( | s | s . entries ( ) . iter ( )
2017-06-13 12:01:59 +03:00
. find ( | e | e . field ( ) = = name & & match required_type {
& ExportEntryType ::Any = > true ,
& ExportEntryType ::Global ( global_type ) = > match e . internal ( ) {
& Internal ::Global ( global_index ) = > self . global ( ItemIndex ::IndexSpace ( global_index ) , Some ( global_type ) ) . map ( | _ | true ) . unwrap_or ( false ) ,
_ = > false ,
} ,
& ExportEntryType ::Function ( ref required_type ) = > match e . internal ( ) {
& Internal ::Function ( function_index ) = >
2017-06-19 12:35:17 +03:00
self . function_type ( ItemIndex ::IndexSpace ( function_index ) )
2017-06-26 11:54:17 +03:00
. map ( | ft | ft = = * required_type )
2017-06-13 12:01:59 +03:00
. unwrap_or ( false ) ,
_ = > false ,
} ,
} )
2017-05-18 15:08:55 +03:00
. map ( | e | * e . internal ( ) )
. ok_or ( Error ::Program ( format! ( " unresolved import {} " , name ) ) ) )
2017-04-21 14:35:12 +03:00
}
2017-05-04 11:25:25 +03:00
fn table ( & self , index : ItemIndex ) -> Result < Arc < TableInstance > , Error > {
2017-04-21 14:35:12 +03:00
match self . imports . parse_table_index ( index ) {
ItemIndex ::IndexSpace ( _ ) = > unreachable! ( " parse_table_index resolves IndexSpace option " ) ,
ItemIndex ::Internal ( index ) = > self . tables . get ( index as usize ) . cloned ( )
. ok_or ( Error ::Table ( format! ( " trying to access table with local index {} when there are only {} local tables " , index , self . tables . len ( ) ) ) ) ,
ItemIndex ::External ( index ) = > self . module . import_section ( )
. ok_or ( Error ::Table ( format! ( " trying to access external table with index {} in module without import section " , index ) ) )
. and_then ( | s | s . entries ( ) . get ( index as usize )
. ok_or ( Error ::Table ( format! ( " trying to access external table with index {} in module with {} -entries import section " , index , s . entries ( ) . len ( ) ) ) ) )
2017-05-18 15:08:55 +03:00
. and_then ( | e | self . imports . table ( None , e ) ) ,
2017-04-21 14:35:12 +03:00
}
}
2017-05-04 11:25:25 +03:00
fn memory ( & self , index : ItemIndex ) -> Result < Arc < MemoryInstance > , Error > {
2017-04-21 14:35:12 +03:00
match self . imports . parse_memory_index ( index ) {
ItemIndex ::IndexSpace ( _ ) = > unreachable! ( " parse_memory_index resolves IndexSpace option " ) ,
ItemIndex ::Internal ( index ) = > self . memory . get ( index as usize ) . cloned ( )
. ok_or ( Error ::Memory ( format! ( " trying to access memory with local index {} when there are only {} memory regions " , index , self . memory . len ( ) ) ) ) ,
ItemIndex ::External ( index ) = > self . module . import_section ( )
. ok_or ( Error ::Memory ( format! ( " trying to access external memory with index {} in module without import section " , index ) ) )
. and_then ( | s | s . entries ( ) . get ( index as usize )
. ok_or ( Error ::Memory ( format! ( " trying to access external memory with index {} in module with {} -entries import section " , index , s . entries ( ) . len ( ) ) ) ) )
2017-05-18 15:08:55 +03:00
. and_then ( | e | self . imports . memory ( None , e ) ) ,
2017-04-21 14:35:12 +03:00
}
}
2017-06-13 12:01:59 +03:00
fn global ( & self , index : ItemIndex , variable_type : Option < VariableType > ) -> Result < Arc < VariableInstance > , Error > {
2017-04-21 14:35:12 +03:00
match self . imports . parse_global_index ( index ) {
ItemIndex ::IndexSpace ( _ ) = > unreachable! ( " parse_global_index resolves IndexSpace option " ) ,
ItemIndex ::Internal ( index ) = > self . globals . get ( index as usize ) . cloned ( )
. ok_or ( Error ::Global ( format! ( " trying to access global with local index {} when there are only {} globals " , index , self . globals . len ( ) ) ) ) ,
ItemIndex ::External ( index ) = > self . module . import_section ( )
. ok_or ( Error ::Global ( format! ( " trying to access external global with index {} in module without import section " , index ) ) )
. and_then ( | s | s . entries ( ) . get ( index as usize )
. ok_or ( Error ::Global ( format! ( " trying to access external global with index {} in module with {} -entries import section " , index , s . entries ( ) . len ( ) ) ) ) )
2017-06-13 12:01:59 +03:00
. and_then ( | e | self . imports . global ( None , e , variable_type ) ) ,
2017-04-21 14:35:12 +03:00
}
}
2017-06-26 11:54:17 +03:00
fn function_type ( & self , function_index : ItemIndex ) -> Result < FunctionSignature , Error > {
2017-06-19 12:04:16 +03:00
match self . imports . parse_function_index ( function_index ) {
ItemIndex ::IndexSpace ( _ ) = > unreachable! ( " parse_function_index resolves IndexSpace option " ) ,
ItemIndex ::Internal ( index ) = > self . require_function ( ItemIndex ::Internal ( index ) )
. and_then ( | ft | self . function_type_by_index ( ft ) ) ,
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 ) ) )
. 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 ( ) ) ) ) )
. and_then ( | e | match e . external ( ) {
& External ::Function ( type_index ) = > self . function_type_by_index ( type_index ) ,
_ = > Err ( Error ::Function ( format! ( " exported function {} is not a function " , index ) ) ) ,
} ) ,
}
}
2017-06-26 11:54:17 +03:00
fn function_type_by_index ( & self , type_index : u32 ) -> Result < FunctionSignature , Error > {
2017-06-19 12:04:16 +03:00
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 ) ) ) ,
} )
2017-06-26 11:54:17 +03:00
. map ( FunctionSignature ::Module )
2017-06-19 12:04:16 +03:00
}
2017-06-16 12:23:49 +03:00
fn function_reference < ' a > ( & self , index : ItemIndex , externals : Option < & ' a HashMap < String , Arc < ModuleInstanceInterface + ' a > > > ) -> Result < InternalFunctionReference < ' a > , Error > {
2017-04-21 14:35:12 +03:00
match self . imports . parse_function_index ( index ) {
ItemIndex ::IndexSpace ( _ ) = > unreachable! ( " parse_function_index resolves IndexSpace option " ) ,
2017-06-16 12:23:49 +03:00
ItemIndex ::Internal ( index ) = > Ok ( InternalFunctionReference {
module : self . self_ref ( externals ) ? ,
internal_index : index ,
} ) ,
ItemIndex ::External ( index ) = > {
2017-06-19 12:04:16 +03:00
let import_entry = self . module . import_section ( )
. expect ( " parse_function_index has returned External(index); it is only returned when import section exists; qed " )
. 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 " ) ;
2017-06-19 12:35:17 +03:00
let required_function_type = self . function_type ( ItemIndex ::External ( index ) ) ? ;
2017-06-26 11:54:17 +03:00
let internal_function_index = self . imports . function ( externals , import_entry , Some ( required_function_type ) ) ? ;
2017-06-16 12:23:49 +03:00
Ok ( InternalFunctionReference {
module : self . imports . module ( externals , import_entry . module ( ) ) ? ,
2017-06-19 11:01:59 +03:00
internal_index : internal_function_index ,
2017-06-16 12:23:49 +03:00
} )
} ,
2017-04-21 14:35:12 +03:00
}
}
2017-04-26 15:41:22 +03:00
2017-06-16 12:23:49 +03:00
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 table = self . table ( ItemIndex ::IndexSpace ( table_idx ) ) ? ;
let ( module , index ) = match table . get ( func_idx ) ? {
2017-06-13 12:01:59 +03:00
RuntimeValue ::AnyFunc ( module , index ) = > ( module . clone ( ) , index ) ,
2017-06-16 12:23:49 +03:00
_ = > return Err ( Error ::Function ( format! ( " trying to indirect call function {} via non-anyfunc table {:?} " , func_idx , table_idx ) ) ) ,
2017-06-13 12:01:59 +03:00
} ;
2017-06-16 12:23:49 +03:00
let module = self . imports . module ( externals , & module ) ? ;
2017-06-19 12:04:16 +03:00
let required_function_type = self . function_type_by_index ( type_idx ) ? ;
2017-06-19 12:35:17 +03:00
let actual_function_type = module . function_type ( ItemIndex ::IndexSpace ( index ) ) ? ;
2017-06-19 12:04:16 +03:00
if required_function_type ! = actual_function_type {
return Err ( Error ::Function ( format! ( " expected indirect function with signature ( {:?} ) -> {:?} when got with ( {:?} ) -> {:?} " ,
required_function_type . params ( ) , required_function_type . return_type ( ) ,
actual_function_type . params ( ) , actual_function_type . return_type ( ) ) ) ) ;
}
2017-06-16 12:23:49 +03:00
module . function_reference ( ItemIndex ::IndexSpace ( index ) , externals )
2017-04-26 15:41:22 +03:00
}
2017-05-02 08:37:48 +03:00
2017-06-19 12:04:16 +03:00
fn function_body < ' a > ( & ' a self , internal_index : u32 ) -> Result < Option < InternalFunction < ' a > > , Error > {
2017-05-02 08:37:48 +03:00
let function_body = self . module
. code_section ( )
2017-06-16 12:23:49 +03:00
. ok_or ( Error ::Function ( format! ( " trying to call function with index {} in module without code section " , internal_index ) ) )
2017-05-02 08:37:48 +03:00
. and_then ( | s | s . bodies ( )
2017-06-16 12:23:49 +03:00
. 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 ( ) ) ) ) ) ? ;
2017-06-22 17:52:05 +03:00
let function_labels = self . functions_labels . get ( & internal_index )
. ok_or ( Error ::Function ( format! ( " trying to call non-validated internal function {} " , internal_index ) ) ) ? ;
2017-06-16 12:23:49 +03:00
Ok ( Some ( InternalFunction {
locals : function_body . locals ( ) ,
body : function_body . code ( ) . elements ( ) ,
2017-06-22 17:52:05 +03:00
labels : function_labels ,
2017-06-16 12:23:49 +03:00
} ) )
}
2017-06-19 12:04:16 +03:00
fn call_internal_function ( & self , mut outer : CallerContext , index : u32 ) -> Result < Option < RuntimeValue > , Error > {
2017-06-22 17:52:05 +03:00
let function_labels = self . functions_labels . get ( & index ) . ok_or ( Error ::Function ( format! ( " trying to call non-validated internal function {} " , index ) ) ) ? ;
2017-06-19 12:35:17 +03:00
let function_type = self . function_type ( ItemIndex ::Internal ( index ) ) ? ;
let args = prepare_function_args ( & function_type , outer . value_stack ) ? ;
2017-06-16 12:23:49 +03:00
let function_ref = InternalFunctionReference { module : self . self_ref ( Some ( outer . externals ) ) ? , internal_index : index } ;
2017-06-22 17:52:05 +03:00
let inner = FunctionContext ::new ( function_ref , outer . externals , function_labels . clone ( ) , outer . value_stack_limit , outer . frame_stack_limit , & function_type , args ) ;
2017-06-16 12:23:49 +03:00
Interpreter ::run_function ( inner )
2017-05-02 08:37:48 +03:00
}
2017-04-21 14:35:12 +03:00
}
2017-04-28 13:34:58 +03:00
impl < ' a > CallerContext < ' a > {
2017-05-15 15:40:08 +03:00
/// Top most args
2017-05-19 09:36:50 +03:00
pub fn topmost ( args : & ' a mut StackWithLimit < RuntimeValue > , externals : & ' a HashMap < String , Arc < ModuleInstanceInterface + ' a > > ) -> Self {
2017-04-28 13:34:58 +03:00
CallerContext {
2017-06-07 14:48:02 +03:00
value_stack_limit : DEFAULT_VALUE_STACK_LIMIT ,
frame_stack_limit : DEFAULT_FRAME_STACK_LIMIT ,
2017-04-28 13:34:58 +03:00
value_stack : args ,
2017-05-18 15:08:55 +03:00
externals : externals ,
2017-04-28 13:34:58 +03:00
}
}
2017-05-15 15:40:08 +03:00
/// Nested context
2017-04-28 13:34:58 +03:00
pub fn nested ( outer : & ' a mut FunctionContext ) -> Self {
CallerContext {
value_stack_limit : outer . value_stack ( ) . limit ( ) - outer . value_stack ( ) . len ( ) ,
frame_stack_limit : outer . frame_stack ( ) . limit ( ) - outer . frame_stack ( ) . len ( ) ,
2017-05-18 15:08:55 +03:00
value_stack : & mut outer . value_stack ,
externals : & outer . externals ,
2017-04-28 13:34:58 +03:00
}
}
}
2017-06-08 10:49:32 +03:00
pub fn check_limits ( limits : & ResizableLimits ) -> Result < ( ) , Error > {
if let Some ( maximum ) = limits . maximum ( ) {
if maximum < limits . initial ( ) {
return Err ( Error ::Validation ( format! ( " maximum limit {} is lesser than minimum {} " , maximum , limits . initial ( ) ) ) ) ;
}
}
Ok ( ( ) )
}
2017-06-13 12:01:59 +03:00
fn get_initializer ( expr : & InitExpr , module : & Module , imports : & ModuleImports , expected_type : VariableType ) -> Result < RuntimeValue , Error > {
2017-06-09 12:13:35 +03:00
let first_opcode = match expr . code ( ) . len ( ) {
1 = > & expr . code ( ) [ 0 ] ,
2 if expr . code ( ) . len ( ) = = 2 & & expr . code ( ) [ 1 ] = = Opcode ::End = > & expr . code ( ) [ 0 ] ,
_ = > return Err ( Error ::Initialization ( format! ( " expected 1-instruction len initializer. Got {:?} " , expr . code ( ) ) ) ) ,
} ;
2017-04-21 14:35:12 +03:00
match first_opcode {
2017-05-04 19:09:43 +03:00
& Opcode ::GetGlobal ( index ) = > {
let index = match imports . parse_global_index ( ItemIndex ::IndexSpace ( index ) ) {
ItemIndex ::External ( index ) = > index ,
_ = > return Err ( Error ::Global ( format! ( " trying to initialize with non-external global {} " , index ) ) ) ,
} ;
module . import_section ( )
. ok_or ( Error ::Global ( format! ( " trying to initialize with external global with index {} in module without import section " , index ) ) )
. and_then ( | s | s . entries ( ) . get ( index as usize )
. ok_or ( Error ::Global ( format! ( " trying to initialize with external global with index {} in module with {} -entries import section " , index , s . entries ( ) . len ( ) ) ) ) )
2017-06-13 12:01:59 +03:00
. and_then ( | e | imports . global ( None , e , Some ( expected_type ) ) )
2017-05-04 19:09:43 +03:00
. map ( | g | g . get ( ) )
} ,
2017-04-21 14:35:12 +03:00
& Opcode ::I32Const ( val ) = > Ok ( RuntimeValue ::I32 ( val ) ) ,
& Opcode ::I64Const ( val ) = > Ok ( RuntimeValue ::I64 ( val ) ) ,
2017-05-31 18:43:09 +02:00
& Opcode ::F32Const ( val ) = > Ok ( RuntimeValue ::decode_f32 ( val ) ) ,
& Opcode ::F64Const ( val ) = > Ok ( RuntimeValue ::decode_f64 ( val ) ) ,
2017-04-21 14:35:12 +03:00
_ = > Err ( Error ::Initialization ( format! ( " not-supported {:?} instruction in instantiation-time initializer " , first_opcode ) ) ) ,
}
}
2017-06-26 11:54:17 +03:00
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 )
}
}