mirror of
https://github.com/fluencelabs/wasmer
synced 2025-05-02 05:42:13 +00:00
Improved tests to use available compilers
This commit is contained in:
parent
5f5928dfbd
commit
b301ac85be
@ -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"]
|
||||||
|
@ -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())
|
||||||
|
10
tests/custom/stack-overflow.wast
Normal file
10
tests/custom/stack-overflow.wast
Normal 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"))
|
@ -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
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
|
||||||
}
|
|
@ -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:
|
||||||
|
@ -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"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
47
tests/utils/macros.rs
Normal 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)*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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)) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user