near_vm_vm/
vmoffsets.rs

1// This file contains code from external sources.
2// Attributions: https://github.com/wasmerio/wasmer/blob/2.3.0/ATTRIBUTIONS.md
3
4//! Offsets and sizes of various structs in near_vm-vm's vmcontext
5//! module.
6
7#![deny(rustdoc::broken_intra_doc_links)]
8
9use crate::VMBuiltinFunctionIndex;
10use more_asserts::assert_lt;
11use near_vm_types::{
12    FunctionIndex, GlobalIndex, LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryIndex,
13    ModuleInfo, SignatureIndex, TableIndex,
14};
15use std::convert::TryFrom;
16
17#[cfg(target_pointer_width = "32")]
18fn cast_to_u32(sz: usize) -> u32 {
19    u32::try_from(sz).unwrap()
20}
21#[cfg(target_pointer_width = "64")]
22fn cast_to_u32(sz: usize) -> u32 {
23    u32::try_from(sz).expect("overflow in cast from usize to u32")
24}
25
26/// Align an offset used in this module to a specific byte-width by rounding up
27#[inline]
28const fn align(offset: u32, width: u32) -> u32 {
29    (offset + (width - 1)) / width * width
30}
31
32/// This class computes offsets to fields within [`VMContext`] and other
33/// related structs that JIT code accesses directly.
34///
35/// [`VMContext`]: crate::vmcontext::VMContext
36// Invariant: the addresses always fit into an u32 without overflowing
37#[derive(Clone, Debug)]
38pub struct VMOffsets {
39    /// The size in bytes of a pointer on the target.
40    pointer_size: u8,
41    /// The number of signature declarations in the module.
42    num_signature_ids: u32,
43    /// The number of imported functions in the module.
44    num_imported_functions: u32,
45    /// The number of imported tables in the module.
46    num_imported_tables: u32,
47    /// The number of imported memories in the module.
48    num_imported_memories: u32,
49    /// The number of imported globals in the module.
50    num_imported_globals: u32,
51    /// The number of defined tables in the module.
52    num_local_tables: u32,
53    /// The number of defined memories in the module.
54    num_local_memories: u32,
55    /// The number of defined globals in the module.
56    num_local_globals: u32,
57    /// If the module has trap handler.
58    has_trap_handlers: bool,
59
60    vmctx_signature_ids_begin: u32,
61    vmctx_imported_functions_begin: u32,
62    vmctx_imported_tables_begin: u32,
63    vmctx_imported_memories_begin: u32,
64    vmctx_imported_globals_begin: u32,
65    vmctx_tables_begin: u32,
66    vmctx_memories_begin: u32,
67    vmctx_globals_begin: u32,
68    vmctx_builtin_functions_begin: u32,
69    vmctx_trap_handler_begin: u32,
70    vmctx_gas_limiter_pointer: u32,
71    vmctx_stack_limit_begin: u32,
72    vmctx_stack_limit_initial_begin: u32,
73    size_of_vmctx: u32,
74}
75
76impl VMOffsets {
77    /// Return a new `VMOffsets` instance, for a given pointer size.
78    ///
79    /// The returned `VMOffsets` has no entities. Add entities with other builder methods for this
80    /// type.
81    pub fn new(pointer_size: u8) -> Self {
82        Self {
83            pointer_size,
84            num_signature_ids: 0,
85            num_imported_functions: 0,
86            num_imported_tables: 0,
87            num_imported_memories: 0,
88            num_imported_globals: 0,
89            num_local_tables: 0,
90            num_local_memories: 0,
91            num_local_globals: 0,
92            has_trap_handlers: false,
93            vmctx_signature_ids_begin: 0,
94            vmctx_imported_functions_begin: 0,
95            vmctx_imported_tables_begin: 0,
96            vmctx_imported_memories_begin: 0,
97            vmctx_imported_globals_begin: 0,
98            vmctx_tables_begin: 0,
99            vmctx_memories_begin: 0,
100            vmctx_globals_begin: 0,
101            vmctx_builtin_functions_begin: 0,
102            vmctx_trap_handler_begin: 0,
103            vmctx_gas_limiter_pointer: 0,
104            vmctx_stack_limit_begin: 0,
105            vmctx_stack_limit_initial_begin: 0,
106            size_of_vmctx: 0,
107        }
108    }
109
110    /// Return a new `VMOffsets` instance, for a host's pointer size.
111    ///
112    /// The returned `VMOffsets` has no entities. Add entities with other builder methods for this
113    /// type.
114    pub fn for_host() -> Self {
115        Self::new(std::mem::size_of::<*const u8>() as u8)
116    }
117
118    /// Add imports and locals from the provided ModuleInfo.
119    #[tracing::instrument(target = "near_vm", level = "trace", skip_all)]
120    pub fn with_module_info(mut self, module: &ModuleInfo) -> Self {
121        self.num_imported_functions = module.import_counts.functions;
122        self.num_imported_tables = module.import_counts.tables;
123        self.num_imported_memories = module.import_counts.memories;
124        self.num_imported_globals = module.import_counts.globals;
125        self.num_signature_ids = cast_to_u32(module.signatures.len());
126        // FIXME = these should most likely be subtracting the corresponding imports!!?
127        self.num_local_tables = cast_to_u32(module.tables.len());
128        self.num_local_memories = cast_to_u32(module.memories.len());
129        self.num_local_globals = cast_to_u32(module.globals.len());
130        self.has_trap_handlers = true;
131        self.precompute();
132        self
133    }
134
135    /// Add imports and locals from the provided ModuleInfo.
136    pub fn with_archived_module_info(mut self, module: &rkyv::Archived<ModuleInfo>) -> Self {
137        self.num_imported_functions = module.import_counts.functions.into();
138        self.num_imported_tables = module.import_counts.tables.into();
139        self.num_imported_memories = module.import_counts.memories.into();
140        self.num_imported_globals = module.import_counts.globals.into();
141        self.num_signature_ids = cast_to_u32(module.signatures.len());
142        // FIXME = these should most likely be subtracting the corresponding imports!!?
143        self.num_local_tables = cast_to_u32(module.tables.len());
144        self.num_local_memories = cast_to_u32(module.memories.len());
145        self.num_local_globals = cast_to_u32(module.globals.len());
146        self.has_trap_handlers = true;
147        self.precompute();
148        self
149    }
150
151    /// Number of local tables defined in the module
152    pub fn num_local_tables(&self) -> u32 {
153        self.num_local_tables
154    }
155
156    /// Number of local memories defined in the module
157    pub fn num_local_memories(&self) -> u32 {
158        self.num_local_memories
159    }
160
161    fn precompute(&mut self) {
162        use std::mem::align_of;
163
164        /// Offset base by num_items items of size item_size, panicking on overflow
165        fn offset_by(
166            base: u32,
167            num_items: u32,
168            prev_item_size: u32,
169            next_item_align: usize,
170        ) -> u32 {
171            align(
172                base.checked_add(num_items.checked_mul(prev_item_size).unwrap()).unwrap(),
173                next_item_align as u32,
174            )
175        }
176
177        self.vmctx_signature_ids_begin = 0;
178        self.vmctx_imported_functions_begin = offset_by(
179            self.vmctx_signature_ids_begin,
180            self.num_signature_ids,
181            u32::from(self.size_of_vmshared_signature_index()),
182            align_of::<crate::VMFunctionImport>(),
183        );
184        self.vmctx_imported_tables_begin = offset_by(
185            self.vmctx_imported_functions_begin,
186            self.num_imported_functions,
187            u32::from(self.size_of_vmfunction_import()),
188            align_of::<crate::VMTableImport>(),
189        );
190        self.vmctx_imported_memories_begin = offset_by(
191            self.vmctx_imported_tables_begin,
192            self.num_imported_tables,
193            u32::from(self.size_of_vmtable_import()),
194            align_of::<crate::VMMemoryImport>(),
195        );
196        self.vmctx_imported_globals_begin = offset_by(
197            self.vmctx_imported_memories_begin,
198            self.num_imported_memories,
199            u32::from(self.size_of_vmmemory_import()),
200            align_of::<crate::VMGlobalImport>(),
201        );
202        self.vmctx_tables_begin = offset_by(
203            self.vmctx_imported_globals_begin,
204            self.num_imported_globals,
205            u32::from(self.size_of_vmglobal_import()),
206            align_of::<crate::VMTableImport>(),
207        );
208        self.vmctx_memories_begin = offset_by(
209            self.vmctx_tables_begin,
210            self.num_local_tables,
211            u32::from(self.size_of_vmtable_definition()),
212            align_of::<crate::VMMemoryDefinition>(),
213        );
214        self.vmctx_globals_begin = offset_by(
215            self.vmctx_memories_begin,
216            self.num_local_memories,
217            u32::from(self.size_of_vmmemory_definition()),
218            align_of::<crate::VMGlobalDefinition>(),
219        );
220        self.vmctx_builtin_functions_begin = offset_by(
221            self.vmctx_globals_begin,
222            self.num_local_globals,
223            u32::from(self.size_of_vmglobal_local()),
224            align_of::<crate::vmcontext::VMBuiltinFunctionsArray>(),
225        );
226        self.vmctx_trap_handler_begin = offset_by(
227            self.vmctx_builtin_functions_begin,
228            VMBuiltinFunctionIndex::builtin_functions_total_number(),
229            u32::from(self.pointer_size),
230            align_of::<fn()>(),
231        );
232        self.vmctx_gas_limiter_pointer = offset_by(
233            self.vmctx_trap_handler_begin,
234            if self.has_trap_handlers { 1 } else { 0 },
235            u32::from(self.pointer_size),
236            align_of::<*mut near_vm_types::FastGasCounter>(),
237        );
238        self.vmctx_stack_limit_begin = offset_by(
239            self.vmctx_gas_limiter_pointer,
240            1,
241            u32::from(self.pointer_size),
242            align_of::<u32>(),
243        );
244        self.vmctx_stack_limit_initial_begin = self.vmctx_stack_limit_begin.checked_add(4).unwrap();
245        self.size_of_vmctx = self.vmctx_stack_limit_begin.checked_add(4).unwrap();
246    }
247}
248
249/// Offsets for [`VMFunctionImport`].
250///
251/// [`VMFunctionImport`]: crate::vmcontext::VMFunctionImport
252impl VMOffsets {
253    /// The offset of the `body` field.
254    #[allow(clippy::erasing_op)]
255    pub const fn vmfunction_import_body(&self) -> u8 {
256        0 * self.pointer_size
257    }
258
259    /// The offset of the `vmctx` field.
260    #[allow(clippy::identity_op)]
261    pub const fn vmfunction_import_vmctx(&self) -> u8 {
262        3 * self.pointer_size
263    }
264
265    /// Return the size of [`VMFunctionImport`].
266    ///
267    /// [`VMFunctionImport`]: crate::vmcontext::VMFunctionImport
268    pub const fn size_of_vmfunction_import(&self) -> u8 {
269        4 * self.pointer_size
270    }
271}
272
273/// Offsets for [`VMDynamicFunctionContext`].
274///
275/// [`VMDynamicFunctionContext`]: crate::vmcontext::VMDynamicFunctionContext
276impl VMOffsets {
277    /// The offset of the `address` field.
278    #[allow(clippy::erasing_op)]
279    pub const fn vmdynamicfunction_import_context_address(&self) -> u8 {
280        0 * self.pointer_size
281    }
282
283    /// The offset of the `ctx` field.
284    #[allow(clippy::identity_op)]
285    pub const fn vmdynamicfunction_import_context_ctx(&self) -> u8 {
286        1 * self.pointer_size
287    }
288
289    /// Return the size of [`VMDynamicFunctionContext`].
290    ///
291    /// [`VMDynamicFunctionContext`]: crate::vmcontext::VMDynamicFunctionContext
292    pub const fn size_of_vmdynamicfunction_import_context(&self) -> u8 {
293        2 * self.pointer_size
294    }
295}
296
297/// Offsets for `*const VMFunctionBody`.
298impl VMOffsets {
299    /// The size of the `current_elements` field.
300    #[allow(clippy::identity_op)]
301    pub const fn size_of_vmfunction_body_ptr(&self) -> u8 {
302        1 * self.pointer_size
303    }
304}
305
306/// Offsets for [`VMTableImport`].
307///
308/// [`VMTableImport`]: crate::vmcontext::VMTableImport
309impl VMOffsets {
310    /// The offset of the `definition` field.
311    #[allow(clippy::erasing_op)]
312    pub const fn vmtable_import_definition(&self) -> u8 {
313        0 * self.pointer_size
314    }
315
316    /// The offset of the `from` field.
317    #[allow(clippy::identity_op)]
318    pub const fn vmtable_import_from(&self) -> u8 {
319        1 * self.pointer_size
320    }
321
322    /// Return the size of [`VMTableImport`].
323    ///
324    /// [`VMTableImport`]: crate::vmcontext::VMTableImport
325    pub const fn size_of_vmtable_import(&self) -> u8 {
326        3 * self.pointer_size
327    }
328}
329
330/// Offsets for [`VMTableDefinition`].
331///
332/// [`VMTableDefinition`]: crate::vmcontext::VMTableDefinition
333impl VMOffsets {
334    /// The offset of the `base` field.
335    #[allow(clippy::erasing_op)]
336    pub const fn vmtable_definition_base(&self) -> u8 {
337        0 * self.pointer_size
338    }
339
340    /// The offset of the `current_elements` field.
341    #[allow(clippy::identity_op)]
342    pub const fn vmtable_definition_current_elements(&self) -> u8 {
343        1 * self.pointer_size
344    }
345
346    /// The size of the `current_elements` field.
347    pub const fn size_of_vmtable_definition_current_elements(&self) -> u8 {
348        4
349    }
350
351    /// Return the size of [`VMTableDefinition`].
352    ///
353    /// [`VMTableDefinition`]: crate::vmcontext::VMTableDefinition
354    pub const fn size_of_vmtable_definition(&self) -> u8 {
355        2 * self.pointer_size
356    }
357}
358
359/// Offsets for [`VMMemoryImport`].
360///
361/// [`VMMemoryImport`]: crate::vmcontext::VMMemoryImport
362impl VMOffsets {
363    /// The offset of the `from` field.
364    #[allow(clippy::erasing_op)]
365    pub const fn vmmemory_import_definition(&self) -> u8 {
366        0 * self.pointer_size
367    }
368
369    /// The offset of the `from` field.
370    #[allow(clippy::identity_op)]
371    pub const fn vmmemory_import_from(&self) -> u8 {
372        1 * self.pointer_size
373    }
374
375    /// Return the size of [`VMMemoryImport`].
376    ///
377    /// [`VMMemoryImport`]: crate::vmcontext::VMMemoryImport
378    pub const fn size_of_vmmemory_import(&self) -> u8 {
379        2 * self.pointer_size
380    }
381}
382
383/// Offsets for [`VMMemoryDefinition`].
384///
385/// [`VMMemoryDefinition`]: crate::vmcontext::VMMemoryDefinition
386impl VMOffsets {
387    /// The offset of the `base` field.
388    #[allow(clippy::erasing_op)]
389    pub const fn vmmemory_definition_base(&self) -> u8 {
390        0 * self.pointer_size
391    }
392
393    /// The offset of the `current_length` field.
394    #[allow(clippy::identity_op)]
395    pub const fn vmmemory_definition_current_length(&self) -> u8 {
396        1 * self.pointer_size
397    }
398
399    /// The size of the `current_length` field.
400    pub const fn size_of_vmmemory_definition_current_length(&self) -> u8 {
401        4
402    }
403
404    /// Return the size of [`VMMemoryDefinition`].
405    ///
406    /// [`VMMemoryDefinition`]: crate::vmcontext::VMMemoryDefinition
407    pub const fn size_of_vmmemory_definition(&self) -> u8 {
408        2 * self.pointer_size
409    }
410}
411
412/// Offsets for [`VMGlobalImport`].
413///
414/// [`VMGlobalImport`]: crate::vmcontext::VMGlobalImport
415impl VMOffsets {
416    /// The offset of the `definition` field.
417    #[allow(clippy::erasing_op)]
418    pub const fn vmglobal_import_definition(&self) -> u8 {
419        0 * self.pointer_size
420    }
421
422    /// The offset of the `from` field.
423    #[allow(clippy::identity_op)]
424    pub const fn vmglobal_import_from(&self) -> u8 {
425        1 * self.pointer_size
426    }
427
428    /// Return the size of [`VMGlobalImport`].
429    ///
430    /// [`VMGlobalImport`]: crate::vmcontext::VMGlobalImport
431    #[allow(clippy::identity_op)]
432    pub const fn size_of_vmglobal_import(&self) -> u8 {
433        2 * self.pointer_size
434    }
435}
436
437/// Offsets for a non-null pointer to a [`VMGlobalDefinition`] used as a local global.
438///
439/// [`VMGlobalDefinition`]: crate::vmcontext::VMGlobalDefinition
440impl VMOffsets {
441    /// Return the size of a pointer to a [`VMGlobalDefinition`];
442    ///
443    /// The underlying global itself is the size of the largest value type (i.e. a V128),
444    /// however the size of this type is just the size of a pointer.
445    ///
446    /// [`VMGlobalDefinition`]: crate::vmcontext::VMGlobalDefinition
447    pub const fn size_of_vmglobal_local(&self) -> u8 {
448        self.pointer_size
449    }
450}
451
452/// Offsets for [`VMSharedSignatureIndex`].
453///
454/// [`VMSharedSignatureIndex`]: crate::sig_registry::VMSharedSignatureIndex
455impl VMOffsets {
456    /// Return the size of [`VMSharedSignatureIndex`].
457    ///
458    /// [`VMSharedSignatureIndex`]: crate::sig_registry::VMSharedSignatureIndex
459    pub const fn size_of_vmshared_signature_index(&self) -> u8 {
460        4
461    }
462}
463
464/// Offsets for [`VMCallerCheckedAnyfunc`].
465///
466/// [`VMCallerCheckedAnyfunc`]: crate::vmcontext::VMCallerCheckedAnyfunc
467impl VMOffsets {
468    /// The offset of the `func_ptr` field.
469    #[allow(clippy::erasing_op)]
470    pub const fn vmcaller_checked_anyfunc_func_ptr(&self) -> u8 {
471        0 * self.pointer_size
472    }
473
474    /// The offset of the `type_index` field.
475    #[allow(clippy::identity_op)]
476    pub const fn vmcaller_checked_anyfunc_type_index(&self) -> u8 {
477        1 * self.pointer_size
478    }
479
480    /// The offset of the `vmctx` field.
481    pub const fn vmcaller_checked_anyfunc_vmctx(&self) -> u8 {
482        2 * self.pointer_size
483    }
484
485    /// Return the size of [`VMCallerCheckedAnyfunc`].
486    ///
487    /// [`VMCallerCheckedAnyfunc`]: crate::vmcontext::VMCallerCheckedAnyfunc
488    pub const fn size_of_vmcaller_checked_anyfunc(&self) -> u8 {
489        3 * self.pointer_size
490    }
491}
492
493/// Offsets for [`VMFuncRef`].
494///
495/// [`VMFuncRef`]: crate::func_data_registry::VMFuncRef
496impl VMOffsets {
497    /// The offset to the pointer to the anyfunc inside the ref.
498    #[allow(clippy::erasing_op)]
499    pub const fn vm_funcref_anyfunc_ptr(&self) -> u8 {
500        0 * self.pointer_size
501    }
502
503    /// Return the size of [`VMFuncRef`].
504    ///
505    /// [`VMFuncRef`]: crate::func_data_registry::VMFuncRef
506    pub const fn size_of_vm_funcref(&self) -> u8 {
507        self.pointer_size
508    }
509}
510
511/// Offsets for [`VMContext`].
512///
513/// [`VMContext`]: crate::vmcontext::VMContext
514impl VMOffsets {
515    /// The offset of the `signature_ids` array.
516    #[inline]
517    pub fn vmctx_signature_ids_begin(&self) -> u32 {
518        self.vmctx_signature_ids_begin
519    }
520
521    /// The offset of the `tables` array.
522    pub fn vmctx_imported_functions_begin(&self) -> u32 {
523        self.vmctx_imported_functions_begin
524    }
525
526    /// The offset of the `tables` array.
527    #[allow(clippy::identity_op)]
528    pub fn vmctx_imported_tables_begin(&self) -> u32 {
529        self.vmctx_imported_tables_begin
530    }
531
532    /// The offset of the `memories` array.
533    pub fn vmctx_imported_memories_begin(&self) -> u32 {
534        self.vmctx_imported_memories_begin
535    }
536
537    /// The offset of the `globals` array.
538    pub fn vmctx_imported_globals_begin(&self) -> u32 {
539        self.vmctx_imported_globals_begin
540    }
541
542    /// The offset of the `tables` array.
543    pub fn vmctx_tables_begin(&self) -> u32 {
544        self.vmctx_tables_begin
545    }
546
547    /// The offset of the `memories` array.
548    pub fn vmctx_memories_begin(&self) -> u32 {
549        self.vmctx_memories_begin
550    }
551
552    /// The offset of the `globals` array.
553    pub fn vmctx_globals_begin(&self) -> u32 {
554        self.vmctx_globals_begin
555    }
556
557    /// The offset of the builtin functions array.
558    pub fn vmctx_builtin_functions_begin(&self) -> u32 {
559        self.vmctx_builtin_functions_begin
560    }
561
562    /// The offset of the trap handler.
563    pub fn vmctx_trap_handler_begin(&self) -> u32 {
564        self.vmctx_trap_handler_begin
565    }
566
567    /// The offset of the gas limiter pointer.
568    pub fn vmctx_gas_limiter_pointer(&self) -> u32 {
569        self.vmctx_gas_limiter_pointer
570    }
571
572    /// The offset of the current stack limit.
573    pub fn vmctx_stack_limit_begin(&self) -> u32 {
574        self.vmctx_stack_limit_begin
575    }
576
577    /// The offset of the initial stack limit.
578    pub fn vmctx_stack_limit_initial_begin(&self) -> u32 {
579        self.vmctx_stack_limit_initial_begin
580    }
581
582    /// Return the size of the [`VMContext`] allocation.
583    ///
584    /// [`VMContext`]: crate::vmcontext::VMContext
585    pub fn size_of_vmctx(&self) -> u32 {
586        self.size_of_vmctx
587    }
588
589    /// Return the offset to [`VMSharedSignatureIndex`] index `index`.
590    ///
591    /// [`VMSharedSignatureIndex`]: crate::sig_registry::VMSharedSignatureIndex
592    // Remember updating precompute upon changes
593    pub fn vmctx_vmshared_signature_id(&self, index: SignatureIndex) -> u32 {
594        assert_lt!(index.as_u32(), self.num_signature_ids);
595        self.vmctx_signature_ids_begin
596            + index.as_u32() * u32::from(self.size_of_vmshared_signature_index())
597    }
598
599    /// Return the offset to [`VMFunctionImport`] index `index`.
600    ///
601    /// [`VMFunctionImport`]: crate::vmcontext::VMFunctionImport
602    // Remember updating precompute upon changes
603    pub fn vmctx_vmfunction_import(&self, index: FunctionIndex) -> u32 {
604        assert_lt!(index.as_u32(), self.num_imported_functions);
605        self.vmctx_imported_functions_begin
606            + index.as_u32() * u32::from(self.size_of_vmfunction_import())
607    }
608
609    /// Return the offset to [`VMTableImport`] index `index`.
610    ///
611    /// [`VMTableImport`]: crate::vmcontext::VMTableImport
612    // Remember updating precompute upon changes
613    pub fn vmctx_vmtable_import(&self, index: TableIndex) -> u32 {
614        assert_lt!(index.as_u32(), self.num_imported_tables);
615        self.vmctx_imported_tables_begin + index.as_u32() * u32::from(self.size_of_vmtable_import())
616    }
617
618    /// Return the offset to [`VMMemoryImport`] index `index`.
619    ///
620    /// [`VMMemoryImport`]: crate::vmcontext::VMMemoryImport
621    // Remember updating precompute upon changes
622    pub fn vmctx_vmmemory_import(&self, index: MemoryIndex) -> u32 {
623        assert_lt!(index.as_u32(), self.num_imported_memories);
624        self.vmctx_imported_memories_begin
625            + index.as_u32() * u32::from(self.size_of_vmmemory_import())
626    }
627
628    /// Return the offset to [`VMGlobalImport`] index `index`.
629    ///
630    /// [`VMGlobalImport`]: crate::vmcontext::VMGlobalImport
631    // Remember updating precompute upon changes
632    pub fn vmctx_vmglobal_import(&self, index: GlobalIndex) -> u32 {
633        assert_lt!(index.as_u32(), self.num_imported_globals);
634        self.vmctx_imported_globals_begin
635            + index.as_u32() * u32::from(self.size_of_vmglobal_import())
636    }
637
638    /// Return the offset to [`VMTableDefinition`] index `index`.
639    ///
640    /// [`VMTableDefinition`]: crate::vmcontext::VMTableDefinition
641    // Remember updating precompute upon changes
642    pub fn vmctx_vmtable_definition(&self, index: LocalTableIndex) -> u32 {
643        assert_lt!(index.as_u32(), self.num_local_tables);
644        self.vmctx_tables_begin + index.as_u32() * u32::from(self.size_of_vmtable_definition())
645    }
646
647    /// Return the offset to [`VMMemoryDefinition`] index `index`.
648    ///
649    /// [`VMMemoryDefinition`]: crate::vmcontext::VMMemoryDefinition
650    // Remember updating precompute upon changes
651    pub fn vmctx_vmmemory_definition(&self, index: LocalMemoryIndex) -> u32 {
652        assert_lt!(index.as_u32(), self.num_local_memories);
653        self.vmctx_memories_begin + index.as_u32() * u32::from(self.size_of_vmmemory_definition())
654    }
655
656    /// Return the offset to the [`VMGlobalDefinition`] index `index`.
657    ///
658    /// [`VMGlobalDefinition`]: crate::vmcontext::VMGlobalDefinition
659    // Remember updating precompute upon changes
660    pub fn vmctx_vmglobal_definition(&self, index: LocalGlobalIndex) -> u32 {
661        assert_lt!(index.as_u32(), self.num_local_globals);
662        self.vmctx_globals_begin + index.as_u32() * u32::from(self.size_of_vmglobal_local())
663    }
664
665    /// Return the offset to the `body` field in `*const VMFunctionBody` index `index`.
666    // Remember updating precompute upon changes
667    pub fn vmctx_vmfunction_import_body(&self, index: FunctionIndex) -> u32 {
668        self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_body())
669    }
670
671    /// Return the offset to the `vmctx` field in `*const VMFunctionBody` index `index`.
672    // Remember updating precompute upon changes
673    pub fn vmctx_vmfunction_import_vmctx(&self, index: FunctionIndex) -> u32 {
674        self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_vmctx())
675    }
676
677    /// Return the offset to the `definition` field in [`VMTableImport`] index `index`.
678    ///
679    /// [`VMTableImport`]: crate::vmcontext::VMTableImport
680    // Remember updating precompute upon changes
681    pub fn vmctx_vmtable_import_definition(&self, index: TableIndex) -> u32 {
682        self.vmctx_vmtable_import(index) + u32::from(self.vmtable_import_definition())
683    }
684
685    /// Return the offset to the `base` field in [`VMTableDefinition`] index `index`.
686    ///
687    /// [`VMTableDefinition`]: crate::vmcontext::VMTableDefinition
688    // Remember updating precompute upon changes
689    pub fn vmctx_vmtable_definition_base(&self, index: LocalTableIndex) -> u32 {
690        self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_base())
691    }
692
693    /// Return the offset to the `current_elements` field in [`VMTableDefinition`] index `index`.
694    ///
695    /// [`VMTableDefinition`]: crate::vmcontext::VMTableDefinition
696    // Remember updating precompute upon changes
697    pub fn vmctx_vmtable_definition_current_elements(&self, index: LocalTableIndex) -> u32 {
698        self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_current_elements())
699    }
700
701    /// Return the offset to the `from` field in [`VMMemoryImport`] index `index`.
702    ///
703    /// [`VMMemoryImport`]: crate::vmcontext::VMMemoryImport
704    // Remember updating precompute upon changes
705    pub fn vmctx_vmmemory_import_definition(&self, index: MemoryIndex) -> u32 {
706        self.vmctx_vmmemory_import(index) + u32::from(self.vmmemory_import_definition())
707    }
708
709    /// Return the offset to the `vmctx` field in [`VMMemoryImport`] index `index`.
710    ///
711    /// [`VMMemoryImport`]: crate::vmcontext::VMMemoryImport
712    // Remember updating precompute upon changes
713    pub fn vmctx_vmmemory_import_from(&self, index: MemoryIndex) -> u32 {
714        self.vmctx_vmmemory_import(index) + u32::from(self.vmmemory_import_from())
715    }
716
717    /// Return the offset to the `base` field in [`VMMemoryDefinition`] index `index`.
718    ///
719    /// [`VMMemoryDefinition`]: crate::vmcontext::VMMemoryDefinition
720    // Remember updating precompute upon changes
721    pub fn vmctx_vmmemory_definition_base(&self, index: LocalMemoryIndex) -> u32 {
722        self.vmctx_vmmemory_definition(index) + u32::from(self.vmmemory_definition_base())
723    }
724
725    /// Return the offset to the `current_length` field in [`VMMemoryDefinition`] index `index`.
726    ///
727    /// [`VMMemoryDefinition`]: crate::vmcontext::VMMemoryDefinition
728    // Remember updating precompute upon changes
729    pub fn vmctx_vmmemory_definition_current_length(&self, index: LocalMemoryIndex) -> u32 {
730        self.vmctx_vmmemory_definition(index) + u32::from(self.vmmemory_definition_current_length())
731    }
732
733    /// Return the offset to the `from` field in [`VMGlobalImport`] index `index`.
734    ///
735    /// [`VMGlobalImport`]: crate::vmcontext::VMGlobalImport
736    // Remember updating precompute upon changes
737    pub fn vmctx_vmglobal_import_definition(&self, index: GlobalIndex) -> u32 {
738        self.vmctx_vmglobal_import(index) + u32::from(self.vmglobal_import_definition())
739    }
740
741    /// Return the offset to builtin function in `VMBuiltinFunctionsArray` index `index`.
742    // Remember updating precompute upon changes
743    pub fn vmctx_builtin_function(&self, index: VMBuiltinFunctionIndex) -> u32 {
744        self.vmctx_builtin_functions_begin + index.index() * u32::from(self.pointer_size)
745    }
746
747    /// Return the offset to the trap handler.
748    pub fn vmctx_trap_handler(&self) -> u32 {
749        // Ensure that we never ask for trap handler offset if it's not enabled.
750        assert!(self.has_trap_handlers);
751        self.vmctx_trap_handler_begin
752    }
753}
754
755/// Target specific type for shared signature index.
756#[derive(Debug, Copy, Clone)]
757pub struct TargetSharedSignatureIndex(u32);
758
759impl TargetSharedSignatureIndex {
760    /// Constructs `TargetSharedSignatureIndex`.
761    pub const fn new(value: u32) -> Self {
762        Self(value)
763    }
764
765    /// Returns index value.
766    pub const fn index(self) -> u32 {
767        self.0
768    }
769}
770
771#[cfg(test)]
772mod tests {
773    use crate::vmoffsets::align;
774
775    #[test]
776    fn alignment() {
777        fn is_aligned(x: u32) -> bool {
778            x % 16 == 0
779        }
780        assert!(is_aligned(align(0, 16)));
781        assert!(is_aligned(align(32, 16)));
782        assert!(is_aligned(align(33, 16)));
783        assert!(is_aligned(align(31, 16)));
784    }
785}