1use std::ffi::c_void;
2use std::future::Future;
3use std::mem::{self, MaybeUninit};
4use std::num::NonZeroU64;
5use std::ops::Range;
6use std::pin::Pin;
7use std::sync::Arc;
8use std::task::{Context, Poll, Waker};
9use std::{ptr, str};
10use wasmtime::{
11 AsContextMut, Func, Instance, Result, RootScope, StackCreator, StackMemory, Trap, Val,
12};
13
14use crate::{
15 WASMTIME_I32, WasmtimeCaller, WasmtimeStoreContextMut, bad_utf8, handle_result, to_str,
16 translate_args, wasm_config_t, wasm_functype_t, wasm_trap_t, wasmtime_caller_t,
17 wasmtime_error_t, wasmtime_instance_pre_t, wasmtime_linker_t, wasmtime_module_t,
18 wasmtime_val_t, wasmtime_val_union,
19};
20
21#[unsafe(no_mangle)]
22pub extern "C" fn wasmtime_config_async_stack_size_set(c: &mut wasm_config_t, size: usize) {
23 c.config.async_stack_size(size);
24}
25
26#[unsafe(no_mangle)]
27pub extern "C" fn wasmtime_context_epoch_deadline_async_yield_and_update(
28 mut store: WasmtimeStoreContextMut<'_>,
29 delta: u64,
30) {
31 store.epoch_deadline_async_yield_and_update(delta);
32}
33
34#[unsafe(no_mangle)]
35pub extern "C" fn wasmtime_context_fuel_async_yield_interval(
36 mut store: WasmtimeStoreContextMut<'_>,
37 interval: Option<NonZeroU64>,
38) -> Option<Box<wasmtime_error_t>> {
39 handle_result(
40 store.fuel_async_yield_interval(interval.map(|n| n.get())),
41 |()| {},
42 )
43}
44
45pub type wasmtime_func_async_callback_t = extern "C" fn(
46 *mut c_void,
47 *mut wasmtime_caller_t,
48 *const wasmtime_val_t,
49 usize,
50 *mut wasmtime_val_t,
51 usize,
52 &mut Option<Box<wasm_trap_t>>,
53 &mut wasmtime_async_continuation_t,
54);
55
56#[repr(C)]
57pub struct wasmtime_async_continuation_t {
58 pub callback: wasmtime_func_async_continuation_callback_t,
59 pub env: *mut c_void,
60 pub finalizer: Option<extern "C" fn(*mut c_void)>,
61}
62
63unsafe impl Send for wasmtime_async_continuation_t {}
64unsafe impl Sync for wasmtime_async_continuation_t {}
65impl Drop for wasmtime_async_continuation_t {
66 fn drop(&mut self) {
67 if let Some(f) = self.finalizer {
68 f(self.env);
69 }
70 }
71}
72impl Future for wasmtime_async_continuation_t {
73 type Output = ();
74 fn poll(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Self::Output> {
75 let this = self.get_mut();
76 let cb = this.callback;
77 if cb(this.env) {
78 Poll::Ready(())
79 } else {
80 Poll::Pending
81 }
82 }
83}
84
85#[derive(Debug)]
89struct CallbackDataPtr {
90 pub ptr: *mut std::ffi::c_void,
91}
92
93unsafe impl Send for CallbackDataPtr {}
94unsafe impl Sync for CallbackDataPtr {}
95
96pub type wasmtime_func_async_continuation_callback_t = extern "C" fn(*mut c_void) -> bool;
97
98async fn invoke_c_async_callback<'a>(
99 cb: wasmtime_func_async_callback_t,
100 data: CallbackDataPtr,
101 mut caller: WasmtimeCaller<'a>,
102 params: &'a [Val],
103 results: &'a mut [Val],
104) -> Result<()> {
105 let mut hostcall_val_storage = mem::take(&mut caller.data_mut().hostcall_val_storage);
109 debug_assert!(hostcall_val_storage.is_empty());
110 hostcall_val_storage.reserve(params.len() + results.len());
111 hostcall_val_storage.extend(
112 params
113 .iter()
114 .cloned()
115 .map(|p| wasmtime_val_t::from_val_unscoped(&mut caller, p)),
116 );
117 hostcall_val_storage.extend((0..results.len()).map(|_| wasmtime_val_t {
118 kind: WASMTIME_I32,
119 of: wasmtime_val_union { i32: 0 },
120 }));
121 let (params, out_results) = hostcall_val_storage.split_at_mut(params.len());
122
123 let mut caller = wasmtime_caller_t { caller };
126 let mut trap = None;
127 extern "C" fn panic_callback(_: *mut c_void) -> bool {
128 panic!("callback must be set")
129 }
130 let mut continuation = wasmtime_async_continuation_t {
131 callback: panic_callback,
132 env: ptr::null_mut(),
133 finalizer: None,
134 };
135 cb(
136 data.ptr,
137 &mut caller,
138 params.as_ptr(),
139 params.len(),
140 out_results.as_mut_ptr(),
141 out_results.len(),
142 &mut trap,
143 &mut continuation,
144 );
145 continuation.await;
146
147 if let Some(trap) = trap {
148 return Err(trap.error);
149 }
150
151 for (i, result) in out_results.iter().enumerate() {
153 unsafe {
154 results[i] = result.to_val_unscoped(&mut caller.caller);
155 }
156 }
157 hostcall_val_storage.truncate(0);
161 caller.caller.data_mut().hostcall_val_storage = hostcall_val_storage;
162 Ok(())
163}
164
165unsafe fn c_async_callback_to_rust_fn(
166 callback: wasmtime_func_async_callback_t,
167 data: *mut c_void,
168 finalizer: Option<extern "C" fn(*mut std::ffi::c_void)>,
169) -> impl for<'a> Fn(
170 WasmtimeCaller<'a>,
171 &'a [Val],
172 &'a mut [Val],
173) -> Box<dyn Future<Output = Result<()>> + Send + 'a>
174+ Send
175+ Sync
176+ 'static {
177 let foreign = crate::ForeignData { data, finalizer };
178 move |caller, params, results| {
179 let _ = &foreign; let data = CallbackDataPtr { ptr: foreign.data };
181 Box::new(invoke_c_async_callback(
182 callback, data, caller, params, results,
183 ))
184 }
185}
186
187#[repr(transparent)]
188pub struct wasmtime_call_future_t<'a> {
189 underlying: Pin<Box<dyn Future<Output = ()> + 'a>>,
190}
191
192#[unsafe(no_mangle)]
193pub extern "C" fn wasmtime_call_future_delete(_future: Box<wasmtime_call_future_t>) {}
194
195#[unsafe(no_mangle)]
196pub extern "C" fn wasmtime_call_future_poll(future: &mut wasmtime_call_future_t) -> bool {
197 match future
198 .underlying
199 .as_mut()
200 .poll(&mut Context::from_waker(Waker::noop()))
201 {
202 Poll::Ready(()) => true,
203 Poll::Pending => false,
204 }
205}
206
207fn handle_call_error(
208 err: wasmtime::Error,
209 trap_ret: &mut *mut wasm_trap_t,
210 err_ret: &mut *mut wasmtime_error_t,
211) {
212 if err.is::<Trap>() {
213 *trap_ret = Box::into_raw(Box::new(wasm_trap_t::new(err)));
214 } else {
215 *err_ret = Box::into_raw(Box::new(wasmtime_error_t::from(err)));
216 }
217}
218
219async fn do_func_call_async(
220 mut store: RootScope<WasmtimeStoreContextMut<'_>>,
221 func: &Func,
222 args: impl ExactSizeIterator<Item = Val>,
223 results: &mut [MaybeUninit<wasmtime_val_t>],
224 trap_ret: &mut *mut wasm_trap_t,
225 err_ret: &mut *mut wasmtime_error_t,
226) {
227 let mut params = mem::take(&mut store.as_context_mut().data_mut().wasm_val_storage);
228 let (wt_params, wt_results) = translate_args(&mut params, args, results.len());
229 let result = func.call_async(&mut store, wt_params, wt_results).await;
230
231 match result {
232 Ok(()) => {
233 for (slot, val) in results.iter_mut().zip(wt_results.iter()) {
234 crate::initialize(slot, wasmtime_val_t::from_val(&mut store, *val));
235 }
236 params.truncate(0);
237 store.as_context_mut().data_mut().wasm_val_storage = params;
238 }
239 Err(err) => handle_call_error(err, trap_ret, err_ret),
240 }
241}
242
243#[unsafe(no_mangle)]
244pub unsafe extern "C" fn wasmtime_func_call_async<'a>(
245 store: WasmtimeStoreContextMut<'a>,
246 func: &'a Func,
247 args: *const wasmtime_val_t,
248 nargs: usize,
249 results: *mut MaybeUninit<wasmtime_val_t>,
250 nresults: usize,
251 trap_ret: &'a mut *mut wasm_trap_t,
252 err_ret: &'a mut *mut wasmtime_error_t,
253) -> Box<wasmtime_call_future_t<'a>> {
254 let mut scope = RootScope::new(store);
255 let args = crate::slice_from_raw_parts(args, nargs)
256 .iter()
257 .map(|i| i.to_val(&mut scope))
258 .collect::<Vec<_>>();
259 let results = crate::slice_from_raw_parts_mut(results, nresults);
260 let fut = Box::pin(do_func_call_async(
261 scope,
262 func,
263 args.into_iter(),
264 results,
265 trap_ret,
266 err_ret,
267 ));
268 Box::new(wasmtime_call_future_t { underlying: fut })
269}
270
271#[unsafe(no_mangle)]
272pub unsafe extern "C" fn wasmtime_linker_define_async_func(
273 linker: &mut wasmtime_linker_t,
274 module: *const u8,
275 module_len: usize,
276 name: *const u8,
277 name_len: usize,
278 ty: &wasm_functype_t,
279 callback: crate::wasmtime_func_async_callback_t,
280 data: *mut c_void,
281 finalizer: Option<extern "C" fn(*mut std::ffi::c_void)>,
282) -> Option<Box<wasmtime_error_t>> {
283 let ty = ty.ty().ty(linker.linker.engine());
284 let module = to_str!(module, module_len);
285 let name = to_str!(name, name_len);
286 let cb = c_async_callback_to_rust_fn(callback, data, finalizer);
287
288 handle_result(
289 linker.linker.func_new_async(module, name, ty, cb),
290 |_linker| (),
291 )
292}
293
294async fn do_linker_instantiate_async(
295 linker: &wasmtime_linker_t,
296 store: WasmtimeStoreContextMut<'_>,
297 module: &wasmtime_module_t,
298 instance_ptr: &mut Instance,
299 trap_ret: &mut *mut wasm_trap_t,
300 err_ret: &mut *mut wasmtime_error_t,
301) {
302 let result = linker.linker.instantiate_async(store, &module.module).await;
303 match result {
304 Ok(instance) => *instance_ptr = instance,
305 Err(err) => handle_call_error(err, trap_ret, err_ret),
306 }
307}
308
309#[unsafe(no_mangle)]
310pub extern "C" fn wasmtime_linker_instantiate_async<'a>(
311 linker: &'a wasmtime_linker_t,
312 store: WasmtimeStoreContextMut<'a>,
313 module: &'a wasmtime_module_t,
314 instance_ptr: &'a mut Instance,
315 trap_ret: &'a mut *mut wasm_trap_t,
316 err_ret: &'a mut *mut wasmtime_error_t,
317) -> Box<crate::wasmtime_call_future_t<'a>> {
318 let fut = Box::pin(do_linker_instantiate_async(
319 linker,
320 store,
321 module,
322 instance_ptr,
323 trap_ret,
324 err_ret,
325 ));
326 Box::new(crate::wasmtime_call_future_t { underlying: fut })
327}
328
329async fn do_instance_pre_instantiate_async(
330 instance_pre: &wasmtime_instance_pre_t,
331 store: WasmtimeStoreContextMut<'_>,
332 instance_ptr: &mut Instance,
333 trap_ret: &mut *mut wasm_trap_t,
334 err_ret: &mut *mut wasmtime_error_t,
335) {
336 let result = instance_pre.underlying.instantiate_async(store).await;
337 match result {
338 Ok(instance) => *instance_ptr = instance,
339 Err(err) => handle_call_error(err, trap_ret, err_ret),
340 }
341}
342
343#[unsafe(no_mangle)]
344pub extern "C" fn wasmtime_instance_pre_instantiate_async<'a>(
345 instance_pre: &'a wasmtime_instance_pre_t,
346 store: WasmtimeStoreContextMut<'a>,
347 instance_ptr: &'a mut Instance,
348 trap_ret: &'a mut *mut wasm_trap_t,
349 err_ret: &'a mut *mut wasmtime_error_t,
350) -> Box<crate::wasmtime_call_future_t<'a>> {
351 let fut = Box::pin(do_instance_pre_instantiate_async(
352 instance_pre,
353 store,
354 instance_ptr,
355 trap_ret,
356 err_ret,
357 ));
358 Box::new(crate::wasmtime_call_future_t { underlying: fut })
359}
360
361pub type wasmtime_stack_memory_get_callback_t =
362 extern "C" fn(env: *mut std::ffi::c_void, out_len: &mut usize) -> *mut u8;
363
364#[repr(C)]
365pub struct wasmtime_stack_memory_t {
366 env: *mut std::ffi::c_void,
367 get_stack_memory: wasmtime_stack_memory_get_callback_t,
368 finalizer: Option<extern "C" fn(arg1: *mut std::ffi::c_void)>,
369}
370
371struct CHostStackMemory {
372 foreign: crate::ForeignData,
373 get_memory: wasmtime_stack_memory_get_callback_t,
374}
375unsafe impl Send for CHostStackMemory {}
376unsafe impl Sync for CHostStackMemory {}
377unsafe impl StackMemory for CHostStackMemory {
378 fn top(&self) -> *mut u8 {
379 let mut len = 0;
380 let cb = self.get_memory;
381 cb(self.foreign.data, &mut len)
382 }
383 fn range(&self) -> Range<usize> {
384 let mut len = 0;
385 let cb = self.get_memory;
386 let top = cb(self.foreign.data, &mut len);
387 let base = unsafe { top.sub(len) as usize };
388 base..base + len
389 }
390 fn guard_range(&self) -> Range<*mut u8> {
391 std::ptr::null_mut()..std::ptr::null_mut()
392 }
393}
394
395pub type wasmtime_new_stack_memory_callback_t = extern "C" fn(
396 env: *mut std::ffi::c_void,
397 size: usize,
398 zeroed: bool,
399 stack_ret: &mut wasmtime_stack_memory_t,
400) -> Option<Box<wasmtime_error_t>>;
401
402#[repr(C)]
403pub struct wasmtime_stack_creator_t {
404 env: *mut std::ffi::c_void,
405 new_stack: wasmtime_new_stack_memory_callback_t,
406 finalizer: Option<extern "C" fn(arg1: *mut std::ffi::c_void)>,
407}
408
409struct CHostStackCreator {
410 foreign: crate::ForeignData,
411 new_stack: wasmtime_new_stack_memory_callback_t,
412}
413unsafe impl Send for CHostStackCreator {}
414unsafe impl Sync for CHostStackCreator {}
415unsafe impl StackCreator for CHostStackCreator {
416 fn new_stack(&self, size: usize, zeroed: bool) -> Result<Box<dyn wasmtime::StackMemory>> {
417 extern "C" fn panic_callback(_env: *mut std::ffi::c_void, _out_len: &mut usize) -> *mut u8 {
418 panic!("a callback must be set");
419 }
420 let mut out = wasmtime_stack_memory_t {
421 env: ptr::null_mut(),
422 get_stack_memory: panic_callback,
423 finalizer: None,
424 };
425 let cb = self.new_stack;
426 let result = cb(self.foreign.data, size, zeroed, &mut out);
427 match result {
428 Some(error) => Err((*error).into()),
429 None => Ok(Box::new(CHostStackMemory {
430 foreign: crate::ForeignData {
431 data: out.env,
432 finalizer: out.finalizer,
433 },
434 get_memory: out.get_stack_memory,
435 })),
436 }
437 }
438}
439
440#[unsafe(no_mangle)]
441pub unsafe extern "C" fn wasmtime_config_host_stack_creator_set(
442 c: &mut wasm_config_t,
443 creator: &wasmtime_stack_creator_t,
444) {
445 c.config.with_host_stack(Arc::new(CHostStackCreator {
446 foreign: crate::ForeignData {
447 data: creator.env,
448 finalizer: creator.finalizer,
449 },
450 new_stack: creator.new_stack,
451 }));
452}