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