Separate testing per compiler

This commit is contained in:
Syrus
2020-06-09 14:33:12 -07:00
parent f8fbb33b00
commit a68bcf95ed
11 changed files with 776 additions and 986 deletions

View File

@ -65,6 +65,7 @@ anyhow = "1.0"
blake3 = "0.3" blake3 = "0.3"
lazy_static = "1.4" lazy_static = "1.4"
test-utils = { path = "tests/lib/test-utils" } test-utils = { path = "tests/lib/test-utils" }
# test-macros = { path = "tests/lib/test-macros" }
wasmer-engine-dummy = { path = "tests/lib/engine-dummy" } wasmer-engine-dummy = { path = "tests/lib/engine-dummy" }
[features] [features]
@ -106,5 +107,16 @@ llvm = [
"compiler", "compiler",
] ]
# Testing features
test-singlepass = [
"singlepass",
]
test-cranelift = [
"cranelift",
]
test-llvm = [
"llvm",
]
# [profile.release] # [profile.release]
# lto = "fat" # lto = "fat"

View File

@ -93,8 +93,21 @@ build-capi-llvm:
# Testing # # Testing #
########### ###########
test: test: $(foreach compiler,$(compilers),test-$(compiler)) test-packages
cargo test --release $(compiler_features)
test-singlepass:
cargo test --release $(compiler_features) --features "test-singlepass"
test-cranelift:
cargo test --release $(compiler_features) --features "test-cranelift"
test-llvm:
cargo test --release $(compiler_features) --features "test-llvm"
test-packages:
cargo test -p wasmer --release
cargo test -p wasmer-runtime --release
cargo test -p wasm-common --release
test-capi-singlepass: build-capi-singlepass test-capi-singlepass: build-capi-singlepass
cargo test --manifest-path lib/c-api/Cargo.toml --release \ cargo test --manifest-path lib/c-api/Cargo.toml --release \

View File

