1 //! Definition of `VM*Context` variant for host functions.
2 //!
3 //! Keep in sync with `wasmtime_environ::VMHostFuncOffsets`.
4 
5 use super::VMOpaqueContext;
6 use crate::runtime::vm::{StoreBox, VMFuncRef};
7 use std::any::Any;
8 use wasmtime_environ::{VM_ARRAY_CALL_HOST_FUNC_MAGIC, VM_NATIVE_CALL_HOST_FUNC_MAGIC};
9 
10 /// The `VM*Context` for array-call host functions.
11 ///
12 /// Its `magic` field must always be
13 /// `wasmtime_environ::VM_ARRAY_CALL_HOST_FUNC_MAGIC`, and this is how you can
14 /// determine whether a `VM*Context` is a `VMArrayCallHostFuncContext` versus a
15 /// different kind of context.
16 #[repr(C)]
17 pub struct VMArrayCallHostFuncContext {
18     magic: u32,
19     // _padding: u32, // (on 64-bit systems)
20     pub(crate) func_ref: VMFuncRef,
21     host_state: Box<dyn Any + Send + Sync>,
22 }
23 
24 impl VMArrayCallHostFuncContext {
25     /// Create the context for the given host function.
26     ///
27     /// # Safety
28     ///
29     /// The `host_func` must be a pointer to a host (not Wasm) function and it
30     /// must be `Send` and `Sync`.
31     pub unsafe fn new(
32         func_ref: VMFuncRef,
33         host_state: Box<dyn Any + Send + Sync>,
34     ) -> StoreBox<VMArrayCallHostFuncContext> {
35         debug_assert!(func_ref.vmctx.is_null());
36         let ctx = StoreBox::new(VMArrayCallHostFuncContext {
37             magic: wasmtime_environ::VM_ARRAY_CALL_HOST_FUNC_MAGIC,
38             func_ref,
39             host_state,
40         });
41         let vmctx = VMOpaqueContext::from_vm_array_call_host_func_context(ctx.get());
42         unsafe {
43             (*ctx.get()).func_ref.vmctx = vmctx;
44         }
45         ctx
46     }
47 
48     /// Get the host state for this host function context.
49     #[inline]
50     pub fn host_state(&self) -> &(dyn Any + Send + Sync) {
51         &*self.host_state
52     }
53 
54     /// Get this context's `VMFuncRef`.
55     #[inline]
56     pub fn func_ref(&self) -> &VMFuncRef {
57         &self.func_ref
58     }
59 
60     /// Helper function to cast between context types using a debug assertion to
61     /// protect against some mistakes.
62     #[inline]
63     pub unsafe fn from_opaque(opaque: *mut VMOpaqueContext) -> *mut VMArrayCallHostFuncContext {
64         // See comments in `VMContext::from_opaque` for this debug assert
65         debug_assert_eq!((*opaque).magic, VM_ARRAY_CALL_HOST_FUNC_MAGIC);
66         opaque.cast()
67     }
68 }
69 
70 /// The `VM*Context` for native-call host functions.
71 ///
72 /// Its `magic` field must always be
73 /// `wasmtime_environ::VM_NATIVE_CALL_HOST_FUNC_MAGIC`, and this is how you can
74 /// determine whether a `VM*Context` is a `VMNativeCallHostFuncContext` versus a
75 /// different kind of context.
76 #[repr(C)]
77 pub struct VMNativeCallHostFuncContext {
78     magic: u32,
79     // _padding: u32, // (on 64-bit systems)
80     func_ref: VMFuncRef,
81     host_state: Box<dyn Any + Send + Sync>,
82 }
83 
84 #[test]
85 fn vmnative_call_host_func_context_offsets() {
86     use memoffset::offset_of;
87     use wasmtime_environ::{HostPtr, PtrSize};
88     assert_eq!(
89         usize::from(HostPtr.vmnative_call_host_func_context_func_ref()),
90         offset_of!(VMNativeCallHostFuncContext, func_ref)
91     );
92 }
93 
94 impl VMNativeCallHostFuncContext {
95     /// Create the context for the given host function.
96     ///
97     /// # Safety
98     ///
99     /// The `host_func` must be a pointer to a host (not Wasm) function and it
100     /// must be `Send` and `Sync`.
101     pub unsafe fn new(
102         func_ref: VMFuncRef,
103         host_state: Box<dyn Any + Send + Sync>,
104     ) -> StoreBox<VMNativeCallHostFuncContext> {
105         let ctx = StoreBox::new(VMNativeCallHostFuncContext {
106             magic: wasmtime_environ::VM_NATIVE_CALL_HOST_FUNC_MAGIC,
107             func_ref,
108             host_state,
109         });
110         let vmctx = VMOpaqueContext::from_vm_native_call_host_func_context(ctx.get());
111         unsafe {
112             (*ctx.get()).func_ref.vmctx = vmctx;
113         }
114         ctx
115     }
116 
117     /// Get the host state for this host function context.
118     #[inline]
119     pub fn host_state(&self) -> &(dyn Any + Send + Sync) {
120         &*self.host_state
121     }
122 
123     /// Get this context's `VMFuncRef`.
124     #[inline]
125     pub fn func_ref(&self) -> &VMFuncRef {
126         &self.func_ref
127     }
128 
129     /// Helper function to cast between context types using a debug assertion to
130     /// protect against some mistakes.
131     #[inline]
132     pub unsafe fn from_opaque(opaque: *mut VMOpaqueContext) -> *mut VMNativeCallHostFuncContext {
133         // See comments in `VMContext::from_opaque` for this debug assert
134         debug_assert_eq!((*opaque).magic, VM_NATIVE_CALL_HOST_FUNC_MAGIC);
135         opaque.cast()
136     }
137 }
138