1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
use crate::module::ModuleInfo; use std::{ffi::c_void, ptr}; /// The context of the currently running WebAssembly instance. /// /// This is implicitly passed to every WebAssembly function. /// Since this is per-instance, each field has a statically /// (as in after compiling the wasm) known size, so no /// runtime checks are necessary. /// /// While the runtime currently just passes this around /// as the first, implicit parameter of every function, /// it may someday be pinned to a register (especially /// on arm, which has a ton of registers) to reduce /// register shuffling. #[derive(Debug, Clone)] #[repr(C)] pub struct Ctx { /// A pointer to the `ModuleInfo` of this instance. pub module_info: *const ModuleInfo, /// This is intended to be user-supplied, per-instance /// contextual data. There are currently some issue with it, /// notably that it cannot be set before running the `start` /// function in a WebAssembly module. Additionally, the `data` /// field may be taken by another ABI implementation that the user /// wishes to use in addition to their own, such as WASI. This issue is /// being discussed at [#1111](https://github.com/wasmerio/wasmer/pull/1111). /// /// Alternatively, per-function data can be used if the function in the /// [`ImportObject`] is a closure. This cannot duplicate data though, /// so if data may be shared if the [`ImportObject`] is reused. pub data: *mut c_void, /// If there's a function set in this field, it gets called /// when the context is destructed, e.g. when an `Instance` /// is dropped. pub data_finalizer: Option<fn(data: *mut c_void)>, } impl Ctx { pub(crate) unsafe fn new_uninit() -> Self { Self { module_info: ptr::null(), data: ptr::null_mut(), data_finalizer: None, } } } impl Drop for Ctx { fn drop(&mut self) { if let Some(ref finalizer) = self.data_finalizer { finalizer(self.data); } } } #[cfg(test)] mod tests { use super::*; use std::mem::forget; #[test] fn test_callback_on_drop() { let foo = String::from("foo"); let mut ctx = unsafe { Ctx::new_uninit() }; ctx.data = foo.as_ptr() as *const _ as *mut _; ctx.data_finalizer = Some(|data| { let foo = unsafe { String::from_raw_parts(data as *mut _, 3, 3) }; assert_eq!(String::from("foo"), foo); drop(foo); }); drop(ctx); forget(foo); } }