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 // }
35 
36 use crate::{
37     DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, DefinedTagIndex, FuncIndex,
38     FuncRefIndex, GlobalIndex, MemoryIndex, Module, OwnedMemoryIndex, TableIndex, TagIndex,
39 };
40 use cranelift_entity::packed_option::ReservedValue;
41 
42 #[cfg(target_pointer_width = "32")]
cast_to_u32(sz: usize) -> u3243 fn cast_to_u32(sz: usize) -> u32 {
44     u32::try_from(sz).unwrap()
45 }
46 #[cfg(target_pointer_width = "64")]
cast_to_u32(sz: usize) -> u3247 fn cast_to_u32(sz: usize) -> u32 {
48     u32::try_from(sz).expect("overflow in cast from usize to u32")
49 }
50 
51 /// Align an offset used in this module to a specific byte-width by rounding up
52 #[inline]
align(offset: u32, width: u32) -> u3253 fn align(offset: u32, width: u32) -> u32 {
54     (offset + (width - 1)) / width * width
55 }
56 
57 /// This class computes offsets to fields within `VMContext` and other
58 /// related structs that JIT code accesses directly.
59 #[derive(Debug, Clone, Copy)]
60 pub struct VMOffsets<P> {
61     /// The size in bytes of a pointer on the target.
62     pub ptr: P,
63     /// The number of imported functions in the module.
64     pub num_imported_functions: u32,
65     /// The number of imported tables in the module.
66     pub num_imported_tables: u32,
67     /// The number of imported memories in the module.
68     pub num_imported_memories: u32,
69     /// The number of imported globals in the module.
70     pub num_imported_globals: u32,
71     /// The number of imported tags in the module.
72     pub num_imported_tags: u32,
73     /// The number of defined tables in the module.
74     pub num_defined_tables: u32,
75     /// The number of defined memories in the module.
76     pub num_defined_memories: u32,
77     /// The number of memories owned by the module instance.
78     pub num_owned_memories: u32,
79     /// The number of defined globals in the module.
80     pub num_defined_globals: u32,
81     /// The number of defined tags in the module.
82     pub num_defined_tags: u32,
83     /// The number of escaped functions in the module, the size of the func_refs
84     /// array.
85     pub num_escaped_funcs: u32,
86 
87     // precalculated offsets of various member fields
88     imported_functions: u32,
89     imported_tables: u32,
90     imported_memories: u32,
91     imported_globals: u32,
92     imported_tags: u32,
93     defined_tables: u32,
94     defined_memories: u32,
95     owned_memories: u32,
96     defined_globals: u32,
97     defined_tags: u32,
98     defined_func_refs: u32,
99     size: u32,
100 }
101 
102 /// Trait used for the `ptr` representation of the field of `VMOffsets`
103 pub trait PtrSize {
104     /// Returns the pointer size, in bytes, for the target.
size(&self) -> u8105     fn size(&self) -> u8;
106 
107     /// The offset of the `VMContext::store_context` field
vmcontext_store_context(&self) -> u8108     fn vmcontext_store_context(&self) -> u8 {
109         u8::try_from(align(
110             u32::try_from(core::mem::size_of::<u32>()).unwrap(),
111             u32::from(self.size()),
112         ))
113         .unwrap()
114     }
115 
116     /// The offset of the `VMContext::builtin_functions` field
vmcontext_builtin_functions(&self) -> u8117     fn vmcontext_builtin_functions(&self) -> u8 {
118         self.vmcontext_store_context() + self.size()
119     }
120 
121     /// The offset of the `array_call` field.
122     #[inline]
vm_func_ref_array_call(&self) -> u8123     fn vm_func_ref_array_call(&self) -> u8 {
124         0 * self.size()
125     }
126 
127     /// The offset of the `wasm_call` field.
128     #[inline]
vm_func_ref_wasm_call(&self) -> u8129     fn vm_func_ref_wasm_call(&self) -> u8 {
130         1 * self.size()
131     }
132 
133     /// The offset of the `type_index` field.
134     #[inline]
vm_func_ref_type_index(&self) -> u8135     fn vm_func_ref_type_index(&self) -> u8 {
136         2 * self.size()
137     }
138 
139     /// The offset of the `vmctx` field.
140     #[inline]
vm_func_ref_vmctx(&self) -> u8141     fn vm_func_ref_vmctx(&self) -> u8 {
142         3 * self.size()
143     }
144 
145     /// Return the size of `VMFuncRef`.
146     #[inline]
size_of_vm_func_ref(&self) -> u8147     fn size_of_vm_func_ref(&self) -> u8 {
148         4 * self.size()
149     }
150 
151     /// Return the size of `VMGlobalDefinition`; this is the size of the largest value type (i.e. a
152     /// V128).
153     #[inline]
size_of_vmglobal_definition(&self) -> u8154     fn size_of_vmglobal_definition(&self) -> u8 {
155         16
156     }
157 
158     /// Return the size of `VMTagDefinition`.
159     #[inline]
size_of_vmtag_definition(&self) -> u8160     fn size_of_vmtag_definition(&self) -> u8 {
161         4
162     }
163 
164     /// This is the size of the largest value type (i.e. a V128).
165     #[inline]
maximum_value_size(&self) -> u8166     fn maximum_value_size(&self) -> u8 {
167         self.size_of_vmglobal_definition()
168     }
169 
170     // Offsets within `VMStoreContext`
171 
172     /// Return the offset of the `fuel_consumed` field of `VMStoreContext`
173     #[inline]
vmstore_context_fuel_consumed(&self) -> u8174     fn vmstore_context_fuel_consumed(&self) -> u8 {
175         0
176     }
177 
178     /// Return the offset of the `epoch_deadline` field of `VMStoreContext`
179     #[inline]
vmstore_context_epoch_deadline(&self) -> u8180     fn vmstore_context_epoch_deadline(&self) -> u8 {
181         self.vmstore_context_fuel_consumed() + 8
182     }
183 
184     /// Return the offset of the `execution_version` field of
185     /// `VMStoreContext`
186     #[inline]
vmstore_context_execution_version(&self) -> u8187     fn vmstore_context_execution_version(&self) -> u8 {
188         self.vmstore_context_epoch_deadline() + 8
189     }
190 
191     /// Return the offset of the `stack_limit` field of `VMStoreContext`
192     #[inline]
vmstore_context_stack_limit(&self) -> u8193     fn vmstore_context_stack_limit(&self) -> u8 {
194         self.vmstore_context_execution_version() + 8
195     }
196 
197     /// Return the offset of the `gc_heap` field of `VMStoreContext`.
198     #[inline]
vmstore_context_gc_heap(&self) -> u8199     fn vmstore_context_gc_heap(&self) -> u8 {
200         self.vmstore_context_stack_limit() + self.size()
201     }
202 
203     /// Return the offset of the `gc_heap.base` field within a `VMStoreContext`.
vmstore_context_gc_heap_base(&self) -> u8204     fn vmstore_context_gc_heap_base(&self) -> u8 {
205         let offset = self.vmstore_context_gc_heap() + self.vmmemory_definition_base();
206         debug_assert!(offset < self.vmstore_context_last_wasm_exit_trampoline_fp());
207         offset
208     }
209 
210     /// Return the offset of the `gc_heap.current_length` field within a `VMStoreContext`.
vmstore_context_gc_heap_current_length(&self) -> u8211     fn vmstore_context_gc_heap_current_length(&self) -> u8 {
212         let offset = self.vmstore_context_gc_heap() + self.vmmemory_definition_current_length();
213         debug_assert!(offset < self.vmstore_context_last_wasm_exit_trampoline_fp());
214         offset
215     }
216 
217     /// Return the offset of the `last_wasm_exit_trampoline_fp` field
218     /// of `VMStoreContext`.
vmstore_context_last_wasm_exit_trampoline_fp(&self) -> u8219     fn vmstore_context_last_wasm_exit_trampoline_fp(&self) -> u8 {
220         self.vmstore_context_gc_heap() + self.size_of_vmmemory_definition()
221     }
222 
223     /// Return the offset of the `last_wasm_exit_pc` field of `VMStoreContext`.
vmstore_context_last_wasm_exit_pc(&self) -> u8224     fn vmstore_context_last_wasm_exit_pc(&self) -> u8 {
225         self.vmstore_context_last_wasm_exit_trampoline_fp() + self.size()
226     }
227 
228     /// Return the offset of the `last_wasm_entry_sp` field of `VMStoreContext`.
vmstore_context_last_wasm_entry_sp(&self) -> u8229     fn vmstore_context_last_wasm_entry_sp(&self) -> u8 {
230         self.vmstore_context_last_wasm_exit_pc() + self.size()
231     }
232 
233     /// Return the offset of the `last_wasm_entry_fp` field of `VMStoreContext`.
vmstore_context_last_wasm_entry_fp(&self) -> u8234     fn vmstore_context_last_wasm_entry_fp(&self) -> u8 {
235         self.vmstore_context_last_wasm_entry_sp() + self.size()
236     }
237 
238     /// Return the offset of the `last_wasm_entry_trap_handler` field of `VMStoreContext`.
vmstore_context_last_wasm_entry_trap_handler(&self) -> u8239     fn vmstore_context_last_wasm_entry_trap_handler(&self) -> u8 {
240         self.vmstore_context_last_wasm_entry_fp() + self.size()
241     }
242 
243     /// Return the offset of the `stack_chain` field of `VMStoreContext`.
vmstore_context_stack_chain(&self) -> u8244     fn vmstore_context_stack_chain(&self) -> u8 {
245         self.vmstore_context_last_wasm_entry_trap_handler() + self.size()
246     }
247 
248     /// Return the offset of the `stack_chain` field of `VMStoreContext`.
vmstore_context_store_data(&self) -> u8249     fn vmstore_context_store_data(&self) -> u8 {
250         self.vmstore_context_stack_chain() + self.size_of_vmstack_chain()
251     }
252 
253     // Offsets within `VMMemoryDefinition`
254 
255     /// The offset of the `base` field.
256     #[inline]
vmmemory_definition_base(&self) -> u8257     fn vmmemory_definition_base(&self) -> u8 {
258         0 * self.size()
259     }
260 
261     /// The offset of the `current_length` field.
262     #[inline]
vmmemory_definition_current_length(&self) -> u8263     fn vmmemory_definition_current_length(&self) -> u8 {
264         1 * self.size()
265     }
266 
267     /// Return the size of `VMMemoryDefinition`.
268     #[inline]
size_of_vmmemory_definition(&self) -> u8269     fn size_of_vmmemory_definition(&self) -> u8 {
270         2 * self.size()
271     }
272 
273     /// Return the size of `*mut VMMemoryDefinition`.
274     #[inline]
size_of_vmmemory_pointer(&self) -> u8275     fn size_of_vmmemory_pointer(&self) -> u8 {
276         self.size()
277     }
278 
279     // Offsets within `VMArrayCallHostFuncContext`.
280 
281     /// Return the offset of `VMArrayCallHostFuncContext::func_ref`.
vmarray_call_host_func_context_func_ref(&self) -> u8282     fn vmarray_call_host_func_context_func_ref(&self) -> u8 {
283         u8::try_from(align(
284             u32::try_from(core::mem::size_of::<u32>()).unwrap(),
285             u32::from(self.size()),
286         ))
287         .unwrap()
288     }
289 
290     /// Return the size of `VMStackChain`.
size_of_vmstack_chain(&self) -> u8291     fn size_of_vmstack_chain(&self) -> u8 {
292         2 * self.size()
293     }
294 
295     // Offsets within `VMStackLimits`
296 
297     /// Return the offset of `VMStackLimits::stack_limit`.
vmstack_limits_stack_limit(&self) -> u8298     fn vmstack_limits_stack_limit(&self) -> u8 {
299         0
300     }
301 
302     /// Return the offset of `VMStackLimits::last_wasm_entry_fp`.
vmstack_limits_last_wasm_entry_fp(&self) -> u8303     fn vmstack_limits_last_wasm_entry_fp(&self) -> u8 {
304         self.size()
305     }
306 
307     // Offsets within `VMHostArray`
308 
309     /// Return the offset of `VMHostArray::length`.
vmhostarray_length(&self) -> u8310     fn vmhostarray_length(&self) -> u8 {
311         0
312     }
313 
314     /// Return the offset of `VMHostArray::capacity`.
vmhostarray_capacity(&self) -> u8315     fn vmhostarray_capacity(&self) -> u8 {
316         4
317     }
318 
319     /// Return the offset of `VMHostArray::data`.
vmhostarray_data(&self) -> u8320     fn vmhostarray_data(&self) -> u8 {
321         8
322     }
323 
324     /// Return the size of `VMHostArray`.
size_of_vmhostarray(&self) -> u8325     fn size_of_vmhostarray(&self) -> u8 {
326         8 + self.size()
327     }
328 
329     // Offsets within `VMCommonStackInformation`
330 
331     /// Return the offset of `VMCommonStackInformation::limits`.
vmcommon_stack_information_limits(&self) -> u8332     fn vmcommon_stack_information_limits(&self) -> u8 {
333         0 * self.size()
334     }
335 
336     /// Return the offset of `VMCommonStackInformation::state`.
vmcommon_stack_information_state(&self) -> u8337     fn vmcommon_stack_information_state(&self) -> u8 {
338         2 * self.size()
339     }
340 
341     /// Return the offset of `VMCommonStackInformation::handlers`.
vmcommon_stack_information_handlers(&self) -> u8342     fn vmcommon_stack_information_handlers(&self) -> u8 {
343         u8::try_from(align(
344             self.vmcommon_stack_information_state() as u32 + 4,
345             u32::from(self.size()),
346         ))
347         .unwrap()
348     }
349 
350     /// Return the offset of `VMCommonStackInformation::first_switch_handler_index`.
vmcommon_stack_information_first_switch_handler_index(&self) -> u8351     fn vmcommon_stack_information_first_switch_handler_index(&self) -> u8 {
352         self.vmcommon_stack_information_handlers() + self.size_of_vmhostarray()
353     }
354 
355     /// Return the size of `VMCommonStackInformation`.
size_of_vmcommon_stack_information(&self) -> u8356     fn size_of_vmcommon_stack_information(&self) -> u8 {
357         u8::try_from(align(
358             self.vmcommon_stack_information_first_switch_handler_index() as u32 + 4,
359             u32::from(self.size()),
360         ))
361         .unwrap()
362     }
363 
364     // Offsets within `VMContObj`
365 
366     /// Return the offset of `VMContObj::contref`
vmcontobj_contref(&self) -> u8367     fn vmcontobj_contref(&self) -> u8 {
368         0
369     }
370 
371     /// Return the offset of `VMContObj::revision`
vmcontobj_revision(&self) -> u8372     fn vmcontobj_revision(&self) -> u8 {
373         self.size()
374     }
375 
376     /// Return the size of `VMContObj`.
size_of_vmcontobj(&self) -> u8377     fn size_of_vmcontobj(&self) -> u8 {
378         u8::try_from(align(
379             u32::from(self.vmcontobj_revision())
380                 + u32::try_from(core::mem::size_of::<usize>()).unwrap(),
381             u32::from(self.size()),
382         ))
383         .unwrap()
384     }
385 
386     // Offsets within `VMContRef`
387 
388     /// Return the offset of `VMContRef::common_stack_information`.
vmcontref_common_stack_information(&self) -> u8389     fn vmcontref_common_stack_information(&self) -> u8 {
390         0 * self.size()
391     }
392 
393     /// Return the offset of `VMContRef::parent_chain`.
vmcontref_parent_chain(&self) -> u8394     fn vmcontref_parent_chain(&self) -> u8 {
395         u8::try_from(align(
396             (self.vmcontref_common_stack_information() + self.size_of_vmcommon_stack_information())
397                 as u32,
398             u32::from(self.size()),
399         ))
400         .unwrap()
401     }
402 
403     /// Return the offset of `VMContRef::last_ancestor`.
vmcontref_last_ancestor(&self) -> u8404     fn vmcontref_last_ancestor(&self) -> u8 {
405         self.vmcontref_parent_chain() + 2 * self.size()
406     }
407 
408     /// Return the offset of `VMContRef::revision`.
vmcontref_revision(&self) -> u8409     fn vmcontref_revision(&self) -> u8 {
410         self.vmcontref_last_ancestor() + self.size()
411     }
412 
413     /// Return the offset of `VMContRef::stack`.
vmcontref_stack(&self) -> u8414     fn vmcontref_stack(&self) -> u8 {
415         self.vmcontref_revision() + self.size()
416     }
417 
418     /// Return the offset of `VMContRef::args`.
vmcontref_args(&self) -> u8419     fn vmcontref_args(&self) -> u8 {
420         self.vmcontref_stack() + 3 * self.size()
421     }
422 
423     /// Return the offset of `VMContRef::values`.
vmcontref_values(&self) -> u8424     fn vmcontref_values(&self) -> u8 {
425         self.vmcontref_args() + self.size_of_vmhostarray()
426     }
427 
428     /// Return the offset to the `magic` value in this `VMContext`.
429     #[inline]
vmctx_magic(&self) -> u8430     fn vmctx_magic(&self) -> u8 {
431         // This is required by the implementation of `VMContext::instance` and
432         // `VMContext::instance_mut`. If this value changes then those locations
433         // need to be updated.
434         0
435     }
436 
437     /// Return the offset to the `VMStoreContext` structure
438     #[inline]
vmctx_store_context(&self) -> u8439     fn vmctx_store_context(&self) -> u8 {
440         self.vmctx_magic() + self.size()
441     }
442 
443     /// Return the offset to the `VMBuiltinFunctionsArray` structure
444     #[inline]
vmctx_builtin_functions(&self) -> u8445     fn vmctx_builtin_functions(&self) -> u8 {
446         self.vmctx_store_context() + self.size()
447     }
448 
449     /// Return the offset to the `*const AtomicU64` epoch-counter
450     /// pointer.
451     #[inline]
vmctx_epoch_ptr(&self) -> u8452     fn vmctx_epoch_ptr(&self) -> u8 {
453         self.vmctx_builtin_functions() + self.size()
454     }
455 
456     /// Return the offset to the `*mut T` collector-specific data.
457     ///
458     /// This is a pointer that different collectors can use however they see
459     /// fit.
460     #[inline]
vmctx_gc_heap_data(&self) -> u8461     fn vmctx_gc_heap_data(&self) -> u8 {
462         self.vmctx_epoch_ptr() + self.size()
463     }
464 
465     /// The offset of the `type_ids` array pointer.
466     #[inline]
vmctx_type_ids_array(&self) -> u8467     fn vmctx_type_ids_array(&self) -> u8 {
468         self.vmctx_gc_heap_data() + self.size()
469     }
470 
471     /// The end of statically known offsets in `VMContext`.
472     ///
473     /// Data after this is dynamically sized.
474     #[inline]
vmctx_dynamic_data_start(&self) -> u8475     fn vmctx_dynamic_data_start(&self) -> u8 {
476         self.vmctx_type_ids_array() + self.size()
477     }
478 }
479 
480 /// Type representing the size of a pointer for the current compilation host
481 #[derive(Clone, Copy)]
482 pub struct HostPtr;
483 
484 impl PtrSize for HostPtr {
485     #[inline]
size(&self) -> u8486     fn size(&self) -> u8 {
487         core::mem::size_of::<usize>() as u8
488     }
489 }
490 
491 impl PtrSize for u8 {
492     #[inline]
size(&self) -> u8493     fn size(&self) -> u8 {
494         *self
495     }
496 }
497 
498 /// Used to construct a `VMOffsets`
499 #[derive(Debug, Clone, Copy)]
500 pub struct VMOffsetsFields<P> {
501     /// The size in bytes of a pointer on the target.
502     pub ptr: P,
503     /// The number of imported functions in the module.
504     pub num_imported_functions: u32,
505     /// The number of imported tables in the module.
506     pub num_imported_tables: u32,
507     /// The number of imported memories in the module.
508     pub num_imported_memories: u32,
509     /// The number of imported globals in the module.
510     pub num_imported_globals: u32,
511     /// The number of imported tags in the module.
512     pub num_imported_tags: u32,
513     /// The number of defined tables in the module.
514     pub num_defined_tables: u32,
515     /// The number of defined memories in the module.
516     pub num_defined_memories: u32,
517     /// The number of memories owned by the module instance.
518     pub num_owned_memories: u32,
519     /// The number of defined globals in the module.
520     pub num_defined_globals: u32,
521     /// The number of defined tags in the module.
522     pub num_defined_tags: u32,
523     /// The number of escaped functions in the module, the size of the function
524     /// references array.
525     pub num_escaped_funcs: u32,
526 }
527 
528 impl<P: PtrSize> VMOffsets<P> {
529     /// Return a new `VMOffsets` instance, for a given pointer size.
new(ptr: P, module: &Module) -> Self530     pub fn new(ptr: P, module: &Module) -> Self {
531         let num_owned_memories = module
532             .memories
533             .iter()
534             .skip(module.num_imported_memories)
535             .filter(|p| !p.1.shared)
536             .count()
537             .try_into()
538             .unwrap();
539         VMOffsets::from(VMOffsetsFields {
540             ptr,
541             num_imported_functions: cast_to_u32(module.num_imported_funcs),
542             num_imported_tables: cast_to_u32(module.num_imported_tables),
543             num_imported_memories: cast_to_u32(module.num_imported_memories),
544             num_imported_globals: cast_to_u32(module.num_imported_globals),
545             num_imported_tags: cast_to_u32(module.num_imported_tags),
546             num_defined_tables: cast_to_u32(module.num_defined_tables()),
547             num_defined_memories: cast_to_u32(module.num_defined_memories()),
548             num_owned_memories,
549             num_defined_globals: cast_to_u32(module.globals.len() - module.num_imported_globals),
550             num_defined_tags: cast_to_u32(module.tags.len() - module.num_imported_tags),
551             num_escaped_funcs: cast_to_u32(module.num_escaped_funcs),
552         })
553     }
554 
555     /// Returns the size, in bytes, of the target
556     #[inline]
pointer_size(&self) -> u8557     pub fn pointer_size(&self) -> u8 {
558         self.ptr.size()
559     }
560 
561     /// Returns an iterator which provides a human readable description and a
562     /// byte size. The iterator returned will iterate over the bytes allocated
563     /// to the entire `VMOffsets` structure to explain where each byte size is
564     /// coming from.
region_sizes(&self) -> impl Iterator<Item = (&str, u32)>565     pub fn region_sizes(&self) -> impl Iterator<Item = (&str, u32)> {
566         macro_rules! calculate_sizes {
567             ($($name:ident: $desc:tt,)*) => {{
568                 let VMOffsets {
569                     // These fields are metadata not talking about specific
570                     // offsets of specific fields.
571                     ptr: _,
572                     num_imported_functions: _,
573                     num_imported_tables: _,
574                     num_imported_memories: _,
575                     num_imported_globals: _,
576                     num_imported_tags: _,
577                     num_defined_tables: _,
578                     num_defined_globals: _,
579                     num_defined_memories: _,
580                     num_defined_tags: _,
581                     num_owned_memories: _,
582                     num_escaped_funcs: _,
583 
584                     // used as the initial size below
585                     size,
586 
587                     // exhaustively match the rest of the fields with input from
588                     // the macro
589                     $($name,)*
590                 } = *self;
591 
592                 // calculate the size of each field by relying on the inputs to
593                 // the macro being in reverse order and determining the size of
594                 // the field as the offset from the field to the last field.
595                 let mut last = size;
596                 $(
597                     assert!($name <= last);
598                     let tmp = $name;
599                     let $name = last - $name;
600                     last = tmp;
601                 )*
602                 assert_ne!(last, 0);
603                 IntoIterator::into_iter([
604                     $(($desc, $name),)*
605                     ("static vmctx data", last),
606                 ])
607             }};
608         }
609 
610         calculate_sizes! {
611             defined_func_refs: "module functions",
612             defined_tags: "defined tags",
613             defined_globals: "defined globals",
614             defined_tables: "defined tables",
615             imported_tags: "imported tags",
616             imported_globals: "imported globals",
617             imported_tables: "imported tables",
618             imported_functions: "imported functions",
619             owned_memories: "owned memories",
620             defined_memories: "defined memories",
621             imported_memories: "imported memories",
622         }
623     }
624 }
625 
626 impl<P: PtrSize> From<VMOffsetsFields<P>> for VMOffsets<P> {
from(fields: VMOffsetsFields<P>) -> VMOffsets<P>627     fn from(fields: VMOffsetsFields<P>) -> VMOffsets<P> {
628         let mut ret = Self {
629             ptr: fields.ptr,
630             num_imported_functions: fields.num_imported_functions,
631             num_imported_tables: fields.num_imported_tables,
632             num_imported_memories: fields.num_imported_memories,
633             num_imported_globals: fields.num_imported_globals,
634             num_imported_tags: fields.num_imported_tags,
635             num_defined_tables: fields.num_defined_tables,
636             num_defined_memories: fields.num_defined_memories,
637             num_owned_memories: fields.num_owned_memories,
638             num_defined_globals: fields.num_defined_globals,
639             num_defined_tags: fields.num_defined_tags,
640             num_escaped_funcs: fields.num_escaped_funcs,
641             imported_functions: 0,
642             imported_tables: 0,
643             imported_memories: 0,
644             imported_globals: 0,
645             imported_tags: 0,
646             defined_tables: 0,
647             defined_memories: 0,
648             owned_memories: 0,
649             defined_globals: 0,
650             defined_tags: 0,
651             defined_func_refs: 0,
652             size: 0,
653         };
654 
655         // Convenience functions for checked addition and multiplication.
656         // As side effect this reduces binary size by using only a single
657         // `#[track_caller]` location for each function instead of one for
658         // each individual invocation.
659         #[inline]
660         fn cadd(count: u32, size: u32) -> u32 {
661             count.checked_add(size).unwrap()
662         }
663 
664         #[inline]
665         fn cmul(count: u32, size: u8) -> u32 {
666             count.checked_mul(u32::from(size)).unwrap()
667         }
668 
669         let mut next_field_offset = u32::from(ret.ptr.vmctx_dynamic_data_start());
670 
671         macro_rules! fields {
672             (size($field:ident) = $size:expr, $($rest:tt)*) => {
673                 ret.$field = next_field_offset;
674                 next_field_offset = cadd(next_field_offset, u32::from($size));
675                 fields!($($rest)*);
676             };
677             (align($align:expr), $($rest:tt)*) => {
678                 next_field_offset = align(next_field_offset, $align);
679                 fields!($($rest)*);
680             };
681             () => {};
682         }
683 
684         fields! {
685             size(imported_memories)
686                 = cmul(ret.num_imported_memories, ret.size_of_vmmemory_import()),
687             size(defined_memories)
688                 = cmul(ret.num_defined_memories, ret.ptr.size_of_vmmemory_pointer()),
689             size(owned_memories)
690                 = cmul(ret.num_owned_memories, ret.ptr.size_of_vmmemory_definition()),
691             size(imported_functions)
692                 = cmul(ret.num_imported_functions, ret.size_of_vmfunction_import()),
693             size(imported_tables)
694                 = cmul(ret.num_imported_tables, ret.size_of_vmtable_import()),
695             size(imported_globals)
696                 = cmul(ret.num_imported_globals, ret.size_of_vmglobal_import()),
697             size(imported_tags)
698                 = cmul(ret.num_imported_tags, ret.size_of_vmtag_import()),
699             size(defined_tables)
700                 = cmul(ret.num_defined_tables, ret.size_of_vmtable_definition()),
701             align(16),
702             size(defined_globals)
703                 = cmul(ret.num_defined_globals, ret.ptr.size_of_vmglobal_definition()),
704             size(defined_tags)
705                 = cmul(ret.num_defined_tags, ret.ptr.size_of_vmtag_definition()),
706             size(defined_func_refs) = cmul(
707                 ret.num_escaped_funcs,
708                 ret.ptr.size_of_vm_func_ref(),
709             ),
710         }
711 
712         ret.size = next_field_offset;
713 
714         return ret;
715     }
716 }
717 
718 impl<P: PtrSize> VMOffsets<P> {
719     /// The offset of the `wasm_call` field.
720     #[inline]
vmfunction_import_wasm_call(&self) -> u8721     pub fn vmfunction_import_wasm_call(&self) -> u8 {
722         0 * self.pointer_size()
723     }
724 
725     /// The offset of the `array_call` field.
726     #[inline]
vmfunction_import_array_call(&self) -> u8727     pub fn vmfunction_import_array_call(&self) -> u8 {
728         1 * self.pointer_size()
729     }
730 
731     /// The offset of the `vmctx` field.
732     #[inline]
vmfunction_import_vmctx(&self) -> u8733     pub fn vmfunction_import_vmctx(&self) -> u8 {
734         2 * self.pointer_size()
735     }
736 
737     /// Return the size of `VMFunctionImport`.
738     #[inline]
size_of_vmfunction_import(&self) -> u8739     pub fn size_of_vmfunction_import(&self) -> u8 {
740         3 * self.pointer_size()
741     }
742 }
743 
744 /// Offsets for `*const VMFunctionBody`.
745 impl<P: PtrSize> VMOffsets<P> {
746     /// The size of the `current_elements` field.
size_of_vmfunction_body_ptr(&self) -> u8747     pub fn size_of_vmfunction_body_ptr(&self) -> u8 {
748         1 * self.pointer_size()
749     }
750 }
751 
752 /// Offsets for `VMTableImport`.
753 impl<P: PtrSize> VMOffsets<P> {
754     /// The offset of the `from` field.
755     #[inline]
vmtable_import_from(&self) -> u8756     pub fn vmtable_import_from(&self) -> u8 {
757         0 * self.pointer_size()
758     }
759 
760     /// The offset of the `vmctx` field.
761     #[inline]
vmtable_import_vmctx(&self) -> u8762     pub fn vmtable_import_vmctx(&self) -> u8 {
763         1 * self.pointer_size()
764     }
765 
766     /// The offset of the `index` field.
767     #[inline]
vmtable_import_index(&self) -> u8768     pub fn vmtable_import_index(&self) -> u8 {
769         2 * self.pointer_size()
770     }
771 
772     /// Return the size of `VMTableImport`.
773     #[inline]
size_of_vmtable_import(&self) -> u8774     pub fn size_of_vmtable_import(&self) -> u8 {
775         3 * self.pointer_size()
776     }
777 }
778 
779 /// Offsets for `VMTableDefinition`.
780 impl<P: PtrSize> VMOffsets<P> {
781     /// The offset of the `base` field.
782     #[inline]
vmtable_definition_base(&self) -> u8783     pub fn vmtable_definition_base(&self) -> u8 {
784         0 * self.pointer_size()
785     }
786 
787     /// The offset of the `current_elements` field.
vmtable_definition_current_elements(&self) -> u8788     pub fn vmtable_definition_current_elements(&self) -> u8 {
789         1 * self.pointer_size()
790     }
791 
792     /// The size of the `current_elements` field.
793     #[inline]
size_of_vmtable_definition_current_elements(&self) -> u8794     pub fn size_of_vmtable_definition_current_elements(&self) -> u8 {
795         self.pointer_size()
796     }
797 
798     /// Return the size of `VMTableDefinition`.
799     #[inline]
size_of_vmtable_definition(&self) -> u8800     pub fn size_of_vmtable_definition(&self) -> u8 {
801         2 * self.pointer_size()
802     }
803 }
804 
805 /// Offsets for `VMMemoryImport`.
806 impl<P: PtrSize> VMOffsets<P> {
807     /// The offset of the `from` field.
808     #[inline]
vmmemory_import_from(&self) -> u8809     pub fn vmmemory_import_from(&self) -> u8 {
810         0 * self.pointer_size()
811     }
812 
813     /// The offset of the `vmctx` field.
814     #[inline]
vmmemory_import_vmctx(&self) -> u8815     pub fn vmmemory_import_vmctx(&self) -> u8 {
816         1 * self.pointer_size()
817     }
818 
819     /// The offset of the `index` field.
820     #[inline]
vmmemory_import_index(&self) -> u8821     pub fn vmmemory_import_index(&self) -> u8 {
822         2 * self.pointer_size()
823     }
824 
825     /// Return the size of `VMMemoryImport`.
826     #[inline]
size_of_vmmemory_import(&self) -> u8827     pub fn size_of_vmmemory_import(&self) -> u8 {
828         3 * self.pointer_size()
829     }
830 }
831 
832 /// Offsets for `VMGlobalImport`.
833 impl<P: PtrSize> VMOffsets<P> {
834     /// The offset of the `from` field.
835     #[inline]
vmglobal_import_from(&self) -> u8836     pub fn vmglobal_import_from(&self) -> u8 {
837         0 * self.pointer_size()
838     }
839 
840     /// Return the size of `VMGlobalImport`.
841     #[inline]
size_of_vmglobal_import(&self) -> u8842     pub fn size_of_vmglobal_import(&self) -> u8 {
843         // `VMGlobalImport` has two pointers plus 8 bytes for `VMGlobalKind`
844         2 * self.pointer_size() + 8
845     }
846 }
847 
848 /// Offsets for `VMSharedTypeIndex`.
849 impl<P: PtrSize> VMOffsets<P> {
850     /// Return the size of `VMSharedTypeIndex`.
851     #[inline]
size_of_vmshared_type_index(&self) -> u8852     pub fn size_of_vmshared_type_index(&self) -> u8 {
853         4
854     }
855 }
856 
857 /// Offsets for `VMTagImport`.
858 impl<P: PtrSize> VMOffsets<P> {
859     /// The offset of the `from` field.
860     #[inline]
vmtag_import_from(&self) -> u8861     pub fn vmtag_import_from(&self) -> u8 {
862         0 * self.pointer_size()
863     }
864 
865     /// The offset of the `vmctx` field.
866     #[inline]
vmtag_import_vmctx(&self) -> u8867     pub fn vmtag_import_vmctx(&self) -> u8 {
868         1 * self.pointer_size()
869     }
870 
871     /// The offset of the `index` field.
872     #[inline]
vmtag_import_index(&self) -> u8873     pub fn vmtag_import_index(&self) -> u8 {
874         2 * self.pointer_size()
875     }
876 
877     /// Return the size of `VMTagImport`.
878     #[inline]
size_of_vmtag_import(&self) -> u8879     pub fn size_of_vmtag_import(&self) -> u8 {
880         3 * self.pointer_size()
881     }
882 }
883 
884 /// Offsets for `VMContext`.
885 impl<P: PtrSize> VMOffsets<P> {
886     /// The offset of the `tables` array.
887     #[inline]
vmctx_imported_functions_begin(&self) -> u32888     pub fn vmctx_imported_functions_begin(&self) -> u32 {
889         self.imported_functions
890     }
891 
892     /// The offset of the `tables` array.
893     #[inline]
vmctx_imported_tables_begin(&self) -> u32894     pub fn vmctx_imported_tables_begin(&self) -> u32 {
895         self.imported_tables
896     }
897 
898     /// The offset of the `memories` array.
899     #[inline]
vmctx_imported_memories_begin(&self) -> u32900     pub fn vmctx_imported_memories_begin(&self) -> u32 {
901         self.imported_memories
902     }
903 
904     /// The offset of the `globals` array.
905     #[inline]
vmctx_imported_globals_begin(&self) -> u32906     pub fn vmctx_imported_globals_begin(&self) -> u32 {
907         self.imported_globals
908     }
909 
910     /// The offset of the `tags` array.
911     #[inline]
vmctx_imported_tags_begin(&self) -> u32912     pub fn vmctx_imported_tags_begin(&self) -> u32 {
913         self.imported_tags
914     }
915 
916     /// The offset of the `tables` array.
917     #[inline]
vmctx_tables_begin(&self) -> u32918     pub fn vmctx_tables_begin(&self) -> u32 {
919         self.defined_tables
920     }
921 
922     /// The offset of the `memories` array.
923     #[inline]
vmctx_memories_begin(&self) -> u32924     pub fn vmctx_memories_begin(&self) -> u32 {
925         self.defined_memories
926     }
927 
928     /// The offset of the `owned_memories` array.
929     #[inline]
vmctx_owned_memories_begin(&self) -> u32930     pub fn vmctx_owned_memories_begin(&self) -> u32 {
931         self.owned_memories
932     }
933 
934     /// The offset of the `globals` array.
935     #[inline]
vmctx_globals_begin(&self) -> u32936     pub fn vmctx_globals_begin(&self) -> u32 {
937         self.defined_globals
938     }
939 
940     /// The offset of the `tags` array.
941     #[inline]
vmctx_tags_begin(&self) -> u32942     pub fn vmctx_tags_begin(&self) -> u32 {
943         self.defined_tags
944     }
945 
946     /// The offset of the `func_refs` array.
947     #[inline]
vmctx_func_refs_begin(&self) -> u32948     pub fn vmctx_func_refs_begin(&self) -> u32 {
949         self.defined_func_refs
950     }
951 
952     /// Return the size of the `VMContext` allocation.
953     #[inline]
size_of_vmctx(&self) -> u32954     pub fn size_of_vmctx(&self) -> u32 {
955         self.size
956     }
957 
958     /// Return the offset to `VMFunctionImport` index `index`.
959     #[inline]
vmctx_vmfunction_import(&self, index: FuncIndex) -> u32960     pub fn vmctx_vmfunction_import(&self, index: FuncIndex) -> u32 {
961         assert!(index.as_u32() < self.num_imported_functions);
962         self.vmctx_imported_functions_begin()
963             + index.as_u32() * u32::from(self.size_of_vmfunction_import())
964     }
965 
966     /// Return the offset to `VMTable` index `index`.
967     #[inline]
vmctx_vmtable_import(&self, index: TableIndex) -> u32968     pub fn vmctx_vmtable_import(&self, index: TableIndex) -> u32 {
969         assert!(index.as_u32() < self.num_imported_tables);
970         self.vmctx_imported_tables_begin()
971             + index.as_u32() * u32::from(self.size_of_vmtable_import())
972     }
973 
974     /// Return the offset to `VMMemoryImport` index `index`.
975     #[inline]
vmctx_vmmemory_import(&self, index: MemoryIndex) -> u32976     pub fn vmctx_vmmemory_import(&self, index: MemoryIndex) -> u32 {
977         assert!(index.as_u32() < self.num_imported_memories);
978         self.vmctx_imported_memories_begin()
979             + index.as_u32() * u32::from(self.size_of_vmmemory_import())
980     }
981 
982     /// Return the offset to `VMGlobalImport` index `index`.
983     #[inline]
vmctx_vmglobal_import(&self, index: GlobalIndex) -> u32984     pub fn vmctx_vmglobal_import(&self, index: GlobalIndex) -> u32 {
985         assert!(index.as_u32() < self.num_imported_globals);
986         self.vmctx_imported_globals_begin()
987             + index.as_u32() * u32::from(self.size_of_vmglobal_import())
988     }
989 
990     /// Return the offset to `VMTagImport` index `index`.
991     #[inline]
vmctx_vmtag_import(&self, index: TagIndex) -> u32992     pub fn vmctx_vmtag_import(&self, index: TagIndex) -> u32 {
993         assert!(index.as_u32() < self.num_imported_tags);
994         self.vmctx_imported_tags_begin() + index.as_u32() * u32::from(self.size_of_vmtag_import())
995     }
996 
997     /// Return the offset to `VMTableDefinition` index `index`.
998     #[inline]
vmctx_vmtable_definition(&self, index: DefinedTableIndex) -> u32999     pub fn vmctx_vmtable_definition(&self, index: DefinedTableIndex) -> u32 {
1000         assert!(index.as_u32() < self.num_defined_tables);
1001         self.vmctx_tables_begin() + index.as_u32() * u32::from(self.size_of_vmtable_definition())
1002     }
1003 
1004     /// Return the offset to the `*mut VMMemoryDefinition` at index `index`.
1005     #[inline]
vmctx_vmmemory_pointer(&self, index: DefinedMemoryIndex) -> u321006     pub fn vmctx_vmmemory_pointer(&self, index: DefinedMemoryIndex) -> u32 {
1007         assert!(index.as_u32() < self.num_defined_memories);
1008         self.vmctx_memories_begin()
1009             + index.as_u32() * u32::from(self.ptr.size_of_vmmemory_pointer())
1010     }
1011 
1012     /// Return the offset to the owned `VMMemoryDefinition` at index `index`.
1013     #[inline]
vmctx_vmmemory_definition(&self, index: OwnedMemoryIndex) -> u321014     pub fn vmctx_vmmemory_definition(&self, index: OwnedMemoryIndex) -> u32 {
1015         assert!(index.as_u32() < self.num_owned_memories);
1016         self.vmctx_owned_memories_begin()
1017             + index.as_u32() * u32::from(self.ptr.size_of_vmmemory_definition())
1018     }
1019 
1020     /// Return the offset to the `VMGlobalDefinition` index `index`.
1021     #[inline]
vmctx_vmglobal_definition(&self, index: DefinedGlobalIndex) -> u321022     pub fn vmctx_vmglobal_definition(&self, index: DefinedGlobalIndex) -> u32 {
1023         assert!(index.as_u32() < self.num_defined_globals);
1024         self.vmctx_globals_begin()
1025             + index.as_u32() * u32::from(self.ptr.size_of_vmglobal_definition())
1026     }
1027 
1028     /// Return the offset to the `VMTagDefinition` index `index`.
1029     #[inline]
vmctx_vmtag_definition(&self, index: DefinedTagIndex) -> u321030     pub fn vmctx_vmtag_definition(&self, index: DefinedTagIndex) -> u32 {
1031         assert!(index.as_u32() < self.num_defined_tags);
1032         self.vmctx_tags_begin() + index.as_u32() * u32::from(self.ptr.size_of_vmtag_definition())
1033     }
1034 
1035     /// Return the offset to the `VMFuncRef` for the given function
1036     /// index (either imported or defined).
1037     #[inline]
vmctx_func_ref(&self, index: FuncRefIndex) -> u321038     pub fn vmctx_func_ref(&self, index: FuncRefIndex) -> u32 {
1039         assert!(!index.is_reserved_value());
1040         assert!(index.as_u32() < self.num_escaped_funcs);
1041         self.vmctx_func_refs_begin() + index.as_u32() * u32::from(self.ptr.size_of_vm_func_ref())
1042     }
1043 
1044     /// Return the offset to the `wasm_call` field in `*const VMFunctionBody` index `index`.
1045     #[inline]
vmctx_vmfunction_import_wasm_call(&self, index: FuncIndex) -> u321046     pub fn vmctx_vmfunction_import_wasm_call(&self, index: FuncIndex) -> u32 {
1047         self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_wasm_call())
1048     }
1049 
1050     /// Return the offset to the `array_call` field in `*const VMFunctionBody` index `index`.
1051     #[inline]
vmctx_vmfunction_import_array_call(&self, index: FuncIndex) -> u321052     pub fn vmctx_vmfunction_import_array_call(&self, index: FuncIndex) -> u32 {
1053         self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_array_call())
1054     }
1055 
1056     /// Return the offset to the `vmctx` field in `*const VMFunctionBody` index `index`.
1057     #[inline]
vmctx_vmfunction_import_vmctx(&self, index: FuncIndex) -> u321058     pub fn vmctx_vmfunction_import_vmctx(&self, index: FuncIndex) -> u32 {
1059         self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_vmctx())
1060     }
1061 
1062     /// Return the offset to the `from` field in the imported `VMTable` at index
1063     /// `index`.
1064     #[inline]
vmctx_vmtable_from(&self, index: TableIndex) -> u321065     pub fn vmctx_vmtable_from(&self, index: TableIndex) -> u32 {
1066         self.vmctx_vmtable_import(index) + u32::from(self.vmtable_import_from())
1067     }
1068 
1069     /// Return the offset to the `base` field in `VMTableDefinition` index `index`.
1070     #[inline]
vmctx_vmtable_definition_base(&self, index: DefinedTableIndex) -> u321071     pub fn vmctx_vmtable_definition_base(&self, index: DefinedTableIndex) -> u32 {
1072         self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_base())
1073     }
1074 
1075     /// Return the offset to the `current_elements` field in `VMTableDefinition` index `index`.
1076     #[inline]
vmctx_vmtable_definition_current_elements(&self, index: DefinedTableIndex) -> u321077     pub fn vmctx_vmtable_definition_current_elements(&self, index: DefinedTableIndex) -> u32 {
1078         self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_current_elements())
1079     }
1080 
1081     /// Return the offset to the `from` field in `VMMemoryImport` index `index`.
1082     #[inline]
vmctx_vmmemory_import_from(&self, index: MemoryIndex) -> u321083     pub fn vmctx_vmmemory_import_from(&self, index: MemoryIndex) -> u32 {
1084         self.vmctx_vmmemory_import(index) + u32::from(self.vmmemory_import_from())
1085     }
1086 
1087     /// Return the offset to the `base` field in `VMMemoryDefinition` index `index`.
1088     #[inline]
vmctx_vmmemory_definition_base(&self, index: OwnedMemoryIndex) -> u321089     pub fn vmctx_vmmemory_definition_base(&self, index: OwnedMemoryIndex) -> u32 {
1090         self.vmctx_vmmemory_definition(index) + u32::from(self.ptr.vmmemory_definition_base())
1091     }
1092 
1093     /// Return the offset to the `current_length` field in `VMMemoryDefinition` index `index`.
1094     #[inline]
vmctx_vmmemory_definition_current_length(&self, index: OwnedMemoryIndex) -> u321095     pub fn vmctx_vmmemory_definition_current_length(&self, index: OwnedMemoryIndex) -> u32 {
1096         self.vmctx_vmmemory_definition(index)
1097             + u32::from(self.ptr.vmmemory_definition_current_length())
1098     }
1099 
1100     /// Return the offset to the `from` field in `VMGlobalImport` index `index`.
1101     #[inline]
vmctx_vmglobal_import_from(&self, index: GlobalIndex) -> u321102     pub fn vmctx_vmglobal_import_from(&self, index: GlobalIndex) -> u32 {
1103         self.vmctx_vmglobal_import(index) + u32::from(self.vmglobal_import_from())
1104     }
1105 
1106     /// Return the offset to the `from` field in `VMTagImport` index `index`.
1107     #[inline]
vmctx_vmtag_import_from(&self, index: TagIndex) -> u321108     pub fn vmctx_vmtag_import_from(&self, index: TagIndex) -> u32 {
1109         self.vmctx_vmtag_import(index) + u32::from(self.vmtag_import_from())
1110     }
1111 
1112     /// Return the offset to the `vmctx` field in `VMTagImport` index `index`.
1113     #[inline]
vmctx_vmtag_import_vmctx(&self, index: TagIndex) -> u321114     pub fn vmctx_vmtag_import_vmctx(&self, index: TagIndex) -> u32 {
1115         self.vmctx_vmtag_import(index) + u32::from(self.vmtag_import_vmctx())
1116     }
1117 
1118     /// Return the offset to the `index` field in `VMTagImport` index `index`.
1119     #[inline]
vmctx_vmtag_import_index(&self, index: TagIndex) -> u321120     pub fn vmctx_vmtag_import_index(&self, index: TagIndex) -> u32 {
1121         self.vmctx_vmtag_import(index) + u32::from(self.vmtag_import_index())
1122     }
1123 }
1124 
1125 /// Offsets for `VMGcHeader`.
1126 impl<P: PtrSize> VMOffsets<P> {
1127     /// Return the offset for the `VMGcHeader::kind` field.
1128     #[inline]
vm_gc_header_kind(&self) -> u321129     pub fn vm_gc_header_kind(&self) -> u32 {
1130         0
1131     }
1132 
1133     /// Return the offset for the `VMGcHeader`'s reserved bits.
1134     #[inline]
vm_gc_header_reserved_bits(&self) -> u321135     pub fn vm_gc_header_reserved_bits(&self) -> u32 {
1136         // NB: The reserved bits are the unused `VMGcKind` bits.
1137         self.vm_gc_header_kind()
1138     }
1139 
1140     /// Return the offset for the `VMGcHeader::ty` field.
1141     #[inline]
vm_gc_header_ty(&self) -> u321142     pub fn vm_gc_header_ty(&self) -> u32 {
1143         self.vm_gc_header_kind() + 4
1144     }
1145 }
1146 
1147 /// Offsets for `VMDrcHeader`.
1148 ///
1149 /// Should only be used when the DRC collector is enabled.
1150 impl<P: PtrSize> VMOffsets<P> {
1151     /// Return the offset for `VMDrcHeader::ref_count`.
1152     #[inline]
vm_drc_header_ref_count(&self) -> u321153     pub fn vm_drc_header_ref_count(&self) -> u32 {
1154         8
1155     }
1156 
1157     /// Return the offset for `VMDrcHeader::next_over_approximated_stack_root`.
1158     #[inline]
vm_drc_header_next_over_approximated_stack_root(&self) -> u321159     pub fn vm_drc_header_next_over_approximated_stack_root(&self) -> u32 {
1160         self.vm_drc_header_ref_count() + 8
1161     }
1162 }
1163 
1164 /// Magic value for core Wasm VM contexts.
1165 ///
1166 /// This is stored at the start of all `VMContext` structures.
1167 pub const VMCONTEXT_MAGIC: u32 = u32::from_le_bytes(*b"core");
1168 
1169 /// Equivalent of `VMCONTEXT_MAGIC` except for array-call host functions.
1170 ///
1171 /// This is stored at the start of all `VMArrayCallHostFuncContext` structures
1172 /// and double-checked on `VMArrayCallHostFuncContext::from_opaque`.
1173 pub const VM_ARRAY_CALL_HOST_FUNC_MAGIC: u32 = u32::from_le_bytes(*b"ACHF");
1174 
1175 #[cfg(test)]
1176 mod tests {
1177     use crate::vmoffsets::align;
1178 
1179     #[test]
alignment()1180     fn alignment() {
1181         fn is_aligned(x: u32) -> bool {
1182             x % 16 == 0
1183         }
1184         assert!(is_aligned(align(0, 16)));
1185         assert!(is_aligned(align(32, 16)));
1186         assert!(is_aligned(align(33, 16)));
1187         assert!(is_aligned(align(31, 16)));
1188     }
1189 }
1190