Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/tests/all/relocs.rs
1692 views
1
//! These tests are intended to exercise various relocation-based logic of
2
//! Wasmtime, especially the "jump veneer" insertion in the object-file-assembly
3
//! for when platform-specific relative call instructors can't always reach
4
//! their destination within the platform-specific limits.
5
//!
6
//! Note that the limits of AArch64 are primarily what's being stressed here
7
//! where the jump target for a call is 26-bits. On x86_64 the jump target is
8
//! 32-bits, and right now object files aren't supported larger than 4gb anyway
9
//! so we would need a lot of other support necessary to exercise that.
10
11
#![cfg(not(miri))]
12
13
use wasmtime::*;
14
15
const MB: usize = 1 << 20;
16
const PADDING: usize = if cfg!(target_pointer_width = "32") {
17
1 * MB
18
} else {
19
128 * MB
20
};
21
22
fn store_with_padding(padding: usize) -> Result<Store<()>> {
23
let mut config = Config::new();
24
// This is an internal debug-only setting specifically recognized for
25
// basically just this set of tests.
26
unsafe {
27
config.cranelift_flag_set(
28
"wasmtime_linkopt_padding_between_functions",
29
&padding.to_string(),
30
);
31
}
32
let engine = Engine::new(&config)?;
33
Ok(Store::new(&engine, ()))
34
}
35
36
#[test]
37
fn forward_call_works() -> Result<()> {
38
let mut store = store_with_padding(PADDING)?;
39
let module = Module::new(
40
store.engine(),
41
r#"
42
(module
43
(func (export "foo") (result i32)
44
call 1)
45
(func (result i32)
46
i32.const 4)
47
)
48
"#,
49
)?;
50
51
let i = Instance::new(&mut store, &module, &[])?;
52
let foo = i.get_typed_func::<(), i32>(&mut store, "foo")?;
53
assert_eq!(foo.call(&mut store, ())?, 4);
54
Ok(())
55
}
56
57
#[test]
58
fn backwards_call_works() -> Result<()> {
59
let mut store = store_with_padding(PADDING)?;
60
let module = Module::new(
61
store.engine(),
62
r#"
63
(module
64
(func (result i32)
65
i32.const 4)
66
(func (export "foo") (result i32)
67
call 0)
68
)
69
"#,
70
)?;
71
72
let i = Instance::new(&mut store, &module, &[])?;
73
let foo = i.get_typed_func::<(), i32>(&mut store, "foo")?;
74
assert_eq!(foo.call(&mut store, ())?, 4);
75
Ok(())
76
}
77
78
#[test]
79
fn mixed() -> Result<()> {
80
test_many_call_module(store_with_padding(MB)?)
81
}
82
83
#[test]
84
fn mixed_forced() -> Result<()> {
85
let mut config = Config::new();
86
unsafe {
87
config.cranelift_flag_set("wasmtime_linkopt_force_jump_veneer", "true");
88
}
89
let engine = Engine::new(&config)?;
90
test_many_call_module(Store::new(&engine, ()))
91
}
92
93
fn test_many_call_module(mut store: Store<()>) -> Result<()> {
94
const N: i32 = 200;
95
96
let mut wat = String::new();
97
wat.push_str("(module\n");
98
wat.push_str("(func $first (result i32) (i32.const 1))\n");
99
for i in 0..N {
100
wat.push_str(&format!("(func (export \"{i}\") (result i32 i32)\n"));
101
wat.push_str("call $first\n");
102
wat.push_str(&format!("i32.const {i}\n"));
103
wat.push_str("i32.add\n");
104
wat.push_str("call $last\n");
105
wat.push_str(&format!("i32.const {i}\n"));
106
wat.push_str("i32.add)\n");
107
}
108
wat.push_str("(func $last (result i32) (i32.const 2))\n");
109
wat.push_str(")\n");
110
111
let module = Module::new(store.engine(), &wat)?;
112
113
let instance = Instance::new(&mut store, &module, &[])?;
114
115
for i in 0..N {
116
let name = i.to_string();
117
let func = instance.get_typed_func::<(), (i32, i32)>(&mut store, &name)?;
118
let (a, b) = func.call(&mut store, ())?;
119
assert_eq!(a, i + 1);
120
assert_eq!(b, i + 2);
121
}
122
Ok(())
123
}
124
125