Skip to main content

substrate_wasmtime_runtime/
vmcontext.rs

1//! This file declares `VMContext` and several related structs which contain
2//! fields that compiled wasm code accesses directly.
3
4use crate::instance::Instance;
5use std::any::Any;
6use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
7use std::{ptr, u32};
8use wasmtime_environ::BuiltinFunctionIndex;
9
10/// An imported function.
11#[derive(Debug, Copy, Clone)]
12#[repr(C)]
13pub struct VMFunctionImport {
14    /// A pointer to the imported function body.
15    pub body: *const VMFunctionBody,
16
17    /// A pointer to the `VMContext` that owns the function.
18    pub vmctx: *mut VMContext,
19}
20
21#[cfg(test)]
22mod test_vmfunction_import {
23    use super::VMFunctionImport;
24    use memoffset::offset_of;
25    use std::mem::size_of;
26    use wasmtime_environ::{Module, VMOffsets};
27
28    #[test]
29    fn check_vmfunction_import_offsets() {
30        let module = Module::new();
31        let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module.local);
32        assert_eq!(
33            size_of::<VMFunctionImport>(),
34            usize::from(offsets.size_of_vmfunction_import())
35        );
36        assert_eq!(
37            offset_of!(VMFunctionImport, body),
38            usize::from(offsets.vmfunction_import_body())
39        );
40        assert_eq!(
41            offset_of!(VMFunctionImport, vmctx),
42            usize::from(offsets.vmfunction_import_vmctx())
43        );
44    }
45}
46
47/// A placeholder byte-sized type which is just used to provide some amount of type
48/// safety when dealing with pointers to JIT-compiled function bodies. Note that it's
49/// deliberately not Copy, as we shouldn't be carelessly copying function body bytes
50/// around.
51#[repr(C)]
52pub struct VMFunctionBody(u8);
53
54#[cfg(test)]
55mod test_vmfunction_body {
56    use super::VMFunctionBody;
57    use std::mem::size_of;
58
59    #[test]
60    fn check_vmfunction_body_offsets() {
61        assert_eq!(size_of::<VMFunctionBody>(), 1);
62    }
63}
64
65/// The fields compiled code needs to access to utilize a WebAssembly table
66/// imported from another instance.
67#[derive(Debug, Copy, Clone)]
68#[repr(C)]
69pub struct VMTableImport {
70    /// A pointer to the imported table description.
71    pub from: *mut VMTableDefinition,
72
73    /// A pointer to the `VMContext` that owns the table description.
74    pub vmctx: *mut VMContext,
75}
76
77#[cfg(test)]
78mod test_vmtable_import {
79    use super::VMTableImport;
80    use memoffset::offset_of;
81    use std::mem::size_of;
82    use wasmtime_environ::{Module, VMOffsets};
83
84    #[test]
85    fn check_vmtable_import_offsets() {
86        let module = Module::new();
87        let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module.local);
88        assert_eq!(
89            size_of::<VMTableImport>(),
90            usize::from(offsets.size_of_vmtable_import())
91        );
92        assert_eq!(
93            offset_of!(VMTableImport, from),
94            usize::from(offsets.vmtable_import_from())
95        );
96        assert_eq!(
97            offset_of!(VMTableImport, vmctx),
98            usize::from(offsets.vmtable_import_vmctx())
99        );
100    }
101}
102
103/// The fields compiled code needs to access to utilize a WebAssembly linear
104/// memory imported from another instance.
105#[derive(Debug, Copy, Clone)]
106#[repr(C)]
107pub struct VMMemoryImport {
108    /// A pointer to the imported memory description.
109    pub from: *mut VMMemoryDefinition,
110
111    /// A pointer to the `VMContext` that owns the memory description.
112    pub vmctx: *mut VMContext,
113}
114
115#[cfg(test)]
116mod test_vmmemory_import {
117    use super::VMMemoryImport;
118    use memoffset::offset_of;
119    use std::mem::size_of;
120    use wasmtime_environ::{Module, VMOffsets};
121
122    #[test]
123    fn check_vmmemory_import_offsets() {
124        let module = Module::new();
125        let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module.local);
126        assert_eq!(
127            size_of::<VMMemoryImport>(),
128            usize::from(offsets.size_of_vmmemory_import())
129        );
130        assert_eq!(
131            offset_of!(VMMemoryImport, from),
132            usize::from(offsets.vmmemory_import_from())
133        );
134        assert_eq!(
135            offset_of!(VMMemoryImport, vmctx),
136            usize::from(offsets.vmmemory_import_vmctx())
137        );
138    }
139}
140
141/// The fields compiled code needs to access to utilize a WebAssembly global
142/// variable imported from another instance.
143#[derive(Debug, Copy, Clone)]
144#[repr(C)]
145pub struct VMGlobalImport {
146    /// A pointer to the imported global variable description.
147    pub from: *mut VMGlobalDefinition,
148}
149
150#[cfg(test)]
151mod test_vmglobal_import {
152    use super::VMGlobalImport;
153    use memoffset::offset_of;
154    use std::mem::size_of;
155    use wasmtime_environ::{Module, VMOffsets};
156
157    #[test]
158    fn check_vmglobal_import_offsets() {
159        let module = Module::new();
160        let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module.local);
161        assert_eq!(
162            size_of::<VMGlobalImport>(),
163            usize::from(offsets.size_of_vmglobal_import())
164        );
165        assert_eq!(
166            offset_of!(VMGlobalImport, from),
167            usize::from(offsets.vmglobal_import_from())
168        );
169    }
170}
171
172/// The fields compiled code needs to access to utilize a WebAssembly linear
173/// memory defined within the instance, namely the start address and the
174/// size in bytes.
175#[derive(Debug, Copy, Clone)]
176#[repr(C)]
177pub struct VMMemoryDefinition {
178    /// The start address.
179    pub base: *mut u8,
180
181    /// The current logical size of this linear memory in bytes.
182    pub current_length: usize,
183}
184
185#[cfg(test)]
186mod test_vmmemory_definition {
187    use super::VMMemoryDefinition;
188    use memoffset::offset_of;
189    use std::mem::size_of;
190    use wasmtime_environ::{Module, VMOffsets};
191
192    #[test]
193    fn check_vmmemory_definition_offsets() {
194        let module = Module::new();
195        let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module.local);
196        assert_eq!(
197            size_of::<VMMemoryDefinition>(),
198            usize::from(offsets.size_of_vmmemory_definition())
199        );
200        assert_eq!(
201            offset_of!(VMMemoryDefinition, base),
202            usize::from(offsets.vmmemory_definition_base())
203        );
204        assert_eq!(
205            offset_of!(VMMemoryDefinition, current_length),
206            usize::from(offsets.vmmemory_definition_current_length())
207        );
208        /* TODO: Assert that the size of `current_length` matches.
209        assert_eq!(
210            size_of::<VMMemoryDefinition::current_length>(),
211            usize::from(offsets.size_of_vmmemory_definition_current_length())
212        );
213        */
214    }
215}
216
217/// The fields compiled code needs to access to utilize a WebAssembly table
218/// defined within the instance.
219#[derive(Debug, Copy, Clone)]
220#[repr(C)]
221pub struct VMTableDefinition {
222    /// Pointer to the table data.
223    pub base: *mut u8,
224
225    /// The current number of elements in the table.
226    pub current_elements: u32,
227}
228
229#[cfg(test)]
230mod test_vmtable_definition {
231    use super::VMTableDefinition;
232    use memoffset::offset_of;
233    use std::mem::size_of;
234    use wasmtime_environ::{Module, VMOffsets};
235
236    #[test]
237    fn check_vmtable_definition_offsets() {
238        let module = Module::new();
239        let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module.local);
240        assert_eq!(
241            size_of::<VMTableDefinition>(),
242            usize::from(offsets.size_of_vmtable_definition())
243        );
244        assert_eq!(
245            offset_of!(VMTableDefinition, base),
246            usize::from(offsets.vmtable_definition_base())
247        );
248        assert_eq!(
249            offset_of!(VMTableDefinition, current_elements),
250            usize::from(offsets.vmtable_definition_current_elements())
251        );
252    }
253}
254
255/// The storage for a WebAssembly global defined within the instance.
256///
257/// TODO: Pack the globals more densely, rather than using the same size
258/// for every type.
259#[derive(Debug, Copy, Clone)]
260#[repr(C, align(16))]
261pub struct VMGlobalDefinition {
262    storage: [u8; 16],
263    // If more elements are added here, remember to add offset_of tests below!
264}
265
266#[cfg(test)]
267mod test_vmglobal_definition {
268    use super::VMGlobalDefinition;
269    use more_asserts::assert_ge;
270    use std::mem::{align_of, size_of};
271    use wasmtime_environ::{Module, VMOffsets};
272
273    #[test]
274    fn check_vmglobal_definition_alignment() {
275        assert_ge!(align_of::<VMGlobalDefinition>(), align_of::<i32>());
276        assert_ge!(align_of::<VMGlobalDefinition>(), align_of::<i64>());
277        assert_ge!(align_of::<VMGlobalDefinition>(), align_of::<f32>());
278        assert_ge!(align_of::<VMGlobalDefinition>(), align_of::<f64>());
279        assert_ge!(align_of::<VMGlobalDefinition>(), align_of::<[u8; 16]>());
280    }
281
282    #[test]
283    fn check_vmglobal_definition_offsets() {
284        let module = Module::new();
285        let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module.local);
286        assert_eq!(
287            size_of::<VMGlobalDefinition>(),
288            usize::from(offsets.size_of_vmglobal_definition())
289        );
290    }
291
292    #[test]
293    fn check_vmglobal_begins_aligned() {
294        let module = Module::new();
295        let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module.local);
296        assert_eq!(offsets.vmctx_globals_begin() % 16, 0);
297    }
298}
299
300impl VMGlobalDefinition {
301    /// Construct a `VMGlobalDefinition`.
302    pub fn new() -> Self {
303        Self { storage: [0; 16] }
304    }
305
306    /// Return a reference to the value as an i32.
307    #[allow(clippy::cast_ptr_alignment)]
308    pub unsafe fn as_i32(&self) -> &i32 {
309        &*(self.storage.as_ref().as_ptr() as *const i32)
310    }
311
312    /// Return a mutable reference to the value as an i32.
313    #[allow(clippy::cast_ptr_alignment)]
314    pub unsafe fn as_i32_mut(&mut self) -> &mut i32 {
315        &mut *(self.storage.as_mut().as_mut_ptr() as *mut i32)
316    }
317
318    /// Return a reference to the value as a u32.
319    #[allow(clippy::cast_ptr_alignment)]
320    pub unsafe fn as_u32(&self) -> &u32 {
321        &*(self.storage.as_ref().as_ptr() as *const u32)
322    }
323
324    /// Return a mutable reference to the value as an u32.
325    #[allow(clippy::cast_ptr_alignment)]
326    pub unsafe fn as_u32_mut(&mut self) -> &mut u32 {
327        &mut *(self.storage.as_mut().as_mut_ptr() as *mut u32)
328    }
329
330    /// Return a reference to the value as an i64.
331    #[allow(clippy::cast_ptr_alignment)]
332    pub unsafe fn as_i64(&self) -> &i64 {
333        &*(self.storage.as_ref().as_ptr() as *const i64)
334    }
335
336    /// Return a mutable reference to the value as an i64.
337    #[allow(clippy::cast_ptr_alignment)]
338    pub unsafe fn as_i64_mut(&mut self) -> &mut i64 {
339        &mut *(self.storage.as_mut().as_mut_ptr() as *mut i64)
340    }
341
342    /// Return a reference to the value as an u64.
343    #[allow(clippy::cast_ptr_alignment)]
344    pub unsafe fn as_u64(&self) -> &u64 {
345        &*(self.storage.as_ref().as_ptr() as *const u64)
346    }
347
348    /// Return a mutable reference to the value as an u64.
349    #[allow(clippy::cast_ptr_alignment)]
350    pub unsafe fn as_u64_mut(&mut self) -> &mut u64 {
351        &mut *(self.storage.as_mut().as_mut_ptr() as *mut u64)
352    }
353
354    /// Return a reference to the value as an f32.
355    #[allow(clippy::cast_ptr_alignment)]
356    pub unsafe fn as_f32(&self) -> &f32 {
357        &*(self.storage.as_ref().as_ptr() as *const f32)
358    }
359
360    /// Return a mutable reference to the value as an f32.
361    #[allow(clippy::cast_ptr_alignment)]
362    pub unsafe fn as_f32_mut(&mut self) -> &mut f32 {
363        &mut *(self.storage.as_mut().as_mut_ptr() as *mut f32)
364    }
365
366    /// Return a reference to the value as f32 bits.
367    #[allow(clippy::cast_ptr_alignment)]
368    pub unsafe fn as_f32_bits(&self) -> &u32 {
369        &*(self.storage.as_ref().as_ptr() as *const u32)
370    }
371
372    /// Return a mutable reference to the value as f32 bits.
373    #[allow(clippy::cast_ptr_alignment)]
374    pub unsafe fn as_f32_bits_mut(&mut self) -> &mut u32 {
375        &mut *(self.storage.as_mut().as_mut_ptr() as *mut u32)
376    }
377
378    /// Return a reference to the value as an f64.
379    #[allow(clippy::cast_ptr_alignment)]
380    pub unsafe fn as_f64(&self) -> &f64 {
381        &*(self.storage.as_ref().as_ptr() as *const f64)
382    }
383
384    /// Return a mutable reference to the value as an f64.
385    #[allow(clippy::cast_ptr_alignment)]
386    pub unsafe fn as_f64_mut(&mut self) -> &mut f64 {
387        &mut *(self.storage.as_mut().as_mut_ptr() as *mut f64)
388    }
389
390    /// Return a reference to the value as f64 bits.
391    #[allow(clippy::cast_ptr_alignment)]
392    pub unsafe fn as_f64_bits(&self) -> &u64 {
393        &*(self.storage.as_ref().as_ptr() as *const u64)
394    }
395
396    /// Return a mutable reference to the value as f64 bits.
397    #[allow(clippy::cast_ptr_alignment)]
398    pub unsafe fn as_f64_bits_mut(&mut self) -> &mut u64 {
399        &mut *(self.storage.as_mut().as_mut_ptr() as *mut u64)
400    }
401
402    /// Return a reference to the value as an u128.
403    #[allow(clippy::cast_ptr_alignment)]
404    pub unsafe fn as_u128(&self) -> &u128 {
405        &*(self.storage.as_ref().as_ptr() as *const u128)
406    }
407
408    /// Return a mutable reference to the value as an u128.
409    #[allow(clippy::cast_ptr_alignment)]
410    pub unsafe fn as_u128_mut(&mut self) -> &mut u128 {
411        &mut *(self.storage.as_mut().as_mut_ptr() as *mut u128)
412    }
413
414    /// Return a reference to the value as u128 bits.
415    #[allow(clippy::cast_ptr_alignment)]
416    pub unsafe fn as_u128_bits(&self) -> &[u8; 16] {
417        &*(self.storage.as_ref().as_ptr() as *const [u8; 16])
418    }
419
420    /// Return a mutable reference to the value as u128 bits.
421    #[allow(clippy::cast_ptr_alignment)]
422    pub unsafe fn as_u128_bits_mut(&mut self) -> &mut [u8; 16] {
423        &mut *(self.storage.as_mut().as_mut_ptr() as *mut [u8; 16])
424    }
425}
426
427/// An index into the shared signature registry, usable for checking signatures
428/// at indirect calls.
429#[repr(C)]
430#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
431pub struct VMSharedSignatureIndex(u32);
432
433#[cfg(test)]
434mod test_vmshared_signature_index {
435    use super::VMSharedSignatureIndex;
436    use std::mem::size_of;
437    use wasmtime_environ::{Module, TargetSharedSignatureIndex, VMOffsets};
438
439    #[test]
440    fn check_vmshared_signature_index() {
441        let module = Module::new();
442        let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module.local);
443        assert_eq!(
444            size_of::<VMSharedSignatureIndex>(),
445            usize::from(offsets.size_of_vmshared_signature_index())
446        );
447    }
448
449    #[test]
450    fn check_target_shared_signature_index() {
451        assert_eq!(
452            size_of::<VMSharedSignatureIndex>(),
453            size_of::<TargetSharedSignatureIndex>()
454        );
455    }
456}
457
458impl VMSharedSignatureIndex {
459    /// Create a new `VMSharedSignatureIndex`.
460    pub fn new(value: u32) -> Self {
461        Self(value)
462    }
463}
464
465impl Default for VMSharedSignatureIndex {
466    fn default() -> Self {
467        Self::new(u32::MAX)
468    }
469}
470
471/// The VM caller-checked "anyfunc" record, for caller-side signature checking.
472/// It consists of the actual function pointer and a signature id to be checked
473/// by the caller.
474#[derive(Debug, Clone)]
475#[repr(C)]
476pub struct VMCallerCheckedAnyfunc {
477    /// Function body.
478    pub func_ptr: *const VMFunctionBody,
479    /// Function signature id.
480    pub type_index: VMSharedSignatureIndex,
481    /// Function `VMContext`.
482    pub vmctx: *mut VMContext,
483    // If more elements are added here, remember to add offset_of tests below!
484}
485
486#[cfg(test)]
487mod test_vmcaller_checked_anyfunc {
488    use super::VMCallerCheckedAnyfunc;
489    use memoffset::offset_of;
490    use std::mem::size_of;
491    use wasmtime_environ::{Module, VMOffsets};
492
493    #[test]
494    fn check_vmcaller_checked_anyfunc_offsets() {
495        let module = Module::new();
496        let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module.local);
497        assert_eq!(
498            size_of::<VMCallerCheckedAnyfunc>(),
499            usize::from(offsets.size_of_vmcaller_checked_anyfunc())
500        );
501        assert_eq!(
502            offset_of!(VMCallerCheckedAnyfunc, func_ptr),
503            usize::from(offsets.vmcaller_checked_anyfunc_func_ptr())
504        );
505        assert_eq!(
506            offset_of!(VMCallerCheckedAnyfunc, type_index),
507            usize::from(offsets.vmcaller_checked_anyfunc_type_index())
508        );
509        assert_eq!(
510            offset_of!(VMCallerCheckedAnyfunc, vmctx),
511            usize::from(offsets.vmcaller_checked_anyfunc_vmctx())
512        );
513    }
514}
515
516impl Default for VMCallerCheckedAnyfunc {
517    fn default() -> Self {
518        Self {
519            func_ptr: ptr::null_mut(),
520            type_index: Default::default(),
521            vmctx: ptr::null_mut(),
522        }
523    }
524}
525
526/// An array that stores addresses of builtin functions. We translate code
527/// to use indirect calls. This way, we don't have to patch the code.
528#[repr(C)]
529pub struct VMBuiltinFunctionsArray {
530    ptrs: [usize; Self::len()],
531}
532
533impl VMBuiltinFunctionsArray {
534    pub const fn len() -> usize {
535        BuiltinFunctionIndex::builtin_functions_total_number() as usize
536    }
537
538    pub fn initialized() -> Self {
539        use crate::libcalls::*;
540
541        let mut ptrs = [0; Self::len()];
542
543        ptrs[BuiltinFunctionIndex::get_memory32_grow_index().index() as usize] =
544            wasmtime_memory32_grow as usize;
545        ptrs[BuiltinFunctionIndex::get_imported_memory32_grow_index().index() as usize] =
546            wasmtime_imported_memory32_grow as usize;
547
548        ptrs[BuiltinFunctionIndex::get_memory32_size_index().index() as usize] =
549            wasmtime_memory32_size as usize;
550        ptrs[BuiltinFunctionIndex::get_imported_memory32_size_index().index() as usize] =
551            wasmtime_imported_memory32_size as usize;
552
553        ptrs[BuiltinFunctionIndex::get_table_copy_index().index() as usize] =
554            wasmtime_table_copy as usize;
555
556        ptrs[BuiltinFunctionIndex::get_table_init_index().index() as usize] =
557            wasmtime_table_init as usize;
558        ptrs[BuiltinFunctionIndex::get_elem_drop_index().index() as usize] =
559            wasmtime_elem_drop as usize;
560
561        ptrs[BuiltinFunctionIndex::get_defined_memory_copy_index().index() as usize] =
562            wasmtime_defined_memory_copy as usize;
563        ptrs[BuiltinFunctionIndex::get_imported_memory_copy_index().index() as usize] =
564            wasmtime_imported_memory_copy as usize;
565        ptrs[BuiltinFunctionIndex::get_memory_fill_index().index() as usize] =
566            wasmtime_memory_fill as usize;
567        ptrs[BuiltinFunctionIndex::get_imported_memory_fill_index().index() as usize] =
568            wasmtime_imported_memory_fill as usize;
569        ptrs[BuiltinFunctionIndex::get_memory_init_index().index() as usize] =
570            wasmtime_memory_init as usize;
571        ptrs[BuiltinFunctionIndex::get_data_drop_index().index() as usize] =
572            wasmtime_data_drop as usize;
573
574        debug_assert!(ptrs.iter().cloned().all(|p| p != 0));
575
576        Self { ptrs }
577    }
578}
579
580/// The storage for a WebAssembly invocation argument
581///
582/// TODO: These could be packed more densely, rather than using the same size for every type.
583#[derive(Debug, Copy, Clone)]
584#[repr(C, align(16))]
585pub struct VMInvokeArgument([u8; 16]);
586
587#[cfg(test)]
588mod test_vm_invoke_argument {
589    use super::VMInvokeArgument;
590    use std::mem::{align_of, size_of};
591    use wasmtime_environ::{Module, VMOffsets};
592
593    #[test]
594    fn check_vm_invoke_argument_alignment() {
595        assert_eq!(align_of::<VMInvokeArgument>(), 16);
596    }
597
598    #[test]
599    fn check_vmglobal_definition_offsets() {
600        let module = Module::new();
601        let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module.local);
602        assert_eq!(
603            size_of::<VMInvokeArgument>(),
604            usize::from(offsets.size_of_vmglobal_definition())
605        );
606    }
607}
608
609impl VMInvokeArgument {
610    /// Create a new invocation argument filled with zeroes
611    pub fn new() -> Self {
612        Self([0; 16])
613    }
614}
615
616/// Structure used to control interrupting wasm code, currently with only one
617/// atomic flag internally used.
618#[derive(Debug)]
619#[repr(C)]
620pub struct VMInterrupts {
621    /// Current stack limit of the wasm module.
622    ///
623    /// This is used to control both stack overflow as well as interrupting wasm
624    /// modules. For more information see `crates/environ/src/cranelift.rs`.
625    pub stack_limit: AtomicUsize,
626}
627
628impl VMInterrupts {
629    /// Flag that an interrupt should occur
630    pub fn interrupt(&self) {
631        self.stack_limit
632            .store(wasmtime_environ::INTERRUPTED, SeqCst);
633    }
634}
635
636impl Default for VMInterrupts {
637    fn default() -> VMInterrupts {
638        VMInterrupts {
639            stack_limit: AtomicUsize::new(usize::max_value()),
640        }
641    }
642}
643
644#[cfg(test)]
645mod test_vminterrupts {
646    use super::VMInterrupts;
647    use memoffset::offset_of;
648    use std::mem::size_of;
649    use wasmtime_environ::{Module, VMOffsets};
650
651    #[test]
652    fn check_vminterrupts_interrupted_offset() {
653        let module = Module::new();
654        let offsets = VMOffsets::new(size_of::<*mut u8>() as u8, &module.local);
655        assert_eq!(
656            offset_of!(VMInterrupts, stack_limit),
657            usize::from(offsets.vminterrupts_stack_limit())
658        );
659    }
660}
661
662/// The VM "context", which is pointed to by the `vmctx` arg in Cranelift.
663/// This has information about globals, memories, tables, and other runtime
664/// state associated with the current instance.
665///
666/// The struct here is empty, as the sizes of these fields are dynamic, and
667/// we can't describe them in Rust's type system. Sufficient memory is
668/// allocated at runtime.
669///
670/// TODO: We could move the globals into the `vmctx` allocation too.
671#[derive(Debug)]
672#[repr(C, align(16))] // align 16 since globals are aligned to that and contained inside
673pub struct VMContext {}
674
675impl VMContext {
676    /// Return a mutable reference to the associated `Instance`.
677    ///
678    /// # Safety
679    /// This is unsafe because it doesn't work on just any `VMContext`, it must
680    /// be a `VMContext` allocated as part of an `Instance`.
681    #[allow(clippy::cast_ptr_alignment)]
682    #[inline]
683    pub(crate) unsafe fn instance(&self) -> &Instance {
684        &*((self as *const Self as *mut u8).offset(-Instance::vmctx_offset()) as *const Instance)
685    }
686
687    /// Return a reference to the host state associated with this `Instance`.
688    ///
689    /// # Safety
690    /// This is unsafe because it doesn't work on just any `VMContext`, it must
691    /// be a `VMContext` allocated as part of an `Instance`.
692    #[inline]
693    pub unsafe fn host_state(&self) -> &dyn Any {
694        self.instance().host_state()
695    }
696}
697
698///
699pub type VMTrampoline = unsafe extern "C" fn(
700    *mut VMContext,        // callee vmctx
701    *mut VMContext,        // caller vmctx
702    *const VMFunctionBody, // function we're actually calling
703    *mut u128,             // space for arguments and return values
704);