2017-05-03 11:06:26 +03:00
///! Basic tests for instructions/constructions, missing in wabt tests
2017-06-14 14:09:00 +03:00
use std ::sync ::{ Arc , Weak } ;
2017-05-03 11:06:26 +03:00
use builder ::module ;
use elements ::{ ExportEntry , Internal , ImportEntry , External , GlobalEntry , GlobalType ,
2017-06-14 14:09:00 +03:00
InitExpr , ValueType , BlockType , Opcodes , Opcode , FunctionType } ;
2017-05-03 11:06:26 +03:00
use interpreter ::Error ;
2017-06-14 17:07:22 +03:00
use interpreter ::env_native ::{ env_native_module , UserFunction , UserFunctions , UserFunctionExecutor , UserFunctionDescriptor } ;
2017-06-14 14:09:00 +03:00
use interpreter ::imports ::ModuleImports ;
2017-05-19 09:36:50 +03:00
use interpreter ::memory ::MemoryInstance ;
2017-06-21 09:23:20 +03:00
use interpreter ::module ::{ ModuleInstanceInterface , CallerContext , ItemIndex , ExecutionParams , ExportEntryType } ;
2017-05-03 11:06:26 +03:00
use interpreter ::program ::ProgramInstance ;
2017-06-14 14:09:00 +03:00
use interpreter ::validator ::{ FunctionValidationContext , Validator } ;
2017-05-03 11:06:26 +03:00
use interpreter ::value ::RuntimeValue ;
#[ test ]
fn import_function ( ) {
let module1 = module ( )
. with_export ( ExportEntry ::new ( " external_func " . into ( ) , Internal ::Function ( 0 ) ) )
. function ( )
. signature ( ) . return_type ( ) . i32 ( ) . build ( )
. body ( ) . with_opcodes ( Opcodes ::new ( vec! [
Opcode ::I32Const ( 3 ) ,
Opcode ::End ,
] ) ) . build ( )
. build ( )
. build ( ) ;
let module2 = module ( )
. with_import ( ImportEntry ::new ( " external_module " . into ( ) , " external_func " . into ( ) , External ::Function ( 0 ) ) )
. function ( )
. signature ( ) . return_type ( ) . i32 ( ) . build ( )
. body ( ) . with_opcodes ( Opcodes ::new ( vec! [
Opcode ::Call ( 0 ) ,
Opcode ::I32Const ( 7 ) ,
Opcode ::I32Add ,
Opcode ::End ,
] ) ) . build ( )
. build ( )
. build ( ) ;
2017-05-04 19:54:51 +03:00
let program = ProgramInstance ::new ( ) . unwrap ( ) ;
2017-06-13 12:01:59 +03:00
let external_module = program . add_module ( " external_module " , module1 , None ) . unwrap ( ) ;
let main_module = program . add_module ( " main " , module2 , None ) . unwrap ( ) ;
2017-05-03 11:06:26 +03:00
2017-05-18 15:08:55 +03:00
assert_eq! ( external_module . execute_index ( 0 , vec! [ ] . into ( ) ) . unwrap ( ) . unwrap ( ) , RuntimeValue ::I32 ( 3 ) ) ;
assert_eq! ( main_module . execute_index ( 1 , vec! [ ] . into ( ) ) . unwrap ( ) . unwrap ( ) , RuntimeValue ::I32 ( 10 ) ) ;
2017-05-03 11:06:26 +03:00
}
2017-05-12 19:49:51 +03:00
#[ test ]
fn wrong_import ( ) {
let side_module = module ( )
. with_export ( ExportEntry ::new ( " cool_func " . into ( ) , Internal ::Function ( 0 ) ) )
. function ( )
. signature ( ) . return_type ( ) . i32 ( ) . build ( )
. body ( ) . with_opcodes ( Opcodes ::new ( vec! [
Opcode ::I32Const ( 3 ) ,
Opcode ::End ,
] ) ) . build ( )
. build ( )
. build ( ) ;
let module = module ( )
. with_import ( ImportEntry ::new ( " side_module " . into ( ) , " not_cool_func " . into ( ) , External ::Function ( 0 ) ) )
. function ( )
. signature ( ) . return_type ( ) . i32 ( ) . build ( )
. body ( ) . with_opcodes ( Opcodes ::new ( vec! [
Opcode ::Call ( 0 ) ,
Opcode ::I32Const ( 7 ) ,
Opcode ::I32Add ,
Opcode ::End ,
] ) ) . build ( )
. build ( )
. build ( ) ;
let program = ProgramInstance ::new ( ) . unwrap ( ) ;
2017-06-13 12:01:59 +03:00
let _side_module_instance = program . add_module ( " side_module " , side_module , None ) . unwrap ( ) ;
assert! ( program . add_module ( " main " , module , None ) . is_err ( ) ) ;
2017-05-12 19:49:51 +03:00
}
2017-05-03 11:06:26 +03:00
#[ test ]
fn global_get_set ( ) {
let module = module ( )
. with_global ( GlobalEntry ::new ( GlobalType ::new ( ValueType ::I32 , true ) , InitExpr ::new ( vec! [ Opcode ::I32Const ( 42 ) ] ) ) )
. with_global ( GlobalEntry ::new ( GlobalType ::new ( ValueType ::I32 , false ) , InitExpr ::new ( vec! [ Opcode ::I32Const ( 777 ) ] ) ) )
. function ( )
. signature ( ) . return_type ( ) . i32 ( ) . build ( )
. body ( ) . with_opcodes ( Opcodes ::new ( vec! [
Opcode ::GetGlobal ( 0 ) ,
Opcode ::I32Const ( 8 ) ,
Opcode ::I32Add ,
Opcode ::SetGlobal ( 0 ) ,
Opcode ::GetGlobal ( 0 ) ,
Opcode ::End ,
] ) ) . build ( )
. build ( )
. function ( )
. signature ( ) . return_type ( ) . i32 ( ) . build ( )
. body ( ) . with_opcodes ( Opcodes ::new ( vec! [
Opcode ::GetGlobal ( 1 ) ,
Opcode ::I32Const ( 8 ) ,
Opcode ::I32Add ,
Opcode ::SetGlobal ( 1 ) ,
Opcode ::GetGlobal ( 1 ) ,
Opcode ::End ,
] ) ) . build ( )
. build ( )
. function ( )
. signature ( ) . return_type ( ) . i32 ( ) . build ( )
. body ( ) . with_opcodes ( Opcodes ::new ( vec! [
Opcode ::I64Const ( 8 ) ,
Opcode ::SetGlobal ( 0 ) ,
Opcode ::GetGlobal ( 0 ) ,
Opcode ::End ,
] ) ) . build ( )
. build ( )
. build ( ) ;
2017-05-04 19:54:51 +03:00
let program = ProgramInstance ::new ( ) . unwrap ( ) ;
2017-06-13 12:01:59 +03:00
let module = program . add_module_without_validation ( " main " , module , None ) . unwrap ( ) ; // validation is failing (accessing immutable global)
2017-05-18 15:08:55 +03:00
assert_eq! ( module . execute_index ( 0 , vec! [ ] . into ( ) ) . unwrap ( ) . unwrap ( ) , RuntimeValue ::I32 ( 50 ) ) ;
assert_eq! ( module . execute_index ( 1 , vec! [ ] . into ( ) ) . unwrap_err ( ) , Error ::Variable ( " trying to update immutable variable " . into ( ) ) ) ;
assert_eq! ( module . execute_index ( 2 , vec! [ ] . into ( ) ) . unwrap_err ( ) , Error ::Variable ( " trying to update variable of type I32 with value of type Some(I64) " . into ( ) ) ) ;
2017-05-03 11:06:26 +03:00
}
2017-05-15 15:40:08 +03:00
2017-06-14 17:07:22 +03:00
const SIGNATURE_I32 : & 'static [ ValueType ] = & [ ValueType ::I32 ] ;
const SIGNATURES : & 'static [ UserFunction ] = & [
UserFunction {
desc : UserFunctionDescriptor ::Static (
" add " ,
SIGNATURE_I32 ,
) ,
result : Some ( ValueType ::I32 ) ,
} ,
UserFunction {
desc : UserFunctionDescriptor ::Static (
" sub " ,
SIGNATURE_I32 ,
) ,
result : Some ( ValueType ::I32 ) ,
} ,
] ;
2017-06-21 09:23:20 +03:00
// user function executor
struct FunctionExecutor {
pub memory : Arc < MemoryInstance > ,
pub values : Vec < i32 > ,
}
2017-05-19 09:36:50 +03:00
2017-06-21 09:23:20 +03:00
impl UserFunctionExecutor for FunctionExecutor {
fn execute ( & mut self , name : & str , context : CallerContext ) -> Result < Option < RuntimeValue > , Error > {
match name {
" add " = > {
let memory_value = self . memory . get ( 0 , 1 ) . unwrap ( ) [ 0 ] ;
let fn_argument = context . value_stack . pop_as ::< u32 > ( ) . unwrap ( ) as u8 ;
let sum = memory_value + fn_argument ;
self . memory . set ( 0 , & vec! [ sum ] ) . unwrap ( ) ;
self . values . push ( sum as i32 ) ;
Ok ( Some ( RuntimeValue ::I32 ( sum as i32 ) ) )
} ,
" sub " = > {
let memory_value = self . memory . get ( 0 , 1 ) . unwrap ( ) [ 0 ] ;
let fn_argument = context . value_stack . pop_as ::< u32 > ( ) . unwrap ( ) as u8 ;
let diff = memory_value - fn_argument ;
self . memory . set ( 0 , & vec! [ diff ] ) . unwrap ( ) ;
self . values . push ( diff as i32 ) ;
Ok ( Some ( RuntimeValue ::I32 ( diff as i32 ) ) )
} ,
_ = > Err ( Error ::Trap ( " not implemented " . into ( ) ) ) ,
2017-05-19 09:36:50 +03:00
}
}
2017-06-21 09:23:20 +03:00
}
2017-05-19 09:36:50 +03:00
2017-06-21 09:23:20 +03:00
#[ test ]
fn single_program_different_modules ( ) {
2017-05-19 09:36:50 +03:00
// create new program
let program = ProgramInstance ::new ( ) . unwrap ( ) ;
// => env module is created
let env_instance = program . module ( " env " ) . unwrap ( ) ;
// => linear memory is created
let env_memory = env_instance . memory ( ItemIndex ::Internal ( 0 ) ) . unwrap ( ) ;
2017-05-15 15:40:08 +03:00
2017-06-13 12:01:59 +03:00
// create native env module executor
2017-05-19 09:36:50 +03:00
let mut executor = FunctionExecutor {
memory : env_memory . clone ( ) ,
values : Vec ::new ( ) ,
} ;
{
let functions : UserFunctions = UserFunctions {
executor : & mut executor ,
2017-06-14 17:07:22 +03:00
functions : ::std ::borrow ::Cow ::from ( SIGNATURES ) ,
2017-05-19 09:36:50 +03:00
} ;
let native_env_instance = Arc ::new ( env_native_module ( env_instance , functions ) . unwrap ( ) ) ;
let params = ExecutionParams ::with_external ( " env " . into ( ) , native_env_instance ) ;
2017-06-13 12:01:59 +03:00
let module = module ( )
. with_import ( ImportEntry ::new ( " env " . into ( ) , " add " . into ( ) , External ::Function ( 0 ) ) )
. with_import ( ImportEntry ::new ( " env " . into ( ) , " sub " . into ( ) , External ::Function ( 0 ) ) )
. function ( )
. signature ( ) . param ( ) . i32 ( ) . return_type ( ) . i32 ( ) . build ( )
. body ( ) . with_opcodes ( Opcodes ::new ( vec! [
Opcode ::GetLocal ( 0 ) ,
Opcode ::Call ( 0 ) ,
Opcode ::End ,
] ) ) . build ( )
. build ( )
. function ( )
. signature ( ) . param ( ) . i32 ( ) . return_type ( ) . i32 ( ) . build ( )
. body ( ) . with_opcodes ( Opcodes ::new ( vec! [
Opcode ::GetLocal ( 0 ) ,
Opcode ::Call ( 1 ) ,
Opcode ::End ,
] ) ) . build ( )
. build ( )
. build ( ) ;
// load module
let module_instance = program . add_module ( " main " , module , Some ( & params . externals ) ) . unwrap ( ) ;
{
assert_eq! ( module_instance . execute_index ( 2 , params . clone ( ) . add_argument ( RuntimeValue ::I32 ( 7 ) ) ) . unwrap ( ) . unwrap ( ) , RuntimeValue ::I32 ( 7 ) ) ;
assert_eq! ( module_instance . execute_index ( 2 , params . clone ( ) . add_argument ( RuntimeValue ::I32 ( 50 ) ) ) . unwrap ( ) . unwrap ( ) , RuntimeValue ::I32 ( 57 ) ) ;
assert_eq! ( module_instance . execute_index ( 3 , params . clone ( ) . add_argument ( RuntimeValue ::I32 ( 15 ) ) ) . unwrap ( ) . unwrap ( ) , RuntimeValue ::I32 ( 42 ) ) ;
}
2017-05-19 09:36:50 +03:00
}
assert_eq! ( executor . memory . get ( 0 , 1 ) . unwrap ( ) [ 0 ] , 42 ) ;
assert_eq! ( executor . values , vec! [ 7 , 57 , 42 ] ) ;
}
2017-06-14 14:09:00 +03:00
2017-06-21 09:23:20 +03:00
#[ test ]
fn env_native_export_entry_type_check ( ) {
let program = ProgramInstance ::new ( ) . unwrap ( ) ;
let mut function_executor = FunctionExecutor {
memory : program . module ( " env " ) . unwrap ( ) . memory ( ItemIndex ::Internal ( 0 ) ) . unwrap ( ) ,
values : Vec ::new ( ) ,
} ;
let native_env_instance = Arc ::new ( env_native_module ( program . module ( " env " ) . unwrap ( ) , UserFunctions {
executor : & mut function_executor ,
functions : ::std ::borrow ::Cow ::from ( SIGNATURES ) ,
} ) . 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 ( 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 ( FunctionType ::new ( vec! [ ValueType ::I32 ] , Some ( ValueType ::I64 ) ) ) ) . is_err ( ) ) ;
}
2017-06-14 14:09:00 +03:00
#[ test ]
fn if_else_with_return_type_validation ( ) {
let module = module ( ) . build ( ) ;
let imports = ModuleImports ::new ( Weak ::default ( ) , None ) ;
let mut context = FunctionValidationContext ::new ( & module , & imports , & [ ] , 1024 , 1024 , & FunctionType ::default ( ) ) ;
2017-06-19 13:55:53 +03:00
Validator ::validate_function ( & mut context , BlockType ::NoResult , & [
2017-06-14 14:09:00 +03:00
Opcode ::I32Const ( 1 ) ,
Opcode ::If ( BlockType ::NoResult , Opcodes ::new ( vec! [
Opcode ::I32Const ( 1 ) ,
Opcode ::If ( BlockType ::Value ( ValueType ::I32 ) , Opcodes ::new ( vec! [
Opcode ::I32Const ( 1 ) ,
Opcode ::Else ,
Opcode ::I32Const ( 2 ) ,
Opcode ::End ,
] ) ) ,
Opcode ::Drop ,
Opcode ::End ,
] ) ) ,
Opcode ::End ,
2017-06-19 13:55:53 +03:00
] ) . unwrap ( ) ;
2017-06-14 14:09:00 +03:00
}