wasmer_types/
vmoffsets.rs

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