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