2017-05-03 11:06:26 +03:00
///! Basic tests for instructions/constructions, missing in wabt tests
2017-05-18 15:08:55 +03:00
use std ::sync ::Arc ;
2017-05-03 11:06:26 +03:00
use builder ::module ;
use elements ::{ ExportEntry , Internal , ImportEntry , External , GlobalEntry , GlobalType ,
InitExpr , ValueType , Opcodes , Opcode } ;
use interpreter ::Error ;
2017-05-15 15:40:08 +03:00
use interpreter ::module ::{ ModuleInstanceInterface , CallerContext } ;
2017-05-03 11:06:26 +03:00
use interpreter ::program ::ProgramInstance ;
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-05-03 11:06:26 +03:00
let external_module = program . add_module ( " external_module " , module1 ) . unwrap ( ) ;
let main_module = program . add_module ( " main " , module2 ) . unwrap ( ) ;
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 ( ) ;
let _side_module_instance = program . add_module ( " side_module " , side_module ) . unwrap ( ) ;
let module_instance = program . add_module ( " main " , module ) . unwrap ( ) ;
2017-05-18 15:08:55 +03:00
assert! ( module_instance . execute_index ( 1 , vec! [ ] . into ( ) ) . 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-05-03 11:06:26 +03:00
let module = program . add_module ( " main " , module ) . unwrap ( ) ;
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
#[ test ]
fn with_user_functions ( ) {
2017-05-18 15:08:55 +03:00
use interpreter ::{ UserFunction , UserFunctions , ExecutionParams , env_native_module } ;
2017-05-15 15:40:08 +03:00
let module = module ( )
. with_import ( ImportEntry ::new ( " env " . into ( ) , " custom_alloc " . into ( ) , External ::Function ( 0 ) ) )
2017-05-15 15:57:46 +03:00
. with_import ( ImportEntry ::new ( " env " . into ( ) , " custom_increment " . into ( ) , External ::Function ( 0 ) ) )
2017-05-15 15:40:08 +03:00
. function ( )
. signature ( ) . return_type ( ) . i32 ( ) . build ( )
. body ( ) . with_opcodes ( Opcodes ::new ( vec! [
Opcode ::I32Const ( 32 ) ,
Opcode ::Call ( 0 ) ,
Opcode ::End ,
] ) ) . build ( )
. build ( )
. build ( ) ;
let mut top = 0 i32 ;
let mut user_functions = UserFunctions ::new ( ) ;
user_functions . insert (
" custom_alloc " . to_owned ( ) ,
UserFunction {
params : vec ! [ ValueType ::I32 ] ,
result : Some ( ValueType ::I32 ) ,
2017-05-18 15:08:55 +03:00
closure : Box ::new ( move | context : CallerContext | {
2017-05-15 15:40:08 +03:00
let prev = top ;
top = top + context . value_stack . pop_as ::< i32 > ( ) ? ;
Ok ( Some ( prev . into ( ) ) )
} ) ,
}
) ;
2017-05-15 15:57:46 +03:00
let mut rolling = 9999 i32 ;
user_functions . insert (
" custom_increment " . to_owned ( ) ,
UserFunction {
params : vec ! [ ValueType ::I32 ] ,
result : Some ( ValueType ::I32 ) ,
2017-05-18 15:08:55 +03:00
closure : Box ::new ( move | _context : CallerContext | {
2017-05-15 15:57:46 +03:00
rolling = rolling + 1 ;
Ok ( Some ( rolling . into ( ) ) )
} ) ,
}
) ;
2017-05-18 15:08:55 +03:00
let program = ProgramInstance ::new ( ) . unwrap ( ) ;
let module_instance = program . add_module ( " main " , module ) . unwrap ( ) ;
let native_env = Arc ::new ( env_native_module ( program . module ( " env " ) . unwrap ( ) , user_functions ) . unwrap ( ) ) ;
let params = ExecutionParams ::with_external ( " env " . into ( ) , native_env ) ;
2017-05-15 15:40:08 +03:00
2017-05-15 15:57:46 +03:00
// internal function using first import
2017-05-18 15:08:55 +03:00
assert_eq! ( module_instance . execute_index ( 2 , params . clone ( ) ) . unwrap ( ) . unwrap ( ) , RuntimeValue ::I32 ( 0 ) ) ;
assert_eq! ( module_instance . execute_index ( 2 , params . clone ( ) ) . unwrap ( ) . unwrap ( ) , RuntimeValue ::I32 ( 32 ) ) ;
assert_eq! ( module_instance . execute_index ( 2 , params . clone ( ) ) . unwrap ( ) . unwrap ( ) , RuntimeValue ::I32 ( 64 ) ) ;
2017-05-15 15:57:46 +03:00
// second import
2017-05-18 15:08:55 +03:00
assert_eq! ( module_instance . execute_index ( 1 , params . clone ( ) ) . unwrap ( ) . unwrap ( ) , RuntimeValue ::I32 ( 10000 ) ) ;
assert_eq! ( module_instance . execute_index ( 1 , params ) . unwrap ( ) . unwrap ( ) , RuntimeValue ::I32 ( 10001 ) ) ;
2017-05-15 15:57:46 +03:00
}
2017-05-15 16:15:05 +03:00
#[ test ]
fn with_user_functions_extended ( ) {
2017-05-18 15:08:55 +03:00
use interpreter ::{ UserFunction , UserFunctions , UserFunctionInterface ,
ExecutionParams , env_native_module } ;
2017-05-15 16:15:05 +03:00
struct UserMAlloc {
top : i32 ,
}
impl UserFunctionInterface for UserMAlloc {
2017-05-18 15:08:55 +03:00
fn call ( & mut self , context : CallerContext ) -> Result < Option < RuntimeValue > , Error > {
2017-05-15 16:15:05 +03:00
let prev = self . top ;
self . top + = context . value_stack . pop_as ::< i32 > ( ) ? ;
Ok ( Some ( prev . into ( ) ) )
}
}
let module = module ( )
. with_import ( ImportEntry ::new ( " env " . into ( ) , " _malloc " . into ( ) , External ::Function ( 0 ) ) )
. function ( )
. signature ( ) . return_type ( ) . i32 ( ) . build ( )
. body ( ) . with_opcodes ( Opcodes ::new ( vec! [
Opcode ::I32Const ( 32 ) ,
Opcode ::Call ( 0 ) ,
Opcode ::End ,
] ) ) . build ( )
. build ( )
. build ( ) ;
let mut user_functions = UserFunctions ::new ( ) ;
user_functions . insert (
" _malloc " . to_owned ( ) ,
UserFunction {
params : vec ! [ ValueType ::I32 ] ,
result : Some ( ValueType ::I32 ) ,
closure : Box ::new ( UserMAlloc { top : 0 } ) ,
}
) ;
2017-05-18 15:08:55 +03:00
let program = ProgramInstance ::new ( ) . unwrap ( ) ;
2017-05-15 16:15:05 +03:00
let module_instance = program . add_module ( " main " , module ) . unwrap ( ) ;
2017-05-18 15:08:55 +03:00
let native_env = Arc ::new ( env_native_module ( program . module ( " env " ) . unwrap ( ) , user_functions ) . unwrap ( ) ) ;
let params = ExecutionParams ::with_external ( " env " . into ( ) , native_env ) ;
2017-05-15 16:15:05 +03:00
// internal function using first import
2017-05-18 15:08:55 +03:00
assert_eq! ( module_instance . execute_index ( 1 , params . clone ( ) ) . unwrap ( ) . unwrap ( ) , RuntimeValue ::I32 ( 0 ) ) ;
assert_eq! ( module_instance . execute_index ( 1 , params . clone ( ) ) . unwrap ( ) . unwrap ( ) , RuntimeValue ::I32 ( 32 ) ) ;
assert_eq! ( module_instance . execute_index ( 1 , params ) . unwrap ( ) . unwrap ( ) , RuntimeValue ::I32 ( 64 ) ) ;
2017-05-15 16:15:05 +03:00
}