@ -2,196 +2,194 @@
//! This tests checks that the provided functions (both native and //! This tests checks that the provided functions (both native and
//! dynamic ones) work properly. //! dynamic ones) work properly.
wasmer_compilers! { use crate::utils::get_store;
use wasmer::*; use anyhow::Result;
use anyhow::Result; use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; use wasmer::*;
fn get_module(store: &Store) -> Result<Module> { fn get_module(store: &Store) -> Result<Module> {
let wat = r#" let wat = r#"
(import "host" "0" (func)) (import "host" "0" (func))
(import "host" "1" (func (param i32) (result i32))) (import "host" "1" (func (param i32) (result i32)))
(import "host" "2" (func (param i32) (param i64))) (import "host" "2" (func (param i32) (param i64)))
(import "host" "3" (func (param i32 i64 i32 f32 f64))) (import "host" "3" (func (param i32 i64 i32 f32 f64)))
(func $foo (func $foo
call 0 call 0
i32.const 0 i32.const 0
call 1 call 1
i32.const 1 i32.const 1
i32.add i32.add
i64.const 3 i64.const 3
call 2 call 2
i32.const 100 i32.const 100
i64.const 200 i64.const 200
i32.const 300 i32.const 300
f32.const 400 f32.const 400
f64.const 500 f64.const 500
call 3 call 3
) )
(start $foo) (start $foo)
"#; "#;
let module = Module::new(&store, &wat)?; let module = Module::new(&store, &wat)?;
Ok(module) Ok(module)
} }
#[test] #[test]
fn dynamic_function() -> Result<()> { fn dynamic_function() -> Result<()> {
let store = get_store(); let store = get_store();
let module = get_module(&store)?; let module = get_module(&store)?;
static HITS: AtomicUsize = AtomicUsize::new(0); static HITS: AtomicUsize = AtomicUsize::new(0);
Instance::new( Instance::new(
&module, &module,
&imports! { &imports! {
"host" => { "host" => {
"0" => Function::new_dynamic(&store, &FunctionType::new(vec![], vec![]), |_values| { "0" => Function::new_dynamic(&store, &FunctionType::new(vec![], vec![]), |_values| {
assert_eq!(HITS.fetch_add(1, SeqCst), 0); assert_eq!(HITS.fetch_add(1, SeqCst), 0);
Ok(vec![]) Ok(vec![])
}), }),
"1" => Function::new_dynamic(&store, &FunctionType::new(vec![ValType::I32], vec![ValType::I32]), |values| { "1" => Function::new_dynamic(&store, &FunctionType::new(vec![ValType::I32], vec![ValType::I32]), |values| {
assert_eq!(values[0], Value::I32(0)); assert_eq!(values[0], Value::I32(0));
assert_eq!(HITS.fetch_add(1, SeqCst), 1); assert_eq!(HITS.fetch_add(1, SeqCst), 1);
Ok(vec![Value::I32(1)]) Ok(vec![Value::I32(1)])
}), }),
"2" => Function::new_dynamic(&store, &FunctionType::new(vec![ValType::I32, ValType::I64], vec![]), |values| { "2" => Function::new_dynamic(&store, &FunctionType::new(vec![ValType::I32, ValType::I64], vec![]), |values| {
assert_eq!(values[0], Value::I32(2)); assert_eq!(values[0], Value::I32(2));
assert_eq!(values[1], Value::I64(3)); assert_eq!(values[1], Value::I64(3));
assert_eq!(HITS.fetch_add(1, SeqCst), 2); assert_eq!(HITS.fetch_add(1, SeqCst), 2);
Ok(vec![]) Ok(vec![])
}), }),
"3" => Function::new_dynamic(&store, &FunctionType::new(vec![ValType::I32, ValType::I64, ValType::I32, ValType::F32, ValType::F64], vec![]), |values| { "3" => Function::new_dynamic(&store, &FunctionType::new(vec![ValType::I32, ValType::I64, ValType::I32, ValType::F32, ValType::F64], vec![]), |values| {
assert_eq!(values[0], Value::I32(100)); assert_eq!(values[0], Value::I32(100));
assert_eq!(values[1], Value::I64(200)); assert_eq!(values[1], Value::I64(200));
assert_eq!(values[2], Value::I32(300)); assert_eq!(values[2], Value::I32(300));
assert_eq!(values[3], Value::F32(400.0)); assert_eq!(values[3], Value::F32(400.0));
assert_eq!(values[4], Value::F64(500.0)); assert_eq!(values[4], Value::F64(500.0));
assert_eq!(HITS.fetch_add(1, SeqCst), 3); assert_eq!(HITS.fetch_add(1, SeqCst), 3);
Ok(vec![]) Ok(vec![])
}), }),
}, },
}, },
)?; )?;
assert_eq!(HITS.load(SeqCst), 4); assert_eq!(HITS.load(SeqCst), 4);
Ok(()) Ok(())
} }
#[test]
#[test] fn dynamic_function_with_env() -> Result<()> {
fn dynamic_function_with_env() -> Result<()> { let store = get_store();
let store = get_store(); let module = get_module(&store)?;
let module = get_module(&store)?;
let mut env: AtomicUsize = AtomicUsize::new(0);
let mut env: AtomicUsize = AtomicUsize::new(0); Instance::new(
Instance::new( &module,
&module, &imports! {
&imports! { "host" => {
"host" => { "0" => Function::new_dynamic_env(&store, &FunctionType::new(vec![], vec![]), &mut env, |env, _values| {
"0" => Function::new_dynamic_env(&store, &FunctionType::new(vec![], vec![]), &mut env, |env, _values| { assert_eq!(env.fetch_add(1, SeqCst), 0);
assert_eq!(env.fetch_add(1, SeqCst), 0); Ok(vec![])
Ok(vec![]) }),
}), "1" => Function::new_dynamic_env(&store, &FunctionType::new(vec![ValType::I32], vec![ValType::I32]), &mut env, |env, values| {
"1" => Function::new_dynamic_env(&store, &FunctionType::new(vec![ValType::I32], vec![ValType::I32]), &mut env, |env, values| { assert_eq!(values[0], Value::I32(0));
assert_eq!(values[0], Value::I32(0)); assert_eq!(env.fetch_add(1, SeqCst), 1);
assert_eq!(env.fetch_add(1, SeqCst), 1); Ok(vec![Value::I32(1)])
Ok(vec![Value::I32(1)]) }),
}), "2" => Function::new_dynamic_env(&store, &FunctionType::new(vec![ValType::I32, ValType::I64], vec![]), &mut env, |env, values| {
"2" => Function::new_dynamic_env(&store, &FunctionType::new(vec![ValType::I32, ValType::I64], vec![]), &mut env, |env, values| { assert_eq!(values[0], Value::I32(2));
assert_eq!(values[0], Value::I32(2)); assert_eq!(values[1], Value::I64(3));
assert_eq!(values[1], Value::I64(3)); assert_eq!(env.fetch_add(1, SeqCst), 2);
assert_eq!(env.fetch_add(1, SeqCst), 2); Ok(vec![])
Ok(vec![]) }),
}), "3" => Function::new_dynamic_env(&store, &FunctionType::new(vec![ValType::I32, ValType::I64, ValType::I32, ValType::F32, ValType::F64], vec![]), &mut env, |env, values| {
"3" => Function::new_dynamic_env(&store, &FunctionType::new(vec![ValType::I32, ValType::I64, ValType::I32, ValType::F32, ValType::F64], vec![]), &mut env, |env, values| { assert_eq!(values[0], Value::I32(100));
assert_eq!(values[0], Value::I32(100)); assert_eq!(values[1], Value::I64(200));
assert_eq!(values[1], Value::I64(200)); assert_eq!(values[2], Value::I32(300));
assert_eq!(values[2], Value::I32(300)); assert_eq!(values[3], Value::F32(400.0));
assert_eq!(values[3], Value::F32(400.0)); assert_eq!(values[4], Value::F64(500.0));
assert_eq!(values[4], Value::F64(500.0)); assert_eq!(env.fetch_add(1, SeqCst), 3);
assert_eq!(env.fetch_add(1, SeqCst), 3); Ok(vec![])
Ok(vec![]) }),
}), },
}, },
}, )?;
)?; assert_eq!(env.load(SeqCst), 4);
assert_eq!(env.load(SeqCst), 4); Ok(())
Ok(()) }
}
#[test]
#[test] fn native_function() -> Result<()> {
fn native_function() -> Result<()> { let store = get_store();
let store = get_store(); let module = get_module(&store)?;
let module = get_module(&store)?;
static HITS: AtomicUsize = AtomicUsize::new(0);
static HITS: AtomicUsize = AtomicUsize::new(0); Instance::new(
Instance::new( &module,
&module, &imports! {
&imports! { "host" => {
"host" => { "0" => Function::new(&store, || {
"0" => Function::new(&store, || { assert_eq!(HITS.fetch_add(1, SeqCst), 0);
assert_eq!(HITS.fetch_add(1, SeqCst), 0); }),
}), "1" => Function::new(&store, |x: i32| -> i32 {
"1" => Function::new(&store, |x: i32| -> i32 { assert_eq!(x, 0);
assert_eq!(x, 0); assert_eq!(HITS.fetch_add(1, SeqCst), 1);
assert_eq!(HITS.fetch_add(1, SeqCst), 1); 1
1 }),
}), "2" => Function::new(&store, |x: i32, y: i64| {
"2" => Function::new(&store, |x: i32, y: i64| { assert_eq!(x, 2);
assert_eq!(x, 2); assert_eq!(y, 3);
assert_eq!(y, 3); assert_eq!(HITS.fetch_add(1, SeqCst), 2);
assert_eq!(HITS.fetch_add(1, SeqCst), 2); }),
}), "3" => Function::new(&store, |a: i32, b: i64, c: i32, d: f32, e: f64| {
"3" => Function::new(&store, |a: i32, b: i64, c: i32, d: f32, e: f64| { assert_eq!(a, 100);
assert_eq!(a, 100); assert_eq!(b, 200);
assert_eq!(b, 200); assert_eq!(c, 300);
assert_eq!(c, 300); assert_eq!(d, 400.0);
assert_eq!(d, 400.0); assert_eq!(e, 500.0);
assert_eq!(e, 500.0); assert_eq!(HITS.fetch_add(1, SeqCst), 3);
assert_eq!(HITS.fetch_add(1, SeqCst), 3); }),
}), },
}, },
}, )?;
)?; assert_eq!(HITS.load(SeqCst), 4);
assert_eq!(HITS.load(SeqCst), 4); Ok(())
Ok(()) }
}
#[test]
#[test] fn native_function_with_env() -> Result<()> {
fn native_function_with_env() -> Result<()> { let store = get_store();
let store = get_store(); let module = get_module(&store)?;
let module = get_module(&store)?;
let mut env: AtomicUsize = AtomicUsize::new(0);
let mut env: AtomicUsize = AtomicUsize::new(0); Instance::new(
Instance::new( &module,
&module, &imports! {
&imports! { "host" => {
"host" => { "0" => Function::new_env(&store, &mut env, |env: &mut AtomicUsize| {
"0" => Function::new_env(&store, &mut env, |env: &mut AtomicUsize| { assert_eq!(env.fetch_add(1, SeqCst), 0);
assert_eq!(env.fetch_add(1, SeqCst), 0); }),
}), "1" => Function::new_env(&store, &mut env, |env: &mut AtomicUsize, x: i32| -> i32 {
"1" => Function::new_env(&store, &mut env, |env: &mut AtomicUsize, x: i32| -> i32 { assert_eq!(x, 0);
assert_eq!(x, 0); assert_eq!(env.fetch_add(1, SeqCst), 1);
assert_eq!(env.fetch_add(1, SeqCst), 1); 1
1 }),
}), "2" => Function::new_env(&store, &mut env, |env: &mut AtomicUsize, x: i32, y: i64| {
"2" => Function::new_env(&store, &mut env, |env: &mut AtomicUsize, x: i32, y: i64| { assert_eq!(x, 2);
assert_eq!(x, 2); assert_eq!(y, 3);
assert_eq!(y, 3); assert_eq!(env.fetch_add(1, SeqCst), 2);
assert_eq!(env.fetch_add(1, SeqCst), 2); }),
}), "3" => Function::new_env(&store, &mut env, |env: &mut AtomicUsize, a: i32, b: i64, c: i32, d: f32, e: f64| {
"3" => Function::new_env(&store, &mut env, |env: &mut AtomicUsize, a: i32, b: i64, c: i32, d: f32, e: f64| { assert_eq!(a, 100);
assert_eq!(a, 100); assert_eq!(b, 200);
assert_eq!(b, 200); assert_eq!(c, 300);
assert_eq!(c, 300); assert_eq!(d, 400.0);
assert_eq!(d, 400.0); assert_eq!(e, 500.0);
assert_eq!(e, 500.0); assert_eq!(env.fetch_add(1, SeqCst), 3);
assert_eq!(env.fetch_add(1, SeqCst), 3); }),
}), },
}, },
}, )?;
)?; assert_eq!(env.load(SeqCst), 4);
assert_eq!(env.load(SeqCst), 4); Ok(())
Ok(())
}
} }

View File

