Skip to main content

wasmtime/runtime/vm/vmcontext/
vm_host_func_context.rs

1//! Definition of `VM*Context` variant for host functions.
2//!
3//! Keep in sync with `wasmtime_environ::VMHostFuncOffsets`.
4
5use super::{VMArrayCallNative, VMOpaqueContext};
6use crate::error::OutOfMemory;
7use crate::prelude::*;
8use crate::runtime::vm::{StoreBox, VMFuncRef};
9use core::any::Any;
10use core::ptr::NonNull;
11use 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)]
20pub 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
27impl 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`.
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]
58    pub fn host_state(&self) -> &(dyn Any + Send + Sync) {
59        &*self.host_state
60    }
61
62    /// Get this context's `VMFuncRef`.
63    #[inline]
64    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]
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]
83fn 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}