wasmtime/trampoline/
func.rs1use crate::{Engine, FuncType, ValRaw};
4use anyhow::Result;
5use std::panic::{self, AssertUnwindSafe};
6use std::ptr::NonNull;
7use wasmtime_jit::{CodeMemory, ProfilingAgent};
8use wasmtime_runtime::{
9 VMContext, VMHostFuncContext, VMOpaqueContext, VMSharedSignatureIndex, VMTrampoline,
10};
11
12struct TrampolineState<F> {
13 func: F,
14 #[allow(dead_code)]
15 code_memory: CodeMemory,
16}
17
18unsafe extern "C" fn stub_fn<F>(
19 vmctx: *mut VMOpaqueContext,
20 caller_vmctx: *mut VMContext,
21 values_vec: *mut ValRaw,
22 values_vec_len: usize,
23) where
24 F: Fn(*mut VMContext, &mut [ValRaw]) -> Result<()> + 'static,
25{
26 let result = panic::catch_unwind(AssertUnwindSafe(|| {
40 let vmctx = VMHostFuncContext::from_opaque(vmctx);
41 let state = (*vmctx).host_state();
45 debug_assert!(state.is::<TrampolineState<F>>());
46 let state = &*(state as *const _ as *const TrampolineState<F>);
47 let values_vec = std::slice::from_raw_parts_mut(values_vec, values_vec_len);
48 (state.func)(caller_vmctx, values_vec)
49 }));
50
51 match result {
52 Ok(Ok(())) => {}
53
54 Ok(Err(trap)) => crate::trap::raise(trap.into()),
60
61 Err(panic) => wasmtime_runtime::resume_panic(panic),
65 }
66}
67
68#[cfg(compiler)]
69fn register_trampolines(profiler: &dyn ProfilingAgent, code: &CodeMemory) {
70 use object::{File, Object as _, ObjectSection, ObjectSymbol, SectionKind, SymbolKind};
71 let pid = std::process::id();
72 let tid = pid;
73
74 let image = match File::parse(&code.mmap()[..]) {
75 Ok(image) => image,
76 Err(_) => return,
77 };
78
79 let text_base = match image.sections().find(|s| s.kind() == SectionKind::Text) {
80 Some(section) => match section.data() {
81 Ok(data) => data.as_ptr() as usize,
82 Err(_) => return,
83 },
84 None => return,
85 };
86
87 for sym in image.symbols() {
88 if !sym.is_definition() {
89 continue;
90 }
91 if sym.kind() != SymbolKind::Text {
92 continue;
93 }
94 let address = sym.address();
95 let size = sym.size();
96 if address == 0 || size == 0 {
97 continue;
98 }
99 if let Ok(name) = sym.name() {
100 let addr = text_base + address as usize;
101 profiler.load_single_trampoline(name, addr as *const u8, size as usize, pid, tid);
102 }
103 }
104}
105
106#[cfg(compiler)]
107pub fn create_function<F>(
108 ft: &FuncType,
109 func: F,
110 engine: &Engine,
111) -> Result<(Box<VMHostFuncContext>, VMSharedSignatureIndex, VMTrampoline)>
112where
113 F: Fn(*mut VMContext, &mut [ValRaw]) -> Result<()> + Send + Sync + 'static,
114{
115 let mut obj = engine
116 .compiler()
117 .object(wasmtime_environ::ObjectKind::Module)?;
118 let (t1, t2) = engine.compiler().emit_trampoline_obj(
119 ft.as_wasm_func_type(),
120 stub_fn::<F> as usize,
121 &mut obj,
122 )?;
123 engine.append_bti(&mut obj);
124 let obj = wasmtime_jit::ObjectBuilder::new(obj, &engine.config().tunables).finish()?;
125
126 let mut code_memory = CodeMemory::new(obj)?;
129 code_memory.publish()?;
130
131 register_trampolines(engine.profiler(), &code_memory);
132
133 let text = code_memory.text();
137 let host_trampoline = text[t1.start as usize..][..t1.length as usize].as_ptr();
138 let wasm_trampoline = text[t2.start as usize..].as_ptr() as *mut _;
139 let wasm_trampoline = NonNull::new(wasm_trampoline).unwrap();
140
141 let sig = engine.signatures().register(ft.as_wasm_func_type());
142
143 unsafe {
144 let ctx = VMHostFuncContext::new(
145 wasm_trampoline,
146 sig,
147 Box::new(TrampolineState { func, code_memory }),
148 );
149 let host_trampoline = std::mem::transmute::<*const u8, VMTrampoline>(host_trampoline);
150 Ok((ctx, sig, host_trampoline))
151 }
152}