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`. 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] 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