wasmtime_runtime/trampolines/
x86_64.rs1use wasmtime_asm_macros::asm_func;
2
3cfg_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}