2017-05-08 11:35:56 +03:00
use std ::sync ::{ Arc , Weak } ;
2017-06-13 12:01:59 +03:00
use std ::collections ::HashMap ;
2017-05-15 13:58:55 +03:00
2017-05-18 15:08:55 +03:00
use builder ::module ;
2017-05-08 11:35:56 +03:00
use elements ::{ Module , FunctionType , ExportEntry , Internal , GlobalEntry , GlobalType ,
ValueType , InitExpr , Opcode , Opcodes } ;
2017-05-04 11:25:25 +03:00
use interpreter ::Error ;
2017-05-18 15:08:55 +03:00
use interpreter ::env_native ::NATIVE_INDEX_FUNC_MIN ;
use interpreter ::module ::{ ModuleInstanceInterface , ModuleInstance , ExecutionParams ,
2017-06-13 12:01:59 +03:00
ItemIndex , CallerContext , ExportEntryType } ;
2017-05-08 11:35:56 +03:00
use interpreter ::memory ::{ MemoryInstance , LINEAR_MEMORY_PAGE_SIZE } ;
2017-05-04 11:25:25 +03:00
use interpreter ::table ::TableInstance ;
2017-05-31 18:43:09 +02:00
use interpreter ::value ::RuntimeValue ;
2017-06-13 12:01:59 +03:00
use interpreter ::variable ::{ VariableInstance , VariableType } ;
2017-05-08 11:35:56 +03:00
/// Memory address, at which stack begins.
const DEFAULT_STACK_BASE : u32 = 0 ;
/// Memory, allocated for stack.
const DEFAULT_TOTAL_STACK : u32 = 5 * 1024 * 1024 ;
/// Total memory, allocated by default.
const DEFAULT_TOTAL_MEMORY : u32 = 16 * 1024 * 1024 ;
/// Whether memory can be enlarged, or not.
const DEFAULT_ALLOW_MEMORY_GROWTH : bool = false ;
/// Default tableBase variable value.
const DEFAULT_TABLE_BASE : u32 = 0 ;
/// Defaul table size.
const DEFAULT_TABLE_SIZE : u32 = 16 ;
/// Index of default memory.
const INDEX_MEMORY : u32 = 0 ;
/// Index of default table.
const INDEX_TABLE : u32 = 0 ;
/// Index of STACK_BASE global variable.
const INDEX_GLOBAL_STACK_BASE : u32 = 0 ;
/// Index of STACK_TOP global variable.
const INDEX_GLOBAL_STACK_TOP : u32 = 1 ;
/// Index of STACK_MAX global variable.
const INDEX_GLOBAL_STACK_MAX : u32 = 2 ;
/// Index of DYNAMIC_BASE global variable.
const INDEX_GLOBAL_DYNAMIC_BASE : u32 = 3 ;
/// Index of DYNAMICTOP_PTR global variable.
const INDEX_GLOBAL_DYNAMICTOP_PTR : u32 = 4 ;
/// Index of TOTAL_MEMORY global variable.
const INDEX_GLOBAL_TOTAL_MEMORY : u32 = 5 ;
/// Index of ABORT global variable.
const INDEX_GLOBAL_ABORT : u32 = 6 ;
/// Index of EXITSTATUS global variable.
const INDEX_GLOBAL_EXIT_STATUS : u32 = 7 ;
/// Index of tableBase global variable.
const INDEX_GLOBAL_TABLE_BASE : u32 = 8 ;
/// Index of abort function.
const INDEX_FUNC_ABORT : u32 = 0 ;
/// Index of assert function.
const INDEX_FUNC_ASSERT : u32 = 1 ;
/// Index of enlargeMemory function.
const INDEX_FUNC_ENLARGE_MEMORY : u32 = 2 ;
/// Index of getTotalMemory function.
const INDEX_FUNC_GET_TOTAL_MEMORY : u32 = 3 ;
/// Min index of reserver function.
2017-05-18 15:08:55 +03:00
const INDEX_FUNC_MIN_NONUSED : u32 = 4 ;
2017-05-08 11:35:56 +03:00
/// Max index of reserved function.
2017-05-18 15:08:55 +03:00
const INDEX_FUNC_MAX : u32 = NATIVE_INDEX_FUNC_MIN - 1 ;
2017-05-15 13:58:55 +03:00
2017-05-08 11:35:56 +03:00
/// Environment parameters.
pub struct EnvParams {
/// Stack size in bytes.
pub total_stack : u32 ,
/// Total memory size in bytes.
pub total_memory : u32 ,
/// Allow memory growth.
pub allow_memory_growth : bool ,
}
2017-05-04 19:09:43 +03:00
2017-05-04 11:25:25 +03:00
pub struct EnvModuleInstance {
2017-05-08 11:35:56 +03:00
_params : EnvParams ,
instance : ModuleInstance ,
2017-05-04 11:25:25 +03:00
}
impl EnvModuleInstance {
2017-05-18 15:08:55 +03:00
pub fn new ( params : EnvParams , module : Module ) -> Result < Self , Error > {
2017-06-13 12:01:59 +03:00
let instance = ModuleInstance ::new ( Weak ::default ( ) , " env " . into ( ) , module ) ? ;
2017-05-08 11:35:56 +03:00
2017-05-04 11:25:25 +03:00
Ok ( EnvModuleInstance {
2017-05-08 11:35:56 +03:00
_params : params ,
instance : instance ,
2017-05-04 11:25:25 +03:00
} )
}
}
impl ModuleInstanceInterface for EnvModuleInstance {
2017-06-13 12:01:59 +03:00
fn instantiate < ' a > ( & self , is_user_module : bool , externals : Option < & ' a HashMap < String , Arc < ModuleInstanceInterface + ' a > > > ) -> Result < ( ) , Error > {
self . instance . instantiate ( is_user_module , externals )
}
2017-05-18 15:08:55 +03:00
fn execute_index ( & self , index : u32 , params : ExecutionParams ) -> Result < Option < RuntimeValue > , Error > {
self . instance . execute_index ( index , params )
2017-05-04 19:09:43 +03:00
}
2017-05-18 15:08:55 +03:00
fn execute_export ( & self , name : & str , params : ExecutionParams ) -> Result < Option < RuntimeValue > , Error > {
self . instance . execute_export ( name , params )
2017-05-04 11:25:25 +03:00
}
2017-06-13 12:01:59 +03:00
fn export_entry < ' a > ( & self , name : & str , externals : Option < & ' a HashMap < String , Arc < ModuleInstanceInterface + ' a > > > , required_type : & ExportEntryType ) -> Result < Internal , Error > {
self . instance . export_entry ( name , externals , required_type )
}
fn function_type < ' a > ( & self , function_index : ItemIndex , externals : Option < & ' a HashMap < String , Arc < ModuleInstanceInterface + ' a > > > ) -> Result < FunctionType , Error > {
self . instance . function_type ( function_index , externals )
2017-05-04 11:25:25 +03:00
}
2017-05-04 19:09:43 +03:00
fn table ( & self , index : ItemIndex ) -> Result < Arc < TableInstance > , Error > {
2017-05-08 11:35:56 +03:00
self . instance . table ( index )
2017-05-04 11:25:25 +03:00
}
2017-05-04 12:01:21 +03:00
fn memory ( & self , index : ItemIndex ) -> Result < Arc < MemoryInstance > , Error > {
2017-05-08 11:35:56 +03:00
self . instance . memory ( index )
2017-05-04 11:25:25 +03:00
}
2017-06-13 12:01:59 +03:00
fn global ( & self , index : ItemIndex , variable_type : Option < VariableType > ) -> Result < Arc < VariableInstance > , Error > {
self . instance . global ( index , variable_type )
2017-05-04 11:25:25 +03:00
}
2017-06-13 12:01:59 +03:00
fn call_function ( & self , outer : CallerContext , index : ItemIndex , function_type : Option < & FunctionType > ) -> Result < Option < RuntimeValue > , Error > {
self . instance . call_function ( outer , index , function_type )
2017-05-04 11:25:25 +03:00
}
2017-05-08 11:35:56 +03:00
fn call_function_indirect ( & self , outer : CallerContext , table_index : ItemIndex , type_index : u32 , func_index : u32 ) -> Result < Option < RuntimeValue > , Error > {
self . instance . call_function_indirect ( outer , table_index , type_index , func_index )
2017-05-04 11:25:25 +03:00
}
2017-05-04 19:50:48 +03:00
fn call_internal_function ( & self , outer : CallerContext , index : u32 , _function_type : Option < & FunctionType > ) -> Result < Option < RuntimeValue > , Error > {
2017-05-18 15:08:55 +03:00
// TODO: check function type
2017-05-08 11:35:56 +03:00
// to make interpreter independent of *SCRIPTEN runtime, just make abort/assert = interpreter Error
2017-05-04 19:30:42 +03:00
match index {
2017-06-13 12:01:59 +03:00
INDEX_FUNC_ABORT = > self . global ( ItemIndex ::IndexSpace ( INDEX_GLOBAL_ABORT ) , Some ( VariableType ::I32 ) )
2017-05-08 11:35:56 +03:00
. and_then ( | g | g . set ( RuntimeValue ::I32 ( 1 ) ) )
. and_then ( | _ | Err ( Error ::Trap ( " abort " . into ( ) ) ) ) ,
INDEX_FUNC_ASSERT = > outer . value_stack . pop_as ::< i32 > ( )
. and_then ( | condition | if condition = = 0 {
2017-06-13 12:01:59 +03:00
self . global ( ItemIndex ::IndexSpace ( INDEX_GLOBAL_ABORT ) , Some ( VariableType ::I32 ) )
2017-05-08 11:35:56 +03:00
. and_then ( | g | g . set ( RuntimeValue ::I32 ( 1 ) ) )
. and_then ( | _ | Err ( Error ::Trap ( " assertion failed " . into ( ) ) ) )
} else {
Ok ( None )
} ) ,
INDEX_FUNC_ENLARGE_MEMORY = > Ok ( Some ( RuntimeValue ::I32 ( 0 ) ) ) , // TODO: support memory enlarge
2017-06-13 12:01:59 +03:00
INDEX_FUNC_GET_TOTAL_MEMORY = > self . global ( ItemIndex ::IndexSpace ( INDEX_GLOBAL_TOTAL_MEMORY ) , Some ( VariableType ::I32 ) )
2017-05-08 11:35:56 +03:00
. map ( | g | g . get ( ) )
. map ( Some ) ,
INDEX_FUNC_MIN_NONUSED .. . INDEX_FUNC_MAX = > Err ( Error ::Trap ( " unimplemented " . into ( ) ) ) ,
2017-05-15 15:40:08 +03:00
_ = > Err ( Error ::Trap ( format! ( " trying to call function with index {} in env module " , index ) ) ) ,
2017-05-04 19:30:42 +03:00
}
2017-05-04 11:25:25 +03:00
}
}
2017-05-30 17:15:36 +03:00
pub fn env_module ( params : EnvParams ) -> Result < EnvModuleInstance , Error > {
debug_assert! ( params . total_stack < params . total_memory ) ;
debug_assert! ( ( params . total_stack % LINEAR_MEMORY_PAGE_SIZE ) = = 0 ) ;
debug_assert! ( ( params . total_memory % LINEAR_MEMORY_PAGE_SIZE ) = = 0 ) ;
2017-05-18 15:08:55 +03:00
let builder = module ( )
2017-05-04 19:09:43 +03:00
// memory regions
2017-05-08 11:35:56 +03:00
. memory ( )
2017-05-30 17:15:36 +03:00
. with_min ( params . total_memory / LINEAR_MEMORY_PAGE_SIZE )
. with_max ( params . max_memory ( ) . map ( | m | m / LINEAR_MEMORY_PAGE_SIZE ) )
2017-05-08 11:35:56 +03:00
. build ( )
. with_export ( ExportEntry ::new ( " memory " . into ( ) , Internal ::Memory ( INDEX_MEMORY ) ) )
2017-05-04 19:09:43 +03:00
// tables
2017-05-08 11:35:56 +03:00
. table ( )
. with_min ( DEFAULT_TABLE_SIZE )
. build ( )
. with_export ( ExportEntry ::new ( " table " . into ( ) , Internal ::Table ( INDEX_TABLE ) ) )
2017-05-04 19:09:43 +03:00
// globals
2017-05-31 18:43:09 +02:00
. with_global ( GlobalEntry ::new ( GlobalType ::new ( ValueType ::I32 , false ) , InitExpr ::new ( vec! [ Opcode ::I32Const ( DEFAULT_STACK_BASE as i32 ) ] ) ) )
2017-05-08 11:35:56 +03:00
. with_export ( ExportEntry ::new ( " STACK_BASE " . into ( ) , Internal ::Global ( INDEX_GLOBAL_STACK_BASE ) ) )
2017-05-31 18:43:09 +02:00
. with_global ( GlobalEntry ::new ( GlobalType ::new ( ValueType ::I32 , true ) , InitExpr ::new ( vec! [ Opcode ::I32Const ( DEFAULT_STACK_BASE as i32 ) ] ) ) )
2017-05-08 11:35:56 +03:00
. with_export ( ExportEntry ::new ( " STACKTOP " . into ( ) , Internal ::Global ( INDEX_GLOBAL_STACK_TOP ) ) )
2017-05-31 18:43:09 +02:00
. with_global ( GlobalEntry ::new ( GlobalType ::new ( ValueType ::I32 , false ) , InitExpr ::new ( vec! [ Opcode ::I32Const ( ( DEFAULT_STACK_BASE + params . total_stack ) as i32 ) ] ) ) )
2017-05-08 11:35:56 +03:00
. with_export ( ExportEntry ::new ( " STACK_MAX " . into ( ) , Internal ::Global ( INDEX_GLOBAL_STACK_MAX ) ) )
2017-05-31 18:43:09 +02:00
. with_global ( GlobalEntry ::new ( GlobalType ::new ( ValueType ::I32 , false ) , InitExpr ::new ( vec! [ Opcode ::I32Const ( ( DEFAULT_STACK_BASE + params . total_stack ) as i32 ) ] ) ) )
2017-05-08 11:35:56 +03:00
. with_export ( ExportEntry ::new ( " DYNAMIC_BASE " . into ( ) , Internal ::Global ( INDEX_GLOBAL_DYNAMIC_BASE ) ) )
2017-05-31 18:43:09 +02:00
. with_global ( GlobalEntry ::new ( GlobalType ::new ( ValueType ::I32 , true ) , InitExpr ::new ( vec! [ Opcode ::I32Const ( ( DEFAULT_STACK_BASE + params . total_stack ) as i32 ) ] ) ) )
2017-05-08 11:35:56 +03:00
. with_export ( ExportEntry ::new ( " DYNAMICTOP_PTR " . into ( ) , Internal ::Global ( INDEX_GLOBAL_DYNAMICTOP_PTR ) ) )
2017-05-31 18:43:09 +02:00
. with_global ( GlobalEntry ::new ( GlobalType ::new ( ValueType ::I32 , params . allow_memory_growth ) , InitExpr ::new ( vec! [ Opcode ::I32Const ( params . total_memory as i32 ) ] ) ) )
2017-05-08 11:35:56 +03:00
. with_export ( ExportEntry ::new ( " TOTAL_MEMORY " . into ( ) , Internal ::Global ( INDEX_GLOBAL_TOTAL_MEMORY ) ) )
. with_global ( GlobalEntry ::new ( GlobalType ::new ( ValueType ::I32 , true ) , InitExpr ::new ( vec! [ Opcode ::I32Const ( 0 ) ] ) ) )
. with_export ( ExportEntry ::new ( " ABORT " . into ( ) , Internal ::Global ( INDEX_GLOBAL_ABORT ) ) )
. with_global ( GlobalEntry ::new ( GlobalType ::new ( ValueType ::I32 , true ) , InitExpr ::new ( vec! [ Opcode ::I32Const ( 0 ) ] ) ) )
. with_export ( ExportEntry ::new ( " EXITSTATUS " . into ( ) , Internal ::Global ( INDEX_GLOBAL_EXIT_STATUS ) ) )
2017-05-31 18:43:09 +02:00
. with_global ( GlobalEntry ::new ( GlobalType ::new ( ValueType ::I32 , false ) , InitExpr ::new ( vec! [ Opcode ::I32Const ( DEFAULT_TABLE_BASE as i32 ) ] ) ) ) // TODO: what is this?
2017-05-08 11:35:56 +03:00
. with_export ( ExportEntry ::new ( " tableBase " . into ( ) , Internal ::Global ( INDEX_GLOBAL_TABLE_BASE ) ) )
2017-05-04 19:09:43 +03:00
// functions
2017-05-08 11:35:56 +03:00
. function ( )
. signature ( ) . build ( )
. body ( ) . with_opcodes ( Opcodes ::new ( vec! [ Opcode ::Unreachable , Opcode ::End ] ) ) . build ( )
. build ( )
. with_export ( ExportEntry ::new ( " abort " . into ( ) , Internal ::Function ( INDEX_FUNC_ABORT ) ) )
. function ( )
. signature ( ) . param ( ) . i32 ( ) . build ( )
. body ( ) . with_opcodes ( Opcodes ::new ( vec! [ Opcode ::Unreachable , Opcode ::End ] ) ) . build ( )
. build ( )
. with_export ( ExportEntry ::new ( " assert " . into ( ) , Internal ::Function ( INDEX_FUNC_ASSERT ) ) )
. function ( )
. signature ( ) . return_type ( ) . i32 ( ) . build ( )
. body ( ) . with_opcodes ( Opcodes ::new ( vec! [ Opcode ::Unreachable , Opcode ::End ] ) ) . build ( )
. build ( )
. with_export ( ExportEntry ::new ( " enlargeMemory " . into ( ) , Internal ::Function ( INDEX_FUNC_ENLARGE_MEMORY ) ) )
. function ( )
. signature ( ) . return_type ( ) . i32 ( ) . build ( )
. body ( ) . with_opcodes ( Opcodes ::new ( vec! [ Opcode ::Unreachable , Opcode ::End ] ) ) . build ( )
. build ( )
2017-05-15 15:40:08 +03:00
. with_export ( ExportEntry ::new ( " getTotalMemory " . into ( ) , Internal ::Function ( INDEX_FUNC_GET_TOTAL_MEMORY ) ) ) ;
2017-05-15 13:58:55 +03:00
2017-05-30 17:15:36 +03:00
EnvModuleInstance ::new ( params , builder . build ( ) )
2017-05-08 11:35:56 +03:00
}
impl Default for EnvParams {
fn default ( ) -> Self {
EnvParams {
total_stack : DEFAULT_TOTAL_STACK ,
total_memory : DEFAULT_TOTAL_MEMORY ,
allow_memory_growth : DEFAULT_ALLOW_MEMORY_GROWTH ,
}
}
}
impl EnvParams {
fn max_memory ( & self ) -> Option < u32 > {
if self . allow_memory_growth { None } else { Some ( self . total_memory ) }
}
2017-05-04 11:25:25 +03:00
}