From c2306bd39e4454c60110d5d3ec13d20df9b225e6 Mon Sep 17 00:00:00 2001 From: Syrus Date: Fri, 10 Apr 2020 20:18:27 -0700 Subject: [PATCH 1/9] Renamed dev_utils to utils --- tests/emtest.rs | 2 +- tests/emtests/_common.rs | 2 +- tests/{dev_utils => utils}/file_descriptor.rs | 0 tests/{dev_utils => utils}/mod.rs | 0 tests/{dev_utils => utils}/stdio.rs | 0 tests/wasitest.rs | 2 +- tests/wasitests/_common.rs | 2 +- 7 files changed, 4 insertions(+), 4 deletions(-) rename tests/{dev_utils => utils}/file_descriptor.rs (100%) rename tests/{dev_utils => utils}/mod.rs (100%) rename tests/{dev_utils => utils}/stdio.rs (100%) diff --git a/tests/emtest.rs b/tests/emtest.rs index ae941d3c84b..206387d1d3e 100644 --- a/tests/emtest.rs +++ b/tests/emtest.rs @@ -1,2 +1,2 @@ -pub mod dev_utils; +pub mod utils; mod emtests; diff --git a/tests/emtests/_common.rs b/tests/emtests/_common.rs index 0547a002a73..9eae188d973 100644 --- a/tests/emtests/_common.rs +++ b/tests/emtests/_common.rs @@ -37,7 +37,7 @@ macro_rules! assert_emscripten_output { EmscriptenGlobals, generate_emscripten_env, }; - use crate::dev_utils::stdio::StdioCapturer; + use crate::utils::stdio::StdioCapturer; let wasm_bytes = include_bytes!($file); let backend = $crate::emtests::_common::get_backend().expect("Please set one of `WASMER_TEST_CRANELIFT`, `WASMER_TEST_LLVM`, or `WASMER_TEST_SINGELPASS` to `1`."); diff --git a/tests/dev_utils/file_descriptor.rs b/tests/utils/file_descriptor.rs similarity index 100% rename from tests/dev_utils/file_descriptor.rs rename to tests/utils/file_descriptor.rs diff --git a/tests/dev_utils/mod.rs b/tests/utils/mod.rs similarity index 100% rename from tests/dev_utils/mod.rs rename to tests/utils/mod.rs diff --git a/tests/dev_utils/stdio.rs b/tests/utils/stdio.rs similarity index 100% rename from tests/dev_utils/stdio.rs rename to tests/utils/stdio.rs diff --git a/tests/wasitest.rs b/tests/wasitest.rs index dd8af38246f..ec5d6a311c2 100644 --- a/tests/wasitest.rs +++ b/tests/wasitest.rs @@ -1,2 +1,2 @@ -pub mod dev_utils; +pub mod utils; mod wasitests; diff --git a/tests/wasitests/_common.rs b/tests/wasitests/_common.rs index 12bde29920f..bd11a407b94 100644 --- a/tests/wasitests/_common.rs +++ b/tests/wasitests/_common.rs @@ -32,7 +32,7 @@ pub fn get_backend() -> Option { macro_rules! assert_wasi_output { ($file:expr, $name:expr, $po_dir_args: expr, $mapdir_args:expr, $envvar_args:expr, $expected:expr) => {{ - use crate::dev_utils::stdio::StdioCapturer; + use crate::utils::stdio::StdioCapturer; use wasmer::Func; use wasmer_wasi::{generate_import_object_for_version, get_wasi_version}; From a7dba54b7fe8f8d032021bfd2f501c12c88458bc Mon Sep 17 00:00:00 2001 From: Syrus Date: Tue, 14 Apr 2020 11:41:12 -0700 Subject: [PATCH 2/9] Improved test generation --- Cargo.lock | 40 +- Cargo.toml | 7 +- Makefile | 8 +- build.rs | 102 +- lib/runtime-core/src/import.rs | 5 + tests/emtest.rs | 2 +- tests/spectest.rs | 1576 +------------------------------ tests/test-generator/Cargo.toml | 8 + tests/test-generator/src/lib.rs | 162 ++++ tests/wast/Cargo.toml | 17 + tests/wast/README.md | 7 + tests/wast/src/errors.rs | 50 + tests/wast/src/lib.rs | 34 + tests/wast/src/spectest.rs | 56 ++ tests/wast/src/wast.rs | 506 ++++++++++ 15 files changed, 1020 insertions(+), 1560 deletions(-) create mode 100644 tests/test-generator/Cargo.toml create mode 100644 tests/test-generator/src/lib.rs create mode 100644 tests/wast/Cargo.toml create mode 100644 tests/wast/README.md create mode 100644 tests/wast/src/errors.rs create mode 100644 tests/wast/src/lib.rs create mode 100644 tests/wast/src/spectest.rs create mode 100644 tests/wast/src/wast.rs diff --git a/Cargo.lock b/Cargo.lock index dc0133cea42..21128ecc0b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2258,6 +2258,14 @@ dependencies = [ "winapi 0.3.8", ] +[[package]] +name = "test-generator" +version = "0.1.0" +dependencies = [ + "anyhow", + "target-lexicon", +] + [[package]] name = "textwrap" version = "0.11.0" @@ -2269,18 +2277,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.11" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee14bf8e6767ab4c687c9e8bc003879e042a96fd67a3ba5934eadb6536bef4db" +checksum = "54b3d3d2ff68104100ab257bb6bb0cb26c901abe4bd4ba15961f3bf867924012" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.11" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7b51e1fbc44b5a0840be594fbc0f960be09050f2617e61e6aa43bef97cd3ef4" +checksum = "ca972988113b7715266f91250ddb98070d033c62a011fa0fcc57434a649310dd" dependencies = [ "proc-macro2 1.0.9", "quote 1.0.2", @@ -2746,6 +2754,7 @@ dependencies = [ name = "wasmer-bin" version = "0.16.2" dependencies = [ + "anyhow", "atty", "byteorder", "criterion", @@ -2759,6 +2768,7 @@ dependencies = [ "rustc_version", "serde", "structopt", + "test-generator", "typetag", "wabt", "wasmer", @@ -2772,6 +2782,7 @@ dependencies = [ "wasmer-singlepass-backend", "wasmer-wasi", "wasmer-wasi-experimental-io-devices", + "wasmer-wast", ] [[package]] @@ -2844,7 +2855,7 @@ version = "0.16.2" dependencies = [ "nom", "serde", - "wast", + "wast 8.0.0", ] [[package]] @@ -2987,6 +2998,16 @@ dependencies = [ "wasmer-wasi", ] +[[package]] +name = "wasmer-wast" +version = "0.16.2" +dependencies = [ + "anyhow", + "thiserror", + "wasmer", + "wast 9.0.0", +] + [[package]] name = "wasmer-win-exception-handler" version = "0.16.2" @@ -3012,6 +3033,15 @@ dependencies = [ "leb128", ] +[[package]] +name = "wast" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee7b16105405ca2aa2376ba522d8d4b1a11604941dd3bb7df9fd2ece60f8d16a" +dependencies = [ + "leb128", +] + [[package]] name = "web-sys" version = "0.3.36" diff --git a/Cargo.toml b/Cargo.toml index 23add2e44f0..075edb4d96d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,18 +59,23 @@ members = [ "examples/parallel", "examples/plugin-for-example", "examples/parallel-guest", + "tests/test-generator", "tests/generate-wasi-tests", "tests/generate-emscripten-tests", + "tests/wast", ] [build-dependencies] -wabt = "0.9.1" +anyhow = "1.0.19" generate-emscripten-tests = { path = "tests/generate-emscripten-tests" } generate-wasi-tests = { path = "tests/generate-wasi-tests" } +test-generator = { path = "tests/test-generator" } glob = "0.3" rustc_version = "0.2" [dev-dependencies] +anyhow = "1.0.19" +wasmer-wast = { path = "tests/wast" } criterion = "0.3" glob = "0.3" libc = "0.2.60" # for `tests/dev-utils`'s Stdout capturing diff --git a/Makefile b/Makefile index 7c9448c254d..38435fc615b 100644 --- a/Makefile +++ b/Makefile @@ -35,17 +35,17 @@ generate: generate-emtests generate-wasitests # Spectests spectests-singlepass: - WASMER_TEST_SINGLEPASS=1 cargo test test_run_spectests --release --no-default-features --features "wasi backend-singlepass" -- --nocapture --test-threads 1 + WASMER_TEST_SINGLEPASS=1 cargo test singlepass::spec --release --no-default-features --features "wasi backend-singlepass" spectests-cranelift: - WASMER_TEST_CRANELFIT=1 cargo test test_run_spectests --release --no-default-features --features "wasi backend-cranelift" -- --nocapture + WASMER_TEST_CRANELFIT=1 cargo test cranelift::spec --release --no-default-features --features "wasi backend-cranelift" spectests-llvm: - WASMER_TEST_LLVM=1 cargo test test_run_spectests --release --no-default-features --features "wasi backend-llvm wasmer-llvm-backend/test" -- --nocapture + WASMER_TEST_LLVM=1 cargo test llvm::spec --release --no-default-features --features "wasi backend-llvm wasmer-llvm-backend/test" spectests-all: WASMER_TEST_CRANELIFT=1 WASMER_TEST_LLVM=1 WASMER_TEST_SINGLEPASS=1 \ - cargo test test_run_spectests --release --no-default-features --features "wasi backend-cranelift backend-singlepass backend-llvm wasmer-llvm-backend/test" -- --nocapture --test-threads 1 + cargo test spec --release --no-default-features --features "wasi backend-cranelift backend-singlepass backend-llvm wasmer-llvm-backend/test" spectests: spectests-singlepass spectests-cranelift spectests-llvm diff --git a/build.rs b/build.rs index 4f74ecfff9f..dc598c2b434 100644 --- a/build.rs +++ b/build.rs @@ -4,8 +4,108 @@ use generate_emscripten_tests; use generate_wasi_tests; +use std::env; +use std::fmt::Write; +use std::fs; +use std::path::PathBuf; +use std::process::Command; +use test_generator::{ + build_ignores_from_textfile, extract_name, test_directory, test_directory_module, + with_test_module, Test, Testsuite, +}; + +/// Given a Testsuite and a path, process the path in case is a wast +/// file. +fn wast_processor(out: &mut Testsuite, p: PathBuf) -> Option { + let ext = p.extension()?; + // Only look at wast files. + if ext != "wast" { + return None; + } + + // Ignore files starting with `.`, which could be editor temporary files + if p.file_stem()?.to_str()?.starts_with(".") { + return None; + } + + let testname = extract_name(&p); + let body = format!( + "crate::run_wast(r#\"{}\"#, \"{}\")", + p.display(), + out.path.get(0).unwrap() + ); + + Some(Test { + name: testname.to_string(), + body: body.to_string(), + }) +} + +fn main() -> anyhow::Result<()> { + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=test/ignores.txt"); -fn main() { generate_wasi_tests::build(); generate_emscripten_tests::build(); + + let out_dir = PathBuf::from( + env::var_os("OUT_DIR").expect("The OUT_DIR environment variable must be set"), + ); + let ignores = build_ignores_from_textfile("tests/ignores.txt".into())?; + let mut out = Testsuite { + buffer: String::new(), + path: vec![], + ignores: ignores, + }; + + for compiler in &["singlepass", "cranelift", "llvm"] { + writeln!(out.buffer, "#[cfg(feature=\"backend-{}\")]", compiler); + writeln!(out.buffer, "#[cfg(test)]")?; + writeln!(out.buffer, "#[allow(non_snake_case)]")?; + with_test_module(&mut out, compiler, |mut out| { + with_test_module(&mut out, "spec", |out| { + let spec_tests = test_directory(out, "tests/spectests", wast_processor)?; + // Skip running spec_testsuite tests if the submodule isn't checked + // out. + // if spec_tests > 0 { + // test_directory_module( + // out, + // "tests/spec_testsuite/proposals/simd", + // wast_processor, + // )?; + // test_directory_module( + // out, + // "tests/spec_testsuite/proposals/multi-value", + // wast_processor, + // )?; + // test_directory_module( + // out, + // "tests/spec_testsuite/proposals/reference-types", + // wast_processor, + // )?; + // test_directory_module( + // out, + // "tests/spec_testsuite/proposals/bulk-memory-operations", + // wast_processor, + // )?; + // } else { + // println!( + // "cargo:warning=The spec testsuite is disabled. To enable, run `git submodule \ + // update --remote`." + // ); + // } + Ok(()) + })?; + Ok(()) + })?; + } + + // println!("{}", out.buffer); + // std::process::exit(1); + // Write out our auto-generated tests and opportunistically format them with + // `rustfmt` if it's installed. + let output = out_dir.join("generated_tests.rs"); + fs::write(&output, out.buffer)?; + drop(Command::new("rustfmt").arg(&output).status()); + Ok(()) } diff --git a/lib/runtime-core/src/import.rs b/lib/runtime-core/src/import.rs index 284ff1725a5..a40f0273d86 100644 --- a/lib/runtime-core/src/import.rs +++ b/lib/runtime-core/src/import.rs @@ -178,6 +178,11 @@ impl ImportObject { } out } + + /// Returns true if the ImportObject contains namespace with the provided name. + pub fn contains_namespace(&self, name: &str) -> bool { + self.map.lock().unwrap().borrow().contains_key(name) + } } /// Iterator for an `ImportObject`'s exports. diff --git a/tests/emtest.rs b/tests/emtest.rs index 206387d1d3e..bf9de1a278d 100644 --- a/tests/emtest.rs +++ b/tests/emtest.rs @@ -1,2 +1,2 @@ -pub mod utils; mod emtests; +pub mod utils; diff --git a/tests/spectest.rs b/tests/spectest.rs index 32a08c39d36..737f0178f1c 100644 --- a/tests/spectest.rs +++ b/tests/spectest.rs @@ -1,11 +1,4 @@ -#![deny( - bad_style, - dead_code, - unused_imports, - unused_variables, - unused_unsafe, - unreachable_patterns -)] +use std::path::Path; #[cfg(not(any( feature = "backend-llvm", @@ -13,1545 +6,32 @@ feature = "backend-singlepass" )))] compile_error!("No compiler backend detected: please specify at least one compiler backend!"); - -#[cfg(test)] -mod tests { - - // TODO fix spec failures - // TODO fix panics and remove panic handlers - // TODO do something with messages _message, message: _, msg: _ - // TODO consider git submodule for spectests? & separate dir for simd/extra tests - // TODO cleanup refactor - // TODO Files could be run with multiple threads - // TODO Allow running WAST &str directly (E.g. for use outside of spectests) - - use std::collections::HashSet; - use std::env; - use std::sync::{Arc, Mutex}; - - struct SpecFailure { - file: String, - line: u64, - kind: String, - message: String, - } - - struct TestReport { - failures: Vec, - passed: u32, - failed: u32, - allowed_failure: u32, - } - - impl TestReport { - pub fn count_passed(&mut self) { - self.passed += 1; - } - - pub fn has_failures(&self) -> bool { - self.failed > 0 - } - - pub fn add_failure( - &mut self, - failure: SpecFailure, - _testkey: &str, - excludes: &mut Vec>, - line: u64, - ) { - // Ensure that each exclude is only used once. - if let Some(_) = excludes - .iter_mut() - .find(|e| { - if let Some(ref e) = e { - e.line_matches(line) && e.exclude_kind == ExcludeKind::Fail - } else { - false - } - }) - .take() - .and_then(|x| x.take()) - { - self.allowed_failure += 1; - return; - } - self.failed += 1; - self.failures.push(failure); - } - } - - fn get_available_compilers() -> &'static [&'static str] { - &[ - #[cfg(feature = "backend-cranelift")] - "clif", - #[cfg(feature = "backend-llvm")] - "llvm", - #[cfg(feature = "backend-singlepass")] - "singlepass", - ] - } - - fn get_compilers_to_test() -> Vec<&'static str> { - let mut out = vec![]; - if let Ok(v) = env::var("WASMER_TEST_CRANELIFT") { - if v == "1" { - out.push("clif"); - } - } - if let Ok(v) = env::var("WASMER_TEST_LLVM") { - if v == "1" { - out.push("llvm"); - } - } - if let Ok(v) = env::var("WASMER_TEST_SINGLEPASS") { - if v == "1" { - out.push("singlepass"); - } - } - - out - } - - #[cfg(unix)] - fn get_target_family() -> &'static str { - "unix" - } - - #[cfg(windows)] - fn get_target_family() -> &'static str { - "windows" - } - - #[cfg(target_os = "android")] - fn get_target_os() -> &'static str { - "android" - } - - #[cfg(target_os = "freebsd")] - fn get_target_os() -> &'static str { - "freebsd" - } - - #[cfg(target_os = "linux")] - fn get_target_os() -> &'static str { - "linux" - } - - #[cfg(target_os = "macos")] - fn get_target_os() -> &'static str { - "macos" - } - - #[cfg(target_os = "windows")] - fn get_target_os() -> &'static str { - "windows" - } - - fn get_target_arch() -> &'static str { - if cfg!(target_arch = "x86_64") { - "x86_64" - } else if cfg!(target_arch = "aarch64") { - "aarch64" - } else if cfg!(target_arch = "x86") { - "x86" - } else if cfg!(target_arch = "mips") { - "mips" - } else if cfg!(target_arch = "powerpc") { - "powerpc" - } else if cfg!(target_arch = "powerpc64") { - "powerpc64" - } else if cfg!(target_arch = "arm") { - "arm" - } else { - panic!("unknown target arch") - } - } - - // clif:skip:data.wast:172:unix:x86 - #[allow(dead_code)] - #[derive(Clone)] - struct Exclude { - backend: Option, - exclude_kind: ExcludeKind, - file: String, - line: Option, - target_family: Option, - target_arch: Option, - } - - impl Exclude { - fn line_matches(&self, value: u64) -> bool { - self.line.is_none() || self.line.unwrap() == value - } - - fn line_exact_match(&self, value: u64) -> bool { - self.line.is_some() && self.line.unwrap() == value - } - - fn matches_backend(&self, value: &str) -> bool { - self.backend.is_none() || self.backend.as_ref().unwrap() == value - } - - fn matches_target_family(&self, value: &str) -> bool { - self.target_family.is_none() || self.target_family.as_ref().unwrap() == value - } - - fn matches_target_arch(&self, value: &str) -> bool { - self.target_arch.is_none() || self.target_arch.as_ref().unwrap() == value - } - - fn from( - backend: &str, - exclude_kind: &str, - file: &str, - line: &str, - target_family: &str, - target_arch: &str, - ) -> Exclude { - let backend: Option = match backend { - "*" => None, - "clif" => Some("clif".to_string()), - "singlepass" => Some("singlepass".to_string()), - "llvm" => Some("llvm".to_string()), - _ => panic!("backend {:?} not recognized", backend), - }; - let exclude_kind = match exclude_kind { - "skip" => ExcludeKind::Skip, - "fail" => ExcludeKind::Fail, - _ => panic!("exclude kind {:?} not recognized", exclude_kind), - }; - let line = match line { - "*" => None, - _ => Some( - line.parse::() - .expect(&format!("expected * or int: {:?}", line)), - ), - }; - let target_family = match target_family { - "*" => None, - _ => Some(target_family.to_string()), - }; - let target_arch = match target_arch { - "*" => None, - _ => Some(target_arch.to_string()), - }; - Exclude { - backend, - exclude_kind, - file: file.to_string(), - line, - target_family, - target_arch, - } - } - } - - fn with_instance( - maybe_instance: Option>>, - named_modules: &HashMap>>, - module: &Option, - f: F, - ) -> Option - where - R: Sized, - F: FnOnce(&Instance) -> R, - { - let ref ins = module - .as_ref() - .and_then(|name| named_modules.get(name).cloned()) - .or(maybe_instance)?; - let guard = ins.lock().unwrap(); - Some(f(guard.borrow())) - } - - use glob::glob; - use std::collections::HashMap; - use std::fs; - use std::panic::AssertUnwindSafe; - use std::path::PathBuf; - use std::str::FromStr; - use wabt::script::{Action, Command, CommandKind, ScriptParser, Value}; - use wasmer::wasm::Export; - use wasmer::{ - compiler::{compile_with_config_with, compiler_for_backend, Backend, CompilerConfig}, - error::CompileError, - func, - import::{ImportObject, LikeNamespace}, - imports, - types::ElementType, - units::Pages, - vm::Ctx, - wasm::{ - self, Features, Global, Instance, Memory, MemoryDescriptor, Table, TableDescriptor, - }, +use anyhow::bail; +use wasmer::compiler::Backend; +use wasmer_wast::Wast; + +// #[cfg(test)] +// mod spectests { +// mod cranelift { +// #[test] +// fn address() -> Result<(), String> { +// crate::run_wast("tests/spectests/address.wast", "llvm") +// } +// } +// } +include!(concat!(env!("OUT_DIR"), "/generated_tests.rs")); + +fn run_wast(wast_path: &str, backend: &str) -> anyhow::Result<()> { + let backend = match backend { + #[cfg(feature = "backend-singlepass")] + "singlepass" => Backend::Singlepass, + #[cfg(feature = "backend-cranelift")] + "cranelift" => Backend::Cranelift, + #[cfg(feature = "backend-llvm")] + "llvm" => Backend::LLVM, + _ => bail!("Backend {} not found", backend), }; - - fn format_panic(e: &dyn std::any::Any) -> String { - if let Some(s) = e.downcast_ref::<&str>() { - format!("{}", s) - } else if let Some(s) = e.downcast_ref::() { - format!("{}", s) - } else { - "(unknown)".into() - } - } - - fn parse_and_run( - path: &PathBuf, - file_excludes: &HashSet, - excludes: &HashMap>, - backend: &'static str, - ) -> Result { - let mut test_report = TestReport { - failures: vec![], - passed: 0, - failed: 0, - allowed_failure: 0, - }; - - let filename = path.file_name().unwrap().to_str().unwrap(); - let source = fs::read(&path).unwrap(); - - // Entire file is excluded by line * and skip - if file_excludes.contains(filename) { - return Ok(test_report); - } - - let mut features = wabt::Features::new(); - features.enable_simd(); - features.enable_threads(); - features.enable_sign_extension(); - features.enable_sat_float_to_int(); - let mut parser: ScriptParser = - ScriptParser::from_source_and_name_with_features(&source, filename, features) - .expect(&format!("Failed to parse script {}", &filename)); - - use std::panic; - let mut instance: Option>> = None; - - let mut named_modules: HashMap>> = HashMap::new(); - - let mut registered_modules: HashMap>> = HashMap::new(); - let mut excludes: Vec<_> = excludes - .get(filename) - .map(|file| file.iter().map(|x| Some(x.clone())).collect()) - .unwrap_or(vec![]); - let excludes = &mut excludes; - let backend_enum = Backend::from_str(if backend == "clif" { - "cranelift" - } else { - backend - }) - .unwrap(); - - while let Some(Command { kind, line }) = - parser.next().map_err(|e| format!("Parse err: {:?}", e))? - { - let test_key = format!("{}:{}:{}", backend, filename, line); - // Use this line to debug which test is running - println!("Running test: {}", test_key); - - // Skip tests that match this line - if excludes - .iter() - .filter_map(|x| x.as_ref()) - .any(|e| e.line_exact_match(line) && e.exclude_kind == ExcludeKind::Skip) - { - continue; - } - - match kind { - CommandKind::Module { module, name } => { - // println!("Module"); - let result = panic::catch_unwind(AssertUnwindSafe(|| { - let spectest_import_object = - get_spectest_import_object(®istered_modules); - let config = CompilerConfig { - features: Features { - simd: true, - threads: true, - }, - nan_canonicalization: true, - enable_verification: true, - ..Default::default() - }; - - let compiler = compiler_for_backend(backend_enum).unwrap(); - let module = - compile_with_config_with(&module.into_vec(), config, &*compiler) - .expect("WASM can't be compiled"); - let i = module - .instantiate(&spectest_import_object) - .expect("WASM can't be instantiated"); - i - })); - match result { - Err(e) => { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line: line, - kind: format!("{}", "Module"), - message: format!("caught panic {}", format_panic(&e)), - }, - &test_key, - excludes, - line, - ); - instance = None; - } - Ok(i) => { - let i = Arc::new(Mutex::new(i)); - if name.is_some() { - named_modules.insert(name.unwrap(), Arc::clone(&i)); - } - instance = Some(i); - } - } - } - CommandKind::AssertReturn { action, expected } => { - match action { - Action::Invoke { - module, - field, - args, - } => { - let maybe_call_result = with_instance( - instance.clone(), - &named_modules, - &module, - |instance| { - let params: Vec = - args.iter().cloned().map(convert_value).collect(); - instance.call(&field, ¶ms[..]) - }, - ); - if maybe_call_result.is_none() { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line: line, - kind: format!("{}", "AssertReturn"), - message: format!("No instance available: {:?}", &module), - }, - &test_key, - excludes, - line, - ); - } else { - let call_result = maybe_call_result.unwrap(); - match call_result { - Err(e) => { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line, - kind: format!("{}", "AssertReturn"), - message: format!("Call failed {:?}", e), - }, - &test_key, - excludes, - line, - ); - } - Ok(values) => { - for (i, v) in values.iter().enumerate() { - let expected_value = - convert_wabt_value(*expected.get(i).unwrap()); - let v = convert_wasmer_value(v.clone()); - if v != expected_value { - test_report.add_failure(SpecFailure { - file: filename.to_string(), - line, - kind: format!("{}", "AssertReturn"), - message: format!( - "result {:?} ({:?}) does not match expected {:?} ({:?})", - v, to_hex(v.clone()), expected_value, to_hex(expected_value.clone()) - ), - }, &test_key, excludes, line); - } else { - test_report.count_passed(); - } - } - } - } - } - } - Action::Get { module, field } => { - let maybe_call_result = with_instance( - instance.clone(), - &named_modules, - &module, - |instance| { - instance - .get_export(&field) - .expect(&format!("missing global {:?}", &field)) - }, - ); - if maybe_call_result.is_none() { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line: line, - kind: format!("{}", "AssertReturn Get"), - message: format!("No instance available {:?}", &module), - }, - &test_key, - excludes, - line, - ); - } else { - let export: Export = maybe_call_result.unwrap(); - match export { - Export::Global(g) => { - let value = g.get(); - let expected_value = - convert_value(*expected.get(0).unwrap()); - if value == expected_value { - test_report.count_passed(); - } else { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line: line, - kind: format!("{}", "AssertReturn Get"), - message: format!( - "Expected Global {:?} got: {:?}", - expected_value, value - ), - }, - &test_key, - excludes, - line, - ); - } - } - _ => { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line: line, - kind: format!("{}", "AssertReturn Get"), - message: format!("Expected Global"), - }, - &test_key, - excludes, - line, - ); - } - } - } - } - } - // println!("in assert return"); - } - CommandKind::AssertReturnCanonicalNan { action } => match action { - Action::Invoke { - module, - field, - args, - } => { - let maybe_call_result = - with_instance(instance.clone(), &named_modules, &module, |instance| { - let params: Vec = - args.iter().cloned().map(convert_value).collect(); - instance.call(&field, ¶ms[..]) - }); - if maybe_call_result.is_none() { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line: line, - kind: format!("{}", "AssertReturnCanonicalNan"), - message: format!("No instance available {:?}", &module), - }, - &test_key, - excludes, - line, - ); - } else { - let call_result = maybe_call_result.unwrap(); - match call_result { - Err(e) => { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line, - kind: format!("{}", "AssertReturnCanonicalNan"), - message: format!("Call failed {:?}", e), - }, - &test_key, - excludes, - line, - ); - } - Ok(values) => { - for v in values.iter() { - if is_canonical_nan(v.clone()) { - test_report.count_passed(); - } else { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line, - kind: format!( - "{:?}", - "AssertReturnCanonicalNan" - ), - message: format!( - "value is not canonical nan {:?} ({:?})", - v, - value_to_hex(v.clone()), - ), - }, - &test_key, - excludes, - line, - ); - } - } - } - } - } - } - _ => panic!("unexpected action in assert return canonical nan"), - }, - CommandKind::AssertReturnArithmeticNan { action } => match action { - Action::Invoke { - module, - field, - args, - } => { - let maybe_call_result = - with_instance(instance.clone(), &named_modules, &module, |instance| { - let params: Vec = - args.iter().cloned().map(convert_value).collect(); - instance.call(&field, ¶ms[..]) - }); - if maybe_call_result.is_none() { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line: line, - kind: format!("{}", "AssertReturnArithmeticNan"), - message: format!("No instance available"), - }, - &test_key, - excludes, - line, - ); - } else { - let call_result = maybe_call_result.unwrap(); - match call_result { - Err(e) => { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line, - kind: format!("{}", "AssertReturnArithmeticNan"), - message: format!("Call failed {:?}", e), - }, - &test_key, - excludes, - line, - ); - } - Ok(values) => { - for v in values.iter() { - if is_arithmetic_nan(v.clone()) { - test_report.count_passed(); - } else { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line, - kind: format!( - "{:?}", - "AssertReturnArithmeticNan" - ), - message: format!( - "value is not arithmetic nan {:?} ({:?})", - v, - value_to_hex(v.clone()), - ), - }, - &test_key, - excludes, - line, - ); - } - } - } - } - } - } - _ => panic!("unexpected action in assert return arithmetic nan"), - }, - CommandKind::AssertTrap { action, message: _ } => match action { - Action::Invoke { - module, - field, - args, - } => { - let maybe_call_result = - with_instance(instance.clone(), &named_modules, &module, |instance| { - #[cfg(unix)] - use wasmer::compiler::{ - pop_code_version, push_code_version, CodeVersion, - }; - - // Manually push code version before calling WebAssembly function, as a hack. - // - // This should eventually be fixed by doing push/pop code version in the function invocation - // logic itself. - - #[cfg(unix)] - let cv_pushed = if let Some(msm) = - instance.module.runnable_module.get_module_state_map() - { - push_code_version(CodeVersion { - baseline: true, - msm: msm, - base: instance - .module - .runnable_module - .get_code() - .unwrap() - .as_ptr() - as usize, - backend: backend.into(), - runnable_module: instance.module.runnable_module.clone(), - }); - true - } else { - false - }; - let params: Vec = - args.iter().cloned().map(convert_value).collect(); - let ret = instance.call(&field, ¶ms[..]); - #[cfg(unix)] - { - if cv_pushed { - pop_code_version().unwrap(); - } - } - ret - }); - if maybe_call_result.is_none() { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line: line, - kind: format!("{}", "AssertTrap"), - message: format!("No instance available"), - }, - &test_key, - excludes, - line, - ); - } else { - let call_result = maybe_call_result.unwrap(); - use wasmer::error::{CallError, RuntimeError}; - match call_result { - Err(e) => match e { - CallError::Resolve(_) => { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line, - kind: format!("{}", "AssertTrap"), - message: format!("expected trap, got {:?}", e), - }, - &test_key, - excludes, - line, - ); - } - CallError::Runtime(RuntimeError(e)) => { - use wasmer::error::ExceptionCode; - if let Some(_) = e.downcast_ref::() { - test_report.count_passed(); - } else { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line, - kind: format!("{}", "AssertTrap"), - message: format!( - "expected trap, got RuntimeError" - ), - }, - &test_key, - excludes, - line, - ); - } - } - }, - Ok(values) => { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line, - kind: format!("{}", "AssertTrap"), - message: format!("expected trap, got {:?}", values), - }, - &test_key, - excludes, - line, - ); - } - } - } - } - _ => println!("unexpected action"), - }, - CommandKind::AssertInvalid { module, message: _ } => { - // println!("AssertInvalid"); - let result = panic::catch_unwind(|| { - let config = CompilerConfig { - features: Features { - simd: true, - threads: true, - }, - nan_canonicalization: true, - enable_verification: true, - ..Default::default() - }; - - let compiler = compiler_for_backend(backend_enum).unwrap(); - compile_with_config_with(&module.into_vec(), config, &*compiler) - }); - match result { - Ok(module) => { - if let Err(CompileError::InternalError { msg: _ }) = module { - test_report.count_passed(); - // println!("expected: {:?}", message); - // println!("actual: {:?}", msg); - } else if let Err(CompileError::ValidationError { msg: _ }) = module { - test_report.count_passed(); - // println!("validation expected: {:?}", message); - // println!("validation actual: {:?}", msg); - } else { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line: line, - kind: format!("{}", "AssertInvalid"), - message: "Should be invalid".to_string(), - }, - &test_key, - excludes, - line, - ); - } - } - Err(p) => { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line: line, - kind: format!("{}", "AssertInvalid"), - message: format!("caught panic {}", format_panic(&p)), - }, - &test_key, - excludes, - line, - ); - } - } - } - CommandKind::AssertMalformed { module, message: _ } => { - // println!("AssertMalformed"); - - let result = panic::catch_unwind(|| { - let config = CompilerConfig { - features: Features { - simd: true, - threads: true, - }, - nan_canonicalization: true, - enable_verification: true, - ..Default::default() - }; - - let compiler = compiler_for_backend(backend_enum).unwrap(); - compile_with_config_with(&module.into_vec(), config, &*compiler) - }); - - match result { - Ok(module) => { - if let Err(CompileError::InternalError { msg: _ }) = module { - test_report.count_passed(); - // println!("expected: {:?}", message); - // println!("actual: {:?}", msg); - } else if let Err(CompileError::ValidationError { msg: _ }) = module { - test_report.count_passed(); - // println!("validation expected: {:?}", message); - // println!("validation actual: {:?}", msg); - } else { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line: line, - kind: format!("{}", "AssertMalformed"), - message: format!("should be malformed"), - }, - &test_key, - excludes, - line, - ); - } - } - Err(p) => { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line: line, - kind: format!("{}", "AssertMalformed"), - message: format!("caught panic {}", format_panic(&p)), - }, - &test_key, - excludes, - line, - ); - } - } - } - CommandKind::AssertUninstantiable { module, message: _ } => { - let spectest_import_object = get_spectest_import_object(®istered_modules); - let config = CompilerConfig { - features: Features { - simd: true, - threads: true, - }, - nan_canonicalization: true, - enable_verification: true, - ..Default::default() - }; - - let compiler = compiler_for_backend(backend_enum).unwrap(); - let module = compile_with_config_with(&module.into_vec(), config, &*compiler) - .expect("WASM can't be compiled"); - let result = panic::catch_unwind(AssertUnwindSafe(|| { - module - .instantiate(&spectest_import_object) - .expect("WASM can't be instantiated"); - })); - match result { - Err(_) => test_report.count_passed(), - Ok(_) => { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line: line, - kind: format!("{}", "AssertUninstantiable"), - message: format!( - "instantiate successful, expected uninstantiable" - ), - }, - &test_key, - excludes, - line, - ); - } - }; - } - CommandKind::AssertExhaustion { action, message: _ } => { - match action { - Action::Invoke { - module, - field, - args, - } => { - let maybe_call_result = with_instance( - instance.clone(), - &named_modules, - &module, - |instance| { - let params: Vec = - args.iter().cloned().map(convert_value).collect(); - instance.call(&field, ¶ms[..]) - }, - ); - if maybe_call_result.is_none() { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line: line, - kind: format!("{}", "AssertExhaustion"), - message: format!("No instance available"), - }, - &test_key, - excludes, - line, - ); - } else { - let call_result = maybe_call_result.unwrap(); - match call_result { - Err(_e) => { - // TODO is specific error required? - test_report.count_passed(); - } - Ok(values) => { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line, - kind: format!("{}", "AssertExhaustion"), - message: format!( - "Expected call failure, got {:?}", - values - ), - }, - &test_key, - excludes, - line, - ); - } - } - } - } - _ => println!("unexpected action in assert exhaustion"), - } - } - CommandKind::AssertUnlinkable { module, message: _ } => { - let result = panic::catch_unwind(AssertUnwindSafe(|| { - let spectest_import_object = - get_spectest_import_object(®istered_modules); - let config = CompilerConfig { - features: Features { - simd: true, - threads: true, - }, - nan_canonicalization: true, - enable_verification: true, - ..Default::default() - }; - - let compiler = compiler_for_backend(backend_enum).unwrap(); - let module = - compile_with_config_with(&module.into_vec(), config, &*compiler) - .expect("WASM can't be compiled"); - module.instantiate(&spectest_import_object) - })); - match result { - Err(e) => { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line: line, - kind: format!("{}", "AssertUnlinkable"), - message: format!("caught panic {}", format_panic(&e)), - }, - &test_key, - excludes, - line, - ); - } - Ok(result) => match result { - Ok(_) => { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line: line, - kind: format!("{}", "AssertUnlinkable"), - message: format!( - "instantiate successful, expected unlinkable" - ), - }, - &test_key, - excludes, - line, - ); - } - Err(e) => match e { - wasmer::error::Error::LinkError(_) => { - test_report.count_passed(); - } - _ => { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line: line, - kind: format!("{}", "AssertUnlinkable"), - message: format!("expected link error, got {:?}", e), - }, - &test_key, - excludes, - line, - ); - } - }, - }, - } - } - CommandKind::Register { name, as_name } => { - let instance: Option>> = match name { - Some(ref name) => { - let i = named_modules.get(name); - match i { - Some(ins) => Some(Arc::clone(ins)), - None => None, - } - } - None => match instance { - Some(ref i) => Some(Arc::clone(i)), - None => None, - }, - }; - - if let Some(ins) = instance { - registered_modules.insert(as_name, ins); - } else { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line: line, - kind: format!("{}", "Register"), - message: format!("No instance available"), - }, - &test_key, - excludes, - line, - ); - } - } - CommandKind::PerformAction(ref action) => match action { - Action::Invoke { - module, - field, - args, - } => { - let maybe_call_result = - with_instance(instance.clone(), &named_modules, &module, |instance| { - let params: Vec = - args.iter().cloned().map(convert_value).collect(); - instance.call(&field, ¶ms[..]) - }); - if maybe_call_result.is_none() { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line: line, - kind: format!("{}", "PerformAction"), - message: format!("No instance available"), - }, - &test_key, - excludes, - line, - ); - } else { - let call_result = maybe_call_result.unwrap(); - match call_result { - Err(e) => { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line, - kind: format!("{}", "PerformAction"), - message: format!("Call failed {:?}", e), - }, - &test_key, - excludes, - line, - ); - } - Ok(_values) => { - test_report.count_passed(); - } - } - } - } - Action::Get { module, field } => println!( - "Action Get not implemented {:?} {:?} {:?} {:?}", - module, field, filename, line - ), - }, - } - } - - // Check for unused excludes. - for excl in excludes { - if let Some(ref excl) = *excl { - if excl.exclude_kind == ExcludeKind::Fail { - test_report.failed += 1; - test_report.failures.push(SpecFailure { - file: filename.to_string(), - line: excl.line.unwrap_or(0), - kind: format!("{}", "Exclude"), - message: format!("Excluded failure did not occur"), - }); - } - } - } - Ok(test_report) - } - - fn is_canonical_nan(val: wasm::Value) -> bool { - match val { - wasm::Value::F32(x) => x.is_canonical_nan(), - wasm::Value::F64(x) => x.is_canonical_nan(), - _ => panic!("value is not a float {:?}", val), - } - } - - fn is_arithmetic_nan(val: wasm::Value) -> bool { - match val { - wasm::Value::F32(x) => x.is_quiet_nan(), - wasm::Value::F64(x) => x.is_quiet_nan(), - _ => panic!("value is not a float {:?}", val), - } - } - - fn value_to_hex(val: wasm::Value) -> String { - match val { - wasm::Value::I32(x) => format!("{:#x}", x), - wasm::Value::I64(x) => format!("{:#x}", x), - wasm::Value::F32(x) => format!("{:#x}", x.to_bits()), - wasm::Value::F64(x) => format!("{:#x}", x.to_bits()), - wasm::Value::V128(x) => format!("{:#x}", x), - } - } - - #[derive(Debug, Clone, Eq, PartialEq)] - pub enum SpectestValue { - I32(i32), - I64(i64), - F32(u32), - F64(u64), - V128(u128), - } - - fn convert_wasmer_value(other: wasm::Value) -> SpectestValue { - match other { - wasm::Value::I32(v) => SpectestValue::I32(v), - wasm::Value::I64(v) => SpectestValue::I64(v), - wasm::Value::F32(v) => SpectestValue::F32(v.to_bits()), - wasm::Value::F64(v) => SpectestValue::F64(v.to_bits()), - wasm::Value::V128(v) => SpectestValue::V128(v), - } - } - - fn convert_wabt_value(other: Value) -> SpectestValue { - match other { - Value::I32(v) => SpectestValue::I32(v), - Value::I64(v) => SpectestValue::I64(v), - Value::F32(v) => SpectestValue::F32(v.to_bits()), - Value::F64(v) => SpectestValue::F64(v.to_bits()), - Value::V128(v) => SpectestValue::V128(v), - } - } - - fn convert_value(other: Value) -> wasm::Value { - match other { - Value::I32(v) => wasm::Value::I32(v), - Value::I64(v) => wasm::Value::I64(v), - Value::F32(v) => wasm::Value::F32(v), - Value::F64(v) => wasm::Value::F64(v), - Value::V128(v) => wasm::Value::V128(v), - } - } - - fn to_hex(v: SpectestValue) -> String { - match v { - SpectestValue::I32(v) => format!("{:#x}", v), - SpectestValue::I64(v) => format!("{:#x}", v), - SpectestValue::F32(v) => format!("{:#x}", v), - SpectestValue::F64(v) => format!("{:#x}", v), - SpectestValue::V128(v) => format!("{:#x}", v), - } - } - - fn print(_ctx: &mut Ctx) { - println!(""); - } - - fn print_i32(_ctx: &mut Ctx, val: i32) { - println!("{}", val); - } - - fn print_f32(_ctx: &mut Ctx, val: f32) { - println!("{}", val); - } - - fn print_f64(_ctx: &mut Ctx, val: f64) { - println!("{}", val); - } - - fn print_i32_f32(_ctx: &mut Ctx, val: i32, val2: f32) { - println!("{} {}", val, val2); - } - - fn print_f64_f64(_ctx: &mut Ctx, val: f64, val2: f64) { - println!("{} {}", val, val2); - } - - fn get_spectest_import_object( - registered_modules: &HashMap>>, - ) -> ImportObject { - let memory_desc = MemoryDescriptor::new(Pages(1), Some(Pages(2)), false).unwrap(); - let memory = Memory::new(memory_desc).unwrap(); - - let global_i32 = Global::new(wasm::Value::I32(666)); - let global_f32 = Global::new(wasm::Value::F32(666.0)); - let global_f64 = Global::new(wasm::Value::F64(666.0)); - - let table = Table::new(TableDescriptor { - element: ElementType::Anyfunc, - minimum: 10, - maximum: Some(20), - }) - .unwrap(); - let mut import_object = imports! { - "spectest" => { - "print" => func!(print), - "print_i32" => func!(print_i32), - "print_f32" => func!(print_f32), - "print_f64" => func!(print_f64), - "print_i32_f32" => func!(print_i32_f32), - "print_f64_f64" => func!(print_f64_f64), - "table" => table, - "memory" => memory, - "global_i32" => global_i32, - "global_f32" => global_f32, - "global_f64" => global_f64, - - }, - }; - - for (name, instance) in registered_modules.iter() { - import_object.register(name.clone(), Arc::clone(instance)); - } - import_object - } - - #[derive(Debug, Copy, Clone, PartialEq, Eq)] - enum ExcludeKind { - Skip, - Fail, - } - - use core::borrow::Borrow; - use std::fs::File; - use std::io::{BufRead, BufReader}; - - /// Reads the excludes.txt file into a hash map - fn read_excludes(current_backend: &str) -> (HashMap>, HashSet) { - let mut excludes_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - excludes_path.push("tests"); - excludes_path.push("spectests"); - excludes_path.push("excludes.txt"); - let input = File::open(excludes_path).unwrap(); - let buffered = BufReader::new(input); - let mut result = HashMap::new(); - let mut file_excludes = HashSet::new(); - let current_target_os = get_target_os(); - let current_target_family = get_target_family(); - let current_target_arch = get_target_arch(); - - for line in buffered.lines() { - let mut line = line.unwrap(); - if line.trim().is_empty() || line.starts_with("#") { - // ignore line - } else { - if line.contains("#") { - // Allow end of line comment - let l: Vec<&str> = line.split('#').collect(); - line = l.get(0).unwrap().to_string(); - } - //println!("exclude line {}", line); - // ::: - let split: Vec<&str> = line.trim().split(':').collect(); - - let file = *split.get(2).unwrap(); - let exclude = match split.len() { - 0..=3 => panic!("expected at least 4 exclude conditions"), - 4 => Exclude::from( - *split.get(0).unwrap(), - *split.get(1).unwrap(), - *split.get(2).unwrap(), - *split.get(3).unwrap(), - "*", - "*", - ), - 5 => Exclude::from( - *split.get(0).unwrap(), - *split.get(1).unwrap(), - *split.get(2).unwrap(), - *split.get(3).unwrap(), - *split.get(4).unwrap(), - "*", - ), - 6 => Exclude::from( - *split.get(0).unwrap(), - *split.get(1).unwrap(), - *split.get(2).unwrap(), - *split.get(3).unwrap(), - *split.get(4).unwrap(), - *split.get(5).unwrap(), - ), - _ => panic!("too many exclude conditions {}", split.len()), - }; - - if exclude.matches_backend(current_backend) - && (exclude.matches_target_family(current_target_os) - || exclude.matches_target_family(current_target_family)) - && exclude.matches_target_arch(current_target_arch) - { - // Skip the whole file for line * and skip - if exclude.line.is_none() && exclude.exclude_kind == ExcludeKind::Skip { - file_excludes.insert(file.to_string()); - } - - if !result.contains_key(file) { - result.insert(file.to_string(), vec![]); - } - result.get_mut(file).unwrap().push(exclude); - } - } - } - (result, file_excludes) - } - - #[test] - fn test_run_spectests() { - let mut glob_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - glob_path.push("tests"); - glob_path.push("spectests"); - glob_path.push("*.wast"); - - let available_compilers = get_available_compilers() - .iter() - .cloned() - .collect::>(); - let desired_compilers = get_compilers_to_test(); - // default to testing all enabled compilers - let compilers_to_test = if desired_compilers.is_empty() { - available_compilers.iter().cloned().collect::>() - } else { - desired_compilers - .iter() - .cloned() - .filter(|c| available_compilers.contains(c)) - .collect::>() - }; - - // if we've asked to run specific compilers, make sure they're all actually enabled - if !desired_compilers.is_empty() && desired_compilers.len() != compilers_to_test.len() { - panic!("Asked to run spectests with `{:?}` compilers but `{:?}` compilers are enabled (found {} of them: {:?})", desired_compilers, get_compilers_to_test(), compilers_to_test.len(), compilers_to_test); - } - - let glob_str = glob_path.to_str().unwrap(); - for backend in compilers_to_test { - println!("Testing `{}` backend", backend); - let (excludes, file_excludes) = read_excludes(backend); - let mut test_reports = vec![]; - let mut success = true; - for entry in glob(glob_str).expect("Failed to read glob pattern") { - match entry { - Ok(wast_path) => { - let result = parse_and_run(&wast_path, &file_excludes, &excludes, backend); - match result { - Ok(test_report) => { - if test_report.has_failures() { - success = false - } - test_reports.push(test_report); - } - Err(e) => { - success = false; - println!("Unexpected test run error: {:?}", e) - } - } - } - Err(e) => panic!("glob err: {:?}", e), - } - } - - // Print summary - let mut failures = vec![]; - let mut total_passed = 0; - let mut total_failed = 0; - let mut total_allowed_failures = 0; - for mut test_report in test_reports.into_iter() { - total_passed += test_report.passed; - total_failed += test_report.failed; - total_allowed_failures += test_report.allowed_failure; - failures.append(&mut test_report.failures); - } - - println!(""); - println!("{} backend results:", backend); - println!("Failures:"); - for failure in failures.iter() { - // To print excludes for all failures: - println!( - "{}:fail:{}:{} # {} - {}", - backend, failure.file, failure.line, failure.kind, failure.message - ); - } - println!(""); - println!(""); - println!("Spec tests summary report: "); - println!( - "total: {}", - total_passed + total_failed + total_allowed_failures - ); - println!("passed: {}", total_passed); - println!("failed: {}", total_failed); - println!("allowed failures: {}", total_allowed_failures); - println!(""); - println!("Tests {}.", if success { "passed" } else { "failed" }); - println!(""); - assert!(success, "tests passed") - } - } - - /// Bit pattern of an f32 value: - /// 1-bit sign + 8-bit mantissa + 23-bit exponent = 32 bits - /// - /// Bit pattern of an f64 value: - /// 1-bit sign + 11-bit mantissa + 52-bit exponent = 64 bits - /// - /// NOTE: On some old platforms (PA-RISC, some MIPS) quiet NaNs (qNaN) have - /// their mantissa MSB unset and set for signaling NaNs (sNaN). - /// - /// Links: - /// * https://en.wikipedia.org/wiki/Floating-point_arithmetic - /// * https://github.com/WebAssembly/spec/issues/286 - /// * https://en.wikipedia.org/wiki/NaN - /// - pub trait NaNCheck { - fn is_quiet_nan(&self) -> bool; - fn is_canonical_nan(&self) -> bool; - } - - impl NaNCheck for f32 { - /// The MSB of the mantissa must be set for a NaN to be a quiet NaN. - fn is_quiet_nan(&self) -> bool { - let mantissa_msb = 0b1 << 22; - self.is_nan() && (self.to_bits() & mantissa_msb) != 0 - } - - /// For a NaN to be canonical, the MSB of the mantissa must be set and - /// all other mantissa bits must be unset. - fn is_canonical_nan(&self) -> bool { - return self.to_bits() == 0xFFC0_0000 || self.to_bits() == 0x7FC0_0000; - } - } - - impl NaNCheck for f64 { - /// The MSB of the mantissa must be set for a NaN to be a quiet NaN. - fn is_quiet_nan(&self) -> bool { - let mantissa_msb = 0b1 << 51; - self.is_nan() && (self.to_bits() & mantissa_msb) != 0 - } - - /// For a NaN to be canonical, the MSB of the mantissa must be set and - /// all other mantissa bits must be unset. - fn is_canonical_nan(&self) -> bool { - self.to_bits() == 0x7FF8_0000_0000_0000 || self.to_bits() == 0xFFF8_0000_0000_0000 - } - } + let mut wast = Wast::new_with_spectest(backend); + let path = Path::new(wast_path); + wast.run_file(path) } diff --git a/tests/test-generator/Cargo.toml b/tests/test-generator/Cargo.toml new file mode 100644 index 00000000000..8714afb9fea --- /dev/null +++ b/tests/test-generator/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "test-generator" +version = "0.1.0" +edition = "2018" + +[dependencies] +anyhow = "1.0.19" +target-lexicon = "0.10.0" diff --git a/tests/test-generator/src/lib.rs b/tests/test-generator/src/lib.rs new file mode 100644 index 00000000000..3ec3ee79a62 --- /dev/null +++ b/tests/test-generator/src/lib.rs @@ -0,0 +1,162 @@ +//! Build library to generate a program which runs all the testsuites. +//! +//! By generating a separate `#[test]` test for each file, we allow cargo test +//! to automatically run the files in parallel. +//! +//! > This program is inspired/forked from: +//! > https://github.com/bytecodealliance/wasmtime/blob/master/build.rs + +use anyhow::Context; +use std::collections::HashSet; +use std::fmt::Write; +use std::fs::{DirEntry, File}; +use std::io::{BufRead, BufReader}; +use std::path::{Path, PathBuf}; +use target_lexicon::Triple; + +pub type Ignores = HashSet; +pub struct Testsuite { + pub buffer: String, + pub path: Vec, + pub ignores: Ignores, +} + +impl Testsuite { + fn ignore_current(&self) -> bool { + let full = self.path.join("::"); + self.ignores.contains(&full) + } +} + +#[derive(PartialEq, Eq, PartialOrd, Ord)] +pub struct Test { + pub name: String, + pub body: String, +} + +pub type ProcessorType = fn(&mut Testsuite, PathBuf) -> Option; + +/// Generates an Ignores struct from a text file +pub fn build_ignores_from_textfile(path: PathBuf) -> anyhow::Result { + let mut ignores = HashSet::new(); + let file = File::open(path)?; + let reader = BufReader::new(file); + let host = Triple::host().to_string(); + for line in reader.lines() { + let line = line.unwrap(); + // If the line has a `#` we discard all the content that comes after + let line = if line.contains("#") { + let l: Vec<&str> = line.split('#').collect(); + l.get(0).unwrap().to_string() + } else { + line + }; + // If the lines contains ` on ` it means the test should be ignored + // on that platform + let (line, target) = if line.contains(" on ") { + let l: Vec<&str> = line.split(" on ").collect(); + ( + l.get(0).unwrap().to_string(), + Some(l.get(1).unwrap().to_string()), + ) + } else { + (line, None) + }; + + let line = line.trim().to_string(); + if line.len() == 0 { + continue; + } + + match target { + Some(t) => { + // We skip the ignore if doesn't apply to the current + // host target + if !host.contains(&t) { + continue; + } + } + None => {} + } + ignores.insert(line); + } + Ok(ignores) +} + +pub fn test_directory_module( + out: &mut Testsuite, + path: impl AsRef, + processor: ProcessorType, +) -> anyhow::Result { + let path = path.as_ref(); + let testsuite = &extract_name(path); + with_test_module(out, testsuite, |out| test_directory(out, path, processor)) +} + +fn write_test(out: &mut Testsuite, testname: &str, body: &str) -> anyhow::Result<()> { + writeln!(out.buffer, "#[test]")?; + if out.ignore_current() { + writeln!(out.buffer, "#[ignore]")?; + } + writeln!(out.buffer, "fn r#{}() -> anyhow::Result<()> {{", &testname)?; + writeln!(out.buffer, "{}", body)?; + writeln!(out.buffer, "}}")?; + writeln!(out.buffer)?; + Ok(()) +} + +pub fn test_directory( + out: &mut Testsuite, + path: impl AsRef, + processor: ProcessorType, +) -> anyhow::Result { + let path = path.as_ref(); + let mut dir_entries: Vec<_> = path + .read_dir() + .context(format!("failed to read {:?}", path))? + .map(|r| r.expect("reading testsuite directory entry")) + .filter_map(|dir_entry| processor(out, dir_entry.path())) + .collect(); + + dir_entries.sort(); + + for Test { + name: testname, + body, + } in dir_entries.iter() + { + out.path.push(testname.to_string()); + write_test(out, &testname, &body).unwrap(); + out.path.pop().unwrap(); + } + + Ok(dir_entries.len()) +} + +/// Extract a valid Rust identifier from the stem of a path. +pub fn extract_name(path: impl AsRef) -> String { + path.as_ref() + .file_stem() + .expect("filename should have a stem") + .to_str() + .expect("filename should be representable as a string") + .replace("-", "_") + .replace("/", "_") +} + +pub fn with_test_module( + out: &mut Testsuite, + testsuite: &str, + f: impl FnOnce(&mut Testsuite) -> anyhow::Result, +) -> anyhow::Result { + out.path.push(testsuite.to_string()); + out.buffer.push_str("mod "); + out.buffer.push_str(testsuite); + out.buffer.push_str(" {\n"); + + let result = f(out)?; + + out.buffer.push_str("}\n"); + out.path.pop().unwrap(); + Ok(result) +} diff --git a/tests/wast/Cargo.toml b/tests/wast/Cargo.toml new file mode 100644 index 00000000000..f1d446eeb15 --- /dev/null +++ b/tests/wast/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "wasmer-wast" +version = "0.16.2" +authors = ["Wasmer Engineering Team "] +description = "wast testing support for wasmer" +license = "MIT OR (Apache-2.0 WITH LLVM-exception)" +categories = ["wasm"] +keywords = ["webassembly", "wasm"] +repository = "https://github.com/wasmerio/wasmer" +readme = "README.md" +edition = "2018" + +[dependencies] +anyhow = "1.0.19" +wasmer = { path = "../../lib/api", version = "0.16.2" } +wast = "9.0.0" +thiserror = "1.0.15" diff --git a/tests/wast/README.md b/tests/wast/README.md new file mode 100644 index 00000000000..a4f673fee30 --- /dev/null +++ b/tests/wast/README.md @@ -0,0 +1,7 @@ +This is the `wasmer-wast` crate, which contains an implementation of WebAssembly's +"wast" test scripting language, which is used in the +[WebAssembly spec testsuite], using wasmer for execution. + +[WebAssembly spec testsuite]: https://github.com/WebAssembly/testsuite + +> Note: this project started as a fork of [this crate](https://crates.io/crates/wasmtime-wast). diff --git a/tests/wast/src/errors.rs b/tests/wast/src/errors.rs new file mode 100644 index 00000000000..8cb473869b8 --- /dev/null +++ b/tests/wast/src/errors.rs @@ -0,0 +1,50 @@ +use std::fmt; +use thiserror::Error; + +/// A call Error +#[derive(Error, Debug)] +pub struct CallError { + /// The failing message received when running the directive + pub message: String, +} + +impl fmt::Display for CallError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + write!(f, "{}", self.message) + } +} + +/// A Directive Error +#[derive(Debug)] +pub struct DirectiveError { + /// The line where the directive is defined + pub line: usize, + /// The column where the directive is defined + pub col: usize, + /// The failing message received when running the directive + pub message: String, +} + +/// A structure holding the list of all executed directives +#[derive(Error, Debug)] +pub struct DirectiveErrors { + /// The filename where the error occured + pub filename: String, + /// The list of errors + pub errors: Vec, +} + +impl fmt::Display for DirectiveErrors { + // This trait requires `fmt` with this exact signature. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Write strictly the first element into the supplied output + // stream: `f`. Returns `fmt::Result` which indicates whether the + // operation succeeded or failed. Note that `write!` uses syntax which + // is very similar to `println!`. + writeln!(f, "Failed directives on {}:", self.filename)?; + for error in self.errors.iter() { + writeln!(f, " • {} ({}:{})", error.message, error.line, error.col)?; + } + Ok(()) + } +} diff --git a/tests/wast/src/lib.rs b/tests/wast/src/lib.rs new file mode 100644 index 00000000000..ba5aed9cbf3 --- /dev/null +++ b/tests/wast/src/lib.rs @@ -0,0 +1,34 @@ +//! Implementation of the WAST text format for wasmer. + +#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)] +#![warn(unused_import_braces)] +#![deny(unstable_features)] +#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))] +#![cfg_attr( + feature = "cargo-clippy", + allow(clippy::new_without_default, clippy::new_without_default_derive) +)] +#![cfg_attr( + feature = "cargo-clippy", + warn( + clippy::float_arithmetic, + clippy::mut_mut, + clippy::nonminimal_bool, + clippy::option_map_unwrap_or, + clippy::option_map_unwrap_or_else, + clippy::print_stdout, + clippy::unicode_not_nfc, + clippy::use_self + ) +)] + +mod errors; +mod spectest; +mod wast; + +pub use crate::errors::{DirectiveError, DirectiveErrors}; +pub use crate::spectest::spectest_importobject; +pub use crate::wast::Wast; + +/// Version number of this crate. +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/tests/wast/src/spectest.rs b/tests/wast/src/spectest.rs new file mode 100644 index 00000000000..bb2c78c5fc7 --- /dev/null +++ b/tests/wast/src/spectest.rs @@ -0,0 +1,56 @@ +use wasmer::import::ImportObject; +use wasmer::types::ElementType; +use wasmer::units::Pages; +use wasmer::wasm::{Func, Global, Memory, MemoryDescriptor, Table, TableDescriptor, Value}; +use wasmer::*; + +/// Return an instance implementing the "spectest" interface used in the +/// spec testsuite. +pub fn spectest_importobject() -> ImportObject { + let print = Func::new(|| {}); + let print_i32 = Func::new(|val: i32| println!("{}: i32", val)); + let print_i64 = Func::new(|val: i64| println!("{}: i64", val)); + let print_f32 = Func::new(|val: f32| println!("{}: f32", val)); + let print_f64 = Func::new(|val: f64| println!("{}: f64", val)); + let print_i32_f32 = Func::new(|i: i32, f: f32| { + println!("{}: i32", i); + println!("{}: f32", f); + }); + let print_f64_f64 = Func::new(|f1: f64, f2: f64| { + println!("{}: f64", f1); + println!("{}: f64", f2); + }); + + let global_i32 = Global::new(Value::I32(666)); + let global_i64 = Global::new(Value::I64(666)); + let global_f32 = Global::new(Value::F32(f32::from_bits(0x4426_8000))); + let global_f64 = Global::new(Value::F64(f64::from_bits(0x4084_d000_0000_0000))); + + let memory_desc = MemoryDescriptor::new(Pages(1), Some(Pages(2)), false).unwrap(); + let memory = Memory::new(memory_desc).unwrap(); + + let table = Table::new(TableDescriptor { + element: ElementType::Anyfunc, + minimum: 10, + maximum: Some(20), + }) + .unwrap(); + + imports! { + "spectest" => { + "print" => print, + "print_i32" => print_i32, + "print_i64" => print_i64, + "print_f32" => print_f32, + "print_f64" => print_f64, + "print_i32_f32" => print_i32_f32, + "print_f64_f64" => print_f64_f64, + "global_i32" => global_i32, + "global_i64" => global_i64, + "global_f32" => global_f32, + "global_f64" => global_f64, + "table" => table, + "memory" => memory, + }, + } +} diff --git a/tests/wast/src/wast.rs b/tests/wast/src/wast.rs new file mode 100644 index 00000000000..1497c5d4389 --- /dev/null +++ b/tests/wast/src/wast.rs @@ -0,0 +1,506 @@ +use crate::errors::{CallError, DirectiveError, DirectiveErrors}; +use crate::spectest::spectest_importobject; +use anyhow::{anyhow, bail, Context as _, Result}; +use std::borrow::Borrow; +use std::collections::HashMap; +use std::path::Path; +use std::str; +use std::sync::{Arc, Mutex}; +use wasmer::compiler::{compile_with_config_with, compiler_for_backend, Backend, CompilerConfig}; +use wasmer::import::ImportObject; +use wasmer::wasm::Value; +use wasmer::wasm::{DynFunc, Features, Global}; +use wasmer::*; + +/// The wast test script language allows modules to be defined and actions +/// to be performed on them. +pub struct Wast { + /// Wast files have a concept of a "current" module, which is the most + /// recently defined. + current: Option>>, + /// The Import Object that all wast tests will have + import_object: ImportObject, + /// The instances in the test + instances: HashMap>>, + /// The Wasmer backend used + backend: Backend, + /// A flag indicating if Wast tests should stop as soon as one test fails. + pub fail_fast: bool, +} + +impl Wast { + /// Construct a new instance of `Wast` with a given imports. + pub fn new(import_object: ImportObject, backend: Backend) -> Self { + Self { + current: None, + backend, + import_object, + instances: HashMap::new(), + fail_fast: false, + } + } + + /// Construcet a new instance of `Wast` with the spectests imports. + pub fn new_with_spectest(backend: Backend) -> Self { + let import_object = spectest_importobject(); + Self::new(import_object, backend) + } + + fn get_instance(&self, instance_name: Option<&str>) -> Result>> { + match instance_name { + Some(name) => self + .instances + .get(name) + .as_ref() + .map(|x| Arc::clone(x)) + .ok_or_else(|| anyhow!("failed to find instance named `{}`", name)), + None => self + .current + .as_ref() + .map(|x| Arc::clone(x)) + .ok_or_else(|| anyhow!("no previous instance found")), + } + } + + /// Perform the action portion of a command. + fn perform_execute(&mut self, exec: wast::WastExecute<'_>) -> Result> { + match exec { + wast::WastExecute::Invoke(invoke) => self.perform_invoke(invoke), + wast::WastExecute::Module(mut module) => { + let binary = module.encode()?; + let result = self.instantiate(&binary); + match result { + Ok(_) => Ok(Vec::new()), + Err(e) => Err(e), + } + } + wast::WastExecute::Get { module, global } => self.get(module.map(|s| s.name()), global), + } + } + + fn perform_invoke(&mut self, exec: wast::WastInvoke<'_>) -> Result> { + let values = exec + .args + .iter() + .map(Self::runtime_value) + .collect::>>()?; + self.invoke(exec.module.map(|i| i.name()), exec.name, &values) + } + + fn assert_return( + &self, + result: Result>, + results: &[wast::AssertExpression], + ) -> Result<()> { + let values = result?; + for (v, e) in values.iter().zip(results) { + if val_matches(v, e)? { + continue; + } + bail!("expected {:?}, got {:?}", e, v) + } + Ok(()) + } + + fn assert_trap(&self, result: Result>, expected: &str) -> Result<()> { + let actual = match result { + Ok(values) => bail!("expected trap, got {:?}", values), + Err(t) => format!("{}", t), + }; + if Self::matches_message_assert_trap(expected, &actual) { + return Ok(()); + } + bail!("expected '{}', got '{}'", expected, actual) + } + + fn run_directive(&mut self, directive: wast::WastDirective) -> Result<()> { + use wast::WastDirective::*; + + match directive { + Module(mut module) => { + let binary = module.encode()?; + self.module(module.id.map(|s| s.name()), &binary)?; + } + Register { + span: _, + name, + module, + } => { + self.register(module.map(|s| s.name()), name)?; + } + Invoke(i) => { + self.perform_invoke(i)?; + } + AssertReturn { + span: _, + exec, + results, + } => { + let result = self.perform_execute(exec); + self.assert_return(result, &results)?; + } + AssertTrap { + span: _, + exec, + message, + } => { + let result = self.perform_execute(exec); + self.assert_trap(result, message)?; + } + AssertExhaustion { + span: _, + call, + message, + } => { + let result = self.perform_invoke(call); + self.assert_trap(result, message)?; + } + AssertInvalid { + span: _, + mut module, + message, + } => { + let bytes = module.encode()?; + let err = match self.module(None, &bytes) { + Ok(()) => bail!("expected module to fail to build"), + Err(e) => e, + }; + let error_message = format!("{:?}", err); + if !Self::matches_message_assert_invalid(&message, &error_message) { + bail!( + "assert_invalid: expected \"{}\", got \"{}\"", + message, + error_message + ) + } + } + AssertMalformed { + module, + span: _, + message: _, + } => { + let mut module = match module { + wast::QuoteModule::Module(m) => m, + // This is a `*.wat` parser test which we're not + // interested in. + wast::QuoteModule::Quote(_) => return Ok(()), + }; + let bytes = module.encode()?; + if let Ok(_) = self.module(None, &bytes) { + bail!("expected malformed module to fail to instantiate"); + } + } + AssertUnlinkable { + span: _, + mut module, + message, + } => { + let bytes = module.encode()?; + let err = match self.module(None, &bytes) { + Ok(()) => bail!("expected module to fail to link"), + Err(e) => e, + }; + let error_message = format!("{:?}", err); + if !Self::matches_message_assert_unlinkable(&message, &error_message) { + bail!( + "assert_unlinkable: expected {}, got {}", + message, + error_message + ) + } + } + } + + Ok(()) + } + + /// Run a wast script from a byte buffer. + pub fn run_buffer(&mut self, filename: &str, wast: &[u8]) -> Result<()> { + let wast = str::from_utf8(wast)?; + + let adjust_wast = |mut err: wast::Error| { + err.set_path(filename.as_ref()); + err.set_text(wast); + err + }; + + let buf = wast::parser::ParseBuffer::new(wast).map_err(adjust_wast)?; + let ast = wast::parser::parse::(&buf).map_err(adjust_wast)?; + let mut errors = Vec::with_capacity(ast.directives.len()); + for directive in ast.directives { + let sp = directive.span(); + match self.run_directive(directive) { + Err(e) => { + let (line, col) = sp.linecol_in(wast); + errors.push(DirectiveError { + line: line + 1, + col, + message: format!("{}", e), + }); + if self.fail_fast { + break; + } + } + Ok(_) => {} + } + } + if !errors.is_empty() { + return Err(DirectiveErrors { + filename: filename.to_string(), + errors, + } + .into()); + } + Ok(()) + } + + /// Run a wast script from a file. + pub fn run_file(&mut self, path: &Path) -> Result<()> { + let bytes = + std::fs::read(path).with_context(|| format!("failed to read `{}`", path.display()))?; + self.run_buffer(path.to_str().unwrap(), &bytes) + } +} + +// This is the implementation specific to the Runtime +impl Wast { + /// Define a module and register it. + fn module(&mut self, instance_name: Option<&str>, module: &[u8]) -> Result<()> { + let instance = match self.instantiate(module) { + Ok(i) => i, + Err(e) => bail!("instantiation failed with: {}", e), + }; + let instance = Arc::new(Mutex::new(instance)); + if let Some(name) = instance_name { + self.instances.insert(name.to_string(), instance.clone()); + } + self.current = Some(instance.clone()); + Ok(()) + } + + fn instantiate(&self, module: &[u8]) -> Result { + // let module = Module::new(module)?; + let config = CompilerConfig { + features: Features { + simd: true, + threads: true, + }, + nan_canonicalization: true, + enable_verification: true, + ..Default::default() + }; + let compiler = compiler_for_backend(self.backend).expect("backend not found"); + let module = compile_with_config_with(module, config, &*compiler)?; + + let mut imports = self.import_object.clone_ref(); + + for import in module.imports() { + let module_name = import.namespace; + if imports.contains_namespace(&module_name) { + continue; + } + let instance = self + .instances + .get(&module_name) + .ok_or_else(|| anyhow!("no module named `{}`", module_name))?; + imports.register(module_name, Arc::clone(instance)); + } + + let instance = module + .instantiate(&imports) + .map_err(|e| anyhow!("Instantiate error: {}", e))?; + Ok(instance) + } + + /// Register an instance to make it available for performing actions. + fn register(&mut self, name: Option<&str>, as_name: &str) -> Result<()> { + let instance = self.get_instance(name)?; + self.instances.insert(as_name.to_string(), instance); + Ok(()) + } + + /// Invoke an exported function from an instance. + fn invoke( + &mut self, + instance_name: Option<&str>, + field: &str, + args: &[Value], + ) -> Result> { + let clonable_instance = self.get_instance(instance_name)?; + let instance = clonable_instance.lock().unwrap(); + let func: DynFunc = instance.borrow().exports.get(field)?; + match func.call(args) { + Ok(result) => Ok(result.into()), + Err(e) => Err(CallError { + message: format!("{}", e), + } + .into()), + } + } + + /// Get the value of an exported global from an instance. + fn get(&mut self, instance_name: Option<&str>, field: &str) -> Result> { + let clonable_instance = self.get_instance(instance_name)?; + let instance = clonable_instance.lock().unwrap(); + let global: Global = instance.borrow().exports.get(field)?; + Ok(vec![global.get()]) + } + + /// Translate from a `script::Value` to a `Val`. + fn runtime_value(v: &wast::Expression<'_>) -> Result { + use wast::Instruction::*; + + if v.instrs.len() != 1 { + bail!("too many instructions in {:?}", v); + } + Ok(match &v.instrs[0] { + I32Const(x) => Value::I32(*x), + I64Const(x) => Value::I64(*x), + F32Const(x) => Value::F32(f32::from_bits(x.bits)), + F64Const(x) => Value::F64(f64::from_bits(x.bits)), + V128Const(x) => Value::V128(u128::from_le_bytes(x.to_le_bytes())), + other => bail!("couldn't convert {:?} to a runtime value", other), + }) + } + + // Checks if the `assert_unlinkable` message matches the expected one + fn matches_message_assert_unlinkable(_expected: &str, _actual: &str) -> bool { + // We skip message matching for now + true + // actual.contains(&expected) + } + + // Checks if the `assert_invalid` message matches the expected one + fn matches_message_assert_invalid(_expected: &str, _actual: &str) -> bool { + // We skip message matching for now + true + // actual.contains(expected) + // // Waiting on https://github.com/WebAssembly/bulk-memory-operations/pull/137 + // // to propagate to WebAssembly/testsuite. + // || (expected.contains("unknown table") && actual.contains("unknown elem")) + // // `elem.wast` and `proposals/bulk-memory-operations/elem.wast` disagree + // // on the expected error message for the same error. + // || (expected.contains("out of bounds") && actual.contains("does not fit")) + } + + // Checks if the `assert_trap` message matches the expected one + fn matches_message_assert_trap(_expected: &str, _actual: &str) -> bool { + // We skip message matching for now + true + // actual.contains(expected) + // // `bulk-memory-operations/bulk.wast` checks for a message that + // // specifies which element is uninitialized, but our traps don't + // // shepherd that information out. + // || (expected.contains("uninitialized element 2") && actual.contains("uninitialized element")) + } +} + +fn extract_lane_as_i8(bytes: u128, lane: usize) -> i8 { + (bytes >> (lane * 8)) as i8 +} + +fn extract_lane_as_i16(bytes: u128, lane: usize) -> i16 { + (bytes >> (lane * 16)) as i16 +} + +fn extract_lane_as_i32(bytes: u128, lane: usize) -> i32 { + (bytes >> (lane * 32)) as i32 +} + +fn extract_lane_as_i64(bytes: u128, lane: usize) -> i64 { + (bytes >> (lane * 64)) as i64 +} + +fn val_matches(actual: &Value, expected: &wast::AssertExpression) -> Result { + Ok(match (actual, expected) { + (Value::I32(a), wast::AssertExpression::I32(b)) => a == b, + (Value::I64(a), wast::AssertExpression::I64(b)) => a == b, + // Note that these float comparisons are comparing bits, not float + // values, so we're testing for bit-for-bit equivalence + (Value::F32(a), wast::AssertExpression::F32(b)) => f32_matches(a.to_bits(), &b), + (Value::F64(a), wast::AssertExpression::F64(b)) => f64_matches(a.to_bits(), &b), + (Value::V128(a), wast::AssertExpression::V128(b)) => v128_matches(*a, &b), + // Legacy comparators + (Value::F32(a), wast::AssertExpression::LegacyCanonicalNaN) => a.is_canonical_nan(), + (Value::F32(a), wast::AssertExpression::LegacyArithmeticNaN) => a.is_arithmetic_nan(), + (Value::F64(a), wast::AssertExpression::LegacyCanonicalNaN) => a.is_canonical_nan(), + (Value::F64(a), wast::AssertExpression::LegacyArithmeticNaN) => a.is_arithmetic_nan(), + _ => bail!( + "don't know how to compare {:?} and {:?} yet", + actual, + expected + ), + }) +} + +fn f32_matches(actual: u32, expected: &wast::NanPattern) -> bool { + match expected { + wast::NanPattern::CanonicalNan => f32::from_bits(actual).is_canonical_nan(), + wast::NanPattern::ArithmeticNan => f32::from_bits(actual).is_arithmetic_nan(), + wast::NanPattern::Value(expected_value) => actual == expected_value.bits, + } +} + +fn f64_matches(actual: u64, expected: &wast::NanPattern) -> bool { + match expected { + wast::NanPattern::CanonicalNan => f64::from_bits(actual).is_canonical_nan(), + wast::NanPattern::ArithmeticNan => f64::from_bits(actual).is_arithmetic_nan(), + wast::NanPattern::Value(expected_value) => actual == expected_value.bits, + } +} + +fn v128_matches(actual: u128, expected: &wast::V128Pattern) -> bool { + match expected { + wast::V128Pattern::I8x16(b) => b + .iter() + .enumerate() + .all(|(i, b)| *b == extract_lane_as_i8(actual, i)), + wast::V128Pattern::I16x8(b) => b + .iter() + .enumerate() + .all(|(i, b)| *b == extract_lane_as_i16(actual, i)), + wast::V128Pattern::I32x4(b) => b + .iter() + .enumerate() + .all(|(i, b)| *b == extract_lane_as_i32(actual, i)), + wast::V128Pattern::I64x2(b) => b + .iter() + .enumerate() + .all(|(i, b)| *b == extract_lane_as_i64(actual, i)), + wast::V128Pattern::F32x4(b) => b.iter().enumerate().all(|(i, b)| { + let a = extract_lane_as_i32(actual, i) as u32; + f32_matches(a, b) + }), + wast::V128Pattern::F64x2(b) => b.iter().enumerate().all(|(i, b)| { + let a = extract_lane_as_i64(actual, i) as u64; + f64_matches(a, b) + }), + } +} + +pub trait NaNCheck { + fn is_arithmetic_nan(&self) -> bool; + fn is_canonical_nan(&self) -> bool; +} + +impl NaNCheck for f32 { + fn is_arithmetic_nan(&self) -> bool { + const AF32_NAN: u32 = 0x0040_0000; + (self.to_bits() & AF32_NAN) == AF32_NAN + } + + fn is_canonical_nan(&self) -> bool { + return (self.to_bits() & 0x7fff_ffff) == 0x7fc0_0000; + } +} + +impl NaNCheck for f64 { + fn is_arithmetic_nan(&self) -> bool { + const AF64_NAN: u64 = 0x0008_0000_0000_0000; + (self.to_bits() & AF64_NAN) == AF64_NAN + } + + fn is_canonical_nan(&self) -> bool { + (self.to_bits() & 0x7fff_ffff_ffff_ffff) == 0x7ff8_0000_0000_0000 + } +} From 7f0c15b0e1b9629b00866e639a3b30ea0a6cc1c8 Mon Sep 17 00:00:00 2001 From: Syrus Date: Tue, 14 Apr 2020 11:42:55 -0700 Subject: [PATCH 3/9] Refactored test ignores --- tests/ignores.txt | 101 +++++++ tests/spectests/excludes.txt | 554 ----------------------------------- 2 files changed, 101 insertions(+), 554 deletions(-) create mode 100644 tests/ignores.txt delete mode 100644 tests/spectests/excludes.txt diff --git a/tests/ignores.txt b/tests/ignores.txt new file mode 100644 index 00000000000..c5bb68ef0b4 --- /dev/null +++ b/tests/ignores.txt @@ -0,0 +1,101 @@ +# Cranelift +cranelift::spec::atomic # Threads not implemented +cranelift::spec::simd # SIMD not implemented +cranelift::spec::simd_binaryen # SIMD not implemented +cranelift::spec::linking + +# Cranelift Windows +cranelift::spec::address on windows +cranelift::spec::call on windows +cranelift::spec::call_indirect on windows +cranelift::spec::conversions on windows +cranelift::spec::elem on windows +cranelift::spec::fac on windows +cranelift::spec::func_ptrs on windows +cranelift::spec::globals on windows +cranelift::spec::i32 on windows +cranelift::spec::i64 on windows +cranelift::spec::if on windows +cranelift::spec::imports on windows +cranelift::spec::int_exprs on windows +cranelift::spec::linking on windows +cranelift::spec::memory_grow on windows +cranelift::spec::memory_trap on windows +cranelift::spec::select on windows +cranelift::spec::stack-guard-page on windows +cranelift::spec::traps on windows +cranelift::spec::unreachable on windows +cranelift::spec::unwind on windows +cranelift::spec::binary-leb128 on windows +cranelift::spec::data on windows +cranelift::spec::align on windows +cranelift::spec::binary-leb128 on windows +cranelift::spec::binary on windows +cranelift::spec::comments on windows +cranelift::spec::const on windows +cranelift::spec::custom on windows +cranelift::spec::data on windows +cranelift::spec::exports on windows +cranelift::spec::func on windows +cranelift::spec::memory on windows +cranelift::spec::stack on windows +cranelift::spec::type on windows +cranelift::spec::data on windows + +# LLVM +llvm::spec::linking + +# LLVM AArch64 +llvm::spec::atomic on aarch64 # Out of range relocations. +llvm::spec::stack-guard-page on aarch64 # Uncaught SIGSEGV only on release builds + +# LLVM Windows +llvm::spec::address on windows +llvm::spec::align on windows +llvm::spec::call on windows +llvm::spec::br_table on windows +llvm::spec::call_indirect on windows +llvm::spec::conversions on windows +llvm::spec::elem on windows +llvm::spec::func_ptrs on windows +llvm::spec::const on windows +llvm::spec::globals on windows +llvm::spec::i32 on windows +llvm::spec::i64 on windows +llvm::spec::if on windows +llvm::spec::imports on windows +llvm::spec::int_exprs on windows +llvm::spec::linking on windows +llvm::spec::memory_grow on windows +llvm::spec::memory_trap on windows +llvm::spec::select on windows +llvm::spec::traps on windows +llvm::spec::unreachable on windows +llvm::spec::unwind on windows + +# LLVM Linux after OSR - https,//github.com/wasmerio/wasmer/pull/567 +llvm::spec::simd on unix +llvm::spec::simd_binaryen on unix + +# Temporary +llvm::spec::simd +llvm::spec::simd_binaryen + +# Singlepass +singlepass::spec::simd # SIMD not implemented +singlepass::spec::simd_binaryen # SIMD not implemented +singlepass::spec::linking + +singlepass::spec::atomic on aarch64 # Threads not yet supported on singlepass + +singlepass::spec::address + +# These failures only happen on AArch64 and not on x86-64. +singlepass::spec::conversions on aarch64 +singlepass::spec::i32 on aarch64 +singlepass::spec::i64 on aarch64 +singlepass::spec::int_exprs on aarch64 +singlepass::spec::traps on aarch64 + +# NaN canonicalization is not yet implemented for aarch64. +singlepass::spec::wasmer on aarch64 diff --git a/tests/spectests/excludes.txt b/tests/spectests/excludes.txt deleted file mode 100644 index 54c886a89a7..00000000000 --- a/tests/spectests/excludes.txt +++ /dev/null @@ -1,554 +0,0 @@ - -# Comment lines begin with # are ignored, empty lines are ignored -# Exclude lines follow the format: -# ::: -# clif:fail:data.wast:172 -# clif:skip:data.wast:172 -# clif:skip:data.wast:172 # comments are allowed here -# clif:fail:conversions.wast:418 -# -# Use skip when the test failure prevents the spec suite from running, otherwise use fail -# -# Star line allows skipping an entire wast file -# clif:skip:simd.wast:* -# -# Excludes can also contain target family -# clif:skip:data.wast:172:windows -# clif:skip:data.wast:172:unix -# -# Or target arch -# singlepass:skip:atomic.wast:*:*:aarch64 - -# Cranelift -clif:skip:atomic.wast:* # Threads not implemented -clif:skip:simd.wast:* # SIMD not implemented -clif:skip:simd_binaryen.wast:* # SIMD not implemented - -# linking.wast:387,388 appear to be related to WABT issue: https://github.com/pepyakin/wabt-rs/issues/51 - -clif:fail:linking.wast:137 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106883062 - illegal instruction" -clif:fail:linking.wast:139 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106883062 - illegal instruction" -clif:fail:linking.wast:142 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106883062 - illegal instruction" -clif:fail:linking.wast:144 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106883062 - illegal instruction" -clif:fail:linking.wast:147 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106883037 - illegal instruction" -clif:fail:linking.wast:149 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106883037 - illegal instruction" -clif:fail:linking.wast:185 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106883062 - illegal instruction" -clif:fail:linking.wast:187 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106883062 - illegal instruction" -clif:fail:linking.wast:388 # AssertReturn - Call failed RuntimeError: WebAssembly trap occurred during runtime: `call_indirect` out-of-bounds - -# clif:skip:skip-stack-guard-page.wast:2 # Slow test - -# Cranelift Windows -clif:skip:address.wast:*:windows -clif:skip:call.wast:*:windows -clif:skip:call_indirect.wast:*:windows -clif:skip:conversions.wast:*:windows -clif:skip:elem.wast:*:windows -clif:skip:fac.wast:*:windows -clif:skip:func_ptrs.wast:*:windows -clif:skip:globals.wast:*:windows -clif:skip:i32.wast:*:windows -clif:skip:i64.wast:*:windows -clif:skip:if.wast:*:windows -clif:skip:imports.wast:*:windows -clif:skip:int_exprs.wast:*:windows -clif:skip:linking.wast:*:windows -clif:skip:memory_grow.wast:*:windows -clif:skip:memory_trap.wast:*:windows -clif:skip:select.wast:*:windows -clif:skip:skip-stack-guard-page.wast:*:windows -clif:skip:traps.wast:*:windows -clif:skip:unreachable.wast:*:windows -clif:skip:unwind.wast:*:windows - -clif:fail:binary-leb128.wast:74:windows # Module - caught panic Any -clif:fail:binary-leb128.wast:86:windows # Module - caught panic Any -clif:fail:binary-leb128.wast:98:windows # Module - caught panic Any -clif:fail:data.wast:27:windows # Module - caught panic Any -clif:fail:data.wast:40:windows # Module - caught panic Any -clif:fail:data.wast:50:windows # Module - caught panic Any -clif:fail:data.wast:55:windows # Module - caught panic Any -clif:fail:data.wast:61:windows # Module - caught panic Any -clif:fail:data.wast:66:windows # Module - caught panic Any -clif:fail:data.wast:83:windows # Module - caught panic Any -clif:fail:data.wast:98:windows # Module - caught panic Any -clif:fail:data.wast:117:windows # Module - caught panic Any -clif:fail:data.wast:127:windows # Module - caught panic Any -clif:fail:data.wast:132:windows # Module - caught panic Any -clif:fail:data.wast:137:windows # Module - caught panic Any -clif:fail:data.wast:143:windows # Module - caught panic Any -clif:fail:data.wast:149:windows # Module - caught panic Any -clif:fail:data.wast:154:windows # Module - caught panic Any -clif:fail:data.wast:211:windows # AssertUnlinkable - caught panic Any -clif:fail:data.wast:227:windows # AssertUnlinkable - caught panic Any -clif:fail:data.wast:258:windows # AssertUnlinkable - caught panic Any -clif:fail:data.wast:273:windows # AssertUnlinkable - caught panic Any -clif:fail:start.wast:92:windows # Module - caught panic Any -clif:skip:start.wast:98:windows - -clif:fail:align.wast:3:windows # Module - caught panic Any -clif:fail:align.wast:4:windows # Module - caught panic Any -clif:fail:align.wast:5:windows # Module - caught panic Any -clif:fail:align.wast:6:windows # Module - caught panic Any -clif:fail:align.wast:7:windows # Module - caught panic Any -clif:fail:align.wast:8:windows # Module - caught panic Any -clif:fail:align.wast:9:windows # Module - caught panic Any -clif:fail:align.wast:10:windows # Module - caught panic Any -clif:fail:align.wast:11:windows # Module - caught panic Any -clif:fail:align.wast:12:windows # Module - caught panic Any -clif:fail:align.wast:13:windows # Module - caught panic Any -clif:fail:align.wast:14:windows # Module - caught panic Any -clif:fail:align.wast:15:windows # Module - caught panic Any -clif:fail:align.wast:16:windows # Module - caught panic Any -clif:fail:align.wast:17:windows # Module - caught panic Any -clif:fail:align.wast:18:windows # Module - caught panic Any -clif:fail:align.wast:19:windows # Module - caught panic Any -clif:fail:align.wast:20:windows # Module - caught panic Any -clif:fail:align.wast:21:windows # Module - caught panic Any -clif:fail:align.wast:22:windows # Module - caught panic Any -clif:fail:align.wast:23:windows # Module - caught panic Any -clif:fail:align.wast:24:windows # Module - caught panic Any -clif:fail:align.wast:25:windows # Module - caught panic Any -clif:fail:binary-leb128.wast:2:windows # Module - caught panic Any -clif:fail:binary-leb128.wast:7:windows # Module - caught panic Any -clif:fail:binary-leb128.wast:12:windows # Module - caught panic Any -clif:fail:binary-leb128.wast:18:windows # Module - caught panic Any -clif:fail:binary-leb128.wast:24:windows # Module - caught panic Any -clif:fail:binary-leb128.wast:32:windows # Module - caught panic Any -clif:fail:binary-leb128.wast:40:windows # Module - caught panic Any -clif:fail:binary-leb128.wast:48:windows # Module - caught panic Any -clif:fail:binary-leb128.wast:56:windows # Module - caught panic Any -clif:fail:binary-leb128.wast:65:windows # Module - caught panic Any -clif:fail:binary-leb128.wast:110:windows # Module - caught panic Any -clif:fail:binary-leb128.wast:145:windows # Module - caught panic Any -clif:fail:binary-leb128.wast:157:windows # Module - caught panic Any -clif:fail:binary-leb128.wast:164:windows # Module - caught panic Any -clif:fail:binary-leb128.wast:171:windows # Module - caught panic Any -clif:fail:binary-leb128.wast:178:windows # Module - caught panic Any -clif:fail:binary-leb128.wast:186:windows # Module - caught panic Any -clif:fail:binary-leb128.wast:193:windows # Module - caught panic Any -clif:fail:binary-leb128.wast:200:windows # Module - caught panic Any -clif:fail:binary-leb128.wast:207:windows # Module - caught panic Any -clif:fail:binary.wast:1:windows # Module - caught panic Any -clif:fail:binary.wast:2:windows # Module - caught panic Any -clif:fail:binary.wast:3:windows # Module - caught panic Any -clif:fail:binary.wast:4:windows # Module - caught panic Any -clif:fail:binary.wast:350:windows # Module - caught panic Any -clif:fail:binary.wast:406:windows # Module - caught panic Any -clif:fail:binary.wast:412:windows # Module - caught panic Any -clif:fail:binary.wast:418:windows # Module - caught panic Any -clif:fail:binary.wast:446:windows # Module - caught panic Any -clif:fail:binary.wast:498:windows # Module - caught panic Any -clif:fail:binary.wast:514:windows # Module - caught panic Any -clif:fail:binary.wast:530:windows # Module - caught panic Any -clif:fail:binary.wast:558:windows # Module - caught panic Any -clif:fail:binary.wast:612:windows # Module - caught panic Any -clif:fail:binary.wast:661:windows # Module - caught panic Any -clif:fail:binary.wast:723:windows # Module - caught panic Any -clif:fail:comments.wast:10:windows # Module - caught panic Any -clif:fail:comments.wast:52:windows # Module - caught panic Any -clif:fail:comments.wast:62:windows # Module - caught panic Any -clif:fail:comments.wast:71:windows # Module - caught panic Any -clif:fail:const.wast:5:windows # Module - caught panic Any -clif:fail:const.wast:6:windows # Module - caught panic Any -clif:fail:const.wast:16:windows # Module - caught panic Any -clif:fail:const.wast:17:windows # Module - caught panic Any -clif:fail:const.wast:27:windows # Module - caught panic Any -clif:fail:const.wast:28:windows # Module - caught panic Any -clif:fail:const.wast:38:windows # Module - caught panic Any -clif:fail:const.wast:39:windows # Module - caught panic Any -clif:fail:const.wast:49:windows # Module - caught panic Any -clif:fail:const.wast:50:windows # Module - caught panic Any -clif:fail:const.wast:51:windows # Module - caught panic Any -clif:fail:const.wast:52:windows # Module - caught panic Any -clif:fail:const.wast:53:windows # Module - caught panic Any -clif:fail:const.wast:54:windows # Module - caught panic Any -clif:fail:const.wast:55:windows # Module - caught panic Any -clif:fail:const.wast:56:windows # Module - caught panic Any -clif:fail:const.wast:57:windows # Module - caught panic Any -clif:fail:const.wast:58:windows # Module - caught panic Any -clif:fail:const.wast:76:windows # Module - caught panic Any -clif:fail:const.wast:77:windows # Module - caught panic Any -clif:fail:const.wast:87:windows # Module - caught panic Any -clif:fail:const.wast:88:windows # Module - caught panic Any -clif:fail:const.wast:98:windows # Module - caught panic Any -clif:fail:const.wast:99:windows # Module - caught panic Any -clif:fail:const.wast:100:windows # Module - caught panic Any -clif:fail:const.wast:101:windows # Module - caught panic Any -clif:fail:const.wast:102:windows # Module - caught panic Any -clif:fail:const.wast:103:windows # Module - caught panic Any -clif:fail:const.wast:104:windows # Module - caught panic Any -clif:fail:const.wast:105:windows # Module - caught panic Any -clif:fail:const.wast:123:windows # Module - caught panic Any -clif:fail:const.wast:124:windows # Module - caught panic Any -clif:fail:const.wast:134:windows # Module - caught panic Any -clif:fail:const.wast:135:windows # Module - caught panic Any -clif:fail:const.wast:145:windows # Module - caught panic Any -clif:fail:const.wast:146:windows # Module - caught panic Any -clif:fail:const.wast:147:windows # Module - caught panic Any -clif:fail:const.wast:148:windows # Module - caught panic Any -clif:fail:custom.wast:1:windows # Module - caught panic Any -clif:fail:custom.wast:14:windows # Module - caught panic Any -clif:fail:data.wast:5:windows # Module - caught panic Any -clif:fail:data.wast:23:windows # Module - caught panic Any -clif:fail:data.wast:32:windows # Module - caught panic Any -clif:fail:data.wast:78:windows # Module - caught panic Any -clif:fail:data.wast:89:windows # Module - caught panic Any -clif:fail:data.wast:94:windows # Module - caught panic Any -clif:fail:data.wast:103:windows # Module - caught panic Any -clif:fail:data.wast:108:windows # Module - caught panic Any -clif:fail:data.wast:113:windows # Module - caught panic Any -clif:fail:data.wast:122:windows # Module - caught panic Any -clif:fail:exports.wast:24:windows # Module - caught panic Any -clif:fail:exports.wast:25:windows # Module - caught panic Any -clif:fail:exports.wast:56:windows # Module - caught panic Any -clif:fail:exports.wast:57:windows # Module - caught panic Any -clif:fail:exports.wast:58:windows # Module - caught panic Any -clif:fail:exports.wast:60:windows # Module - caught panic Any -clif:fail:exports.wast:61:windows # Module - caught panic Any -clif:fail:exports.wast:62:windows # Module - caught panic Any -clif:fail:exports.wast:63:windows # Module - caught panic Any -clif:fail:exports.wast:64:windows # Module - caught panic Any -clif:fail:exports.wast:65:windows # Module - caught panic Any -clif:fail:exports.wast:67:windows # Module - caught panic Any -clif:fail:exports.wast:71:windows # AssertReturn Get - No instance available None -clif:fail:exports.wast:72:windows # AssertReturn Get - No instance available Some("$Global") -clif:fail:exports.wast:73:windows # Module - caught panic Any -clif:fail:exports.wast:74:windows # Module - caught panic Any -clif:fail:exports.wast:75:windows # AssertReturn Get - No instance available Some("$Global") -clif:fail:exports.wast:105:windows # Module - caught panic Any -clif:fail:exports.wast:106:windows # Module - caught panic Any -clif:fail:exports.wast:110:windows # Module - caught panic Any -clif:fail:exports.wast:111:windows # Module - caught panic Any -clif:fail:exports.wast:112:windows # Module - caught panic Any -clif:fail:exports.wast:113:windows # Module - caught panic Any -clif:fail:exports.wast:114:windows # Module - caught panic Any -clif:fail:exports.wast:115:windows # Module - caught panic Any -clif:fail:exports.wast:116:windows # Module - caught panic Any -clif:fail:exports.wast:117:windows # Module - caught panic Any -clif:fail:exports.wast:118:windows # Module - caught panic Any -clif:fail:exports.wast:119:windows # Module - caught panic Any -clif:fail:exports.wast:120:windows # Module - caught panic Any -clif:fail:exports.wast:121:windows # Module - caught panic Any -clif:fail:exports.wast:154:windows # Module - caught panic Any -clif:fail:exports.wast:155:windows # Module - caught panic Any -clif:fail:exports.wast:159:windows # Module - caught panic Any -clif:fail:exports.wast:160:windows # Module - caught panic Any -clif:fail:exports.wast:161:windows # Module - caught panic Any -clif:fail:exports.wast:162:windows # Module - caught panic Any -clif:fail:exports.wast:163:windows # Module - caught panic Any -clif:fail:exports.wast:164:windows # Module - caught panic Any -clif:fail:exports.wast:165:windows # Module - caught panic Any -clif:fail:exports.wast:166:windows # Module - caught panic Any -clif:fail:exports.wast:167:windows # Module - caught panic Any -clif:fail:exports.wast:168:windows # Module - caught panic Any -clif:fail:exports.wast:169:windows # Module - caught panic Any -clif:fail:exports.wast:170:windows # Module - caught panic Any -clif:fail:func.wast:289:windows # Module - caught panic Any -clif:fail:memory.wast:3:windows # Module - caught panic Any -clif:fail:memory.wast:4:windows # Module - caught panic Any -clif:fail:memory.wast:5:windows # Module - caught panic Any -clif:fail:memory.wast:6:windows # Module - caught panic Any -clif:fail:stack.wast:137:windows # Module - caught panic Any -clif:fail:type.wast:3:windows # Module - caught panic Any -clif:fail:data.wast:162:windows # AssertUnlinkable - caught panic Any -clif:fail:data.wast:170:windows # AssertUnlinkable - caught panic Any -clif:fail:data.wast:178:windows # AssertUnlinkable - caught panic Any -clif:fail:data.wast:220:windows # AssertUnlinkable - caught panic Any -clif:fail:data.wast:235:windows # AssertUnlinkable - caught panic Any -clif:fail:data.wast:243:windows # AssertUnlinkable - caught panic Any -clif:fail:data.wast:251:windows # AssertUnlinkable - caught panic Any -clif:fail:data.wast:266:windows # AssertUnlinkable - caught panic Any -clif:fail:data.wast:186:windows # AssertUnlinkable - caught panic Any -clif:fail:data.wast:194:windows # AssertUnlinkable - caught panic Any - -# LLVM -llvm:fail:linking.wast:388 # AssertReturn - Call failed RuntimeError: WebAssembly trap occurred during runtime: incorrect `call_indirect` signature - -# LLVM AArch64 -llvm:skip:atomic.wast:*:*:aarch64 # Out of range relocations. -llvm:skip:skip-stack-guard-page.wast:2275:*:aarch64 # Uncaught SIGSEGV only in release builds -llvm:skip:skip-stack-guard-page.wast:2282:*:aarch64 # Uncaught SIGSEGV only in release builds - -# LLVM Windows -llvm:skip:address.wast:*:windows -llvm:skip:align.wast:*:windows -llvm:skip:call.wast:*:windows -llvm:skip:br_table.wast:*:windows -llvm:skip:call_indirect.wast:*:windows -llvm:skip:conversions.wast:*:windows -llvm:skip:elem.wast:*:windows -llvm:skip:func_ptrs.wast:*:windows -llvm:skip:const.wast:*:windows -llvm:skip:globals.wast:*:windows -llvm:skip:i32.wast:*:windows -llvm:skip:i64.wast:*:windows -llvm:skip:if.wast:*:windows -llvm:skip:imports.wast:*:windows -llvm:skip:int_exprs.wast:*:windows -llvm:skip:linking.wast:*:windows -llvm:skip:memory_grow.wast:*:windows -llvm:skip:memory_trap.wast:*:windows -llvm:skip:select.wast:*:windows -llvm:skip:traps.wast:*:windows -llvm:skip:unreachable.wast:*:windows -llvm:skip:unwind.wast:*:windows - -# LLVM Linux after OSR - https://github.com/wasmerio/wasmer/pull/567 -llvm:skip:simd.wast:352:unix # Module - caught panic Any -llvm:skip:simd_binaryen.wast:*:unix # Module - caught panic Any - -# Singlepass -singlepass:skip:simd.wast:* # SIMD not implemented -singlepass:skip:simd_binaryen.wast:* # SIMD not implemented - -singlepass:skip:atomic.wast:*:*:aarch64 # Threads not yet supported on singlepass - -singlepass:fail:address.wast:194:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:195:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:196:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:197:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:198:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:200:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:201:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:202:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:203:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:204:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:481:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:482:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:483:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:484:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:485:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:486:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:487:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:489:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:490:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:491:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:492:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:493:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:494:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:495:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:541:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:542:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:588:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:589:freebsd # AssertTrap - expected trap, got [] -singlepass:fail:linking.wast:137:freebsd # AssertTrap - expected trap, got RuntimeError -singlepass:fail:linking.wast:139:freebsd # AssertTrap - expected trap, got RuntimeError -singlepass:fail:linking.wast:142:freebsd # AssertTrap - expected trap, got RuntimeError -singlepass:fail:linking.wast:144:freebsd # AssertTrap - expected trap, got RuntimeError -singlepass:fail:linking.wast:147:freebsd # AssertTrap - expected trap, got RuntimeError -singlepass:fail:linking.wast:149:freebsd # AssertTrap - expected trap, got RuntimeError -singlepass:fail:linking.wast:185:freebsd # AssertTrap - expected trap, got RuntimeError -singlepass:fail:linking.wast:187:freebsd # AssertTrap - expected trap, got RuntimeError -singlepass:fail:linking.wast:388:freebsd # AssertReturn - Call failed RuntimeError: unknown error - -singlepass:fail:address.wast:200:linux:x86_64 # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:201:linux:x86_64 # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:202:linux:x86_64 # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:203:linux:x86_64 # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:204:linux:x86_64 # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:489:linux:x86_64 # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:490:linux:x86_64 # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:491:linux:x86_64 # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:492:linux:x86_64 # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:495:linux:x86_64 # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:542:linux:x86_64 # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:589:linux:x86_64 # AssertTrap - expected trap, got [] -singlepass:fail:linking.wast:137:linux # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:linking.wast:139:linux # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:linking.wast:142:linux # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:linking.wast:144:linux # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:linking.wast:147:linux # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:linking.wast:149:linux # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:linking.wast:185:linux # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:linking.wast:187:linux # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:linking.wast:388:linux # AssertReturn - Call failed RuntimeError: unknown error - -singlepass:fail:address.wast:194:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:195:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:196:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:197:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:198:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:200:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:201:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:202:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:203:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:204:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:481:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:482:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:483:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:484:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:485:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:486:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:487:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:489:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:490:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:491:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:492:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:493:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:494:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:495:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:541:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:542:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:588:macos # AssertTrap - expected trap, got [] -singlepass:fail:address.wast:589:macos # AssertTrap - expected trap, got [] -singlepass:fail:linking.wast:137:macos # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:linking.wast:139:macos # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:linking.wast:142:macos # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:linking.wast:144:macos # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:linking.wast:147:macos # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:linking.wast:149:macos # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:linking.wast:185:macos # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:linking.wast:187:macos # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:linking.wast:388:macos # AssertReturn - Call failed RuntimeError: unknown error - -# These failures only happen on AArch64 and not on x86-64. -singlepass:fail:conversions.wast:83:*:aarch64 # AssertTrap - expected trap, got [I32(2147483647)] -singlepass:fail:conversions.wast:84:*:aarch64 # AssertTrap - expected trap, got [I32(-2147483648)] -singlepass:fail:conversions.wast:85:*:aarch64 # AssertTrap - expected trap, got [I32(2147483647)] -singlepass:fail:conversions.wast:86:*:aarch64 # AssertTrap - expected trap, got [I32(-2147483648)] -singlepass:fail:conversions.wast:87:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:conversions.wast:88:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:conversions.wast:89:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:conversions.wast:90:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:conversions.wast:105:*:aarch64 # AssertTrap - expected trap, got [I32(-1)] -singlepass:fail:conversions.wast:106:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:conversions.wast:107:*:aarch64 # AssertTrap - expected trap, got [I32(-1)] -singlepass:fail:conversions.wast:108:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:conversions.wast:109:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:conversions.wast:110:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:conversions.wast:111:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:conversions.wast:112:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:conversions.wast:128:*:aarch64 # AssertTrap - expected trap, got [I32(2147483647)] -singlepass:fail:conversions.wast:129:*:aarch64 # AssertTrap - expected trap, got [I32(-2147483648)] -singlepass:fail:conversions.wast:130:*:aarch64 # AssertTrap - expected trap, got [I32(2147483647)] -singlepass:fail:conversions.wast:131:*:aarch64 # AssertTrap - expected trap, got [I32(-2147483648)] -singlepass:fail:conversions.wast:132:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:conversions.wast:133:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:conversions.wast:134:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:conversions.wast:135:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:conversions.wast:151:*:aarch64 # AssertTrap - expected trap, got [I32(-1)] -singlepass:fail:conversions.wast:152:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:conversions.wast:153:*:aarch64 # AssertTrap - expected trap, got [I32(-1)] -singlepass:fail:conversions.wast:154:*:aarch64 # AssertTrap - expected trap, got [I32(-1)] -singlepass:fail:conversions.wast:155:*:aarch64 # AssertTrap - expected trap, got [I32(-1)] -singlepass:fail:conversions.wast:156:*:aarch64 # AssertTrap - expected trap, got [I32(-1)] -singlepass:fail:conversions.wast:157:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:conversions.wast:158:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:conversions.wast:159:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:conversions.wast:160:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:conversions.wast:161:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:conversions.wast:179:*:aarch64 # AssertTrap - expected trap, got [I64(9223372036854775807)] -singlepass:fail:conversions.wast:180:*:aarch64 # AssertTrap - expected trap, got [I64(-9223372036854775808)] -singlepass:fail:conversions.wast:181:*:aarch64 # AssertTrap - expected trap, got [I64(9223372036854775807)] -singlepass:fail:conversions.wast:182:*:aarch64 # AssertTrap - expected trap, got [I64(-9223372036854775808)] -singlepass:fail:conversions.wast:183:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:conversions.wast:184:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:conversions.wast:185:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:conversions.wast:186:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:conversions.wast:199:*:aarch64 # AssertTrap - expected trap, got [I64(-1)] -singlepass:fail:conversions.wast:200:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:conversions.wast:201:*:aarch64 # AssertTrap - expected trap, got [I64(-1)] -singlepass:fail:conversions.wast:202:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:conversions.wast:203:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:conversions.wast:204:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:conversions.wast:205:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:conversions.wast:206:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:conversions.wast:224:*:aarch64 # AssertTrap - expected trap, got [I64(9223372036854775807)] -singlepass:fail:conversions.wast:225:*:aarch64 # AssertTrap - expected trap, got [I64(-9223372036854775808)] -singlepass:fail:conversions.wast:226:*:aarch64 # AssertTrap - expected trap, got [I64(9223372036854775807)] -singlepass:fail:conversions.wast:227:*:aarch64 # AssertTrap - expected trap, got [I64(-9223372036854775808)] -singlepass:fail:conversions.wast:228:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:conversions.wast:229:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:conversions.wast:230:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:conversions.wast:231:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:conversions.wast:248:*:aarch64 # AssertTrap - expected trap, got [I64(-1)] -singlepass:fail:conversions.wast:249:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:conversions.wast:250:*:aarch64 # AssertTrap - expected trap, got [I64(-1)] -singlepass:fail:conversions.wast:251:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:conversions.wast:252:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:conversions.wast:253:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:conversions.wast:254:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:conversions.wast:255:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:i32.wast:62:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:i32.wast:63:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:i32.wast:64:*:aarch64 # AssertTrap - expected trap, got [I32(-2147483648)] -singlepass:fail:i32.wast:82:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:i32.wast:83:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:i32.wast:99:*:aarch64 # AssertTrap - expected trap, got [I32(1)] -singlepass:fail:i32.wast:100:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:i32.wast:120:*:aarch64 # AssertTrap - expected trap, got [I32(1)] -singlepass:fail:i32.wast:121:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:i64.wast:62:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:i64.wast:63:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:i64.wast:64:*:aarch64 # AssertTrap - expected trap, got [I64(-9223372036854775808)] -singlepass:fail:i64.wast:82:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:i64.wast:83:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:i64.wast:99:*:aarch64 # AssertTrap - expected trap, got [I64(1)] -singlepass:fail:i64.wast:100:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:i64.wast:120:*:aarch64 # AssertTrap - expected trap, got [I64(1)] -singlepass:fail:i64.wast:121:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:int_exprs.wast:113:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:int_exprs.wast:114:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:int_exprs.wast:115:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:int_exprs.wast:116:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:int_exprs.wast:132:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:int_exprs.wast:133:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:int_exprs.wast:134:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:int_exprs.wast:135:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:int_exprs.wast:196:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:int_exprs.wast:197:*:aarch64 # AssertTrap - expected trap, got [I32(0)] -singlepass:fail:int_exprs.wast:198:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:int_exprs.wast:199:*:aarch64 # AssertTrap - expected trap, got [I64(0)] -singlepass:fail:int_exprs.wast:349:*:aarch64 # AssertTrap - expected trap, got [I32(-2147483648)] -singlepass:fail:int_exprs.wast:350:*:aarch64 # AssertTrap - expected trap, got [I64(-9223372036854775808)] -singlepass:fail:traps.wast:16:*:aarch64 # AssertTrap - expected trap, got [] -singlepass:fail:traps.wast:17:*:aarch64 # AssertTrap - expected trap, got [] -singlepass:fail:traps.wast:18:*:aarch64 # AssertTrap - expected trap, got [] -singlepass:fail:traps.wast:19:*:aarch64 # AssertTrap - expected trap, got [] -singlepass:fail:traps.wast:20:*:aarch64 # AssertTrap - expected trap, got [] -singlepass:fail:traps.wast:21:*:aarch64 # AssertTrap - expected trap, got [] -singlepass:fail:traps.wast:34:*:aarch64 # AssertTrap - expected trap, got [] -singlepass:fail:traps.wast:35:*:aarch64 # AssertTrap - expected trap, got [] -singlepass:fail:traps.wast:36:*:aarch64 # AssertTrap - expected trap, got [] -singlepass:fail:traps.wast:37:*:aarch64 # AssertTrap - expected trap, got [] -singlepass:fail:traps.wast:50:*:aarch64 # AssertTrap - expected trap, got [] -singlepass:fail:traps.wast:51:*:aarch64 # AssertTrap - expected trap, got [] -singlepass:fail:traps.wast:52:*:aarch64 # AssertTrap - expected trap, got [] -singlepass:fail:traps.wast:53:*:aarch64 # AssertTrap - expected trap, got [] -singlepass:fail:traps.wast:54:*:aarch64 # AssertTrap - expected trap, got [] -singlepass:fail:traps.wast:55:*:aarch64 # AssertTrap - expected trap, got [] -singlepass:fail:traps.wast:56:*:aarch64 # AssertTrap - expected trap, got [] -singlepass:fail:traps.wast:57:*:aarch64 # AssertTrap - expected trap, got [] - -# NaN canonicalization is not yet implemented for aarch64. -singlepass:fail:wasmer.wast:177:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000") -singlepass:fail:wasmer.wast:178:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000") -singlepass:fail:wasmer.wast:179:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000") -singlepass:fail:wasmer.wast:180:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000") -singlepass:fail:wasmer.wast:181:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000") -singlepass:fail:wasmer.wast:182:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000") -singlepass:fail:wasmer.wast:183:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000") -singlepass:fail:wasmer.wast:184:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000") -singlepass:fail:wasmer.wast:185:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000") -singlepass:fail:wasmer.wast:186:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000") -singlepass:fail:wasmer.wast:187:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000") -singlepass:fail:wasmer.wast:189:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000") -singlepass:fail:wasmer.wast:191:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000") -singlepass:fail:wasmer.wast:193:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000") -singlepass:fail:wasmer.wast:195:*:aarch64 # AssertReturn - result I32(2143289345) ("0x7fc00001") does not match expected I32(2143289344) ("0x7fc00000") -singlepass:fail:wasmer.wast:197:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000") -singlepass:fail:wasmer.wast:198:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000") -singlepass:fail:wasmer.wast:199:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000") -singlepass:fail:wasmer.wast:200:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000") -singlepass:fail:wasmer.wast:201:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000") -singlepass:fail:wasmer.wast:202:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000") -singlepass:fail:wasmer.wast:203:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000") -singlepass:fail:wasmer.wast:204:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000") -singlepass:fail:wasmer.wast:205:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000") -singlepass:fail:wasmer.wast:206:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000") -singlepass:fail:wasmer.wast:207:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000") -singlepass:fail:wasmer.wast:209:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000") -singlepass:fail:wasmer.wast:211:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000") -singlepass:fail:wasmer.wast:213:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000") -singlepass:fail:wasmer.wast:215:*:aarch64 # AssertReturn - result I64(9221120237041090561) ("0x7ff8000000000001") does not match expected I64(9221120237041090560) ("0x7ff8000000000000") \ No newline at end of file From cebd0ed7ab62d0a58e8913889582b87244b0762c Mon Sep 17 00:00:00 2001 From: Syrus Date: Tue, 14 Apr 2020 12:41:05 -0700 Subject: [PATCH 4/9] Improved attributions --- ATTRIBUTIONS.md | 17 ++++++++--------- tests/wast/README.md | 4 +++- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/ATTRIBUTIONS.md b/ATTRIBUTIONS.md index 5d918141d28..c39778fa372 100644 --- a/ATTRIBUTIONS.md +++ b/ATTRIBUTIONS.md @@ -10,15 +10,14 @@ These are the projects that were used as inspiration and/or that we are using co - [WAVM](https://github.com/wavm/wavm): for their great integration and testing framework - [greenwasm](https://github.com/Kimundi/greenwasm): for their [spectests framework](https://github.com/Kimundi/greenwasm/tree/master/greenwasm-spectest) - [wasmtime](https://github.com/CraneStation/wasmtime): - - For their [mmap implementation](https://github.com/CraneStation/wasmtime/blob/3f24098edc81cd9bf0f877fb7fba018cad0f039e/lib/runtime/src/mmap.rs) - - For the implementation of the `__jit_debug_register_code` function - in Rust, the structure of using Cranelift with the GDB JIT - interface including implementation details regarding the structure - of generating debug information for each function with Cranelift - (for example, the sorting of the extended basic blocks before - processing the instructions), and the API for transforming DWARF - see [wasm-debug's attribution file](https://github.com/wasmerio/wasm-debug/blob/master/ATTRIBUTIONS.md) - for more information + For their [mmap implementation](https://github.com/CraneStation/wasmtime/blob/3f24098edc81cd9bf0f877fb7fba018cad0f039e/lib/runtime/src/mmap.rs), the wast test implementation and the implementation of the `__jit_debug_register_code` function + in Rust, the structure of using Cranelift with the GDB JIT + interface including implementation details regarding the structure + of generating debug information for each function with Cranelift + (for example, the sorting of the extended basic blocks before + processing the instructions), and the API for transforming DWARF + see [wasm-debug's attribution file](https://github.com/wasmerio/wasm-debug/blob/master/ATTRIBUTIONS.md) + for more information - [stackoverflow](https://stackoverflow.com/a/45795699/1072990): to create an efficient HashMap with pair keys - [Emscripten](https://github.com/kripken/emscripten): for emtests test sources to ensure compatibility - [The WebAssembly spec](https://github.com/WebAssembly/spec/tree/master/test): for implementation details of WebAssembly and spectests diff --git a/tests/wast/README.md b/tests/wast/README.md index a4f673fee30..6659b960b70 100644 --- a/tests/wast/README.md +++ b/tests/wast/README.md @@ -4,4 +4,6 @@ This is the `wasmer-wast` crate, which contains an implementation of WebAssembly [WebAssembly spec testsuite]: https://github.com/WebAssembly/testsuite -> Note: this project started as a fork of [this crate](https://crates.io/crates/wasmtime-wast). +> Note: this project started as a fork of [this crate](https://crates.io/crates/wasmtime-wast) +> at commit `157aab50f5745e08eb0feb905c131f81284f9a7c`. +> Attributions can be found [here](https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md#wasmtime) From a840b45ed7a2b1d8ca0687b08a25af8e79c6af16 Mon Sep 17 00:00:00 2001 From: Syrus Date: Tue, 14 Apr 2020 12:42:45 -0700 Subject: [PATCH 5/9] Improved PR based on feedback. Fixed ignores --- build.rs | 2 +- tests/ignores.txt | 4 ++-- tests/test-generator/src/lib.rs | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/build.rs b/build.rs index dc598c2b434..47cdcf25dbb 100644 --- a/build.rs +++ b/build.rs @@ -106,6 +106,6 @@ fn main() -> anyhow::Result<()> { // `rustfmt` if it's installed. let output = out_dir.join("generated_tests.rs"); fs::write(&output, out.buffer)?; - drop(Command::new("rustfmt").arg(&output).status()); + Command::new("rustfmt").arg(&output).status(); Ok(()) } diff --git a/tests/ignores.txt b/tests/ignores.txt index c5bb68ef0b4..0c582039dd7 100644 --- a/tests/ignores.txt +++ b/tests/ignores.txt @@ -22,7 +22,7 @@ cranelift::spec::linking on windows cranelift::spec::memory_grow on windows cranelift::spec::memory_trap on windows cranelift::spec::select on windows -cranelift::spec::stack-guard-page on windows +cranelift::spec::skip_stack_guard_page on windows cranelift::spec::traps on windows cranelift::spec::unreachable on windows cranelift::spec::unwind on windows @@ -47,7 +47,7 @@ llvm::spec::linking # LLVM AArch64 llvm::spec::atomic on aarch64 # Out of range relocations. -llvm::spec::stack-guard-page on aarch64 # Uncaught SIGSEGV only on release builds +llvm::spec::skip_stack_guard_page on aarch64 # Uncaught SIGSEGV only on release builds # LLVM Windows llvm::spec::address on windows diff --git a/tests/test-generator/src/lib.rs b/tests/test-generator/src/lib.rs index 3ec3ee79a62..1b927d5a152 100644 --- a/tests/test-generator/src/lib.rs +++ b/tests/test-generator/src/lib.rs @@ -51,6 +51,9 @@ pub fn build_ignores_from_textfile(path: PathBuf) -> anyhow::Result { } else { line }; + + let line = line.trim().to_string(); + // If the lines contains ` on ` it means the test should be ignored // on that platform let (line, target) = if line.contains(" on ") { @@ -62,8 +65,6 @@ pub fn build_ignores_from_textfile(path: PathBuf) -> anyhow::Result { } else { (line, None) }; - - let line = line.trim().to_string(); if line.len() == 0 { continue; } From 6216891ded8b9be6d6bd18fa21c3e9e2c71cd04b Mon Sep 17 00:00:00 2001 From: Syrus Date: Tue, 14 Apr 2020 12:46:20 -0700 Subject: [PATCH 6/9] Fixed windows tests ignores --- tests/ignores.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ignores.txt b/tests/ignores.txt index 0c582039dd7..4b79f301098 100644 --- a/tests/ignores.txt +++ b/tests/ignores.txt @@ -26,10 +26,10 @@ cranelift::spec::skip_stack_guard_page on windows cranelift::spec::traps on windows cranelift::spec::unreachable on windows cranelift::spec::unwind on windows -cranelift::spec::binary-leb128 on windows +cranelift::spec::binary_leb128 on windows cranelift::spec::data on windows cranelift::spec::align on windows -cranelift::spec::binary-leb128 on windows +cranelift::spec::binary_leb128 on windows cranelift::spec::binary on windows cranelift::spec::comments on windows cranelift::spec::const on windows From 952374ccfa9c9a49d10b1fc494d725a5468bb327 Mon Sep 17 00:00:00 2001 From: Syrus Date: Tue, 14 Apr 2020 13:19:40 -0700 Subject: [PATCH 7/9] Fixed android tests --- ci/docker/aarch64-linux-android/Dockerfile | 2 +- ci/docker/x86_64-linux-android/Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/docker/aarch64-linux-android/Dockerfile b/ci/docker/aarch64-linux-android/Dockerfile index 31a21112fcd..a452519cf1e 100644 --- a/ci/docker/aarch64-linux-android/Dockerfile +++ b/ci/docker/aarch64-linux-android/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:19.04 +FROM ubuntu:19.10 RUN dpkg --add-architecture i386 && \ apt-get update && \ diff --git a/ci/docker/x86_64-linux-android/Dockerfile b/ci/docker/x86_64-linux-android/Dockerfile index 2ccc1baac0e..48631aacd3f 100644 --- a/ci/docker/x86_64-linux-android/Dockerfile +++ b/ci/docker/x86_64-linux-android/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:19.04 +FROM ubuntu:19.10 RUN apt-get update && \ apt-get install -y --no-install-recommends \ From a85bc193f72e2453e0b15eaba986bcb5b6a25c03 Mon Sep 17 00:00:00 2001 From: Syrus Date: Tue, 14 Apr 2020 13:19:52 -0700 Subject: [PATCH 8/9] Ignore spec start on cranelift windows --- tests/ignores.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ignores.txt b/tests/ignores.txt index 4b79f301098..7a4bd7ba5c6 100644 --- a/tests/ignores.txt +++ b/tests/ignores.txt @@ -41,6 +41,7 @@ cranelift::spec::memory on windows cranelift::spec::stack on windows cranelift::spec::type on windows cranelift::spec::data on windows +cranelift::spec::start on windows # LLVM llvm::spec::linking From 2dc501822b5243b69b8f6cadef5c9efd611b167c Mon Sep 17 00:00:00 2001 From: Syrus Date: Tue, 14 Apr 2020 13:21:39 -0700 Subject: [PATCH 9/9] Trying to make tests pass --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 38435fc615b..b12fc95d51f 100644 --- a/Makefile +++ b/Makefile @@ -35,13 +35,13 @@ generate: generate-emtests generate-wasitests # Spectests spectests-singlepass: - WASMER_TEST_SINGLEPASS=1 cargo test singlepass::spec --release --no-default-features --features "wasi backend-singlepass" + WASMER_TEST_SINGLEPASS=1 cargo test singlepass::spec --release --no-default-features --features "wasi backend-singlepass" -- --nocapture spectests-cranelift: - WASMER_TEST_CRANELFIT=1 cargo test cranelift::spec --release --no-default-features --features "wasi backend-cranelift" + WASMER_TEST_CRANELFIT=1 cargo test cranelift::spec --release --no-default-features --features "wasi backend-cranelift" -- --nocapture spectests-llvm: - WASMER_TEST_LLVM=1 cargo test llvm::spec --release --no-default-features --features "wasi backend-llvm wasmer-llvm-backend/test" + WASMER_TEST_LLVM=1 cargo test llvm::spec --release --no-default-features --features "wasi backend-llvm wasmer-llvm-backend/test" -- --nocapture --test-threads=1 spectests-all: WASMER_TEST_CRANELIFT=1 WASMER_TEST_LLVM=1 WASMER_TEST_SINGLEPASS=1 \