mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-30 00:51:34 +00:00
Only run runtime_core tests on Android
This commit is contained in:
2
Makefile
2
Makefile
@ -169,7 +169,7 @@ test: spectests emtests middleware wasitests test-rest examples
|
|||||||
|
|
||||||
test-android:
|
test-android:
|
||||||
ci/run-docker.sh x86_64-linux-android --manifest-path=lib/singlepass-backend/Cargo.toml
|
ci/run-docker.sh x86_64-linux-android --manifest-path=lib/singlepass-backend/Cargo.toml
|
||||||
ci/run-docker.sh x86_64-linux-android
|
ci/run-docker.sh x86_64-linux-android runtime_core
|
||||||
|
|
||||||
# Integration tests
|
# Integration tests
|
||||||
integration-tests: release-clif examples
|
integration-tests: release-clif examples
|
||||||
|
@ -1,23 +1,25 @@
|
|||||||
mod runtime_core_tests;
|
mod runtime_core_tests;
|
||||||
|
|
||||||
use runtime_core_tests::{get_compiler, wat2wasm};
|
pub mod runtime_core_exception_handling {
|
||||||
use wasmer_runtime_core::{compile_with, imports};
|
use super::runtime_core_tests::{get_compiler, wat2wasm};
|
||||||
|
use wasmer_runtime_core::{compile_with, imports};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exception_handling_works() {
|
fn exception_handling_works() {
|
||||||
const MODULE: &str = r#"
|
const MODULE: &str = r#"
|
||||||
(module
|
(module
|
||||||
(func (export "throw_trap")
|
(func (export "throw_trap")
|
||||||
unreachable
|
unreachable
|
||||||
))
|
))
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let wasm_binary = wat2wasm(MODULE.as_bytes()).expect("WAST not valid or malformed");
|
let wasm_binary = wat2wasm(MODULE.as_bytes()).expect("WAST not valid or malformed");
|
||||||
let module = compile_with(&wasm_binary, &get_compiler()).unwrap();
|
let module = compile_with(&wasm_binary, &get_compiler()).unwrap();
|
||||||
|
|
||||||
let imports = imports! {};
|
let imports = imports! {};
|
||||||
for _ in 0..2 {
|
for _ in 0..2 {
|
||||||
let instance = module.instantiate(&imports).unwrap();
|
let instance = module.instantiate(&imports).unwrap();
|
||||||
assert!(instance.call("throw_trap", &[]).is_err());
|
assert!(instance.call("throw_trap", &[]).is_err());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
450
tests/imports.rs
450
tests/imports.rs
@ -1,22 +1,25 @@
|
|||||||
mod runtime_core_tests;
|
mod runtime_core_tests;
|
||||||
|
|
||||||
use runtime_core_tests::{get_compiler, wat2wasm};
|
#[cfg(test)]
|
||||||
use std::{convert::TryInto, sync::Arc};
|
pub mod runtime_core_imports {
|
||||||
use wasmer_runtime_core::{
|
|
||||||
compile_with,
|
|
||||||
error::RuntimeError,
|
|
||||||
global::Global,
|
|
||||||
imports,
|
|
||||||
memory::Memory,
|
|
||||||
typed_func::{DynamicFunc, Func},
|
|
||||||
types::{FuncSig, MemoryDescriptor, Type, Value},
|
|
||||||
units::Pages,
|
|
||||||
vm, DynFunc, Instance,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[test]
|
use super::runtime_core_tests::{get_compiler, wat2wasm};
|
||||||
fn new_api_works() {
|
use std::{convert::TryInto, sync::Arc};
|
||||||
let wasm = r#"
|
use wasmer_runtime_core::{
|
||||||
|
compile_with,
|
||||||
|
error::RuntimeError,
|
||||||
|
global::Global,
|
||||||
|
imports,
|
||||||
|
memory::Memory,
|
||||||
|
typed_func::{DynamicFunc, Func},
|
||||||
|
types::{FuncSig, MemoryDescriptor, Type, Value},
|
||||||
|
units::Pages,
|
||||||
|
vm, DynFunc, Instance,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn runtime_core_new_api_works() {
|
||||||
|
let wasm = r#"
|
||||||
(module
|
(module
|
||||||
(type $type (func (param i32) (result i32)))
|
(type $type (func (param i32) (result i32)))
|
||||||
(global (export "my_global") i32 (i32.const 45))
|
(global (export "my_global") i32 (i32.const 45))
|
||||||
@ -27,22 +30,22 @@ fn new_api_works() {
|
|||||||
(i32.mul (get_local 0)
|
(i32.mul (get_local 0)
|
||||||
(i32.const 2)))
|
(i32.const 2)))
|
||||||
)"#;
|
)"#;
|
||||||
let wasm_binary = wat2wasm(wasm.as_bytes()).expect("WAST not valid or malformed");
|
let wasm_binary = wat2wasm(wasm.as_bytes()).expect("WAST not valid or malformed");
|
||||||
let module = compile_with(&wasm_binary, &get_compiler()).unwrap();
|
let module = compile_with(&wasm_binary, &get_compiler()).unwrap();
|
||||||
let import_object = imports! {};
|
let import_object = imports! {};
|
||||||
let instance = module.instantiate(&import_object).unwrap();
|
let instance = module.instantiate(&import_object).unwrap();
|
||||||
|
|
||||||
let my_global: Global = instance.exports.get("my_global").unwrap();
|
let my_global: Global = instance.exports.get("my_global").unwrap();
|
||||||
assert_eq!(my_global.get(), Value::I32(45));
|
assert_eq!(my_global.get(), Value::I32(45));
|
||||||
let double: Func<i32, i32> = instance.exports.get("double").unwrap();
|
let double: Func<i32, i32> = instance.exports.get("double").unwrap();
|
||||||
assert_eq!(double.call(5).unwrap(), 10);
|
assert_eq!(double.call(5).unwrap(), 10);
|
||||||
let add_one: DynFunc = instance.exports.get("add_one").unwrap();
|
let add_one: DynFunc = instance.exports.get("add_one").unwrap();
|
||||||
assert_eq!(add_one.call(&[Value::I32(5)]).unwrap(), &[Value::I32(6)]);
|
assert_eq!(add_one.call(&[Value::I32(5)]).unwrap(), &[Value::I32(6)]);
|
||||||
let add_one_memory: Result<DynFunc, _> = instance.exports.get("my_global");
|
let add_one_memory: Result<DynFunc, _> = instance.exports.get("my_global");
|
||||||
assert!(add_one_memory.is_err());
|
assert!(add_one_memory.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! call_and_assert {
|
macro_rules! call_and_assert {
|
||||||
($instance:ident, $function:ident( $( $inputs:ty ),* ) -> $output:ty, ( $( $arguments:expr ),* ) == $expected_value:expr) => {
|
($instance:ident, $function:ident( $( $inputs:ty ),* ) -> $output:ty, ( $( $arguments:expr ),* ) == $expected_value:expr) => {
|
||||||
#[allow(unused_parens)]
|
#[allow(unused_parens)]
|
||||||
let $function: Func<( $( $inputs ),* ), $output> = $instance.exports.get(stringify!($function)).expect(concat!("Failed to get the `", stringify!($function), "` export function."));
|
let $function: Func<( $( $inputs ),* ), $output> = $instance.exports.get(stringify!($function)).expect(concat!("Failed to get the `", stringify!($function), "` export function."));
|
||||||
@ -89,20 +92,20 @@ macro_rules! call_and_assert {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The shift that is set in the instance memory. The value is part of
|
/// The shift that is set in the instance memory. The value is part of
|
||||||
/// the result returned by the imported functions if the memory is
|
/// the result returned by the imported functions if the memory is
|
||||||
/// read properly.
|
/// read properly.
|
||||||
const SHIFT: i32 = 10;
|
const SHIFT: i32 = 10;
|
||||||
|
|
||||||
/// The shift that is captured in the environment of a closure. The
|
/// The shift that is captured in the environment of a closure. The
|
||||||
/// value is part of the result returned by the imported function if
|
/// value is part of the result returned by the imported function if
|
||||||
/// the closure captures its environment properly.
|
/// the closure captures its environment properly.
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
const shift: i32 = 100;
|
const shift: i32 = 100;
|
||||||
|
|
||||||
#[cfg(all(unix, target_arch = "x86_64"))]
|
#[cfg(all(unix, target_arch = "x86_64"))]
|
||||||
fn imported_functions_forms(test: &dyn Fn(&Instance)) {
|
fn imported_functions_forms(test: &dyn Fn(&Instance)) {
|
||||||
const MODULE: &str = r#"
|
const MODULE: &str = r#"
|
||||||
(module
|
(module
|
||||||
(type $type (func (param i32) (result i32)))
|
(type $type (func (param i32) (result i32)))
|
||||||
(import "env" "memory" (memory 1 1))
|
(import "env" "memory" (memory 1 1))
|
||||||
@ -203,194 +206,194 @@ fn imported_functions_forms(test: &dyn Fn(&Instance)) {
|
|||||||
call $callback_closure_trap_with_vmctx_and_env))
|
call $callback_closure_trap_with_vmctx_and_env))
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let wasm_binary = wat2wasm(MODULE.as_bytes()).expect("WAST not valid or malformed");
|
let wasm_binary = wat2wasm(MODULE.as_bytes()).expect("WAST not valid or malformed");
|
||||||
let module = compile_with(&wasm_binary, &get_compiler()).unwrap();
|
let module = compile_with(&wasm_binary, &get_compiler()).unwrap();
|
||||||
let memory_descriptor = MemoryDescriptor::new(Pages(1), Some(Pages(1)), false).unwrap();
|
let memory_descriptor = MemoryDescriptor::new(Pages(1), Some(Pages(1)), false).unwrap();
|
||||||
let memory = Memory::new(memory_descriptor).unwrap();
|
let memory = Memory::new(memory_descriptor).unwrap();
|
||||||
|
|
||||||
memory.view()[0].set(SHIFT);
|
memory.view()[0].set(SHIFT);
|
||||||
|
|
||||||
let import_object = imports! {
|
let import_object = imports! {
|
||||||
"env" => {
|
"env" => {
|
||||||
"memory" => memory.clone(),
|
"memory" => memory.clone(),
|
||||||
|
|
||||||
// Regular function.
|
// Regular function.
|
||||||
"callback_fn" => Func::new(callback_fn),
|
"callback_fn" => Func::new(callback_fn),
|
||||||
|
|
||||||
// Closure without a captured environment.
|
// Closure without a captured environment.
|
||||||
"callback_closure" => Func::new(|n: i32| -> Result<i32, ()> {
|
"callback_closure" => Func::new(|n: i32| -> Result<i32, ()> {
|
||||||
Ok(n + 1)
|
Ok(n + 1)
|
||||||
}),
|
}),
|
||||||
|
|
||||||
// Regular polymorphic function.
|
// Regular polymorphic function.
|
||||||
"callback_fn_dynamic" => DynamicFunc::new(
|
"callback_fn_dynamic" => DynamicFunc::new(
|
||||||
Arc::new(FuncSig::new(vec![Type::I32], vec![Type::I32])),
|
Arc::new(FuncSig::new(vec![Type::I32], vec![Type::I32])),
|
||||||
callback_fn_dynamic,
|
callback_fn_dynamic,
|
||||||
),
|
),
|
||||||
|
|
||||||
// Polymorphic function that panics.
|
// Polymorphic function that panics.
|
||||||
"callback_fn_dynamic_panic" => DynamicFunc::new(
|
"callback_fn_dynamic_panic" => DynamicFunc::new(
|
||||||
Arc::new(FuncSig::new(vec![Type::I32], vec![Type::I32])),
|
Arc::new(FuncSig::new(vec![Type::I32], vec![Type::I32])),
|
||||||
callback_fn_dynamic_panic,
|
callback_fn_dynamic_panic,
|
||||||
),
|
),
|
||||||
|
|
||||||
// Polymorphic closure “closures”.
|
// Polymorphic closure “closures”.
|
||||||
"callback_closure_dynamic_0" => DynamicFunc::new(
|
"callback_closure_dynamic_0" => DynamicFunc::new(
|
||||||
Arc::new(FuncSig::new(vec![], vec![])),
|
Arc::new(FuncSig::new(vec![], vec![])),
|
||||||
|_, inputs: &[Value]| -> Vec<Value> {
|
|_, inputs: &[Value]| -> Vec<Value> {
|
||||||
assert!(inputs.is_empty());
|
assert!(inputs.is_empty());
|
||||||
|
|
||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
"callback_closure_dynamic_1" => DynamicFunc::new(
|
"callback_closure_dynamic_1" => DynamicFunc::new(
|
||||||
Arc::new(FuncSig::new(vec![Type::I32], vec![Type::I32])),
|
Arc::new(FuncSig::new(vec![Type::I32], vec![Type::I32])),
|
||||||
move |vmctx: &mut vm::Ctx, inputs: &[Value]| -> Vec<Value> {
|
move |vmctx: &mut vm::Ctx, inputs: &[Value]| -> Vec<Value> {
|
||||||
assert_eq!(inputs.len(), 1);
|
assert_eq!(inputs.len(), 1);
|
||||||
|
|
||||||
|
let memory = vmctx.memory(0);
|
||||||
|
let shift_ = shift + memory.view::<i32>()[0].get();
|
||||||
|
let n: i32 = (&inputs[0]).try_into().unwrap();
|
||||||
|
|
||||||
|
vec![Value::I32(shift_ + n)]
|
||||||
|
}
|
||||||
|
),
|
||||||
|
"callback_closure_dynamic_2" => DynamicFunc::new(
|
||||||
|
Arc::new(FuncSig::new(vec![Type::I32, Type::I64], vec![Type::I64])),
|
||||||
|
move |vmctx: &mut vm::Ctx, inputs: &[Value]| -> Vec<Value> {
|
||||||
|
assert_eq!(inputs.len(), 2);
|
||||||
|
|
||||||
|
let memory = vmctx.memory(0);
|
||||||
|
let shift_ = shift + memory.view::<i32>()[0].get();
|
||||||
|
let i: i32 = (&inputs[0]).try_into().unwrap();
|
||||||
|
let j: i64 = (&inputs[1]).try_into().unwrap();
|
||||||
|
|
||||||
|
vec![Value::I64(shift_ as i64 + i as i64 + j)]
|
||||||
|
}
|
||||||
|
),
|
||||||
|
"callback_closure_dynamic_3" => DynamicFunc::new(
|
||||||
|
Arc::new(FuncSig::new(vec![Type::I32, Type::I64, Type::F32], vec![Type::F32])),
|
||||||
|
move |vmctx: &mut vm::Ctx, inputs: &[Value]| -> Vec<Value> {
|
||||||
|
assert_eq!(inputs.len(), 3);
|
||||||
|
|
||||||
|
let memory = vmctx.memory(0);
|
||||||
|
let shift_ = shift + memory.view::<i32>()[0].get();
|
||||||
|
let i: i32 = (&inputs[0]).try_into().unwrap();
|
||||||
|
let j: i64 = (&inputs[1]).try_into().unwrap();
|
||||||
|
let k: f32 = (&inputs[2]).try_into().unwrap();
|
||||||
|
|
||||||
|
vec![Value::F32(shift_ as f32 + i as f32 + j as f32 + k)]
|
||||||
|
}
|
||||||
|
),
|
||||||
|
"callback_closure_dynamic_4" => DynamicFunc::new(
|
||||||
|
Arc::new(FuncSig::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![Type::F64])),
|
||||||
|
move |vmctx: &mut vm::Ctx, inputs: &[Value]| -> Vec<Value> {
|
||||||
|
assert_eq!(inputs.len(), 4);
|
||||||
|
|
||||||
|
let memory = vmctx.memory(0);
|
||||||
|
let shift_ = shift + memory.view::<i32>()[0].get();
|
||||||
|
let i: i32 = (&inputs[0]).try_into().unwrap();
|
||||||
|
let j: i64 = (&inputs[1]).try_into().unwrap();
|
||||||
|
let k: f32 = (&inputs[2]).try_into().unwrap();
|
||||||
|
let l: f64 = (&inputs[3]).try_into().unwrap();
|
||||||
|
|
||||||
|
vec![Value::F64(shift_ as f64 + i as f64 + j as f64 + k as f64 + l)]
|
||||||
|
}
|
||||||
|
),
|
||||||
|
|
||||||
|
// Closure with a captured environment (a single variable + an instance of `Memory`).
|
||||||
|
"callback_closure_with_env" => Func::new(move |n: i32| -> Result<i32, ()> {
|
||||||
|
let shift_ = shift + memory.view::<i32>()[0].get();
|
||||||
|
|
||||||
|
Ok(shift_ + n + 1)
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Regular function with an explicit `vmctx`.
|
||||||
|
"callback_fn_with_vmctx" => Func::new(callback_fn_with_vmctx),
|
||||||
|
|
||||||
|
// Closure without a captured environment but with an explicit `vmctx`.
|
||||||
|
"callback_closure_with_vmctx" => Func::new(|vmctx: &mut vm::Ctx, n: i32| -> Result<i32, ()> {
|
||||||
|
let memory = vmctx.memory(0);
|
||||||
|
let shift_: i32 = memory.view()[0].get();
|
||||||
|
|
||||||
|
Ok(shift_ + n + 1)
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Closure with a captured environment (a single variable) and with an explicit `vmctx`.
|
||||||
|
"callback_closure_with_vmctx_and_env" => Func::new(move |vmctx: &mut vm::Ctx, n: i32| -> Result<i32, ()> {
|
||||||
let memory = vmctx.memory(0);
|
let memory = vmctx.memory(0);
|
||||||
let shift_ = shift + memory.view::<i32>()[0].get();
|
let shift_ = shift + memory.view::<i32>()[0].get();
|
||||||
let n: i32 = (&inputs[0]).try_into().unwrap();
|
|
||||||
|
|
||||||
vec![Value::I32(shift_ + n)]
|
Ok(shift_ + n + 1)
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
"callback_closure_dynamic_2" => DynamicFunc::new(
|
|
||||||
Arc::new(FuncSig::new(vec![Type::I32, Type::I64], vec![Type::I64])),
|
|
||||||
move |vmctx: &mut vm::Ctx, inputs: &[Value]| -> Vec<Value> {
|
|
||||||
assert_eq!(inputs.len(), 2);
|
|
||||||
|
|
||||||
|
// Trap a regular function.
|
||||||
|
"callback_fn_trap" => Func::new(callback_fn_trap),
|
||||||
|
|
||||||
|
// Trap a closure without a captured environment.
|
||||||
|
"callback_closure_trap" => Func::new(|n: i32| -> Result<i32, String> {
|
||||||
|
Err(format!("bar {}", n + 1))
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Trap a regular function with an explicit `vmctx`.
|
||||||
|
"callback_fn_trap_with_vmctx" => Func::new(callback_fn_trap_with_vmctx),
|
||||||
|
|
||||||
|
// Trap a closure without a captured environment but with an explicit `vmctx`.
|
||||||
|
"callback_closure_trap_with_vmctx" => Func::new(|vmctx: &mut vm::Ctx, n: i32| -> Result<i32, String> {
|
||||||
|
let memory = vmctx.memory(0);
|
||||||
|
let shift_: i32 = memory.view()[0].get();
|
||||||
|
|
||||||
|
Err(format!("qux {}", shift_ + n + 1))
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Trap a closure with a captured environment (a single variable) and with an explicit `vmctx`.
|
||||||
|
"callback_closure_trap_with_vmctx_and_env" => Func::new(move |vmctx: &mut vm::Ctx, n: i32| -> Result<i32, String> {
|
||||||
let memory = vmctx.memory(0);
|
let memory = vmctx.memory(0);
|
||||||
let shift_ = shift + memory.view::<i32>()[0].get();
|
let shift_ = shift + memory.view::<i32>()[0].get();
|
||||||
let i: i32 = (&inputs[0]).try_into().unwrap();
|
|
||||||
let j: i64 = (&inputs[1]).try_into().unwrap();
|
|
||||||
|
|
||||||
vec![Value::I64(shift_ as i64 + i as i64 + j)]
|
Err(format!("! {}", shift_ + n + 1))
|
||||||
}
|
}),
|
||||||
),
|
},
|
||||||
"callback_closure_dynamic_3" => DynamicFunc::new(
|
};
|
||||||
Arc::new(FuncSig::new(vec![Type::I32, Type::I64, Type::F32], vec![Type::F32])),
|
let instance = module.instantiate(&import_object).unwrap();
|
||||||
move |vmctx: &mut vm::Ctx, inputs: &[Value]| -> Vec<Value> {
|
|
||||||
assert_eq!(inputs.len(), 3);
|
|
||||||
|
|
||||||
let memory = vmctx.memory(0);
|
test(&instance);
|
||||||
let shift_ = shift + memory.view::<i32>()[0].get();
|
|
||||||
let i: i32 = (&inputs[0]).try_into().unwrap();
|
|
||||||
let j: i64 = (&inputs[1]).try_into().unwrap();
|
|
||||||
let k: f32 = (&inputs[2]).try_into().unwrap();
|
|
||||||
|
|
||||||
vec![Value::F32(shift_ as f32 + i as f32 + j as f32 + k)]
|
|
||||||
}
|
|
||||||
),
|
|
||||||
"callback_closure_dynamic_4" => DynamicFunc::new(
|
|
||||||
Arc::new(FuncSig::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![Type::F64])),
|
|
||||||
move |vmctx: &mut vm::Ctx, inputs: &[Value]| -> Vec<Value> {
|
|
||||||
assert_eq!(inputs.len(), 4);
|
|
||||||
|
|
||||||
let memory = vmctx.memory(0);
|
|
||||||
let shift_ = shift + memory.view::<i32>()[0].get();
|
|
||||||
let i: i32 = (&inputs[0]).try_into().unwrap();
|
|
||||||
let j: i64 = (&inputs[1]).try_into().unwrap();
|
|
||||||
let k: f32 = (&inputs[2]).try_into().unwrap();
|
|
||||||
let l: f64 = (&inputs[3]).try_into().unwrap();
|
|
||||||
|
|
||||||
vec![Value::F64(shift_ as f64 + i as f64 + j as f64 + k as f64 + l)]
|
|
||||||
}
|
|
||||||
),
|
|
||||||
|
|
||||||
// Closure with a captured environment (a single variable + an instance of `Memory`).
|
|
||||||
"callback_closure_with_env" => Func::new(move |n: i32| -> Result<i32, ()> {
|
|
||||||
let shift_ = shift + memory.view::<i32>()[0].get();
|
|
||||||
|
|
||||||
Ok(shift_ + n + 1)
|
|
||||||
}),
|
|
||||||
|
|
||||||
// Regular function with an explicit `vmctx`.
|
|
||||||
"callback_fn_with_vmctx" => Func::new(callback_fn_with_vmctx),
|
|
||||||
|
|
||||||
// Closure without a captured environment but with an explicit `vmctx`.
|
|
||||||
"callback_closure_with_vmctx" => Func::new(|vmctx: &mut vm::Ctx, n: i32| -> Result<i32, ()> {
|
|
||||||
let memory = vmctx.memory(0);
|
|
||||||
let shift_: i32 = memory.view()[0].get();
|
|
||||||
|
|
||||||
Ok(shift_ + n + 1)
|
|
||||||
}),
|
|
||||||
|
|
||||||
// Closure with a captured environment (a single variable) and with an explicit `vmctx`.
|
|
||||||
"callback_closure_with_vmctx_and_env" => Func::new(move |vmctx: &mut vm::Ctx, n: i32| -> Result<i32, ()> {
|
|
||||||
let memory = vmctx.memory(0);
|
|
||||||
let shift_ = shift + memory.view::<i32>()[0].get();
|
|
||||||
|
|
||||||
Ok(shift_ + n + 1)
|
|
||||||
}),
|
|
||||||
|
|
||||||
// Trap a regular function.
|
|
||||||
"callback_fn_trap" => Func::new(callback_fn_trap),
|
|
||||||
|
|
||||||
// Trap a closure without a captured environment.
|
|
||||||
"callback_closure_trap" => Func::new(|n: i32| -> Result<i32, String> {
|
|
||||||
Err(format!("bar {}", n + 1))
|
|
||||||
}),
|
|
||||||
|
|
||||||
// Trap a regular function with an explicit `vmctx`.
|
|
||||||
"callback_fn_trap_with_vmctx" => Func::new(callback_fn_trap_with_vmctx),
|
|
||||||
|
|
||||||
// Trap a closure without a captured environment but with an explicit `vmctx`.
|
|
||||||
"callback_closure_trap_with_vmctx" => Func::new(|vmctx: &mut vm::Ctx, n: i32| -> Result<i32, String> {
|
|
||||||
let memory = vmctx.memory(0);
|
|
||||||
let shift_: i32 = memory.view()[0].get();
|
|
||||||
|
|
||||||
Err(format!("qux {}", shift_ + n + 1))
|
|
||||||
}),
|
|
||||||
|
|
||||||
// Trap a closure with a captured environment (a single variable) and with an explicit `vmctx`.
|
|
||||||
"callback_closure_trap_with_vmctx_and_env" => Func::new(move |vmctx: &mut vm::Ctx, n: i32| -> Result<i32, String> {
|
|
||||||
let memory = vmctx.memory(0);
|
|
||||||
let shift_ = shift + memory.view::<i32>()[0].get();
|
|
||||||
|
|
||||||
Err(format!("! {}", shift_ + n + 1))
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let instance = module.instantiate(&import_object).unwrap();
|
|
||||||
|
|
||||||
test(&instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn callback_fn(n: i32) -> Result<i32, ()> {
|
|
||||||
Ok(n + 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn callback_fn_dynamic(_: &mut vm::Ctx, inputs: &[Value]) -> Vec<Value> {
|
|
||||||
match inputs[0] {
|
|
||||||
Value::I32(x) => vec![Value::I32(x + 1)],
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn callback_fn_dynamic_panic(_: &mut vm::Ctx, _: &[Value]) -> Vec<Value> {
|
fn callback_fn(n: i32) -> Result<i32, ()> {
|
||||||
panic!("test");
|
Ok(n + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn callback_fn_with_vmctx(vmctx: &mut vm::Ctx, n: i32) -> Result<i32, ()> {
|
fn callback_fn_dynamic(_: &mut vm::Ctx, inputs: &[Value]) -> Vec<Value> {
|
||||||
let memory = vmctx.memory(0);
|
match inputs[0] {
|
||||||
let shift_: i32 = memory.view()[0].get();
|
Value::I32(x) => vec![Value::I32(x + 1)],
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(shift_ + n + 1)
|
fn callback_fn_dynamic_panic(_: &mut vm::Ctx, _: &[Value]) -> Vec<Value> {
|
||||||
}
|
panic!("test");
|
||||||
|
}
|
||||||
|
|
||||||
fn callback_fn_trap(n: i32) -> Result<i32, String> {
|
fn callback_fn_with_vmctx(vmctx: &mut vm::Ctx, n: i32) -> Result<i32, ()> {
|
||||||
Err(format!("foo {}", n + 1))
|
let memory = vmctx.memory(0);
|
||||||
}
|
let shift_: i32 = memory.view()[0].get();
|
||||||
|
|
||||||
fn callback_fn_trap_with_vmctx(vmctx: &mut vm::Ctx, n: i32) -> Result<i32, String> {
|
Ok(shift_ + n + 1)
|
||||||
let memory = vmctx.memory(0);
|
}
|
||||||
let shift_: i32 = memory.view()[0].get();
|
|
||||||
|
|
||||||
Err(format!("baz {}", shift_ + n + 1))
|
fn callback_fn_trap(n: i32) -> Result<i32, String> {
|
||||||
}
|
Err(format!("foo {}", n + 1))
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! test {
|
fn callback_fn_trap_with_vmctx(vmctx: &mut vm::Ctx, n: i32) -> Result<i32, String> {
|
||||||
|
let memory = vmctx.memory(0);
|
||||||
|
let shift_: i32 = memory.view()[0].get();
|
||||||
|
|
||||||
|
Err(format!("baz {}", shift_ + n + 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! test {
|
||||||
($test_name:ident, $function:ident( $( $inputs:ty ),* ) -> $output:ty, ( $( $arguments:expr ),* ) == $expected_value:expr) => {
|
($test_name:ident, $function:ident( $( $inputs:ty ),* ) -> $output:ty, ( $( $arguments:expr ),* ) == $expected_value:expr) => {
|
||||||
#[cfg(all(unix, target_arch = "x86_64"))]
|
#[cfg(all(unix, target_arch = "x86_64"))]
|
||||||
#[test]
|
#[test]
|
||||||
@ -402,73 +405,74 @@ macro_rules! test {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
test!(test_fn, function_fn(i32) -> i32, (1) == Ok(2));
|
test!(test_fn, function_fn(i32) -> i32, (1) == Ok(2));
|
||||||
test!(test_closure, function_closure(i32) -> i32, (1) == Ok(2));
|
test!(test_closure, function_closure(i32) -> i32, (1) == Ok(2));
|
||||||
test!(test_fn_dynamic, function_fn_dynamic(i32) -> i32, (1) == Ok(2));
|
test!(test_fn_dynamic, function_fn_dynamic(i32) -> i32, (1) == Ok(2));
|
||||||
test!(test_fn_dynamic_panic, function_fn_dynamic_panic(i32) -> i32, (1) == Err(RuntimeError(Box::new("test"))));
|
test!(test_fn_dynamic_panic, function_fn_dynamic_panic(i32) -> i32, (1) == Err(RuntimeError(Box::new("test"))));
|
||||||
test!(
|
test!(
|
||||||
test_closure_dynamic_0,
|
test_closure_dynamic_0,
|
||||||
function_closure_dynamic_0(()) -> (),
|
function_closure_dynamic_0(()) -> (),
|
||||||
() == Ok(())
|
() == Ok(())
|
||||||
);
|
);
|
||||||
test!(
|
test!(
|
||||||
test_closure_dynamic_1,
|
test_closure_dynamic_1,
|
||||||
function_closure_dynamic_1(i32) -> i32,
|
function_closure_dynamic_1(i32) -> i32,
|
||||||
(1) == Ok(1 + shift + SHIFT)
|
(1) == Ok(1 + shift + SHIFT)
|
||||||
);
|
);
|
||||||
test!(
|
test!(
|
||||||
test_closure_dynamic_2,
|
test_closure_dynamic_2,
|
||||||
function_closure_dynamic_2(i32, i64) -> i64,
|
function_closure_dynamic_2(i32, i64) -> i64,
|
||||||
(1, 2) == Ok(1 + 2 + shift as i64 + SHIFT as i64)
|
(1, 2) == Ok(1 + 2 + shift as i64 + SHIFT as i64)
|
||||||
);
|
);
|
||||||
test!(
|
test!(
|
||||||
test_closure_dynamic_3,
|
test_closure_dynamic_3,
|
||||||
function_closure_dynamic_3(i32, i64, f32) -> f32,
|
function_closure_dynamic_3(i32, i64, f32) -> f32,
|
||||||
(1, 2, 3.) == Ok(1. + 2. + 3. + shift as f32 + SHIFT as f32)
|
(1, 2, 3.) == Ok(1. + 2. + 3. + shift as f32 + SHIFT as f32)
|
||||||
);
|
);
|
||||||
test!(
|
test!(
|
||||||
test_closure_dynamic_4,
|
test_closure_dynamic_4,
|
||||||
function_closure_dynamic_4(i32, i64, f32, f64) -> f64,
|
function_closure_dynamic_4(i32, i64, f32, f64) -> f64,
|
||||||
(1, 2, 3., 4.) == Ok(1. + 2. + 3. + 4. + shift as f64 + SHIFT as f64)
|
(1, 2, 3., 4.) == Ok(1. + 2. + 3. + 4. + shift as f64 + SHIFT as f64)
|
||||||
);
|
);
|
||||||
test!(
|
test!(
|
||||||
test_closure_with_env,
|
test_closure_with_env,
|
||||||
function_closure_with_env(i32) -> i32,
|
function_closure_with_env(i32) -> i32,
|
||||||
(1) == Ok(2 + shift + SHIFT)
|
(1) == Ok(2 + shift + SHIFT)
|
||||||
);
|
);
|
||||||
test!(test_fn_with_vmctx, function_fn_with_vmctx(i32) -> i32, (1) == Ok(2 + SHIFT));
|
test!(test_fn_with_vmctx, function_fn_with_vmctx(i32) -> i32, (1) == Ok(2 + SHIFT));
|
||||||
test!(
|
test!(
|
||||||
test_closure_with_vmctx,
|
test_closure_with_vmctx,
|
||||||
function_closure_with_vmctx(i32) -> i32,
|
function_closure_with_vmctx(i32) -> i32,
|
||||||
(1) == Ok(2 + SHIFT)
|
(1) == Ok(2 + SHIFT)
|
||||||
);
|
);
|
||||||
test!(
|
test!(
|
||||||
test_closure_with_vmctx_and_env,
|
test_closure_with_vmctx_and_env,
|
||||||
function_closure_with_vmctx_and_env(i32) -> i32,
|
function_closure_with_vmctx_and_env(i32) -> i32,
|
||||||
(1) == Ok(2 + shift + SHIFT)
|
(1) == Ok(2 + shift + SHIFT)
|
||||||
);
|
);
|
||||||
test!(
|
test!(
|
||||||
test_fn_trap,
|
test_fn_trap,
|
||||||
function_fn_trap(i32) -> i32,
|
function_fn_trap(i32) -> i32,
|
||||||
(1) == Err(RuntimeError(Box::new(format!("foo {}", 2))))
|
(1) == Err(RuntimeError(Box::new(format!("foo {}", 2))))
|
||||||
);
|
);
|
||||||
test!(
|
test!(
|
||||||
test_closure_trap,
|
test_closure_trap,
|
||||||
function_closure_trap(i32) -> i32,
|
function_closure_trap(i32) -> i32,
|
||||||
(1) == Err(RuntimeError(Box::new(format!("bar {}", 2))))
|
(1) == Err(RuntimeError(Box::new(format!("bar {}", 2))))
|
||||||
);
|
);
|
||||||
test!(
|
test!(
|
||||||
test_fn_trap_with_vmctx,
|
test_fn_trap_with_vmctx,
|
||||||
function_fn_trap_with_vmctx(i32) -> i32,
|
function_fn_trap_with_vmctx(i32) -> i32,
|
||||||
(1) == Err(RuntimeError(Box::new(format!("baz {}", 2 + SHIFT))))
|
(1) == Err(RuntimeError(Box::new(format!("baz {}", 2 + SHIFT))))
|
||||||
);
|
);
|
||||||
test!(
|
test!(
|
||||||
test_closure_trap_with_vmctx,
|
test_closure_trap_with_vmctx,
|
||||||
function_closure_trap_with_vmctx(i32) -> i32,
|
function_closure_trap_with_vmctx(i32) -> i32,
|
||||||
(1) == Err(RuntimeError(Box::new(format!("qux {}", 2 + SHIFT))))
|
(1) == Err(RuntimeError(Box::new(format!("qux {}", 2 + SHIFT))))
|
||||||
);
|
);
|
||||||
test!(
|
test!(
|
||||||
test_closure_trap_with_vmctx_and_env,
|
test_closure_trap_with_vmctx_and_env,
|
||||||
function_closure_trap_with_vmctx_and_env(i32) -> i32,
|
function_closure_trap_with_vmctx_and_env(i32) -> i32,
|
||||||
(1) == Err(RuntimeError(Box::new(format!("! {}", 2 + shift + SHIFT))))
|
(1) == Err(RuntimeError(Box::new(format!("! {}", 2 + shift + SHIFT))))
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user