@ -1,66 +0,0 @@
#[macro_export]
macro_rules! wasmer_compilers {
{ $($code:item)* } => {
#[cfg(feature = "singlepass")]
#[cfg(test)]
mod singlepass {
use std::sync::Arc;
use wasmer::{Features, Store, Tunables};
use wasmer_engine_jit::JITEngine;
use test_utils::get_compiler_config_from_str;
#[allow(dead_code)]
fn get_store() -> Store {
let features = Features::default();
let try_nan_canonicalization = false;
let compiler_config =
get_compiler_config_from_str("singlepass", try_nan_canonicalization, features);
let tunables = Tunables::for_target(compiler_config.target().triple());
let store = Store::new(Arc::new(JITEngine::new(compiler_config, tunables)));
store
}
$($code)*
}
#[cfg(feature = "cranelift")]
#[cfg(test)]
mod cranelift {
use std::sync::Arc;
use wasmer::{Features, Store, Tunables};
use wasmer_engine_jit::JITEngine;
use test_utils::get_compiler_config_from_str;
#[allow(dead_code)]
fn get_store() -> Store {
let features = Features::default();
let try_nan_canonicalization = false;
let compiler_config =
get_compiler_config_from_str("cranelift", try_nan_canonicalization, features);
let tunables = Tunables::for_target(compiler_config.target().triple());
let store = Store::new(Arc::new(JITEngine::new(compiler_config, tunables)));
store
}
$($code)*
}
#[cfg(feature = "llvm")]
#[cfg(test)]
mod llvm {
use std::sync::Arc;
use wasmer::{Features, Store, Tunables};
use wasmer_engine_jit::JITEngine;
use test_utils::get_compiler_config_from_str;
#[allow(dead_code)]
fn get_store() -> Store {
let features = Features::default();
let try_nan_canonicalization = false;
let compiler_config =
get_compiler_config_from_str("llvm", try_nan_canonicalization, features);
let tunables = Tunables::for_target(compiler_config.target().triple());
let store = Store::new(Arc::new(JITEngine::new(compiler_config, tunables)));
store
}
$($code)*
}
};
}

View File

@ -2,11 +2,7 @@
//! implementation, such as: singlepass, cranelift or llvm depending //! implementation, such as: singlepass, cranelift or llvm depending
//! on what's available on the target. //! on what's available on the target.
#[macro_use]
mod macros;
mod imports; mod imports;
mod multi_value_imports; mod multi_value_imports;
mod traps; mod traps;
mod wast; mod utils;
#[macro_use]
extern crate lazy_static;

View File

