1 //! Definition of `VM*Context` variant for host functions.
2 //!
3 //! Keep in sync with `wasmtime_environ::VMHostFuncOffsets`.
4 
5 use super::{VMArrayCallNative, VMOpaqueContext};
6 use crate::prelude::*;
7 use crate::runtime::vm::{StoreBox, VMFuncRef};
8 use core::any::Any;
9 use core::ptr::NonNull;
10 use wasmtime_environ::{VM_ARRAY_CALL_HOST_FUNC_MAGIC, VMSharedTypeIndex};
11 
12 /// The `VM*Context` for array-call host functions.
13 ///
14 /// Its `magic` field must always be
15 /// `wasmtime_environ::VM_ARRAY_CALL_HOST_FUNC_MAGIC`, and this is how you can
16 /// determine whether a `VM*Context` is a `VMArrayCallHostFuncContext` versus a
17 /// different kind of context.
18 #[repr(C)]
19 pub struct VMArrayCallHostFuncContext {
20     magic: u32,
21     // _padding: u32, // (on 64-bit systems)
22     pub(crate) func_ref: VMFuncRef,
23     host_state: Box<dyn Any + Send + Sync>,
24 }
25 
26 impl VMArrayCallHostFuncContext {
27     /// Create the context for the given host function.
28     ///
29     /// # Safety
30     ///
31     /// The `host_func` must be a pointer to a host (not Wasm) function and it
32     /// must be `Send` and `Sync`.
33     pub unsafe fn new(
34         host_func: VMArrayCallNative,
35         type_index: VMSharedTypeIndex,
36         host_state: Box<dyn Any + Send + Sync>,
37     ) -> StoreBox<VMArrayCallHostFuncContext> {
38         let ctx = StoreBox::new(VMArrayCallHostFuncContext {
39             magic: wasmtime_environ::VM_ARRAY_CALL_HOST_FUNC_MAGIC,
40             func_ref: VMFuncRef {
41                 array_call: NonNull::new(host_func as *mut u8).unwrap().cast().into(),
42                 type_index,
43                 wasm_call: None,
44                 vmctx: NonNull::dangling().into(),
45             },
46             host_state,
47         });
48         let vmctx = VMOpaqueContext::from_vm_array_call_host_func_context(ctx.get());
49         unsafe {
50             ctx.get().as_mut().func_ref.vmctx = vmctx.into();
51         }
52         ctx
53     }
54 
55     /// Get the host state for this host function context.
56     #[inline]
57     pub fn host_state(&self) -> &(dyn Any + Send + Sync) {
58         &*self.host_state
59     }
60 
61     /// Get this context's `VMFuncRef`.
62     #[inline]
63     pub fn func_ref(&self) -> &VMFuncRef {
64         &self.func_ref
65     }
66 
67     /// Helper function to cast between context types using a debug assertion to
68     /// protect against some mistakes.
69     #[inline]
70     pub unsafe fn from_opaque(
71         opaque: NonNull<VMOpaqueContext>,
72     ) -> NonNull<VMArrayCallHostFuncContext> {
73         // See comments in `VMContext::from_opaque` for this debug assert
74         unsafe {
75             debug_assert_eq!(opaque.as_ref().magic, VM_ARRAY_CALL_HOST_FUNC_MAGIC);
76         }
77         opaque.cast()
78     }
79 }
80 
81 #[test]
82 fn vmarray_call_host_func_context_offsets() {
83     use core::mem::offset_of;
84     use wasmtime_environ::{HostPtr, PtrSize};
85     assert_eq!(
86         usize::from(HostPtr.vmarray_call_host_func_context_func_ref()),
87         offset_of!(VMArrayCallHostFuncContext, func_ref)
88     );
89 }
90