wasmtime_runtime/trampolines/
x86_64.rs

1use wasmtime_asm_macros::asm_func;
2
3// Helper macros for getting the first and second arguments according to the
4// system calling convention, as well as some callee-saved scratch registers we
5// can safely use in the trampolines.
6cfg_if::cfg_if! {
7    if #[cfg(windows)] {
8        macro_rules! arg0 { () => ("rcx") }
9        macro_rules! arg1 { () => ("rdx") }
10        macro_rules! scratch0 { () => ("r10") }
11        macro_rules! scratch1 { () => ("r11") }
12    } else if #[cfg(unix)] {
13        macro_rules! arg0 { () => ("rdi") }
14        macro_rules! arg1 { () => ("rsi") }
15        macro_rules! scratch0 { () => ("r10") }
16        macro_rules! scratch1 { () => ("r11") }
17    } else {
18        compile_error!("platform not supported");
19    }
20}
21
22#[rustfmt::skip]
23asm_func!(
24    "host_to_wasm_trampoline",
25    concat!(
26        "
27            .cfi_startproc simple
28            .cfi_def_cfa_offset 0
29
30            // Load the pointer to `VMRuntimeLimits` in `scratch0`.
31            mov ", scratch0!(), ", 8[", arg1!(), "]
32
33            // Check to see if this is a core `VMContext` (MAGIC == 'core').
34            cmp DWORD PTR [", arg0!(), "], 0x65726f63
35
36            // Store the last Wasm SP into the `last_wasm_entry_sp` in the limits, if this
37            // was core Wasm, otherwise store an invalid sentinal value.
38            mov ", scratch1!(), ", -1
39            cmove ", scratch1!(), ", rsp
40            mov 40[", scratch0!(), "], ", scratch1!(), "
41
42            // Tail call to the callee function pointer in the vmctx.
43            jmp 16[", arg1!(), "]
44
45            .cfi_endproc
46        ",
47    ),
48);
49
50#[cfg(test)]
51mod host_to_wasm_trampoline_offsets_tests {
52    use wasmtime_environ::{Module, PtrSize, VMOffsets};
53
54    #[test]
55    fn test() {
56        let module = Module::new();
57        let offsets = VMOffsets::new(std::mem::size_of::<*mut u8>() as u8, &module);
58
59        assert_eq!(8, offsets.vmctx_runtime_limits());
60        assert_eq!(40, offsets.ptr.vmruntime_limits_last_wasm_entry_sp());
61        assert_eq!(16, offsets.vmctx_callee());
62        assert_eq!(0x65726f63, u32::from_le_bytes(*b"core"));
63    }
64}
65
66#[rustfmt::skip]
67asm_func!(
68    "wasm_to_host_trampoline",
69    concat!(
70        "
71            .cfi_startproc simple
72            .cfi_def_cfa_offset 0
73
74            // Load the pointer to `VMRuntimeLimits` in `scratch0`.
75            mov ", scratch0!(), ", 8[", arg1!(), "]
76
77            // Store the last Wasm FP into the `last_wasm_exit_fp` in the limits.
78            mov 24[", scratch0!(), "], rbp
79
80            // Store the last Wasm PC into the `last_wasm_exit_pc` in the limits.
81            mov ", scratch1!(), ", [rsp]
82            mov 32[", scratch0!(), "], ", scratch1!(), "
83
84            // Tail call to the actual host function.
85            //
86            // This *must* be a tail call so that we do not push to the stack and mess
87            // up the offsets of stack arguments (if any).
88            jmp 8[", arg0!(), "]
89
90            .cfi_endproc
91        ",
92    ),
93);
94
95#[cfg(test)]
96mod wasm_to_host_trampoline_offsets_tests {
97    use crate::VMHostFuncContext;
98    use memoffset::offset_of;
99    use wasmtime_environ::{Module, PtrSize, VMOffsets};
100
101    #[test]
102    fn test() {
103        let module = Module::new();
104        let offsets = VMOffsets::new(std::mem::size_of::<*mut u8>() as u8, &module);
105
106        assert_eq!(8, offsets.vmctx_runtime_limits());
107        assert_eq!(24, offsets.ptr.vmruntime_limits_last_wasm_exit_fp());
108        assert_eq!(32, offsets.ptr.vmruntime_limits_last_wasm_exit_pc());
109        assert_eq!(8, offset_of!(VMHostFuncContext, host_func));
110    }
111}
112
113#[rustfmt::skip]
114macro_rules! wasm_to_libcall_trampoline {
115    ($libcall:ident ; $libcall_impl:ident) => {
116        wasmtime_asm_macros::asm_func!(
117            stringify!($libcall),
118            concat!(
119                "
120                   .cfi_startproc simple
121                   .cfi_def_cfa_offset 0
122
123                    // Load the pointer to `VMRuntimeLimits` in `", scratch0!(), "`.
124                    mov ", scratch0!(), ", 8[", arg0!(), "]
125
126                    // Store the last Wasm FP into the `last_wasm_exit_fp` in the limits.
127                    mov 24[", scratch0!(), "], rbp
128
129                    // Store the last Wasm PC into the `last_wasm_exit_pc` in the limits.
130                    mov ", scratch1!(), ", [rsp]
131                    mov 32[", scratch0!(), "], ", scratch1!(), "
132
133                    // Tail call to the actual implementation of this libcall.
134                    jmp {}
135
136                    .cfi_endproc
137                ",
138            ),
139            sym $libcall_impl
140        );
141    };
142}