You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

117 lines
3.5 KiB

//! These tests are intended to exercise various relocation-based logic of
//! Wasmtime, especially the "jump veneer" insertion in the object-file-assembly
//! for when platform-specific relative call instructios can't always reach
//! their destination within the platform-specific limits.
//!
//! Note that the limits of AArch64 are primarily what's being stressed here
//! where the jump target for a call is 26-bits. On x86_64 the jump target is
//! 32-bits, and right now object files aren't supported larger than 4gb anyway
//! so we would need a lot of other support necessary to exercise that.
use anyhow::Result;
use wasmtime::*;
const MB: usize = 1 << 20;
fn store_with_padding(padding: usize) -> Result<Store<()>> {
let mut config = Config::new();
// This is an internal debug-only setting specifically recognized for
// basically just this set of tests.
unsafe {
config.cranelift_flag_set(
"wasmtime_linkopt_padding_between_functions",
&padding.to_string(),
)?;
}
let engine = Engine::new(&config)?;
Ok(Store::new(&engine, ()))
}
#[test]
fn forward_call_works() -> Result<()> {
let mut store = store_with_padding(128 * MB)?;
let module = Module::new(
store.engine(),
r#"
(module
(func (export "foo") (result i32)
call 1)
(func (result i32)
i32.const 4)
)
"#,
)?;
let i = Instance::new(&mut store, &module, &[])?;
let foo = i.get_typed_func::<(), i32, _>(&mut store, "foo")?;
assert_eq!(foo.call(&mut store, ())?, 4);
Ok(())
}
#[test]
fn backwards_call_works() -> Result<()> {
let mut store = store_with_padding(128 * MB)?;
let module = Module::new(
store.engine(),
r#"
(module
(func (result i32)
i32.const 4)
(func (export "foo") (result i32)
call 0)
)
"#,
)?;
let i = Instance::new(&mut store, &module, &[])?;
let foo = i.get_typed_func::<(), i32, _>(&mut store, "foo")?;
assert_eq!(foo.call(&mut store, ())?, 4);
Ok(())
}
#[test]
fn mixed() -> Result<()> {
test_many_call_module(store_with_padding(MB)?)
}
#[test]
fn mixed_forced() -> Result<()> {
let mut config = Config::new();
unsafe {
config.cranelift_flag_set("wasmtime_linkopt_force_jump_veneer", "true")?;
}
let engine = Engine::new(&config)?;
test_many_call_module(Store::new(&engine, ()))
}
fn test_many_call_module(mut store: Store<()>) -> Result<()> {
const N: i32 = 200;
let mut wat = String::new();
wat.push_str("(module\n");
wat.push_str("(func $first (result i32) (i32.const 1))\n");
for i in 0..N {
wat.push_str(&format!("(func (export \"{}\") (result i32 i32)\n", i));
wat.push_str("call $first\n");
wat.push_str(&format!("i32.const {}\n", i));
wat.push_str("i32.add\n");
wat.push_str("call $last\n");
wat.push_str(&format!("i32.const {}\n", i));
wat.push_str("i32.add)\n");
}
wat.push_str("(func $last (result i32) (i32.const 2))\n");
wat.push_str(")\n");
let module = Module::new(store.engine(), &wat)?;
let instance = Instance::new(&mut store, &module, &[])?;
for i in 0..N {
let name = i.to_string();
let func = instance.get_typed_func::<(), (i32, i32), _>(&mut store, &name)?;
let (a, b) = func.call(&mut store, ())?;
assert_eq!(a, i + 1);
assert_eq!(b, i + 2);
}
Ok(())
}