Improved tests to use available compilers

This commit is contained in:
Syrus 2020-04-16 11:52:11 -07:00
parent 5f5928dfbd
commit b301ac85be
14 changed files with 428 additions and 467 deletions

View File

@ -96,7 +96,7 @@ wabt = "0.9.1"
# Don't add the backend features in default, please add them on the Makefile # Don't add the backend features in default, please add them on the Makefile
# since we might want to autoconfigure them depending on the availability on the host. # since we might want to autoconfigure them depending on the availability on the host.
default = ["wasi", "wabt"] default = ["wasi", "wabt"]
"loader-kernel" = ["wasmer-kernel-loader"] loader-kernel = ["wasmer-kernel-loader"]
debug = ["fern", "log/max_level_debug", "log/release_max_level_debug"] debug = ["fern", "log/max_level_debug", "log/release_max_level_debug"]
trace = ["fern", "log/max_level_trace", "log/release_max_level_trace"] trace = ["fern", "log/max_level_trace", "log/release_max_level_trace"]
docs = ["wasmer-runtime/docs"] docs = ["wasmer-runtime/docs"]

View File

@ -351,6 +351,10 @@ pub mod error {
/// Idea for generic trait; consider rename; it will need to be moved somewhere else /// Idea for generic trait; consider rename; it will need to be moved somewhere else
pub trait CompiledModule { pub trait CompiledModule {
fn new(bytes: impl AsRef<[u8]>) -> error::CompileResult<Module>; fn new(bytes: impl AsRef<[u8]>) -> error::CompileResult<Module>;
fn new_with_compiler(
bytes: impl AsRef<[u8]>,
compiler: Box<dyn compiler::Compiler>,
) -> error::CompileResult<Module>;
fn from_binary(bytes: impl AsRef<[u8]>) -> error::CompileResult<Module>; fn from_binary(bytes: impl AsRef<[u8]>) -> error::CompileResult<Module>;
fn from_binary_unchecked(bytes: impl AsRef<[u8]>) -> error::CompileResult<Module>; fn from_binary_unchecked(bytes: impl AsRef<[u8]>) -> error::CompileResult<Module>;
fn from_file(file: impl AsRef<std::path::Path>) -> Result<Module, error::CompileFromFileError>; fn from_file(file: impl AsRef<std::path::Path>) -> Result<Module, error::CompileFromFileError>;
@ -365,6 +369,14 @@ impl CompiledModule for Module {
wasmer_runtime_core::compile_with(bytes, &compiler::default_compiler()) wasmer_runtime_core::compile_with(bytes, &compiler::default_compiler())
} }
fn new_with_compiler(
bytes: impl AsRef<[u8]>,
compiler: Box<dyn compiler::Compiler>,
) -> error::CompileResult<Module> {
let bytes = bytes.as_ref();
wasmer_runtime_core::compile_with(bytes, &*compiler)
}
fn from_binary(bytes: impl AsRef<[u8]>) -> error::CompileResult<Module> { fn from_binary(bytes: impl AsRef<[u8]>) -> error::CompileResult<Module> {
let bytes = bytes.as_ref(); let bytes = bytes.as_ref();
wasmer_runtime_core::compile_with(bytes, &compiler::default_compiler()) wasmer_runtime_core::compile_with(bytes, &compiler::default_compiler())

View File

@ -0,0 +1,10 @@
(module
(type (;0;) (func))
(func (;0;) (type 0)
i32.const 0
call_indirect (type 0))
(table (;0;) 1 anyfunc)
(export "stack-overflow" (func 0))
(elem (;0;) (i32.const 0) 0))
(assert_exhaustion (invoke "stack-overflow"))

View File

@ -1,3 +1,8 @@
#![cfg(test)]
#[macro_use]
mod utils;
static TEST_WAT: &str = r#" static TEST_WAT: &str = r#"
(module (module
(import "env" "outside-global" (global $outside-global (mut i32))) (import "env" "outside-global" (global $outside-global (mut i32)))
@ -47,8 +52,11 @@ fn append_custom_section(
wasm.extend(custom_section_contents); wasm.extend(custom_section_contents);
} }
#[test] wasmer_backends! {
fn custom_section_parsing_works() { use super::{TEST_WAT, append_custom_section};
#[test]
fn custom_section_parsing_works() {
use wasmer::{CompiledModule, Module}; use wasmer::{CompiledModule, Module};
let wasm = { let wasm = {
let mut wasm = wabt::wat2wasm(TEST_WAT).unwrap(); let mut wasm = wabt::wat2wasm(TEST_WAT).unwrap();
@ -58,23 +66,23 @@ fn custom_section_parsing_works() {
wasm wasm
}; };
let module = Module::new(wasm).unwrap(); let module = Module::new_with_compiler(wasm, get_compiler()).unwrap();
assert_eq!( assert_eq!(
module.custom_sections("test_custom_section"), module.custom_sections("test_custom_section"),
Some(&[b"hello, world!".to_vec(), b"goodbye, world!".to_vec()][..]) Some(&[b"hello, world!".to_vec(), b"goodbye, world!".to_vec()][..])
); );
} }
#[test] #[test]
fn module_exports_are_ordered() { fn module_exports_are_ordered() {
use wasmer::types::{ElementType, FuncSig, GlobalDescriptor, TableDescriptor, Type}; use wasmer::types::{ElementType, FuncSig, GlobalDescriptor, TableDescriptor, Type};
use wasmer::{export, CompiledModule, Module}; use wasmer::{export, CompiledModule, Module};
let wasm = wabt::wat2wasm(TEST_WAT).unwrap(); let wasm = wabt::wat2wasm(TEST_WAT).unwrap();
// TODO: review error messages when `CompiledModule` is not in scope. My hypothesis is that they'll be // TODO: review error messages when `CompiledModule` is not in scope. My hypothesis is that they'll be
// misleading, if so we may want to do something about it. // misleading, if so we may want to do something about it.
let module = Module::new(wasm).unwrap(); let module = Module::new_with_compiler(wasm, get_compiler()).unwrap();
let exports = module.exports(); let exports = module.exports();
assert_eq!( assert_eq!(
exports, exports,
@ -112,31 +120,31 @@ fn module_exports_are_ordered() {
}, },
] ]
); );
} }
#[test] #[test]
fn module_imports_are_correct() { fn module_imports_are_correct() {
use wasmer::{CompiledModule, Module}; use wasmer::{CompiledModule, Module};
let wasm = wabt::wat2wasm(TEST_WAT).unwrap(); let wasm = wabt::wat2wasm(TEST_WAT).unwrap();
// TODO: review error messages when `CompiledModule` is not in scope. My hypothesis is that they'll be // TODO: review error messages when `CompiledModule` is not in scope. My hypothesis is that they'll be
// misleading, if so we may want to do something about it. // misleading, if so we may want to do something about it.
let module = Module::new(wasm).unwrap(); let module = Module::new_with_compiler(wasm, get_compiler()).unwrap();
// TODO: test this more later // TODO: test this more later
let imports = module.imports(); let imports = module.imports();
assert_eq!(imports.len(), 2); assert_eq!(imports.len(), 2);
} }
#[test] #[test]
fn module_can_be_instantiated() { fn module_can_be_instantiated() {
use wasmer::wasm::{Global, Value}; use wasmer::wasm::{Global, Value};
use wasmer::{func, imports, CompiledModule, Module}; use wasmer::{func, imports, CompiledModule, Module};
let wasm = wabt::wat2wasm(TEST_WAT).unwrap(); let wasm = wabt::wat2wasm(TEST_WAT).unwrap();
// TODO: review error messages when `CompiledModule` is not in scope. My hypothesis is that they'll be // TODO: review error messages when `CompiledModule` is not in scope. My hypothesis is that they'll be
// misleading, if so we may want to do something about it. // misleading, if so we may want to do something about it.
let module = Module::new(wasm).unwrap(); let module = Module::new_with_compiler(wasm, get_compiler()).unwrap();
let outside_global = Global::new_mutable(Value::I32(15)); let outside_global = Global::new_mutable(Value::I32(15));
let import_object = imports! { let import_object = imports! {
@ -148,17 +156,17 @@ fn module_can_be_instantiated() {
let instance = module.instantiate(&import_object); let instance = module.instantiate(&import_object);
assert!(instance.is_ok()); assert!(instance.is_ok());
} }
#[test] #[test]
fn exports_work() { fn exports_work() {
use wasmer::wasm::{Global, Value}; use wasmer::wasm::{Global, Value};
use wasmer::{func, imports, CompiledModule, Func, Module, Table}; use wasmer::{func, imports, CompiledModule, Func, Module, Table};
let wasm = wabt::wat2wasm(TEST_WAT).unwrap(); let wasm = wabt::wat2wasm(TEST_WAT).unwrap();
// TODO: review error messages when `CompiledModule` is not in scope. My hypothesis is that they'll be // TODO: review error messages when `CompiledModule` is not in scope. My hypothesis is that they'll be
// misleading, if so we may want to do something about it. // misleading, if so we may want to do something about it.
let module = Module::new(wasm).unwrap(); let module = Module::new_with_compiler(wasm, get_compiler()).unwrap();
let outside_global = Global::new_mutable(Value::I32(15)); let outside_global = Global::new_mutable(Value::I32(15));
@ -192,6 +200,7 @@ fn exports_work() {
assert_eq!(outside_global.get(), Value::I32(15 * 2)); assert_eq!(outside_global.get(), Value::I32(15 * 2));
update_outside_global.call().unwrap(); update_outside_global.call().unwrap();
assert_eq!(outside_global.get(), Value::I32(15 * 2 * 2)); assert_eq!(outside_global.get(), Value::I32(15 * 2 * 2));
}
} }
// copied from Rust stdlib: https://doc.rust-lang.org/nightly/nightly-rustc/src/serialize/leb128.rs.html#4-14 // copied from Rust stdlib: https://doc.rust-lang.org/nightly/nightly-rustc/src/serialize/leb128.rs.html#4-14

View File

@ -1,3 +1,6 @@
#[macro_use]
mod utils;
use std::{convert::TryInto, sync::Arc}; use std::{convert::TryInto, sync::Arc};
use wabt::wat2wasm; use wabt::wat2wasm;
use wasmer::compiler::{compile_with, compiler_for_backend, Backend}; use wasmer::compiler::{compile_with, compiler_for_backend, Backend};
@ -386,98 +389,99 @@ fn callback_fn_trap_with_vmctx(vmctx: &mut vm::Ctx, n: i32) -> Result<i32, Strin
} }
macro_rules! test { macro_rules! test {
($backend:expr, $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]
fn $test_name() { fn $test_name() {
imported_functions_forms($backend, &|instance| { imported_functions_forms(get_backend(), &|instance| {
call_and_assert!(instance, $function( $( $inputs ),* ) -> $output, ( $( $arguments ),* ) == $expected_value); call_and_assert!(instance, $function( $( $inputs ),* ) -> $output, ( $( $arguments ),* ) == $expected_value);
}); });
} }
};
} }
}
macro_rules! tests_for_backend { wasmer_backends! {
($backend:expr) => { use super::*;
test!($backend, test_fn, function_fn(i32) -> i32, (1) == Ok(2));
test!($backend, test_closure, function_closure(i32) -> i32, (1) == Ok(2)); test!( test_fn, function_fn(i32) -> i32, (1) == Ok(2));
test!($backend, test_fn_dynamic, function_fn_dynamic(i32) -> i32, (1) == Ok(2)); test!( test_closure, function_closure(i32) -> i32, (1) == Ok(2));
test!($backend, test_fn_dynamic_panic, function_fn_dynamic_panic(i32) -> i32, (1) == Err(RuntimeError(Box::new("test")))); 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!(
$backend,
test_closure_dynamic_0, test_closure_dynamic_0,
function_closure_dynamic_0(()) -> (), function_closure_dynamic_0(()) -> (),
() == Ok(()) () == Ok(())
); );
test!( test!(
$backend,
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!(
$backend,
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!(
$backend,
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!(
$backend,
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!(
$backend,
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!($backend, 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!(
$backend,
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!(
$backend,
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!(
$backend,
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!(
$backend,
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!(
$backend,
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!(
$backend,
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!(
$backend,
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))))
@ -485,29 +489,6 @@ macro_rules! tests_for_backend {
#[test] #[test]
fn runtime_core_new_api() { fn runtime_core_new_api() {
runtime_core_new_api_works($backend) runtime_core_new_api_works(get_backend())
} }
}
}
#[cfg(feature = "backend-singlepass")]
#[cfg(test)]
mod singlepass {
use super::*;
tests_for_backend!(Backend::Singlepass);
}
#[cfg(feature = "backend-cranelift")]
#[cfg(test)]
mod cranelift {
use super::*;
tests_for_backend!(Backend::Cranelift);
}
#[cfg(feature = "backend-llvm")]
#[cfg(test)]
mod llvm {
use super::*;
tests_for_backend!(Backend::LLVM);
} }

View File

@ -9,26 +9,26 @@
unreachable_patterns unreachable_patterns
)] )]
use wabt::wat2wasm; mod llvm {
use wasmer::compiler::Compiler; use wabt::wat2wasm;
use wasmer_llvm_backend::LLVMCompiler; use wasmer::compiler::Compiler;
use wasmer::compiler::CompilerConfig;
use wasmer::compiler::{compile_with, compile_with_config_with, BackendCompilerConfig};
use wasmer::imports;
use wasmer_llvm_backend::LLVMCompiler;
use wasmer_llvm_backend::{InkwellModule, LLVMBackendConfig, LLVMCallbacks};
pub fn get_compiler() -> impl Compiler { use std::cell::RefCell;
use std::rc::Rc;
pub fn get_compiler() -> impl Compiler {
LLVMCompiler::new() LLVMCompiler::new()
} }
use wasmer::compiler::CompilerConfig; #[test]
use wasmer::compiler::{compile_with, compile_with_config_with, BackendCompilerConfig}; fn crash_return_with_float_on_stack() {
use wasmer::imports;
use wasmer_llvm_backend::{InkwellModule, LLVMBackendConfig, LLVMCallbacks};
use std::cell::RefCell;
use std::rc::Rc;
#[test]
fn crash_return_with_float_on_stack() {
const MODULE: &str = r#" const MODULE: &str = r#"
(module (module
(type (func)) (type (func))
(type (func (param f64) (result f64))) (type (func (param f64) (result f64)))
(func $_start (type 0)) (func $_start (type 0))
@ -37,25 +37,25 @@ fn crash_return_with_float_on_stack() {
f64.const 0x0p+0 f64.const 0x0p+0
f64.mul f64.mul
return)) return))
"#; "#;
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();
module.instantiate(&imports! {}).unwrap(); module.instantiate(&imports! {}).unwrap();
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct RecordPreOptIR { pub struct RecordPreOptIR {
preopt_ir: String, preopt_ir: String,
} }
impl LLVMCallbacks for RecordPreOptIR { impl LLVMCallbacks for RecordPreOptIR {
fn preopt_ir_callback(&mut self, module: &InkwellModule) { fn preopt_ir_callback(&mut self, module: &InkwellModule) {
self.preopt_ir = module.print_to_string().to_string(); self.preopt_ir = module.print_to_string().to_string();
} }
} }
#[test] #[test]
fn crash_select_with_mismatched_pending() { fn crash_select_with_mismatched_pending() {
const WAT: &str = r#" const WAT: &str = r#"
(module (module
(func (param f64) (result f64) (func (param f64) (result f64)
@ -65,7 +65,7 @@ fn crash_select_with_mismatched_pending() {
f64.const 0x0p+0 f64.const 0x0p+0
i32.const 0 i32.const 0
select)) select))
"#; "#;
let record_pre_opt_ir = Rc::new(RefCell::new(RecordPreOptIR::default())); let record_pre_opt_ir = Rc::new(RefCell::new(RecordPreOptIR::default()));
let compiler_config = CompilerConfig { let compiler_config = CompilerConfig {
backend_specific_config: Some(BackendCompilerConfig(Box::new(LLVMBackendConfig { backend_specific_config: Some(BackendCompilerConfig(Box::new(LLVMBackendConfig {
@ -74,7 +74,8 @@ fn crash_select_with_mismatched_pending() {
..Default::default() ..Default::default()
}; };
let wasm_binary = wat2wasm(WAT.as_bytes()).expect("WAST not valid or malformed"); let wasm_binary = wat2wasm(WAT.as_bytes()).expect("WAST not valid or malformed");
let module = compile_with_config_with(&wasm_binary, compiler_config, &get_compiler()).unwrap(); let module =
compile_with_config_with(&wasm_binary, compiler_config, &get_compiler()).unwrap();
module.instantiate(&imports! {}).unwrap(); module.instantiate(&imports! {}).unwrap();
const LLVM: &str = r#" const LLVM: &str = r#"
%s3 = fadd double 0.000000e+00, %s2 %s3 = fadd double 0.000000e+00, %s2
@ -83,5 +84,7 @@ fn crash_select_with_mismatched_pending() {
%s5 = select i1 false, double %2, double 0.000000e+00 %s5 = select i1 false, double %2, double 0.000000e+00
br label %return br label %return
"#; "#;
// println!("Compiler IR {}", record_pre_opt_ir.borrow().preopt_ir);
assert!(&record_pre_opt_ir.borrow().preopt_ir.contains(LLVM)); assert!(&record_pre_opt_ir.borrow().preopt_ir.contains(LLVM));
}
} }

View File

@ -1,64 +0,0 @@
use wabt::wat2wasm;
use wasmer::compiler::compile;
use wasmer::{
import::ImportObject,
wasm::{Instance, Value},
DynFunc,
};
#[test]
fn override_works() {
let instance = create_module_1();
let result = instance
.exports
.get::<DynFunc>("call-overwritten-element")
.unwrap()
.call(&[])
.unwrap();
assert_eq!(result, vec![Value::I32(66)]);
println!("result: {:?}", result);
}
fn create_module_1() -> Instance {
let module_str = r#"(module
(type (;0;) (func (result i32)))
(import "spectest" "table" (table (;0;) 10 anyfunc))
(func (;0;) (type 0) (result i32)
i32.const 65)
(func (;1;) (type 0) (result i32)
i32.const 66)
(func (;2;) (type 0) (result i32)
i32.const 9
call_indirect (type 0))
(export "call-overwritten-element" (func 2))
(elem (;0;) (i32.const 9) 0)
(elem (;1;) (i32.const 9) 1))
"#;
let wasm_binary = wat2wasm(module_str.as_bytes()).expect("WAST not valid or malformed");
let module = compile(&wasm_binary[..]).expect("WASM can't be compiled");
module
.instantiate(&generate_imports())
.expect("WASM can't be instantiated")
}
static IMPORT_MODULE: &str = r#"
(module
(type $t0 (func (param i32)))
(type $t1 (func))
(func $print_i32 (export "print_i32") (type $t0) (param $lhs i32))
(func $print (export "print") (type $t1))
(table $table (export "table") 10 20 anyfunc)
(memory $memory (export "memory") 1 2)
(global $global_i32 (export "global_i32") i32 (i32.const 666)))
"#;
pub fn generate_imports() -> ImportObject {
let wasm_binary = wat2wasm(IMPORT_MODULE.as_bytes()).expect("WAST not valid or malformed");
let module = compile(&wasm_binary[..]).expect("WASM can't be compiled");
let instance = module
.instantiate(&ImportObject::new())
.expect("WASM can't be instantiated");
let mut imports = ImportObject::new();
imports.register("spectest", instance);
imports
}

View File

@ -1,14 +1,6 @@
mod utils; mod utils;
use std::path::Path; use std::path::Path;
#[cfg(not(any(
feature = "backend-llvm",
feature = "backend-cranelift",
feature = "backend-singlepass"
)))]
compile_error!("No compiler backend detected: please specify at least one compiler backend!");
use wasmer_wast::Wast; use wasmer_wast::Wast;
// The generated tests (from build.rs) look like: // The generated tests (from build.rs) look like:

View File

@ -1,39 +0,0 @@
#[cfg(test)]
mod tests {
use wabt::wat2wasm;
use wasmer::error::{CallError, ExceptionCode, RuntimeError};
use wasmer::import::ImportObject;
// The semantics of stack overflow are documented at:
// https://webassembly.org/docs/semantics/#stack-overflow
#[test]
#[ignore]
fn test_stack_overflow() {
let module_str = r#"(module
(type (;0;) (func))
(func (;0;) (type 0)
i32.const 0
call_indirect (type 0))
(table (;0;) 1 anyfunc)
(export "stack-overflow" (func 0))
(elem (;0;) (i32.const 0) 0))
"#;
let wasm_binary = wat2wasm(module_str.as_bytes()).expect("WAST not valid or malformed");
let module = wasmer::compiler::compile(&wasm_binary[..]).expect("WASM can't be compiled");
let instance = module
.instantiate(&ImportObject::new())
.expect("WASM can't be instantiated");
let result = instance.call("stack-overflow", &[]);
match result {
Err(err) => match err {
CallError::Runtime(RuntimeError(e)) => {
e.downcast::<ExceptionCode>()
.expect("expecting exception code");
}
_ => unimplemented!(),
},
Ok(_) => panic!("should fail with error due to stack overflow"),
}
}
}

View File

@ -7,6 +7,7 @@ use wasmer::compiler::Backend;
/// ///
/// This function errors if the backend doesn't exist or /// This function errors if the backend doesn't exist or
/// is not enabled. /// is not enabled.
#[allow(dead_code)]
pub fn get_backend_from_str(backend: &str) -> Result<Backend> { pub fn get_backend_from_str(backend: &str) -> Result<Backend> {
match backend { match backend {
#[cfg(feature = "backend-singlepass")] #[cfg(feature = "backend-singlepass")]

47
tests/utils/macros.rs Normal file
View File

@ -0,0 +1,47 @@
#[macro_export]
macro_rules! wasmer_backends {
{ $($code:item)* } => {
#[cfg(feature = "backend-singlepass")]
#[cfg(test)]
mod singlepass {
use wasmer::compiler::{Backend, Compiler, compiler_for_backend};
#[allow(dead_code)]
fn get_backend() -> Backend {
Backend::Singlepass
}
#[allow(dead_code)]
fn get_compiler() -> Box<dyn Compiler> {
compiler_for_backend(get_backend()).expect("Backend must have a compiler")
}
$($code)*
}
#[cfg(feature = "backend-cranelift")]
#[cfg(test)]
mod cranelift {
use wasmer::compiler::{Backend, Compiler, compiler_for_backend};
#[allow(dead_code)]
fn get_backend() -> Backend {
Backend::Cranelift
}
#[allow(dead_code)]
fn get_compiler() -> Box<dyn Compiler> {
compiler_for_backend(get_backend()).expect("Backend must have a compiler")
}
$($code)*
}
#[cfg(feature = "backend-llvm")]
#[cfg(test)]
mod llvm {
use wasmer::compiler::{Backend, Compiler, compiler_for_backend};
#[allow(dead_code)]
fn get_backend() -> Backend {
Backend::LLVM
}
#[allow(dead_code)]
fn get_compiler() -> Box<dyn Compiler> {
compiler_for_backend(get_backend()).expect("Backend must have a compiler")
}
$($code)*
}
};
}

View File

@ -1,6 +1,8 @@
mod backend; mod backend;
mod file_descriptor; mod file_descriptor;
mod stdio; mod stdio;
#[macro_use]
mod macros;
pub use backend::get_backend_from_str; pub use backend::get_backend_from_str;
pub use stdio::StdioCapturer; pub use stdio::StdioCapturer;

View File

@ -1,3 +1,5 @@
#![allow(dead_code)]
use super::file_descriptor::FileDescriptor; use super::file_descriptor::FileDescriptor;
use libc; use libc;
use std::io; use std::io;

View File

@ -1,14 +1,18 @@
#![cfg(test)] #![cfg(test)]
use wasmer::{compiler::compile, vm::Ctx, Func};
use wasmer_wasi::{state::*, *};
use std::ffi::c_void; #[macro_use]
mod utils;
// TODO: fix this test! wasmer_backends! {
#[ignore] use wasmer::{compiler::compile_with, vm::Ctx, Func};
#[cfg(not(feature = "singlepass"))] use wasmer_wasi::{state::*, *};
#[test] use std::ffi::c_void;
fn serializing_works() {
// TODO: fix this test!
#[ignore]
#[cfg(not(feature = "singlepass"))]
#[test]
fn serializing_works() {
let args = vec![ let args = vec![
b"program_name".into_iter().cloned().collect(), b"program_name".into_iter().cloned().collect(),
b"arg1".into_iter().cloned().collect(), b"arg1".into_iter().cloned().collect(),
@ -18,7 +22,7 @@ fn serializing_works() {
b"GOROOT=$HOME/.cargo/bin".into_iter().cloned().collect(), b"GOROOT=$HOME/.cargo/bin".into_iter().cloned().collect(),
]; ];
let wasm_binary = include_bytes!("wasi_test_resources/unstable/fd_read.wasm"); let wasm_binary = include_bytes!("wasi_test_resources/unstable/fd_read.wasm");
let module = compile(&wasm_binary[..]) let module = compile_with(&wasm_binary[..], &*get_compiler())
.map_err(|e| format!("Can't compile module: {:?}", e)) .map_err(|e| format!("Can't compile module: {:?}", e))
.unwrap(); .unwrap();
@ -57,9 +61,10 @@ fn serializing_works() {
let second_entry: Func<(), i32> = instance.exports.get("second_entry").unwrap(); let second_entry: Func<(), i32> = instance.exports.get("second_entry").unwrap();
let result = second_entry.call().unwrap(); let result = second_entry.call().unwrap();
assert_eq!(result, true as i32); assert_eq!(result, true as i32);
} }
#[allow(clippy::mut_from_ref)] #[allow(clippy::mut_from_ref)]
pub(crate) fn get_wasi_state(ctx: &Ctx) -> &mut WasiState { pub(crate) fn get_wasi_state(ctx: &Ctx) -> &mut WasiState {
unsafe { state::get_wasi_state(&mut *(ctx as *const Ctx as *mut Ctx)) } unsafe { state::get_wasi_state(&mut *(ctx as *const Ctx as *mut Ctx)) }
}
} }