Skip to main content

wasmtime_environ/
vmoffsets.rs

1//! Offsets and sizes of various structs in `wasmtime::runtime::vm::*` that are
2//! accessed directly by compiled Wasm code.
3
4// Currently the `VMContext` allocation by field looks like this:
5//
6// struct VMContext {
7//      // Fixed-width data comes first so the calculation of the offset of
8//      // these fields is a compile-time constant when using `HostPtr`.
9//      magic: u32,
10//      _padding: u32, // (On 64-bit systems)
11//      vm_store_context: *const VMStoreContext,
12//      builtin_functions: *mut VMBuiltinFunctionsArray,
13//      epoch_ptr: *mut AtomicU64,
14//      gc_heap_data: *mut T, // Collector-specific pointer
15//      type_ids: *const VMSharedTypeIndex,
16//
17//      // Variable-width fields come after the fixed-width fields above. Place
18//      // memory-related items first as they're some of the most frequently
19//      // accessed items and minimizing their offset in this structure can
20//      // shrink the size of load/store instruction offset immediates on
21//      // platforms like x64 and Pulley (e.g. fit in an 8-bit offset instead
22//      // of needing a 32-bit offset)
23//      imported_memories: [VMMemoryImport; module.num_imported_memories],
24//      memories: [*mut VMMemoryDefinition; module.num_defined_memories],
25//      owned_memories: [VMMemoryDefinition; module.num_owned_memories],
26//      imported_functions: [VMFunctionImport; module.num_imported_functions],
27//      imported_tables: [VMTableImport; module.num_imported_tables],
28//      imported_globals: [VMGlobalImport; module.num_imported_globals],
29//      imported_tags: [VMTagImport; module.num_imported_tags],
30//      tables: [VMTableDefinition; module.num_defined_tables],
31//      globals: [VMGlobalDefinition; module.num_defined_globals],
32//      tags: [VMTagDefinition; module.num_defined_tags],
33//      func_refs: [VMFuncRef; module.num_escaped_funcs],
34//      startup_func_ref: [VMFuncRef; module.has_startup_func ? 1 : 0],
35//      runtime_data_bases: [*const u8; module.num_runtime_data],
36//      runtime_data_lengths: [u32; module.num_runtime_data],
37// }
38
39use crate::{
40    DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, DefinedTagIndex, FuncIndex,
41    FuncRefIndex, GlobalIndex, MemoryIndex, Module, OwnedMemoryIndex, RuntimeDataIndex, TableIndex,
42    TagIndex,
43};
44use cranelift_entity::packed_option::ReservedValue;
45
46/// Number of slots in for `component_context` in the `VMStoreContext`. This is
47/// defined by the component model's `context.{get,set}` intrinsics.
48pub const NUM_COMPONENT_CONTEXT_SLOTS: usize = 2;
49
50#[cfg(target_pointer_width = "32")]
51fn cast_to_u32(sz: usize) -> u32 {
52    u32::try_from(sz).unwrap()
53}
54#[cfg(target_pointer_width = "64")]
55fn cast_to_u32(sz: usize) -> u32 {
56    u32::try_from(sz).expect("overflow in cast from usize to u32")
57}
58
59/// Align an offset used in this module to a specific byte-width by rounding up
60#[inline]
61fn align(offset: u32, width: u32) -> u32 {
62    (offset + (width - 1)) / width * width
63}
64
65/// This class computes offsets to fields within `VMContext` and other
66/// related structs that JIT code accesses directly.
67#[derive(Debug, Clone, Copy)]
68pub struct VMOffsets<P> {
69    /// The size in bytes of a pointer on the target.
70    pub ptr: P,
71    /// The number of imported functions in the module.
72    pub num_imported_functions: u32,
73    /// The number of imported tables in the module.
74    pub num_imported_tables: u32,
75    /// The number of imported memories in the module.
76    pub num_imported_memories: u32,
77    /// The number of imported globals in the module.
78    pub num_imported_globals: u32,
79    /// The number of imported tags in the module.
80    pub num_imported_tags: u32,
81    /// The number of defined tables in the module.
82    pub num_defined_tables: u32,
83    /// The number of defined memories in the module.
84    pub num_defined_memories: u32,
85    /// The number of memories owned by the module instance.
86    pub num_owned_memories: u32,
87    /// The number of defined globals in the module.
88    pub num_defined_globals: u32,
89    /// The number of defined tags in the module.
90    pub num_defined_tags: u32,
91    /// The number of escaped functions in the module, the size of the func_refs
92    /// array.
93    pub num_escaped_funcs: u32,
94    /// The number of runtime data segments in the module.
95    pub num_runtime_data: u32,
96    /// Whether or not the module has a start function.
97    pub has_startup_func: bool,
98
99    // precalculated offsets of various member fields
100    imported_functions: u32,
101    imported_tables: u32,
102    imported_memories: u32,
103    imported_globals: u32,
104    imported_tags: u32,
105    defined_tables: u32,
106    defined_memories: u32,
107    owned_memories: u32,
108    defined_globals: u32,
109    defined_tags: u32,
110    defined_func_refs: u32,
111    startup_func_ref: u32,
112    runtime_data_bases: u32,
113    runtime_data_lengths: u32,
114    size: u32,
115}
116
117/// Trait used for the `ptr` representation of the field of `VMOffsets`
118pub trait PtrSize {
119    /// Returns the pointer size, in bytes, for the target.
120    fn size(&self) -> u8;
121
122    /// The offset of the `VMContext::store_context` field
123    fn vmcontext_store_context(&self) -> u8 {
124        u8::try_from(align(
125            u32::try_from(core::mem::size_of::<u32>()).unwrap(),
126            u32::from(self.size()),
127        ))
128        .unwrap()
129    }
130
131    /// The offset of the `VMContext::builtin_functions` field
132    fn vmcontext_builtin_functions(&self) -> u8 {
133        self.vmcontext_store_context() + self.size()
134    }
135
136    /// The offset of the `array_call` field.
137    #[inline]
138    fn vm_func_ref_array_call(&self) -> u8 {
139        0 * self.size()
140    }
141
142    /// The offset of the `wasm_call` field.
143    #[inline]
144    fn vm_func_ref_wasm_call(&self) -> u8 {
145        1 * self.size()
146    }
147
148    /// The offset of the `type_index` field.
149    #[inline]
150    fn vm_func_ref_type_index(&self) -> u8 {
151        2 * self.size()
152    }
153
154    /// The offset of the `vmctx` field.
155    #[inline]
156    fn vm_func_ref_vmctx(&self) -> u8 {
157        3 * self.size()
158    }
159
160    /// Return the size of `VMFuncRef`.
161    #[inline]
162    fn size_of_vm_func_ref(&self) -> u8 {
163        4 * self.size()
164    }
165
166    /// Return the size of `VMSharedTypeIndex`.
167    #[inline]
168    fn size_of_vmshared_type_index(&self) -> u8 {
169        4
170    }
171
172    /// Return the size of `VMGlobalDefinition`; this is the size of the largest value type (i.e. a
173    /// V128).
174    #[inline]
175    fn size_of_vmglobal_definition(&self) -> u8 {
176        16
177    }
178
179    /// Return the size of `VMTagDefinition`.
180    #[inline]
181    fn size_of_vmtag_definition(&self) -> u8 {
182        4
183    }
184
185    /// This is the size of the largest value type (i.e. a V128).
186    #[inline]
187    fn maximum_value_size(&self) -> u8 {
188        self.size_of_vmglobal_definition()
189    }
190
191    // Offsets within `VMStoreContext`
192
193    /// Return the offset of the `fuel_consumed` field of `VMStoreContext`
194    #[inline]
195    fn vmstore_context_fuel_consumed(&self) -> u8 {
196        0
197    }
198
199    /// Return the offset of the `epoch_deadline` field of `VMStoreContext`
200    #[inline]
201    fn vmstore_context_epoch_deadline(&self) -> u8 {
202        self.vmstore_context_fuel_consumed() + 8
203    }
204
205    /// Return the offset of the `execution_version` field of
206    /// `VMStoreContext`
207    #[inline]
208    fn vmstore_context_execution_version(&self) -> u8 {
209        self.vmstore_context_epoch_deadline() + 8
210    }
211
212    /// Return the offset of the `stack_limit` field of `VMStoreContext`
213    #[inline]
214    fn vmstore_context_stack_limit(&self) -> u8 {
215        self.vmstore_context_execution_version() + 8
216    }
217
218    /// Return the offset of the `gc_heap` field of `VMStoreContext`.
219    #[inline]
220    fn vmstore_context_gc_heap(&self) -> u8 {
221        self.vmstore_context_stack_limit() + self.size()
222    }
223
224    /// Return the offset of the `gc_heap.base` field within a `VMStoreContext`.
225    fn vmstore_context_gc_heap_base(&self) -> u8 {
226        let offset = self.vmstore_context_gc_heap() + self.vmmemory_definition_base();
227        debug_assert!(offset < self.vmstore_context_last_wasm_exit_trampoline_fp());
228        offset
229    }
230
231    /// Return the offset of the `gc_heap.current_length` field within a `VMStoreContext`.
232    fn vmstore_context_gc_heap_current_length(&self) -> u8 {
233        let offset = self.vmstore_context_gc_heap() + self.vmmemory_definition_current_length();
234        debug_assert!(offset < self.vmstore_context_last_wasm_exit_trampoline_fp());
235        offset
236    }
237
238    /// Return the offset of the `last_wasm_exit_trampoline_fp` field
239    /// of `VMStoreContext`.
240    fn vmstore_context_last_wasm_exit_trampoline_fp(&self) -> u8 {
241        self.vmstore_context_gc_heap() + self.size_of_vmmemory_definition()
242    }
243
244    /// Return the offset of the `last_wasm_exit_pc` field of `VMStoreContext`.
245    fn vmstore_context_last_wasm_exit_pc(&self) -> u8 {
246        self.vmstore_context_last_wasm_exit_trampoline_fp() + self.size()
247    }
248
249    /// Return the offset of the `last_wasm_entry_sp` field of `VMStoreContext`.
250    fn vmstore_context_last_wasm_entry_sp(&self) -> u8 {
251        self.vmstore_context_last_wasm_exit_pc() + self.size()
252    }
253
254    /// Return the offset of the `last_wasm_entry_fp` field of `VMStoreContext`.
255    fn vmstore_context_last_wasm_entry_fp(&self) -> u8 {
256        self.vmstore_context_last_wasm_entry_sp() + self.size()
257    }
258
259    /// Return the offset of the `last_wasm_entry_trap_handler` field of `VMStoreContext`.
260    fn vmstore_context_last_wasm_entry_trap_handler(&self) -> u8 {
261        self.vmstore_context_last_wasm_entry_fp() + self.size()
262    }
263
264    /// Return the offset of the `stack_chain` field of `VMStoreContext`.
265    fn vmstore_context_stack_chain(&self) -> u8 {
266        self.vmstore_context_last_wasm_entry_trap_handler() + self.size()
267    }
268
269    /// Return the offset of the `stack_chain` field of `VMStoreContext`.
270    fn vmstore_context_store_data(&self) -> u8 {
271        self.vmstore_context_stack_chain() + self.size_of_vmstack_chain()
272    }
273
274    /// Return the offset of the `async_guard_range` field of `VMStoreContext`.
275    fn vmstore_context_async_guard_range(&self) -> u8 {
276        self.vmstore_context_store_data() + self.size()
277    }
278
279    /// Return the offset of the `component_context[i]` field of
280    /// `VMStoreContext`.
281    fn vmstore_context_component_context_slot(&self, i: u8) -> u8 {
282        assert!(usize::from(i) < NUM_COMPONENT_CONTEXT_SLOTS);
283        let base = self.vmstore_context_async_guard_range() + 2 * self.size();
284        let slot_size = 4;
285        base + i * slot_size
286    }
287
288    /// Return the offset of the `current_thread` field of `VMStoreContext`.
289    fn vmstore_context_current_thread(&self) -> u8 {
290        self.vmstore_context_component_context_slot(0) + (NUM_COMPONENT_CONTEXT_SLOTS as u8) * 4
291    }
292
293    // Offsets within `VMDeferredThread`
294
295    /// Offset of `VMDeferredThread::parent`.
296    fn vmdeferred_thread_parent(&self) -> u8 {
297        0
298    }
299
300    /// Offset of `VMDeferredThread::caller_instance`.
301    fn vmdeferred_thread_caller_instance(&self) -> u8 {
302        self.size()
303    }
304
305    /// Offset of `VMDeferredThread::callee_async`.
306    fn vmdeferred_thread_callee_async(&self) -> u8 {
307        self.vmdeferred_thread_caller_instance() + 4
308    }
309
310    /// Offset of `VMDeferredThread::callee_instance`.
311    fn vmdeferred_thread_callee_instance(&self) -> u8 {
312        self.vmdeferred_thread_callee_async() + 4
313    }
314
315    /// Offset of `VMDeferredThread::saved_context[i]`.
316    fn vmdeferred_thread_saved_context(&self, i: u8) -> u8 {
317        assert!(usize::from(i) < NUM_COMPONENT_CONTEXT_SLOTS);
318        self.vmdeferred_thread_callee_instance() + 4 + i * 4
319    }
320
321    /// Return the size of `VMDeferredThread`, rounded up to pointer alignment.
322    fn size_of_vmdeferred_thread(&self) -> u8 {
323        let unaligned =
324            self.vmdeferred_thread_callee_instance() + 4 + (NUM_COMPONENT_CONTEXT_SLOTS as u8) * 4;
325        align(u32::from(unaligned), u32::from(self.size())) as u8
326    }
327
328    // Offsets within `VMMemoryDefinition`
329
330    /// The offset of the `base` field.
331    #[inline]
332    fn vmmemory_definition_base(&self) -> u8 {
333        0 * self.size()
334    }
335
336    /// The offset of the `current_length` field.
337    #[inline]
338    fn vmmemory_definition_current_length(&self) -> u8 {
339        1 * self.size()
340    }
341
342    /// Return the size of `VMMemoryDefinition`.
343    #[inline]
344    fn size_of_vmmemory_definition(&self) -> u8 {
345        2 * self.size()
346    }
347
348    /// Return the size of `*mut VMMemoryDefinition`.
349    #[inline]
350    fn size_of_vmmemory_pointer(&self) -> u8 {
351        self.size()
352    }
353
354    // Offsets within `VMArrayCallHostFuncContext`.
355
356    /// Return the offset of `VMArrayCallHostFuncContext::func_ref`.
357    fn vmarray_call_host_func_context_func_ref(&self) -> u8 {
358        u8::try_from(align(
359            u32::try_from(core::mem::size_of::<u32>()).unwrap(),
360            u32::from(self.size()),
361        ))
362        .unwrap()
363    }
364
365    /// Return the size of `VMStackChain`.
366    fn size_of_vmstack_chain(&self) -> u8 {
367        2 * self.size()
368    }
369
370    // Offsets within `VMStackLimits`
371
372    /// Return the offset of `VMStackLimits::stack_limit`.
373    fn vmstack_limits_stack_limit(&self) -> u8 {
374        0
375    }
376
377    /// Return the offset of `VMStackLimits::last_wasm_entry_fp`.
378    fn vmstack_limits_last_wasm_entry_fp(&self) -> u8 {
379        self.size()
380    }
381
382    // Offsets within `VMHostArray`
383
384    /// Return the offset of `VMHostArray::length`.
385    fn vmhostarray_length(&self) -> u8 {
386        0
387    }
388
389    /// Return the offset of `VMHostArray::capacity`.
390    fn vmhostarray_capacity(&self) -> u8 {
391        4
392    }
393
394    /// Return the offset of `VMHostArray::data`.
395    fn vmhostarray_data(&self) -> u8 {
396        8
397    }
398
399    /// Return the size of `VMHostArray`.
400    fn size_of_vmhostarray(&self) -> u8 {
401        8 + self.size()
402    }
403
404    // Offsets within `VMCommonStackInformation`
405
406    /// Return the offset of `VMCommonStackInformation::limits`.
407    fn vmcommon_stack_information_limits(&self) -> u8 {
408        0 * self.size()
409    }
410
411    /// Return the offset of `VMCommonStackInformation::state`.
412    fn vmcommon_stack_information_state(&self) -> u8 {
413        2 * self.size()
414    }
415
416    /// Return the offset of `VMCommonStackInformation::handlers`.
417    fn vmcommon_stack_information_handlers(&self) -> u8 {
418        u8::try_from(align(
419            self.vmcommon_stack_information_state() as u32 + 4,
420            u32::from(self.size()),
421        ))
422        .unwrap()
423    }
424
425    /// Return the offset of `VMCommonStackInformation::first_switch_handler_index`.
426    fn vmcommon_stack_information_first_switch_handler_index(&self) -> u8 {
427        self.vmcommon_stack_information_handlers() + self.size_of_vmhostarray()
428    }
429
430    /// Return the size of `VMCommonStackInformation`.
431    fn size_of_vmcommon_stack_information(&self) -> u8 {
432        u8::try_from(align(
433            self.vmcommon_stack_information_first_switch_handler_index() as u32 + 4,
434            u32::from(self.size()),
435        ))
436        .unwrap()
437    }
438
439    // Offsets within `VMContObj`
440
441    /// Return the offset of `VMContObj::contref`
442    fn vmcontobj_contref(&self) -> u8 {
443        0
444    }
445
446    /// Return the offset of `VMContObj::revision`
447    fn vmcontobj_revision(&self) -> u8 {
448        self.size()
449    }
450
451    /// Return the size of `VMContObj`.
452    fn size_of_vmcontobj(&self) -> u8 {
453        u8::try_from(align(
454            u32::from(self.vmcontobj_revision())
455                + u32::try_from(core::mem::size_of::<usize>()).unwrap(),
456            u32::from(self.size()),
457        ))
458        .unwrap()
459    }
460
461    // Offsets within `VMContRef`
462
463    /// Return the offset of `VMContRef::common_stack_information`.
464    fn vmcontref_common_stack_information(&self) -> u8 {
465        0 * self.size()
466    }
467
468    /// Return the offset of `VMContRef::parent_chain`.
469    fn vmcontref_parent_chain(&self) -> u8 {
470        u8::try_from(align(
471            (self.vmcontref_common_stack_information() + self.size_of_vmcommon_stack_information())
472                as u32,
473            u32::from(self.size()),
474        ))
475        .unwrap()
476    }
477
478    /// Return the offset of `VMContRef::last_ancestor`.
479    fn vmcontref_last_ancestor(&self) -> u8 {
480        self.vmcontref_parent_chain() + 2 * self.size()
481    }
482
483    /// Return the offset of `VMContRef::revision`.
484    fn vmcontref_revision(&self) -> u8 {
485        self.vmcontref_last_ancestor() + self.size()
486    }
487
488    /// Return the offset of `VMContRef::stack`.
489    fn vmcontref_stack(&self) -> u8 {
490        self.vmcontref_revision() + self.size()
491    }
492
493    /// Return the offset of `VMContRef::args`.
494    fn vmcontref_args(&self) -> u8 {
495        self.vmcontref_stack() + 3 * self.size()
496    }
497
498    /// Return the offset of `VMContRef::values`.
499    fn vmcontref_values(&self) -> u8 {
500        self.vmcontref_args() + self.size_of_vmhostarray()
501    }
502
503    /// Return the offset to the `magic` value in this `VMContext`.
504    #[inline]
505    fn vmctx_magic(&self) -> u8 {
506        // This is required by the implementation of `VMContext::instance` and
507        // `VMContext::instance_mut`. If this value changes then those locations
508        // need to be updated.
509        0
510    }
511
512    /// Return the offset to the `VMStoreContext` structure
513    #[inline]
514    fn vmctx_store_context(&self) -> u8 {
515        self.vmctx_magic() + self.size()
516    }
517
518    /// Return the offset to the `VMBuiltinFunctionsArray` structure
519    #[inline]
520    fn vmctx_builtin_functions(&self) -> u8 {
521        self.vmctx_store_context() + self.size()
522    }
523
524    /// Return the offset to the `*const AtomicU64` epoch-counter
525    /// pointer.
526    #[inline]
527    fn vmctx_epoch_ptr(&self) -> u8 {
528        self.vmctx_builtin_functions() + self.size()
529    }
530
531    /// Return the offset to the `*mut T` collector-specific data.
532    ///
533    /// This is a pointer that different collectors can use however they see
534    /// fit.
535    #[inline]
536    fn vmctx_gc_heap_data(&self) -> u8 {
537        self.vmctx_epoch_ptr() + self.size()
538    }
539
540    /// Return the offset of the `over_approximated_stack_roots` field within
541    /// `VMDrcHeapData`.
542    #[inline]
543    fn vmdrc_heap_data_over_approximated_stack_roots(&self) -> u8 {
544        0
545    }
546
547    /// Return the offset of the `current_over_approximated_stack_roots_len`
548    /// field within `VMDrcHeapData`.
549    #[inline]
550    fn vmdrc_heap_data_current_over_approximated_stack_roots_len(&self) -> u8 {
551        4
552    }
553
554    /// Return the offset of the
555    /// `over_approximated_stack_roots_len_after_last_gc` field within
556    /// `VMDrcHeapData`.
557    #[inline]
558    fn vmdrc_heap_data_over_approximated_stack_roots_len_after_last_gc(&self) -> u8 {
559        8
560    }
561
562    /// Return the size of `VMDrcHeapData`.
563    #[inline]
564    fn size_of_vmdrc_heap_data(&self) -> u8 {
565        12
566    }
567
568    /// Return the alignment of `VMDrcHeapData`.
569    #[inline]
570    fn align_of_vmdrc_heap_data(&self) -> u8 {
571        4
572    }
573
574    /// Return the offset of the `bump_ptr` field within `VMCopyingHeapData`.
575    #[inline]
576    fn vmcopying_heap_data_bump_ptr(&self) -> u8 {
577        0
578    }
579
580    /// Return the offset of the `active_space_end` field within
581    /// `VMCopyingHeapData`.
582    #[inline]
583    fn vmcopying_heap_data_active_space_end(&self) -> u8 {
584        4
585    }
586
587    /// Return the size of `VMCopyingHeapData`.
588    #[inline]
589    fn size_of_vmcopying_heap_data(&self) -> u8 {
590        8
591    }
592
593    /// Return the alignment of `VMCopyingHeapData`.
594    #[inline]
595    fn align_of_vmcopying_heap_data(&self) -> u8 {
596        4
597    }
598
599    /// The offset of the `type_ids` array pointer.
600    #[inline]
601    fn vmctx_type_ids_array(&self) -> u8 {
602        self.vmctx_gc_heap_data() + self.size()
603    }
604
605    /// The end of statically known offsets in `VMContext`.
606    ///
607    /// Data after this is dynamically sized.
608    #[inline]
609    fn vmctx_dynamic_data_start(&self) -> u8 {
610        self.vmctx_type_ids_array() + self.size()
611    }
612}
613
614/// A trait to abstract over various types that contain a `P: PtrSize`.
615pub trait GetPtrSize {
616    /// The type that implements `PtrSize`.
617    type Ptr: PtrSize;
618
619    /// Get a `&P` where `P: PtrSize`.
620    fn get_ptr_size(&self) -> &Self::Ptr;
621}
622
623impl<P> GetPtrSize for P
624where
625    P: PtrSize,
626{
627    type Ptr = Self;
628
629    #[inline]
630    fn get_ptr_size(&self) -> &Self::Ptr {
631        self
632    }
633}
634
635/// Type representing the size of a pointer for the current compilation host
636#[derive(Clone, Copy)]
637pub struct HostPtr;
638
639impl PtrSize for HostPtr {
640    #[inline]
641    fn size(&self) -> u8 {
642        core::mem::size_of::<usize>() as u8
643    }
644}
645
646impl PtrSize for u8 {
647    #[inline]
648    fn size(&self) -> u8 {
649        *self
650    }
651}
652
653/// Used to construct a `VMOffsets`
654#[derive(Debug, Clone, Copy)]
655pub struct VMOffsetsFields<P> {
656    /// The size in bytes of a pointer on the target.
657    pub ptr: P,
658    /// The number of imported functions in the module.
659    pub num_imported_functions: u32,
660    /// The number of imported tables in the module.
661    pub num_imported_tables: u32,
662    /// The number of imported memories in the module.
663    pub num_imported_memories: u32,
664    /// The number of imported globals in the module.
665    pub num_imported_globals: u32,
666    /// The number of imported tags in the module.
667    pub num_imported_tags: u32,
668    /// The number of defined tables in the module.
669    pub num_defined_tables: u32,
670    /// The number of defined memories in the module.
671    pub num_defined_memories: u32,
672    /// The number of memories owned by the module instance.
673    pub num_owned_memories: u32,
674    /// The number of defined globals in the module.
675    pub num_defined_globals: u32,
676    /// The number of defined tags in the module.
677    pub num_defined_tags: u32,
678    /// The number of escaped functions in the module, the size of the function
679    /// references array.
680    pub num_escaped_funcs: u32,
681    /// The number of runtime data segments in the module.
682    pub num_runtime_data: u32,
683    /// Whether or not the module has a start function.
684    pub has_startup_func: bool,
685}
686
687impl<P: PtrSize> VMOffsets<P> {
688    /// Return a new `VMOffsets` instance, for a given pointer size.
689    pub fn new(ptr: P, module: &Module) -> Self {
690        let num_owned_memories = module
691            .memories
692            .iter()
693            .skip(module.num_imported_memories)
694            .filter(|p| !p.1.shared)
695            .count()
696            .try_into()
697            .unwrap();
698        VMOffsets::from(VMOffsetsFields {
699            ptr,
700            num_imported_functions: cast_to_u32(module.num_imported_funcs),
701            num_imported_tables: cast_to_u32(module.num_imported_tables),
702            num_imported_memories: cast_to_u32(module.num_imported_memories),
703            num_imported_globals: cast_to_u32(module.num_imported_globals),
704            num_imported_tags: cast_to_u32(module.num_imported_tags),
705            num_defined_tables: cast_to_u32(module.num_defined_tables()),
706            num_defined_memories: cast_to_u32(module.num_defined_memories()),
707            num_owned_memories,
708            num_defined_globals: cast_to_u32(module.globals.len() - module.num_imported_globals),
709            num_defined_tags: cast_to_u32(module.tags.len() - module.num_imported_tags),
710            num_escaped_funcs: cast_to_u32(module.num_escaped_funcs),
711            num_runtime_data: cast_to_u32(module.runtime_data.len()),
712            has_startup_func: !module.startup.is_none(),
713        })
714    }
715
716    /// Returns the size, in bytes, of the target
717    #[inline]
718    pub fn pointer_size(&self) -> u8 {
719        self.ptr.size()
720    }
721
722    /// Returns an iterator which provides a human readable description and a
723    /// byte size. The iterator returned will iterate over the bytes allocated
724    /// to the entire `VMOffsets` structure to explain where each byte size is
725    /// coming from.
726    pub fn region_sizes(&self) -> impl Iterator<Item = (&str, u32)> {
727        macro_rules! calculate_sizes {
728            ($($name:ident: $desc:tt,)*) => {{
729                let VMOffsets {
730                    // These fields are metadata not talking about specific
731                    // offsets of specific fields.
732                    ptr: _,
733                    num_imported_functions: _,
734                    num_imported_tables: _,
735                    num_imported_memories: _,
736                    num_imported_globals: _,
737                    num_imported_tags: _,
738                    num_defined_tables: _,
739                    num_defined_globals: _,
740                    num_defined_memories: _,
741                    num_defined_tags: _,
742                    num_owned_memories: _,
743                    num_escaped_funcs: _,
744                    num_runtime_data: _,
745                    has_startup_func: _,
746
747                    // used as the initial size below
748                    size,
749
750                    // exhaustively match the rest of the fields with input from
751                    // the macro
752                    $($name,)*
753                } = *self;
754
755                // calculate the size of each field by relying on the inputs to
756                // the macro being in reverse order and determining the size of
757                // the field as the offset from the field to the last field.
758                let mut last = size;
759                $(
760                    assert!($name <= last);
761                    let tmp = $name;
762                    let $name = last - $name;
763                    last = tmp;
764                )*
765                assert_ne!(last, 0);
766                IntoIterator::into_iter([
767                    $(($desc, $name),)*
768                    ("static vmctx data", last),
769                ])
770            }};
771        }
772
773        calculate_sizes! {
774            runtime_data_lengths: "runtime data lengths",
775            runtime_data_bases: "runtime data base pointers",
776            startup_func_ref: "startup funcref",
777            defined_func_refs: "module functions",
778            defined_tags: "defined tags",
779            defined_globals: "defined globals",
780            defined_tables: "defined tables",
781            imported_tags: "imported tags",
782            imported_globals: "imported globals",
783            imported_tables: "imported tables",
784            imported_functions: "imported functions",
785            owned_memories: "owned memories",
786            defined_memories: "defined memories",
787            imported_memories: "imported memories",
788        }
789    }
790}
791
792impl<P: PtrSize> GetPtrSize for VMOffsets<P> {
793    type Ptr = P;
794
795    #[inline]
796    fn get_ptr_size(&self) -> &Self::Ptr {
797        &self.ptr
798    }
799}
800
801impl<P: PtrSize> From<VMOffsetsFields<P>> for VMOffsets<P> {
802    fn from(fields: VMOffsetsFields<P>) -> VMOffsets<P> {
803        let mut ret = Self {
804            ptr: fields.ptr,
805            num_imported_functions: fields.num_imported_functions,
806            num_imported_tables: fields.num_imported_tables,
807            num_imported_memories: fields.num_imported_memories,
808            num_imported_globals: fields.num_imported_globals,
809            num_imported_tags: fields.num_imported_tags,
810            num_defined_tables: fields.num_defined_tables,
811            num_defined_memories: fields.num_defined_memories,
812            num_owned_memories: fields.num_owned_memories,
813            num_defined_globals: fields.num_defined_globals,
814            num_defined_tags: fields.num_defined_tags,
815            num_escaped_funcs: fields.num_escaped_funcs,
816            num_runtime_data: fields.num_runtime_data,
817            has_startup_func: fields.has_startup_func,
818            imported_functions: 0,
819            imported_tables: 0,
820            imported_memories: 0,
821            imported_globals: 0,
822            imported_tags: 0,
823            defined_tables: 0,
824            defined_memories: 0,
825            owned_memories: 0,
826            defined_globals: 0,
827            defined_tags: 0,
828            defined_func_refs: 0,
829            startup_func_ref: 0,
830            runtime_data_bases: 0,
831            runtime_data_lengths: 0,
832            size: 0,
833        };
834
835        // Convenience functions for checked addition and multiplication.
836        // As side effect this reduces binary size by using only a single
837        // `#[track_caller]` location for each function instead of one for
838        // each individual invocation.
839        #[inline]
840        fn cadd(count: u32, size: u32) -> u32 {
841            count.checked_add(size).unwrap()
842        }
843
844        #[inline]
845        fn cmul(count: u32, size: u8) -> u32 {
846            count.checked_mul(u32::from(size)).unwrap()
847        }
848
849        let mut next_field_offset = u32::from(ret.ptr.vmctx_dynamic_data_start());
850
851        macro_rules! fields {
852            (size($field:ident) = $size:expr, $($rest:tt)*) => {
853                ret.$field = next_field_offset;
854                next_field_offset = cadd(next_field_offset, u32::from($size));
855                fields!($($rest)*);
856            };
857            (align($align:expr), $($rest:tt)*) => {
858                next_field_offset = align(next_field_offset, $align);
859                fields!($($rest)*);
860            };
861            () => {};
862        }
863
864        fields! {
865            size(imported_memories)
866                = cmul(ret.num_imported_memories, ret.size_of_vmmemory_import()),
867            size(defined_memories)
868                = cmul(ret.num_defined_memories, ret.ptr.size_of_vmmemory_pointer()),
869            size(owned_memories)
870                = cmul(ret.num_owned_memories, ret.ptr.size_of_vmmemory_definition()),
871            size(imported_functions)
872                = cmul(ret.num_imported_functions, ret.size_of_vmfunction_import()),
873            size(imported_tables)
874                = cmul(ret.num_imported_tables, ret.size_of_vmtable_import()),
875            size(imported_globals)
876                = cmul(ret.num_imported_globals, ret.size_of_vmglobal_import()),
877            size(imported_tags)
878                = cmul(ret.num_imported_tags, ret.size_of_vmtag_import()),
879            size(defined_tables)
880                = cmul(ret.num_defined_tables, ret.size_of_vmtable_definition()),
881            align(16),
882            size(defined_globals)
883                = cmul(ret.num_defined_globals, ret.ptr.size_of_vmglobal_definition()),
884            size(defined_tags)
885                = cmul(ret.num_defined_tags, ret.ptr.size_of_vmtag_definition()),
886            size(defined_func_refs) = cmul(
887                ret.num_escaped_funcs,
888                ret.ptr.size_of_vm_func_ref(),
889            ),
890            size(startup_func_ref) = if ret.has_startup_func {
891                ret.ptr.size_of_vm_func_ref()
892            } else {
893                0
894            },
895            size(runtime_data_bases) = cmul(ret.num_runtime_data, ret.ptr.size()),
896            size(runtime_data_lengths) = cmul(ret.num_runtime_data, 4),
897        }
898
899        ret.size = next_field_offset;
900
901        return ret;
902    }
903}
904
905impl<P: PtrSize> VMOffsets<P> {
906    /// The offset of the `VMFunctionImport::array_call` field.
907    #[inline]
908    pub fn vmfunction_import_array_call(&self) -> u8 {
909        0 * self.pointer_size()
910    }
911
912    /// The offset of the `VMFunctionImport::wasm_call` field.
913    #[inline]
914    pub fn vmfunction_import_wasm_call(&self) -> u8 {
915        1 * self.pointer_size()
916    }
917
918    /// The offset of the `VMFunctionImport::type_index` field.
919    #[inline]
920    pub fn vmfunction_import_type_index(&self) -> u8 {
921        2 * self.pointer_size()
922    }
923
924    /// The offset of the `VMFunctionImport::vmctx` field.
925    #[inline]
926    pub fn vmfunction_import_vmctx(&self) -> u8 {
927        3 * self.pointer_size()
928    }
929
930    /// Return the size of `VMFunctionImport`.
931    #[inline]
932    pub fn size_of_vmfunction_import(&self) -> u8 {
933        4 * self.pointer_size()
934    }
935}
936
937/// Offsets for `*const VMFunctionBody`.
938impl<P: PtrSize> VMOffsets<P> {
939    /// The size of the `current_elements` field.
940    pub fn size_of_vmfunction_body_ptr(&self) -> u8 {
941        1 * self.pointer_size()
942    }
943}
944
945/// Offsets for `VMTableImport`.
946impl<P: PtrSize> VMOffsets<P> {
947    /// The offset of the `from` field.
948    #[inline]
949    pub fn vmtable_import_from(&self) -> u8 {
950        0 * self.pointer_size()
951    }
952
953    /// The offset of the `vmctx` field.
954    #[inline]
955    pub fn vmtable_import_vmctx(&self) -> u8 {
956        1 * self.pointer_size()
957    }
958
959    /// The offset of the `index` field.
960    #[inline]
961    pub fn vmtable_import_index(&self) -> u8 {
962        2 * self.pointer_size()
963    }
964
965    /// Return the size of `VMTableImport`.
966    #[inline]
967    pub fn size_of_vmtable_import(&self) -> u8 {
968        3 * self.pointer_size()
969    }
970}
971
972/// Offsets for `VMTableDefinition`.
973impl<P: PtrSize> VMOffsets<P> {
974    /// The offset of the `base` field.
975    #[inline]
976    pub fn vmtable_definition_base(&self) -> u8 {
977        0 * self.pointer_size()
978    }
979
980    /// The offset of the `current_elements` field.
981    pub fn vmtable_definition_current_elements(&self) -> u8 {
982        1 * self.pointer_size()
983    }
984
985    /// The size of the `current_elements` field.
986    #[inline]
987    pub fn size_of_vmtable_definition_current_elements(&self) -> u8 {
988        self.pointer_size()
989    }
990
991    /// Return the size of `VMTableDefinition`.
992    #[inline]
993    pub fn size_of_vmtable_definition(&self) -> u8 {
994        2 * self.pointer_size()
995    }
996}
997
998/// Offsets for `VMMemoryImport`.
999impl<P: PtrSize> VMOffsets<P> {
1000    /// The offset of the `from` field.
1001    #[inline]
1002    pub fn vmmemory_import_from(&self) -> u8 {
1003        0 * self.pointer_size()
1004    }
1005
1006    /// The offset of the `vmctx` field.
1007    #[inline]
1008    pub fn vmmemory_import_vmctx(&self) -> u8 {
1009        1 * self.pointer_size()
1010    }
1011
1012    /// The offset of the `index` field.
1013    #[inline]
1014    pub fn vmmemory_import_index(&self) -> u8 {
1015        2 * self.pointer_size()
1016    }
1017
1018    /// Return the size of `VMMemoryImport`.
1019    #[inline]
1020    pub fn size_of_vmmemory_import(&self) -> u8 {
1021        3 * self.pointer_size()
1022    }
1023}
1024
1025/// Offsets for `VMGlobalImport`.
1026impl<P: PtrSize> VMOffsets<P> {
1027    /// The offset of the `from` field.
1028    #[inline]
1029    pub fn vmglobal_import_from(&self) -> u8 {
1030        0 * self.pointer_size()
1031    }
1032
1033    /// Return the size of `VMGlobalImport`.
1034    #[inline]
1035    pub fn size_of_vmglobal_import(&self) -> u8 {
1036        // `VMGlobalImport` has two pointers plus 8 bytes for `VMGlobalKind`
1037        2 * self.pointer_size() + 8
1038    }
1039}
1040
1041/// Offsets for `VMSharedTypeIndex`.
1042impl<P: PtrSize> VMOffsets<P> {
1043    /// Return the size of `VMSharedTypeIndex`.
1044    #[inline]
1045    pub fn size_of_vmshared_type_index(&self) -> u8 {
1046        self.ptr.size_of_vmshared_type_index()
1047    }
1048}
1049
1050/// Offsets for `VMTagImport`.
1051impl<P: PtrSize> VMOffsets<P> {
1052    /// The offset of the `from` field.
1053    #[inline]
1054    pub fn vmtag_import_from(&self) -> u8 {
1055        0 * self.pointer_size()
1056    }
1057
1058    /// The offset of the `vmctx` field.
1059    #[inline]
1060    pub fn vmtag_import_vmctx(&self) -> u8 {
1061        1 * self.pointer_size()
1062    }
1063
1064    /// The offset of the `index` field.
1065    #[inline]
1066    pub fn vmtag_import_index(&self) -> u8 {
1067        2 * self.pointer_size()
1068    }
1069
1070    /// Return the size of `VMTagImport`.
1071    #[inline]
1072    pub fn size_of_vmtag_import(&self) -> u8 {
1073        3 * self.pointer_size()
1074    }
1075}
1076
1077/// Offsets for `VMContext`.
1078impl<P: PtrSize> VMOffsets<P> {
1079    /// The offset of the `tables` array.
1080    #[inline]
1081    pub fn vmctx_imported_functions_begin(&self) -> u32 {
1082        self.imported_functions
1083    }
1084
1085    /// The offset of the `tables` array.
1086    #[inline]
1087    pub fn vmctx_imported_tables_begin(&self) -> u32 {
1088        self.imported_tables
1089    }
1090
1091    /// The offset of the `memories` array.
1092    #[inline]
1093    pub fn vmctx_imported_memories_begin(&self) -> u32 {
1094        self.imported_memories
1095    }
1096
1097    /// The offset of the `globals` array.
1098    #[inline]
1099    pub fn vmctx_imported_globals_begin(&self) -> u32 {
1100        self.imported_globals
1101    }
1102
1103    /// The offset of the `tags` array.
1104    #[inline]
1105    pub fn vmctx_imported_tags_begin(&self) -> u32 {
1106        self.imported_tags
1107    }
1108
1109    /// The offset of the `tables` array.
1110    #[inline]
1111    pub fn vmctx_tables_begin(&self) -> u32 {
1112        self.defined_tables
1113    }
1114
1115    /// The offset of the `memories` array.
1116    #[inline]
1117    pub fn vmctx_memories_begin(&self) -> u32 {
1118        self.defined_memories
1119    }
1120
1121    /// The offset of the `owned_memories` array.
1122    #[inline]
1123    pub fn vmctx_owned_memories_begin(&self) -> u32 {
1124        self.owned_memories
1125    }
1126
1127    /// The offset of the `globals` array.
1128    #[inline]
1129    pub fn vmctx_globals_begin(&self) -> u32 {
1130        self.defined_globals
1131    }
1132
1133    /// The offset of the `tags` array.
1134    #[inline]
1135    pub fn vmctx_tags_begin(&self) -> u32 {
1136        self.defined_tags
1137    }
1138
1139    /// The offset of the `func_refs` array.
1140    #[inline]
1141    pub fn vmctx_func_refs_begin(&self) -> u32 {
1142        self.defined_func_refs
1143    }
1144
1145    /// The offset of the `runtime_data_bases` array.
1146    #[inline]
1147    pub fn vmctx_runtime_data_bases_begin(&self) -> u32 {
1148        self.runtime_data_bases
1149    }
1150
1151    /// The offset of the `runtime_data_lengths` array.
1152    #[inline]
1153    pub fn vmctx_runtime_data_lengths_begin(&self) -> u32 {
1154        self.runtime_data_lengths
1155    }
1156
1157    /// Return the size of the `VMContext` allocation.
1158    #[inline]
1159    pub fn size_of_vmctx(&self) -> u32 {
1160        self.size
1161    }
1162
1163    /// Return the offset to `VMFunctionImport` index `index`.
1164    #[inline]
1165    pub fn vmctx_vmfunction_import(&self, index: FuncIndex) -> u32 {
1166        assert!(index.as_u32() < self.num_imported_functions);
1167        self.vmctx_imported_functions_begin()
1168            + index.as_u32() * u32::from(self.size_of_vmfunction_import())
1169    }
1170
1171    /// Return the offset to `VMTable` index `index`.
1172    #[inline]
1173    pub fn vmctx_vmtable_import(&self, index: TableIndex) -> u32 {
1174        assert!(index.as_u32() < self.num_imported_tables);
1175        self.vmctx_imported_tables_begin()
1176            + index.as_u32() * u32::from(self.size_of_vmtable_import())
1177    }
1178
1179    /// Return the offset to `VMMemoryImport` index `index`.
1180    #[inline]
1181    pub fn vmctx_vmmemory_import(&self, index: MemoryIndex) -> u32 {
1182        assert!(index.as_u32() < self.num_imported_memories);
1183        self.vmctx_imported_memories_begin()
1184            + index.as_u32() * u32::from(self.size_of_vmmemory_import())
1185    }
1186
1187    /// Return the offset to `VMGlobalImport` index `index`.
1188    #[inline]
1189    pub fn vmctx_vmglobal_import(&self, index: GlobalIndex) -> u32 {
1190        assert!(index.as_u32() < self.num_imported_globals);
1191        self.vmctx_imported_globals_begin()
1192            + index.as_u32() * u32::from(self.size_of_vmglobal_import())
1193    }
1194
1195    /// Return the offset to `VMTagImport` index `index`.
1196    #[inline]
1197    pub fn vmctx_vmtag_import(&self, index: TagIndex) -> u32 {
1198        assert!(index.as_u32() < self.num_imported_tags);
1199        self.vmctx_imported_tags_begin() + index.as_u32() * u32::from(self.size_of_vmtag_import())
1200    }
1201
1202    /// Return the offset to `VMTableDefinition` index `index`.
1203    #[inline]
1204    pub fn vmctx_vmtable_definition(&self, index: DefinedTableIndex) -> u32 {
1205        assert!(index.as_u32() < self.num_defined_tables);
1206        self.vmctx_tables_begin() + index.as_u32() * u32::from(self.size_of_vmtable_definition())
1207    }
1208
1209    /// Return the offset to the `*mut VMMemoryDefinition` at index `index`.
1210    #[inline]
1211    pub fn vmctx_vmmemory_pointer(&self, index: DefinedMemoryIndex) -> u32 {
1212        assert!(index.as_u32() < self.num_defined_memories);
1213        self.vmctx_memories_begin()
1214            + index.as_u32() * u32::from(self.ptr.size_of_vmmemory_pointer())
1215    }
1216
1217    /// Return the offset to the owned `VMMemoryDefinition` at index `index`.
1218    #[inline]
1219    pub fn vmctx_vmmemory_definition(&self, index: OwnedMemoryIndex) -> u32 {
1220        assert!(index.as_u32() < self.num_owned_memories);
1221        self.vmctx_owned_memories_begin()
1222            + index.as_u32() * u32::from(self.ptr.size_of_vmmemory_definition())
1223    }
1224
1225    /// Return the offset to the `VMGlobalDefinition` index `index`.
1226    #[inline]
1227    pub fn vmctx_vmglobal_definition(&self, index: DefinedGlobalIndex) -> u32 {
1228        assert!(index.as_u32() < self.num_defined_globals);
1229        self.vmctx_globals_begin()
1230            + index.as_u32() * u32::from(self.ptr.size_of_vmglobal_definition())
1231    }
1232
1233    /// Return the offset to the `VMTagDefinition` index `index`.
1234    #[inline]
1235    pub fn vmctx_vmtag_definition(&self, index: DefinedTagIndex) -> u32 {
1236        assert!(index.as_u32() < self.num_defined_tags);
1237        self.vmctx_tags_begin() + index.as_u32() * u32::from(self.ptr.size_of_vmtag_definition())
1238    }
1239
1240    /// Return the offset to the `VMFuncRef` for the given function
1241    /// index (either imported or defined).
1242    #[inline]
1243    pub fn vmctx_func_ref(&self, index: FuncRefIndex) -> u32 {
1244        assert!(!index.is_reserved_value());
1245        assert!(index.as_u32() < self.num_escaped_funcs);
1246        self.vmctx_func_refs_begin() + index.as_u32() * u32::from(self.ptr.size_of_vm_func_ref())
1247    }
1248
1249    /// Returns the offset to the `VMFuncRef` for the module startup function.
1250    ///
1251    /// Panics if this module does not have a startup function.
1252    #[inline]
1253    pub fn vmctx_startup_func_ref(&self) -> u32 {
1254        assert!(self.has_startup_func);
1255        self.startup_func_ref
1256    }
1257
1258    /// Return the offset to the base of the runtime data segment at `index`.
1259    #[inline]
1260    pub fn vmctx_runtime_data_base(&self, index: RuntimeDataIndex) -> u32 {
1261        assert!(!index.is_reserved_value());
1262        assert!(index.as_u32() < self.num_runtime_data);
1263        self.vmctx_runtime_data_bases_begin() + index.as_u32() * u32::from(self.ptr.size())
1264    }
1265
1266    /// Return the offset to the length of the runtime data segment at `index`.
1267    #[inline]
1268    pub fn vmctx_runtime_data_length(&self, index: RuntimeDataIndex) -> u32 {
1269        assert!(!index.is_reserved_value());
1270        assert!(index.as_u32() < self.num_runtime_data);
1271        self.vmctx_runtime_data_lengths_begin() + index.as_u32() * 4
1272    }
1273
1274    /// Return the offset to the `wasm_call` field in `*const VMFunctionBody` index `index`.
1275    #[inline]
1276    pub fn vmctx_vmfunction_import_wasm_call(&self, index: FuncIndex) -> u32 {
1277        self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_wasm_call())
1278    }
1279
1280    /// Return the offset to the `array_call` field in `*const VMFunctionBody` index `index`.
1281    #[inline]
1282    pub fn vmctx_vmfunction_import_array_call(&self, index: FuncIndex) -> u32 {
1283        self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_array_call())
1284    }
1285
1286    /// Return the offset to the `vmctx` field in `*const VMFunctionBody` index `index`.
1287    #[inline]
1288    pub fn vmctx_vmfunction_import_vmctx(&self, index: FuncIndex) -> u32 {
1289        self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_vmctx())
1290    }
1291
1292    /// Return the offset to the `from` field in the imported `VMTable` at index
1293    /// `index`.
1294    #[inline]
1295    pub fn vmctx_vmtable_from(&self, index: TableIndex) -> u32 {
1296        self.vmctx_vmtable_import(index) + u32::from(self.vmtable_import_from())
1297    }
1298
1299    /// Return the offset to the `base` field in `VMTableDefinition` index `index`.
1300    #[inline]
1301    pub fn vmctx_vmtable_definition_base(&self, index: DefinedTableIndex) -> u32 {
1302        self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_base())
1303    }
1304
1305    /// Return the offset to the `current_elements` field in `VMTableDefinition` index `index`.
1306    #[inline]
1307    pub fn vmctx_vmtable_definition_current_elements(&self, index: DefinedTableIndex) -> u32 {
1308        self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_current_elements())
1309    }
1310
1311    /// Return the offset to the `from` field in `VMMemoryImport` index `index`.
1312    #[inline]
1313    pub fn vmctx_vmmemory_import_from(&self, index: MemoryIndex) -> u32 {
1314        self.vmctx_vmmemory_import(index) + u32::from(self.vmmemory_import_from())
1315    }
1316
1317    /// Return the offset to the `base` field in `VMMemoryDefinition` index `index`.
1318    #[inline]
1319    pub fn vmctx_vmmemory_definition_base(&self, index: OwnedMemoryIndex) -> u32 {
1320        self.vmctx_vmmemory_definition(index) + u32::from(self.ptr.vmmemory_definition_base())
1321    }
1322
1323    /// Return the offset to the `current_length` field in `VMMemoryDefinition` index `index`.
1324    #[inline]
1325    pub fn vmctx_vmmemory_definition_current_length(&self, index: OwnedMemoryIndex) -> u32 {
1326        self.vmctx_vmmemory_definition(index)
1327            + u32::from(self.ptr.vmmemory_definition_current_length())
1328    }
1329
1330    /// Return the offset to the `from` field in `VMGlobalImport` index `index`.
1331    #[inline]
1332    pub fn vmctx_vmglobal_import_from(&self, index: GlobalIndex) -> u32 {
1333        self.vmctx_vmglobal_import(index) + u32::from(self.vmglobal_import_from())
1334    }
1335
1336    /// Return the offset to the `from` field in `VMTagImport` index `index`.
1337    #[inline]
1338    pub fn vmctx_vmtag_import_from(&self, index: TagIndex) -> u32 {
1339        self.vmctx_vmtag_import(index) + u32::from(self.vmtag_import_from())
1340    }
1341
1342    /// Return the offset to the `vmctx` field in `VMTagImport` index `index`.
1343    #[inline]
1344    pub fn vmctx_vmtag_import_vmctx(&self, index: TagIndex) -> u32 {
1345        self.vmctx_vmtag_import(index) + u32::from(self.vmtag_import_vmctx())
1346    }
1347
1348    /// Return the offset to the `index` field in `VMTagImport` index `index`.
1349    #[inline]
1350    pub fn vmctx_vmtag_import_index(&self, index: TagIndex) -> u32 {
1351        self.vmctx_vmtag_import(index) + u32::from(self.vmtag_import_index())
1352    }
1353}
1354
1355/// Offsets for `VMGcHeader`.
1356impl<P: PtrSize> VMOffsets<P> {
1357    /// Return the offset for the `VMGcHeader::kind` field.
1358    #[inline]
1359    pub fn vm_gc_header_kind(&self) -> u32 {
1360        0
1361    }
1362
1363    /// Return the offset for the `VMGcHeader`'s reserved bits.
1364    #[inline]
1365    pub fn vm_gc_header_reserved_bits(&self) -> u32 {
1366        // NB: The reserved bits are the unused `VMGcKind` bits.
1367        self.vm_gc_header_kind()
1368    }
1369
1370    /// Return the offset for the `VMGcHeader::ty` field.
1371    #[inline]
1372    pub fn vm_gc_header_ty(&self) -> u32 {
1373        self.vm_gc_header_kind() + 4
1374    }
1375}
1376
1377/// Offsets for `VMDrcHeader`.
1378///
1379/// Should only be used when the DRC collector is enabled.
1380impl<P: PtrSize> VMOffsets<P> {
1381    /// Return the offset for `VMDrcHeader::ref_count`.
1382    #[inline]
1383    pub fn vm_drc_header_ref_count(&self) -> u32 {
1384        8
1385    }
1386
1387    /// Return the offset for `VMDrcHeader::next_over_approximated_stack_root`.
1388    #[inline]
1389    pub fn vm_drc_header_next_over_approximated_stack_root(&self) -> u32 {
1390        self.vm_drc_header_ref_count() + 8
1391    }
1392}
1393
1394/// Magic value for core Wasm VM contexts.
1395///
1396/// This is stored at the start of all `VMContext` structures.
1397pub const VMCONTEXT_MAGIC: u32 = u32::from_le_bytes(*b"core");
1398
1399/// Equivalent of `VMCONTEXT_MAGIC` except for array-call host functions.
1400///
1401/// This is stored at the start of all `VMArrayCallHostFuncContext` structures
1402/// and double-checked on `VMArrayCallHostFuncContext::from_opaque`.
1403pub const VM_ARRAY_CALL_HOST_FUNC_MAGIC: u32 = u32::from_le_bytes(*b"ACHF");
1404
1405#[cfg(test)]
1406mod tests {
1407    use crate::vmoffsets::align;
1408
1409    #[test]
1410    fn alignment() {
1411        fn is_aligned(x: u32) -> bool {
1412            x % 16 == 0
1413        }
1414        assert!(is_aligned(align(0, 16)));
1415        assert!(is_aligned(align(32, 16)));
1416        assert!(is_aligned(align(33, 16)));
1417        assert!(is_aligned(align(31, 16)));
1418    }
1419}
1420
1421/// The bit pattern of `VMLazyThread::forced()`.
1422pub const VM_LAZY_THREAD_FORCED: u64 = 1;