Files
wasmtime/tests/all/iloop.rs
Alex Crichton d1aa86f91a Add AArch64 tests to CI (#1526)
* Add AArch64 tests to CI

This commit enhances our CI with an AArch64 builder. Currently we have
no physical hardware to run on so for now we run all tests in an
emulator. The AArch64 build is cross-compiled from x86_64 from Linux.
Tests all happen in release mode with a recent version of QEMU (recent
version because it's so much faster, and in release mode because debug
mode tests take quite a long time in an emulator).

The goal here was not to get all tests passing on CI, but rather to get
AArch64 running on CI and get it green at the same time. To achieve that
goal many tests are now ignored on aarch64 platforms. Many tests fail
due to unimplemented functionality in the aarch64 backend (#1521), and
all wasmtime tests involving compilation are also disabled due to
panicking attempting to generate generate instruction offset information
for trap symbolication (#1523).

Despite this, though, all Cranelift tests and other wasmtime tests
should be runnin on AArch64 through QEMU with this PR. Additionally
we'll have an AArch64 binary release of Wasmtime for Linux, although it
won't be too useful just yet since it will panic on almost all wasm
modules.

* Review comments
2020-04-22 12:56:54 -05:00

137 lines
4.3 KiB
Rust

use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
use wasmtime::*;
fn interruptable_store() -> Store {
let engine = Engine::new(Config::new().interruptable(true));
Store::new(&engine)
}
fn hugely_recursive_module(store: &Store) -> anyhow::Result<Module> {
let mut wat = String::new();
wat.push_str(
r#"
(import "" "" (func))
(func (export "loop") call 2 call 2)
"#,
);
for i in 0..100 {
wat.push_str(&format!("(func call {0} call {0})\n", i + 3));
}
wat.push_str("(func call 0)\n");
Module::new(&store, &wat)
}
#[test]
fn loops_interruptable() -> anyhow::Result<()> {
let store = interruptable_store();
let module = Module::new(&store, r#"(func (export "loop") (loop br 0))"#)?;
let instance = Instance::new(&module, &[])?;
let iloop = instance.get_func("loop").unwrap().get0::<()>()?;
store.interrupt_handle()?.interrupt();
let trap = iloop().unwrap_err();
assert!(trap.message().contains("wasm trap: interrupt"));
Ok(())
}
#[test]
fn functions_interruptable() -> anyhow::Result<()> {
let store = interruptable_store();
let module = hugely_recursive_module(&store)?;
let func = Func::wrap(&store, || {});
let instance = Instance::new(&module, &[func.into()])?;
let iloop = instance.get_func("loop").unwrap().get0::<()>()?;
store.interrupt_handle()?.interrupt();
let trap = iloop().unwrap_err();
assert!(
trap.message().contains("wasm trap: interrupt"),
"{}",
trap.message()
);
Ok(())
}
#[test]
fn loop_interrupt_from_afar() -> anyhow::Result<()> {
// Create an instance which calls an imported function on each iteration of
// the loop so we can count the number of loop iterations we've executed so
// far.
static HITS: AtomicUsize = AtomicUsize::new(0);
let store = interruptable_store();
let module = Module::new(
&store,
r#"
(import "" "" (func))
(func (export "loop")
(loop
call 0
br 0)
)
"#,
)?;
let func = Func::wrap(&store, || {
HITS.fetch_add(1, SeqCst);
});
let instance = Instance::new(&module, &[func.into()])?;
// Use the instance's interrupt handle to wait for it to enter the loop long
// enough and then we signal an interrupt happens.
let handle = store.interrupt_handle()?;
let thread = std::thread::spawn(move || {
while HITS.load(SeqCst) <= 100_000 {
// continue ...
}
handle.interrupt();
});
// Enter the infinitely looping function and assert that our interrupt
// handle does indeed actually interrupt the function.
let iloop = instance.get_func("loop").unwrap().get0::<()>()?;
let trap = iloop().unwrap_err();
thread.join().unwrap();
assert!(
trap.message().contains("wasm trap: interrupt"),
"bad message: {}",
trap.message()
);
Ok(())
}
#[test]
#[cfg_attr(target_arch = "aarch64", ignore)] // FIXME(#1569)
fn function_interrupt_from_afar() -> anyhow::Result<()> {
// Create an instance which calls an imported function on each iteration of
// the loop so we can count the number of loop iterations we've executed so
// far.
static HITS: AtomicUsize = AtomicUsize::new(0);
let store = interruptable_store();
let module = hugely_recursive_module(&store)?;
let func = Func::wrap(&store, || {
HITS.fetch_add(1, SeqCst);
});
let instance = Instance::new(&module, &[func.into()])?;
// Use the instance's interrupt handle to wait for it to enter the loop long
// enough and then we signal an interrupt happens.
let handle = store.interrupt_handle()?;
let thread = std::thread::spawn(move || {
while HITS.load(SeqCst) <= 100_000 {
// continue ...
}
handle.interrupt();
});
// Enter the infinitely looping function and assert that our interrupt
// handle does indeed actually interrupt the function.
let iloop = instance.get_func("loop").unwrap().get0::<()>()?;
let trap = iloop().unwrap_err();
thread.join().unwrap();
assert!(
trap.message().contains("wasm trap: interrupt"),
"bad message: {}",
trap.message()
);
Ok(())
}