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);
    }
}