@ -2,185 +2,8 @@
//! This tests checks that the provided functions (both native and //! This tests checks that the provided functions (both native and
//! dynamic ones) work properly. //! dynamic ones) work properly.
use std::collections::HashSet; use crate::utils::get_store;
use wasmer::*;
// These tests are skipped because they are known failing.
lazy_static! {
static ref SKIP_TESTS: HashSet<&'static str> = [
// https://github.com/bytecodealliance/wasmtime/issues/1178
(concat!(module_path!(), "::cranelift::test_mvr_f32_f32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_f32_f32_f32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_f32_f32_f32_f32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_f32_f32_f32_i32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_f32_f32_f64::native")),
(concat!(module_path!(), "::cranelift::test_mvr_f32_f32_i32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_f32_f32_i32_f32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_f32_f32_i32_i32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_f32_f32_i64::native")),
(concat!(module_path!(), "::cranelift::test_mvr_f32_f64_i32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_f32_i32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_f32_i32_f32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_f32_i32_f32_f32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_f32_i32_f32_i32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_f32_i32_f64::native")),
(concat!(module_path!(), "::cranelift::test_mvr_f32_i32_i32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_f32_i32_i32_f32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_f32_i32_i32_i32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_f32_i32_i64::native")),
(concat!(module_path!(), "::cranelift::test_mvr_f32_i64_f32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_f32_i64_i32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_f64_f32_f32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_f64_f32_i32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_f64_i32_f32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_f64_i32_i32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_i32_f32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_i32_f32_f32_f32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_i32_f32_f32_i32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_i32_f32_f64::native")),
(concat!(module_path!(), "::cranelift::test_mvr_i32_f64_f32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_i32_f64_i32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_i32_i32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_i32_i32_f32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_i32_i32_f32_f32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_i32_i32_f32_i32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_i32_i32_f64::native")),
(concat!(module_path!(), "::cranelift::test_mvr_i32_i32_i32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_i32_i32_i32_f32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_i32_i32_i32_i32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_i32_i32_i64::native")),
(concat!(module_path!(), "::cranelift::test_mvr_i32_i64_f32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_i32_i64_i32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_i64_f32_i32::native")),
(concat!(module_path!(), "::cranelift::test_mvr_i64_i32_i32::native")),
// Multi-value is not implemented in singlepass yet.
(concat!(module_path!(), "::singlepass::test_mvr_f32_f32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_f32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_f32_f32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_f32_f32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_f32_f32_f32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_f32_f32_f32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_f32_f32_i32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_f32_f32_i32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_f32_f64::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_f32_f64::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_f32_i32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_f32_i32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_f32_i32_f32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_f32_i32_f32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_f32_i32_i32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_f32_i32_i32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_f32_i64::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_f32_i64::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_f64::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_f64::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_f64_f32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_f64_f32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_f64_i32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_f64_i32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_i32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_i32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_i32_f32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_i32_f32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_i32_f32_f32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_i32_f32_f32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_i32_f32_i32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_i32_f32_i32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_i32_f64::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_i32_f64::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_i32_i32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_i32_i32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_i32_i32_f32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_i32_i32_f32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_i32_i32_i32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_i32_i32_i32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_i32_i64::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_i32_i64::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_i64::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_i64::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_i64_f32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_i64_f32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_i64_i32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f32_i64_i32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f64_f32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f64_f32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f64_f32_f32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f64_f32_f32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f64_f32_i32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f64_f32_i32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f64_i32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f64_i32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f64_i32_f32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f64_i32_f32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_f64_i32_i32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_f64_i32_i32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_f32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_f32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_f32_f32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_f32_f32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_f32_f32_f32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_f32_f32_f32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_f32_f32_i32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_f32_f32_i32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_f32_f64::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_f32_f64::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_f32_i32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_f32_i32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_f32_i32_f32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_f32_i32_f32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_f32_i32_i32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_f32_i32_i32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_f32_i64::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_f32_i64::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_f64::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_f64::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_f64_f32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_f64_f32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_f64_i32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_f64_i32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i32_f32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i32_f32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i32_f32_f32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i32_f32_f32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i32_f32_i32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i32_f32_i32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i32_f64::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i32_f64::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i32_i32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i32_i32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i32_i32_f32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i32_i32_f32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i32_i32_i32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i32_i32_i32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i32_i32_i32_i32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i32_i32_i32_i32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i32_i64::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i32_i64::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i64::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i64::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i64_f32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i64_f32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i64_i32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i32_i64_i32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i64_f32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i64_f32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i64_f32_f32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i64_f32_f32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i64_f32_i32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i64_f32_i32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i64_i32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i64_i32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i64_i32_f32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i64_i32_f32::native")),
(concat!(module_path!(), "::singlepass::test_mvr_i64_i32_i32::dynamic")),
(concat!(module_path!(), "::singlepass::test_mvr_i64_i32_i32::native")),
]
.iter()
.copied()
.collect();
}
macro_rules! mvr_test { macro_rules! mvr_test {
($test_name:ident, $( $result_type:ty ),* ) => { ($test_name:ident, $( $result_type:ty ),* ) => {
@ -214,13 +37,8 @@ macro_rules! mvr_test {
} }
#[test] #[test]
#[cfg_attr(any(feature = "test-cranelift", feature="test-singlepass"), ignore)]
fn native() -> anyhow::Result<()> { fn native() -> anyhow::Result<()> {
dbg!(concat!(module_path!(), "::native"));
if crate::multi_value_imports::SKIP_TESTS.contains(concat!(module_path!(), "::native")) {
println!("skipped");
return Ok(());
}
let store = get_store(); let store = get_store();
let module = get_module(&store)?; let module = get_module(&store)?;
let instance = wasmer::Instance::new( let instance = wasmer::Instance::new(
@ -245,12 +63,8 @@ macro_rules! mvr_test {
} }
#[test] #[test]
#[cfg_attr(feature="test-singlepass", ignore)]
fn dynamic() -> anyhow::Result<()> { fn dynamic() -> anyhow::Result<()> {
if crate::multi_value_imports::SKIP_TESTS.contains(concat!(module_path!(), "::dynamic")) {
println!("skipped");
return Ok(());
}
let store = get_store(); let store = get_store();
let module = get_module(&store)?; let module = get_module(&store)?;
let instance = wasmer::Instance::new( let instance = wasmer::Instance::new(
@ -272,124 +86,122 @@ macro_rules! mvr_test {
} }
} }
wasmer_compilers! { trait ExpectedExpr {
trait ExpectedExpr { fn expected_value(n: i32) -> Self;
fn expected_value(n: i32) -> Self; fn expected_val(n: i32) -> wasmer::Val;
fn expected_val(n: i32) -> wasmer::Val; fn expected_valtype() -> wasmer::ValType;
fn expected_valtype() -> wasmer::ValType;
}
impl ExpectedExpr for i32 {
fn expected_value(n: i32) -> i32 {
n + 1
}
fn expected_val(n: i32) -> wasmer::Val {
wasmer::Val::I32(Self::expected_value(n))
}
fn expected_valtype() -> wasmer::ValType {
wasmer::ValType::I32
}
}
impl ExpectedExpr for i64 {
fn expected_value(n: i32) -> i64 {
n as i64 + 2i64
}
fn expected_val(n: i32) -> wasmer::Val {
wasmer::Val::I64(Self::expected_value(n))
}
fn expected_valtype() -> wasmer::ValType {
wasmer::ValType::I64
}
}
impl ExpectedExpr for f32 {
fn expected_value(n: i32) -> f32 {
n as f32 * 0.1
}
fn expected_val(n: i32) -> wasmer::Val {
wasmer::Val::F32(Self::expected_value(n))
}
fn expected_valtype() -> wasmer::ValType {
wasmer::ValType::F32
}
}
impl ExpectedExpr for f64 {
fn expected_value(n: i32) -> f64 {
n as f64 * 0.12
}
fn expected_val(n: i32) -> wasmer::Val {
wasmer::Val::F64(Self::expected_value(n))
}
fn expected_valtype() -> wasmer::ValType {
wasmer::ValType::F64
}
}
mvr_test!(test_mvr_i32_i32, i32, i32);
mvr_test!(test_mvr_i32_f32, i32, f32);
mvr_test!(test_mvr_f32_i32, f32, i32);
mvr_test!(test_mvr_f32_f32, f32, f32);
mvr_test!(test_mvr_i64_i32, i64, i32);
mvr_test!(test_mvr_i64_f32, i64, f32);
mvr_test!(test_mvr_f64_i32, f64, i32);
mvr_test!(test_mvr_f64_f32, f64, f32);
mvr_test!(test_mvr_i32_i64, i32, i64);
mvr_test!(test_mvr_f32_i64, f32, i64);
mvr_test!(test_mvr_i32_f64, i32, f64);
mvr_test!(test_mvr_f32_f64, f32, f64);
mvr_test!(test_mvr_i32_i32_i32, i32, i32, i32);
mvr_test!(test_mvr_i32_i32_f32, i32, i32, f32);
mvr_test!(test_mvr_i32_f32_i32, i32, f32, i32);
mvr_test!(test_mvr_i32_f32_f32, i32, f32, f32);
mvr_test!(test_mvr_f32_i32_i32, f32, i32, i32);
mvr_test!(test_mvr_f32_i32_f32, f32, i32, f32);
mvr_test!(test_mvr_f32_f32_i32, f32, f32, i32);
mvr_test!(test_mvr_f32_f32_f32, f32, f32, f32);
mvr_test!(test_mvr_i32_i32_i64, i32, i32, i64);
mvr_test!(test_mvr_i32_f32_i64, i32, f32, i64);
mvr_test!(test_mvr_f32_i32_i64, f32, i32, i64);
mvr_test!(test_mvr_f32_f32_i64, f32, f32, i64);
mvr_test!(test_mvr_i32_i32_f64, i32, i32, f64);
mvr_test!(test_mvr_i32_f32_f64, i32, f32, f64);
mvr_test!(test_mvr_f32_i32_f64, f32, i32, f64);
mvr_test!(test_mvr_f32_f32_f64, f32, f32, f64);
mvr_test!(test_mvr_i32_i64_i32, i32, i64, i32);
mvr_test!(test_mvr_i32_i64_f32, i32, i64, f32);
mvr_test!(test_mvr_f32_i64_i32, f32, i64, i32);
mvr_test!(test_mvr_f32_i64_f32, f32, i64, f32);
mvr_test!(test_mvr_i32_f64_i32, i32, f64, i32);
mvr_test!(test_mvr_i32_f64_f32, i32, f64, f32);
mvr_test!(test_mvr_f32_f64_i32, f32, f64, i32);
mvr_test!(test_mvr_f32_f64_f32, f32, f64, f32);
mvr_test!(test_mvr_i64_i32_i32, i64, i32, i32);
mvr_test!(test_mvr_i64_i32_f32, i64, i32, f32);
mvr_test!(test_mvr_i64_f32_i32, i64, f32, i32);
mvr_test!(test_mvr_i64_f32_f32, i64, f32, f32);
mvr_test!(test_mvr_f64_i32_i32, f64, i32, i32);
mvr_test!(test_mvr_f64_i32_f32, f64, i32, f32);
mvr_test!(test_mvr_f64_f32_i32, f64, f32, i32);
mvr_test!(test_mvr_f64_f32_f32, f64, f32, f32);
mvr_test!(test_mvr_i32_i32_i32_i32, i32, i32, i32, i32);
mvr_test!(test_mvr_i32_i32_i32_f32, i32, i32, i32, f32);
mvr_test!(test_mvr_i32_i32_f32_i32, i32, i32, f32, i32);
mvr_test!(test_mvr_i32_i32_f32_f32, i32, i32, f32, f32);
mvr_test!(test_mvr_i32_f32_i32_i32, i32, f32, i32, i32);
mvr_test!(test_mvr_i32_f32_i32_f32, i32, f32, i32, f32);
mvr_test!(test_mvr_i32_f32_f32_i32, i32, f32, f32, i32);
mvr_test!(test_mvr_i32_f32_f32_f32, i32, f32, f32, f32);
mvr_test!(test_mvr_f32_i32_i32_i32, f32, i32, i32, i32);
mvr_test!(test_mvr_f32_i32_i32_f32, f32, i32, i32, f32);
mvr_test!(test_mvr_f32_i32_f32_i32, f32, i32, f32, i32);
mvr_test!(test_mvr_f32_i32_f32_f32, f32, i32, f32, f32);
mvr_test!(test_mvr_f32_f32_i32_i32, f32, f32, i32, i32);
mvr_test!(test_mvr_f32_f32_i32_f32, f32, f32, i32, f32);
mvr_test!(test_mvr_f32_f32_f32_i32, f32, f32, f32, i32);
mvr_test!(test_mvr_f32_f32_f32_f32, f32, f32, f32, f32);
mvr_test!(test_mvr_i32_i32_i32_i32_i32, i32, i32, i32, i32, i32);
} }
impl ExpectedExpr for i32 {
fn expected_value(n: i32) -> i32 {
n + 1
}
fn expected_val(n: i32) -> wasmer::Val {
wasmer::Val::I32(Self::expected_value(n))
}
fn expected_valtype() -> wasmer::ValType {
wasmer::ValType::I32
}
}
impl ExpectedExpr for i64 {
fn expected_value(n: i32) -> i64 {
n as i64 + 2i64
}
fn expected_val(n: i32) -> wasmer::Val {
wasmer::Val::I64(Self::expected_value(n))
}
fn expected_valtype() -> wasmer::ValType {
wasmer::ValType::I64
}
}
impl ExpectedExpr for f32 {
fn expected_value(n: i32) -> f32 {
n as f32 * 0.1
}
fn expected_val(n: i32) -> wasmer::Val {
wasmer::Val::F32(Self::expected_value(n))
}
fn expected_valtype() -> wasmer::ValType {
wasmer::ValType::F32
}
}
impl ExpectedExpr for f64 {
fn expected_value(n: i32) -> f64 {
n as f64 * 0.12
}
fn expected_val(n: i32) -> wasmer::Val {
wasmer::Val::F64(Self::expected_value(n))
}
fn expected_valtype() -> wasmer::ValType {
wasmer::ValType::F64
}
}
mvr_test!(test_mvr_i32_i32, i32, i32);
mvr_test!(test_mvr_i32_f32, i32, f32);
mvr_test!(test_mvr_f32_i32, f32, i32);
mvr_test!(test_mvr_f32_f32, f32, f32);
mvr_test!(test_mvr_i64_i32, i64, i32);
mvr_test!(test_mvr_i64_f32, i64, f32);
mvr_test!(test_mvr_f64_i32, f64, i32);
mvr_test!(test_mvr_f64_f32, f64, f32);
mvr_test!(test_mvr_i32_i64, i32, i64);
mvr_test!(test_mvr_f32_i64, f32, i64);
mvr_test!(test_mvr_i32_f64, i32, f64);
mvr_test!(test_mvr_f32_f64, f32, f64);
mvr_test!(test_mvr_i32_i32_i32, i32, i32, i32);
mvr_test!(test_mvr_i32_i32_f32, i32, i32, f32);
mvr_test!(test_mvr_i32_f32_i32, i32, f32, i32);
mvr_test!(test_mvr_i32_f32_f32, i32, f32, f32);
mvr_test!(test_mvr_f32_i32_i32, f32, i32, i32);
mvr_test!(test_mvr_f32_i32_f32, f32, i32, f32);
mvr_test!(test_mvr_f32_f32_i32, f32, f32, i32);
mvr_test!(test_mvr_f32_f32_f32, f32, f32, f32);
mvr_test!(test_mvr_i32_i32_i64, i32, i32, i64);
mvr_test!(test_mvr_i32_f32_i64, i32, f32, i64);
mvr_test!(test_mvr_f32_i32_i64, f32, i32, i64);
mvr_test!(test_mvr_f32_f32_i64, f32, f32, i64);
mvr_test!(test_mvr_i32_i32_f64, i32, i32, f64);
mvr_test!(test_mvr_i32_f32_f64, i32, f32, f64);
mvr_test!(test_mvr_f32_i32_f64, f32, i32, f64);
mvr_test!(test_mvr_f32_f32_f64, f32, f32, f64);
mvr_test!(test_mvr_i32_i64_i32, i32, i64, i32);
mvr_test!(test_mvr_i32_i64_f32, i32, i64, f32);
mvr_test!(test_mvr_f32_i64_i32, f32, i64, i32);
mvr_test!(test_mvr_f32_i64_f32, f32, i64, f32);
mvr_test!(test_mvr_i32_f64_i32, i32, f64, i32);
mvr_test!(test_mvr_i32_f64_f32, i32, f64, f32);
mvr_test!(test_mvr_f32_f64_i32, f32, f64, i32);
mvr_test!(test_mvr_f32_f64_f32, f32, f64, f32);
mvr_test!(test_mvr_i64_i32_i32, i64, i32, i32);
mvr_test!(test_mvr_i64_i32_f32, i64, i32, f32);
mvr_test!(test_mvr_i64_f32_i32, i64, f32, i32);
mvr_test!(test_mvr_i64_f32_f32, i64, f32, f32);
mvr_test!(test_mvr_f64_i32_i32, f64, i32, i32);
mvr_test!(test_mvr_f64_i32_f32, f64, i32, f32);
mvr_test!(test_mvr_f64_f32_i32, f64, f32, i32);
mvr_test!(test_mvr_f64_f32_f32, f64, f32, f32);
mvr_test!(test_mvr_i32_i32_i32_i32, i32, i32, i32, i32);
mvr_test!(test_mvr_i32_i32_i32_f32, i32, i32, i32, f32);
mvr_test!(test_mvr_i32_i32_f32_i32, i32, i32, f32, i32);
mvr_test!(test_mvr_i32_i32_f32_f32, i32, i32, f32, f32);
mvr_test!(test_mvr_i32_f32_i32_i32, i32, f32, i32, i32);
mvr_test!(test_mvr_i32_f32_i32_f32, i32, f32, i32, f32);
mvr_test!(test_mvr_i32_f32_f32_i32, i32, f32, f32, i32);
mvr_test!(test_mvr_i32_f32_f32_f32, i32, f32, f32, f32);
mvr_test!(test_mvr_f32_i32_i32_i32, f32, i32, i32, i32);
mvr_test!(test_mvr_f32_i32_i32_f32, f32, i32, i32, f32);
mvr_test!(test_mvr_f32_i32_f32_i32, f32, i32, f32, i32);
mvr_test!(test_mvr_f32_i32_f32_f32, f32, i32, f32, f32);
mvr_test!(test_mvr_f32_f32_i32_i32, f32, f32, i32, i32);
mvr_test!(test_mvr_f32_f32_i32_f32, f32, f32, i32, f32);
mvr_test!(test_mvr_f32_f32_f32_i32, f32, f32, f32, i32);
mvr_test!(test_mvr_f32_f32_f32_f32, f32, f32, f32, f32);
mvr_test!(test_mvr_i32_i32_i32_i32_i32, i32, i32, i32, i32, i32);

View File

@ -1,228 +1,229 @@
wasmer_compilers! { use crate::utils::get_store;
use anyhow::Result; use anyhow::Result;
use std::panic::{self, AssertUnwindSafe}; use std::panic::{self, AssertUnwindSafe};
use wasmer::*; use wasmer::*;
#[test] #[test]
fn test_trap_return() -> Result<()> { fn test_trap_return() -> Result<()> {
let store = get_store(); let store = get_store();
let wat = r#" let wat = r#"
(module (module
(func $hello (import "" "hello")) (func $hello (import "" "hello"))
(func (export "run") (call $hello))
)
"#;
let module = Module::new(&store, wat)?;
let hello_type = FunctionType::new(vec![], vec![]);
let hello_func =
Function::new_dynamic(&store, &hello_type, |_| Err(RuntimeError::new("test 123")));
let instance = Instance::new(
&module,
&imports! {
"" => {
"hello" => hello_func
}
},
)?;
let run_func = instance
.exports
.get_function("run")
.expect("expected function export");
let e = run_func.call(&[]).err().expect("error calling function");
assert_eq!(e.message(), "test 123");
Ok(())
}
#[test]
#[cfg_attr(any(feature = "test-singlepass", feature = "test-llvm"), ignore)]
fn test_trap_trace() -> Result<()> {
let store = get_store();
let wat = r#"
(module $hello_mod
(func (export "run") (call $hello)) (func (export "run") (call $hello))
) (func $hello (unreachable))
"#; )
"#;
let module = Module::new(&store, wat)?; let module = Module::new(&store, wat)?;
let hello_type = FunctionType::new(vec![], vec![]); let instance = Instance::new(&module, &imports! {})?;
let hello_func = let run_func = instance
Function::new_dynamic(&store, &hello_type, |_| Err(RuntimeError::new("test 123"))); .exports
.get_function("run")
.expect("expected function export");
let instance = Instance::new( let e = run_func.call(&[]).err().expect("error calling function");
&module,
&imports! {
"" => {
"hello" => hello_func
}
},
)?;
let run_func = instance
.exports
.get_function("run")
.expect("expected function export");
let e = run_func.call(&[]).err().expect("error calling function"); let trace = e.trace();
assert_eq!(trace.len(), 2);
assert_eq!(trace[0].module_name(), "hello_mod");
assert_eq!(trace[0].func_index(), 1);
assert_eq!(trace[0].func_name(), Some("hello"));
assert_eq!(trace[1].module_name(), "hello_mod");
assert_eq!(trace[1].func_index(), 0);
assert_eq!(trace[1].func_name(), None);
assert!(
e.message().contains("unreachable"),
"wrong message: {}",
e.message()
);
assert_eq!(e.message(), "test 123"); Ok(())
}
Ok(()) #[test]
fn test_trap_trace_cb() -> Result<()> {
let store = get_store();
let wat = r#"
(module $hello_mod
(import "" "throw" (func $throw))
(func (export "run") (call $hello))
(func $hello (call $throw))
)
"#;
let fn_type = FunctionType::new(vec![], vec![]);
let fn_func = Function::new_dynamic(&store, &fn_type, |_| Err(RuntimeError::new("cb throw")));
let module = Module::new(&store, wat)?;
let instance = Instance::new(
&module,
&imports! {
"" => {
"throw" => fn_func
}
},
)?;
let run_func = instance
.exports
.get_function("run")
.expect("expected function export");
let e = run_func.call(&[]).err().expect("error calling function");
let trace = e.trace();
println!("Trace {:?}", trace);
// TODO: Reenable this (disabled as it was not working with llvm/singlepass)
// assert_eq!(trace.len(), 2);
// assert_eq!(trace[0].module_name(), "hello_mod");
// assert_eq!(trace[0].func_index(), 2);
// assert_eq!(trace[1].module_name(), "hello_mod");
// assert_eq!(trace[1].func_index(), 1);
assert_eq!(e.message(), "cb throw");
Ok(())
}
#[test]
#[cfg_attr(any(feature = "test-singlepass", feature = "test-llvm"), ignore)]
fn test_trap_stack_overflow() -> Result<()> {
let store = get_store();
let wat = r#"
(module $rec_mod
(func $run (export "run") (call $run))
)
"#;
let module = Module::new(&store, wat)?;
let instance = Instance::new(&module, &imports! {})?;
let run_func = instance
.exports
.get_function("run")
.expect("expected function export");
let e = run_func.call(&[]).err().expect("error calling function");
let trace = e.trace();
assert!(trace.len() >= 32);
for i in 0..trace.len() {
assert_eq!(trace[i].module_name(), "rec_mod");
assert_eq!(trace[i].func_index(), 0);
assert_eq!(trace[i].func_name(), Some("run"));
} }
assert!(e.message().contains("call stack exhausted"));
#[test] Ok(())
#[ignore] }
fn test_trap_trace() -> Result<()> {
let store = get_store();
let wat = r#"
(module $hello_mod
(func (export "run") (call $hello))
(func $hello (unreachable))
)
"#;
let module = Module::new(&store, wat)?; #[test]
let instance = Instance::new(&module, &imports! {})?; #[cfg_attr(any(feature = "test-singlepass", feature = "test-llvm"), ignore)]
let run_func = instance fn trap_display_pretty() -> Result<()> {
.exports let store = get_store();
.get_function("run") let wat = r#"
.expect("expected function export"); (module $m
(func $die unreachable)
(func call $die)
(func $foo call 1)
(func (export "bar") call $foo)
)
"#;
let e = run_func.call(&[]).err().expect("error calling function"); let module = Module::new(&store, wat)?;
let instance = Instance::new(&module, &imports! {})?;
let run_func = instance
.exports
.get_function("bar")
.expect("expected function export");
let trace = e.trace(); let e = run_func.call(&[]).err().expect("error calling function");
assert_eq!(trace.len(), 2); assert_eq!(
assert_eq!(trace[0].module_name(), "hello_mod"); e.to_string(),
assert_eq!(trace[0].func_index(), 1); "\
assert_eq!(trace[0].func_name(), Some("hello"));
assert_eq!(trace[1].module_name(), "hello_mod");
assert_eq!(trace[1].func_index(), 0);
assert_eq!(trace[1].func_name(), None);
assert!(
e.message().contains("unreachable"),
"wrong message: {}",
e.message()
);
Ok(())
}
#[test]
fn test_trap_trace_cb() -> Result<()> {
let store = get_store();
let wat = r#"
(module $hello_mod
(import "" "throw" (func $throw))
(func (export "run") (call $hello))
(func $hello (call $throw))
)
"#;
let fn_type = FunctionType::new(vec![], vec![]);
let fn_func = Function::new_dynamic(&store, &fn_type, |_| Err(RuntimeError::new("cb throw")));
let module = Module::new(&store, wat)?;
let instance = Instance::new(
&module,
&imports! {
"" => {
"throw" => fn_func
}
},
)?;
let run_func = instance
.exports
.get_function("run")
.expect("expected function export");
let e = run_func.call(&[]).err().expect("error calling function");
let trace = e.trace();
println!("Trace {:?}", trace);
// TODO: Reenable this (disabled as it was not working with llvm/singlepass)
// assert_eq!(trace.len(), 2);
// assert_eq!(trace[0].module_name(), "hello_mod");
// assert_eq!(trace[0].func_index(), 2);
// assert_eq!(trace[1].module_name(), "hello_mod");
// assert_eq!(trace[1].func_index(), 1);
assert_eq!(e.message(), "cb throw");
Ok(())
}
#[test]
fn test_trap_stack_overflow() -> Result<()> {
let store = get_store();
let wat = r#"
(module $rec_mod
(func $run (export "run") (call $run))
)
"#;
let module = Module::new(&store, wat)?;
let instance = Instance::new(&module, &imports! {})?;
let run_func = instance
.exports
.get_function("run")
.expect("expected function export");
let e = run_func.call(&[]).err().expect("error calling function");
let trace = e.trace();
// assert!(trace.len() >= 32);
for i in 0..trace.len() {
assert_eq!(trace[i].module_name(), "rec_mod");
assert_eq!(trace[i].func_index(), 0);
assert_eq!(trace[i].func_name(), Some("run"));
}
assert!(e.message().contains("call stack exhausted"));
Ok(())
}
#[test]
#[ignore]
fn trap_display_pretty() -> Result<()> {
let store = get_store();
let wat = r#"
(module $m
(func $die unreachable)
(func call $die)
(func $foo call 1)
(func (export "bar") call $foo)
)
"#;
let module = Module::new(&store, wat)?;
let instance = Instance::new(&module, &imports! {})?;
let run_func = instance
.exports
.get_function("bar")
.expect("expected function export");
let e = run_func.call(&[]).err().expect("error calling function");
assert_eq!(
e.to_string(),
"\
RuntimeError: unreachable RuntimeError: unreachable
at die (m[0]:0x23) at die (m[0]:0x23)
at <unnamed> (m[1]:0x27) at <unnamed> (m[1]:0x27)
at foo (m[2]:0x2c) at foo (m[2]:0x2c)
at <unnamed> (m[3]:0x31)" at <unnamed> (m[3]:0x31)"
); );
Ok(()) Ok(())
} }
#[test] #[test]
#[ignore] #[cfg_attr(any(feature = "test-singlepass", feature = "test-llvm"), ignore)]
fn trap_display_multi_module() -> Result<()> { fn trap_display_multi_module() -> Result<()> {
let store = get_store(); let store = get_store();
let wat = r#" let wat = r#"
(module $a (module $a
(func $die unreachable) (func $die unreachable)
(func call $die) (func call $die)
(func $foo call 1) (func $foo call 1)
(func (export "bar") call $foo) (func (export "bar") call $foo)
) )
"#; "#;
let module = Module::new(&store, wat)?; let module = Module::new(&store, wat)?;
let instance = Instance::new(&module, &imports! {})?; let instance = Instance::new(&module, &imports! {})?;
let bar = instance.exports.get_function("bar")?.clone(); let bar = instance.exports.get_function("bar")?.clone();
let wat = r#" let wat = r#"
(module $b (module $b
(import "" "" (func $bar)) (import "" "" (func $bar))
(func $middle call $bar) (func $middle call $bar)
(func (export "bar2") call $middle) (func (export "bar2") call $middle)
) )
"#; "#;
let module = Module::new(&store, wat)?; let module = Module::new(&store, wat)?;
let instance = Instance::new( let instance = Instance::new(
&module, &module,
&imports! { &imports! {
"" => { "" => {
"" => bar "" => bar
} }
}, },
)?; )?;
let bar2 = instance let bar2 = instance
.exports .exports
.get_function("bar2") .get_function("bar2")
.expect("expected function export"); .expect("expected function export");
let e = bar2.call(&[]).err().expect("error calling function"); let e = bar2.call(&[]).err().expect("error calling function");
assert_eq!( assert_eq!(
e.to_string(), e.to_string(),
"\ "\
RuntimeError: unreachable RuntimeError: unreachable
at die (a[0]:0x23) at die (a[0]:0x23)
at <unnamed> (a[1]:0x27) at <unnamed> (a[1]:0x27)
@ -230,244 +231,243 @@ RuntimeError: unreachable
at <unnamed> (a[3]:0x31) at <unnamed> (a[3]:0x31)
at middle (b[1]:0x29) at middle (b[1]:0x29)
at <unnamed> (b[2]:0x2e)" at <unnamed> (b[2]:0x2e)"
); );
Ok(()) Ok(())
}
#[test]
fn trap_start_function_import() -> Result<()> {
let store = get_store();
let binary = r#"
(module $a
(import "" "" (func $foo))
(start $foo)
)
"#;
let module = Module::new(&store, &binary)?;
let sig = FunctionType::new(vec![], vec![]);
let func = Function::new_dynamic(&store, &sig, |_| Err(RuntimeError::new("user trap")));
let err = Instance::new(
&module,
&imports! {
"" => {
"" => func
}
},
)
.err()
.unwrap();
match err {
InstantiationError::Link(_) => panic!("It should be a start error"),
InstantiationError::Start(err) => {
assert_eq!(err.message(), "user trap");
}
} }
#[test] Ok(())
fn trap_start_function_import() -> Result<()> { }
let store = get_store();
let binary = r#"
(module $a
(import "" "" (func $foo))
(start $foo)
)
"#;
let module = Module::new(&store, &binary)?; #[test]
let sig = FunctionType::new(vec![], vec![]); fn rust_panic_import() -> Result<()> {
let func = Function::new_dynamic(&store, &sig, |_| Err(RuntimeError::new("user trap"))); let store = get_store();
let err = Instance::new( let binary = r#"
(module $a
(import "" "foo" (func $foo))
(import "" "bar" (func $bar))
(func (export "foo") call $foo)
(func (export "bar") call $bar)
)
"#;
let module = Module::new(&store, &binary)?;
let sig = FunctionType::new(vec![], vec![]);
let func = Function::new_dynamic(&store, &sig, |_| panic!("this is a panic"));
let instance = Instance::new(
&module,
&imports! {
"" => {
"foo" => func,
"bar" => Function::new(&store, || panic!("this is another panic"))
}
},
)?;
let func = instance.exports.get_function("foo")?.clone();
let err = panic::catch_unwind(AssertUnwindSafe(|| {
drop(func.call(&[]));
}))
.unwrap_err();
assert_eq!(err.downcast_ref::<&'static str>(), Some(&"this is a panic"));
// TODO: Reenable this (disabled as it was not working with llvm/singlepass)
// It doesnt' work either with cranelift and `--test-threads=1`.
// let func = instance.exports.get_function("bar")?.clone();
// let err = panic::catch_unwind(AssertUnwindSafe(|| {
// drop(func.call(&[]));
// }))
// .unwrap_err();
// assert_eq!(
// err.downcast_ref::<&'static str>(),
// Some(&"this is another panic")
// );
Ok(())
}
#[test]
fn rust_panic_start_function() -> Result<()> {
let store = get_store();
let binary = r#"
(module $a
(import "" "" (func $foo))
(start $foo)
)
"#;
let module = Module::new(&store, &binary)?;
let sig = FunctionType::new(vec![], vec![]);
let func = Function::new_dynamic(&store, &sig, |_| panic!("this is a panic"));
let err = panic::catch_unwind(AssertUnwindSafe(|| {
drop(Instance::new(
&module, &module,
&imports! { &imports! {
"" => { "" => {
"" => func "" => func
} }
}, },
) ));
.err() }))
.unwrap(); .unwrap_err();
match err { assert_eq!(err.downcast_ref::<&'static str>(), Some(&"this is a panic"));
InstantiationError::Link(_) => panic!("It should be a start error"),
InstantiationError::Start(err) => {
assert_eq!(err.message(), "user trap");
}
}
Ok(()) let func = Function::new(&store, || panic!("this is another panic"));
} let err = panic::catch_unwind(AssertUnwindSafe(|| {
drop(Instance::new(
#[test]
fn rust_panic_import() -> Result<()> {
let store = get_store();
let binary = r#"
(module $a
(import "" "foo" (func $foo))
(import "" "bar" (func $bar))
(func (export "foo") call $foo)
(func (export "bar") call $bar)
)
"#;
let module = Module::new(&store, &binary)?;
let sig = FunctionType::new(vec![], vec![]);
let func = Function::new_dynamic(&store, &sig, |_| panic!("this is a panic"));
let instance = Instance::new(
&module, &module,
&imports! { &imports! {
"" => { "" => {
"foo" => func, "" => func
"bar" => Function::new(&store, || panic!("this is another panic"))
} }
}, },
)?; ));
let func = instance.exports.get_function("foo")?.clone(); }))
let err = panic::catch_unwind(AssertUnwindSafe(|| { .unwrap_err();
drop(func.call(&[])); assert_eq!(
})) err.downcast_ref::<&'static str>(),
.unwrap_err(); Some(&"this is another panic")
assert_eq!(err.downcast_ref::<&'static str>(), Some(&"this is a panic")); );
Ok(())
}
// TODO: Reenable this (disabled as it was not working with llvm/singlepass) #[test]
// It doesnt' work either with cranelift and `--test-threads=1`. fn mismatched_arguments() -> Result<()> {
// let func = instance.exports.get_function("bar")?.clone(); let store = get_store();
// let err = panic::catch_unwind(AssertUnwindSafe(|| { let binary = r#"
// drop(func.call(&[])); (module $a
// })) (func (export "foo") (param i32))
// .unwrap_err(); )
// assert_eq!( "#;
// err.downcast_ref::<&'static str>(),
// Some(&"this is another panic")
// );
Ok(())
}
#[test] let module = Module::new(&store, &binary)?;
fn rust_panic_start_function() -> Result<()> { let instance = Instance::new(&module, &imports! {})?;
let store = get_store(); let func: &Function = instance.exports.get("foo")?;
let binary = r#" assert_eq!(
(module $a func.call(&[]).unwrap_err().message(),
(import "" "" (func $foo)) "Parameters of type [] did not match signature [I32] -> []"
(start $foo) );
) assert_eq!(
"#; func.call(&[Val::F32(0.0)]).unwrap_err().message(),
"Parameters of type [F32] did not match signature [I32] -> []",
);
assert_eq!(
func.call(&[Val::I32(0), Val::I32(1)])
.unwrap_err()
.message(),
"Parameters of type [I32, I32] did not match signature [I32] -> []"
);
Ok(())
}
let module = Module::new(&store, &binary)?; #[test]
let sig = FunctionType::new(vec![], vec![]); #[cfg_attr(any(feature = "test-singlepass", feature = "test-llvm"), ignore)]
let func = Function::new_dynamic(&store, &sig, |_| panic!("this is a panic")); fn call_signature_mismatch() -> Result<()> {
let err = panic::catch_unwind(AssertUnwindSafe(|| { let store = get_store();
drop(Instance::new( let binary = r#"
&module, (module $a
&imports! { (func $foo
"" => { i32.const 0
"" => func call_indirect)
} (func $bar (param i32))
}, (start $foo)
));
}))
.unwrap_err();
assert_eq!(err.downcast_ref::<&'static str>(), Some(&"this is a panic"));
let func = Function::new(&store, || panic!("this is another panic")); (table 1 anyfunc)
let err = panic::catch_unwind(AssertUnwindSafe(|| { (elem (i32.const 0) 1)
drop(Instance::new( )
&module, "#;
&imports! {
"" => {
"" => func
}
},
));
}))
.unwrap_err();
assert_eq!(
err.downcast_ref::<&'static str>(),
Some(&"this is another panic")
);
Ok(())
}
#[test] let module = Module::new(&store, &binary)?;
fn mismatched_arguments() -> Result<()> { let err = Instance::new(&module, &imports! {})
let store = get_store(); .err()
let binary = r#" .expect("expected error");
(module $a assert_eq!(
(func (export "foo") (param i32)) format!("{}", err),
) "\
"#;
let module = Module::new(&store, &binary)?;
let instance = Instance::new(&module, &imports! {})?;
let func: &Function = instance.exports.get("foo")?;
assert_eq!(
func.call(&[]).unwrap_err().message(),
"Parameters of type [] did not match signature [I32] -> []"
);
assert_eq!(
func.call(&[Val::F32(0.0)]).unwrap_err().message(),
"Parameters of type [F32] did not match signature [I32] -> []",
);
assert_eq!(
func.call(&[Val::I32(0), Val::I32(1)])
.unwrap_err()
.message(),
"Parameters of type [I32, I32] did not match signature [I32] -> []"
);
Ok(())
}
#[test]
#[ignore]
fn call_signature_mismatch() -> Result<()> {
let store = get_store();
let binary = r#"
(module $a
(func $foo
i32.const 0
call_indirect)
(func $bar (param i32))
(start $foo)
(table 1 anyfunc)
(elem (i32.const 0) 1)
)
"#;
let module = Module::new(&store, &binary)?;
let err = Instance::new(&module, &imports! {})
.err()
.expect("expected error");
assert_eq!(
format!("{}", err),
"\
RuntimeError: indirect call type mismatch RuntimeError: indirect call type mismatch
at foo (a[0]:0x30)\ at foo (a[0]:0x30)\
" "
); );
Ok(()) Ok(())
} }
#[ignore] #[ignore]
#[test] #[cfg_attr(any(feature = "test-singlepass", feature = "test-llvm"), ignore)]
fn start_trap_pretty() -> Result<()> { fn start_trap_pretty() -> Result<()> {
let store = get_store(); let store = get_store();
let wat = r#" let wat = r#"
(module $m (module $m
(func $die unreachable) (func $die unreachable)
(func call $die) (func call $die)
(func $foo call 1) (func $foo call 1)
(func $start call $foo) (func $start call $foo)
(start $start) (start $start)
) )
"#; "#;
let module = Module::new(&store, wat)?; let module = Module::new(&store, wat)?;
let err = Instance::new(&module, &imports! {}) let err = Instance::new(&module, &imports! {})
.err() .err()
.expect("expected error"); .expect("expected error");
assert_eq!( assert_eq!(
format!("{}", err), format!("{}", err),
"\ "\
RuntimeError: unreachable RuntimeError: unreachable
at die (m[0]:0x1d) at die (m[0]:0x1d)
at <unnamed> (m[1]:0x21) at <unnamed> (m[1]:0x21)
at foo (m[2]:0x26) at foo (m[2]:0x26)
at start (m[3]:0x2b)\ at start (m[3]:0x2b)\
" "
); );
Ok(()) Ok(())
} }
#[test] #[test]
fn present_after_module_drop() -> Result<()> { fn present_after_module_drop() -> Result<()> {
let store = get_store(); let store = get_store();
let module = Module::new(&store, r#"(func (export "foo") unreachable)"#)?; let module = Module::new(&store, r#"(func (export "foo") unreachable)"#)?;
let instance = Instance::new(&module, &imports! {})?; let instance = Instance::new(&module, &imports! {})?;
let func: Function = instance.exports.get_function("foo")?.clone(); let func: Function = instance.exports.get_function("foo")?.clone();
println!("asserting before we drop modules"); println!("asserting before we drop modules");
assert_trap(func.call(&[]).unwrap_err()); assert_trap(func.call(&[]).unwrap_err());
drop((instance, module)); drop((instance, module));
println!("asserting after drop"); println!("asserting after drop");
assert_trap(func.call(&[]).unwrap_err()); assert_trap(func.call(&[]).unwrap_err());
return Ok(()); return Ok(());
fn assert_trap(t: RuntimeError) { fn assert_trap(t: RuntimeError) {
println!("{}", t); println!("{}", t);
// assert_eq!(t.trace().len(), 1); // assert_eq!(t.trace().len(), 1);
// assert_eq!(t.trace()[0].func_index(), 0); // assert_eq!(t.trace()[0].func_index(), 0);
}
} }
} }

29
tests/compilers/utils.rs Normal file
View File

@ -0,0 +1,29 @@
use std::sync::Arc;
use test_utils::get_compiler_config_from_str;
use wasmer::{Features, Store, Tunables};
use wasmer_engine_jit::JITEngine;
fn get_compiler_str() -> &'static str {
cfg_if::cfg_if! {
if #[cfg(feature = "test-cranelift")] {
"cranelift"
} else if #[cfg(feature = "test-llvm")] {
"llvm"
} else if #[cfg(feature = "test-singlepass")] {
"singlepass"
}
else {
compile_error!("No compiler chosen for the tests")
}
}
}
pub fn get_store() -> Store {
let features = Features::default();
let try_nan_canonicalization = false;
let compiler_config =
get_compiler_config_from_str(get_compiler_str(), try_nan_canonicalization, features);
let tunables = Tunables::for_target(compiler_config.target().triple());
let store = Store::new(Arc::new(JITEngine::new(compiler_config, tunables)));
store
}

View File

@ -169,7 +169,7 @@ pub fn with_features(
f: impl Fn(&mut Testsuite) -> anyhow::Result<()> + Copy, f: impl Fn(&mut Testsuite) -> anyhow::Result<()> + Copy,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
for compiler in features.iter() { for compiler in features.iter() {
writeln!(out.buffer, "#[cfg(feature=\"{}\")]", compiler)?; writeln!(out.buffer, "#[cfg(feature=\"test-{}\")]", compiler)?;
writeln!(out.buffer, "#[cfg(test)]")?; writeln!(out.buffer, "#[cfg(test)]")?;
writeln!(out.buffer, "#[allow(non_snake_case)]")?; writeln!(out.buffer, "#[allow(non_snake_case)]")?;
with_test_module(&mut out, &compiler, f)?; with_test_module(&mut out, &compiler, f)?;

View File

@ -20,11 +20,7 @@ pub fn wast_processor(out: &mut Testsuite, p: PathBuf) -> Option<Test> {
let compiler = out.path.get(0).unwrap(); let compiler = out.path.get(0).unwrap();
// The implementation of `run_wast` lives in /tests/spectest.rs // The implementation of `run_wast` lives in /tests/spectest.rs
let body = format!( let body = format!("crate::run_wast(r#\"{}\"#, \"{}\")", p.display(), compiler);
"crate::wast::run_wast(r#\"{}\"#, \"{}\")",
p.display(),
compiler
);
Some(Test { Some(Test {
name: testname, name: testname,