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 `debug_usize` builtin function.
146    pub const fn get_imported_debug_usize_index() -> Self {
147        Self(30)
148    }
149
150    /// Returns an index for wasm's imported `debug_str` builtin function.
151    pub const fn get_imported_debug_str_index() -> Self {
152        Self(31)
153    }
154
155    /// Returns the total number of builtin functions.
156    pub const fn builtin_functions_total_number() -> u32 {
157        32
158    }
159
160    /// Return the index as an u32 number.
161    pub const fn index(self) -> u32 {
162        self.0
163    }
164}
165
166#[cfg(target_pointer_width = "32")]
167fn cast_to_u32(sz: usize) -> u32 {
168    u32::try_from(sz).unwrap()
169}
170#[cfg(target_pointer_width = "64")]
171fn cast_to_u32(sz: usize) -> u32 {
172    u32::try_from(sz).expect("overflow in cast from usize to u32")
173}
174
175/// Align an offset used in this module to a specific byte-width by rounding up
176#[inline]
177const fn align(offset: u32, width: u32) -> u32 {
178    offset.div_ceil(width) * width
179}
180
181/// This class computes offsets to fields within VMContext and other
182/// related structs that JIT code accesses directly.
183#[derive(Clone, Debug)]
184pub struct VMOffsets {
185    /// The size in bytes of a pointer on the target.
186    pointer_size: u8,
187    /// The number of signature declarations in the module.
188    num_signature_ids: u32,
189    /// The number of imported functions in the module.
190    num_imported_functions: u32,
191    /// The number of imported tables in the module.
192    num_imported_tables: u32,
193    /// The number of imported memories in the module.
194    num_imported_memories: u32,
195    /// The number of tags in the module.
196    num_tag_ids: u32,
197    /// The number of imported globals in the module.
198    num_imported_globals: u32,
199    /// The number of defined tables in the module.
200    num_local_tables: u32,
201    /// The number of defined memories in the module.
202    num_local_memories: u32,
203    /// The number of defined globals in the module.
204    num_local_globals: u32,
205
206    vmctx_signature_ids_begin: u32,
207    vmctx_imported_functions_begin: u32,
208    vmctx_imported_tables_begin: u32,
209    vmctx_imported_memories_begin: u32,
210    vmctx_tag_ids_begin: u32,
211    vmctx_imported_globals_begin: u32,
212    vmctx_tables_begin: u32,
213    vmctx_memories_begin: u32,
214    vmctx_globals_begin: u32,
215    vmctx_builtin_functions_begin: u32,
216    vmctx_trap_handler_begin: u32,
217    vmctx_gas_limiter_pointer: u32,
218    vmctx_stack_limit_begin: u32,
219    vmctx_stack_limit_initial_begin: u32,
220    size_of_vmctx: u32,
221}
222
223impl VMOffsets {
224    /// Return a new `VMOffsets` instance, for a given pointer size.
225    pub fn new(pointer_size: u8, module: &ModuleInfo) -> Self {
226        let mut ret = Self {
227            pointer_size,
228            num_signature_ids: cast_to_u32(module.signatures.len()),
229            num_imported_functions: cast_to_u32(module.num_imported_functions),
230            num_imported_tables: cast_to_u32(module.num_imported_tables),
231            num_imported_memories: cast_to_u32(module.num_imported_memories),
232            num_tag_ids: cast_to_u32(module.tags.len()),
233            num_imported_globals: cast_to_u32(module.num_imported_globals),
234            num_local_tables: cast_to_u32(module.tables.len()),
235            num_local_memories: cast_to_u32(module.memories.len()),
236            num_local_globals: cast_to_u32(module.globals.len()),
237            vmctx_signature_ids_begin: 0,
238            vmctx_imported_functions_begin: 0,
239            vmctx_imported_tables_begin: 0,
240            vmctx_imported_memories_begin: 0,
241            vmctx_tag_ids_begin: 0,
242            vmctx_imported_globals_begin: 0,
243            vmctx_tables_begin: 0,
244            vmctx_memories_begin: 0,
245            vmctx_globals_begin: 0,
246            vmctx_builtin_functions_begin: 0,
247            vmctx_trap_handler_begin: 0,
248            vmctx_gas_limiter_pointer: 0,
249            vmctx_stack_limit_begin: 0,
250            vmctx_stack_limit_initial_begin: 0,
251            size_of_vmctx: 0,
252        };
253        ret.precompute();
254        ret
255    }
256
257    /// Return a new `VMOffsets` instance, for a given pointer size
258    /// skipping the `ModuleInfo`.
259    ///
260    /// Note: This should only when generating code for trampolines.
261    pub fn new_for_trampolines(pointer_size: u8) -> Self {
262        Self {
263            pointer_size,
264            num_signature_ids: 0,
265            num_imported_functions: 0,
266            num_imported_tables: 0,
267            num_imported_memories: 0,
268            num_tag_ids: 0,
269            num_imported_globals: 0,
270            num_local_tables: 0,
271            num_local_memories: 0,
272            num_local_globals: 0,
273            vmctx_signature_ids_begin: 0,
274            vmctx_imported_functions_begin: 0,
275            vmctx_imported_tables_begin: 0,
276            vmctx_imported_memories_begin: 0,
277            vmctx_tag_ids_begin: 0,
278            vmctx_imported_globals_begin: 0,
279            vmctx_tables_begin: 0,
280            vmctx_memories_begin: 0,
281            vmctx_globals_begin: 0,
282            vmctx_builtin_functions_begin: 0,
283            vmctx_trap_handler_begin: 0,
284            vmctx_gas_limiter_pointer: 0,
285            vmctx_stack_limit_begin: 0,
286            vmctx_stack_limit_initial_begin: 0,
287            size_of_vmctx: 0,
288        }
289    }
290
291    /// Number of local tables defined in the module
292    pub fn num_local_tables(&self) -> u32 {
293        self.num_local_tables
294    }
295
296    /// Number of local memories defined in the module
297    pub fn num_local_memories(&self) -> u32 {
298        self.num_local_memories
299    }
300
301    fn precompute(&mut self) {
302        /// Offset base by num_items items of size item_size, panicking on overflow
303        fn offset_by(base: u32, num_items: u32, item_size: u32) -> u32 {
304            base.checked_add(num_items.checked_mul(item_size).unwrap())
305                .unwrap()
306        }
307        /// Offset base by num_items items of size item_size, panicking on overflow
308        /// Also, will align the value on pointer size boundary,
309        /// to avoid misalignement issue
310        fn offset_by_aligned(base: u32, num_items: u32, item_size: u32) -> u32 {
311            align(
312                base.checked_add(num_items.checked_mul(item_size).unwrap())
313                    .unwrap(),
314                size_of::<&u32>() as u32,
315            )
316        }
317
318        self.vmctx_signature_ids_begin = 0;
319        self.vmctx_imported_functions_begin = offset_by_aligned(
320            self.vmctx_signature_ids_begin,
321            self.num_signature_ids,
322            u32::from(self.size_of_vmshared_signature_index()),
323        );
324        self.vmctx_imported_tables_begin = offset_by_aligned(
325            self.vmctx_imported_functions_begin,
326            self.num_imported_functions,
327            u32::from(self.size_of_vmfunction_import()),
328        );
329        self.vmctx_imported_memories_begin = offset_by_aligned(
330            self.vmctx_imported_tables_begin,
331            self.num_imported_tables,
332            u32::from(self.size_of_vmtable_import()),
333        );
334
335        self.vmctx_tag_ids_begin = offset_by_aligned(
336            self.vmctx_imported_memories_begin,
337            self.num_imported_memories,
338            u32::from(self.size_of_vmmemory_import()),
339        );
340
341        self.vmctx_imported_globals_begin = offset_by_aligned(
342            self.vmctx_tag_ids_begin,
343            self.num_tag_ids,
344            u32::from(self.size_of_vmshared_tag_index()),
345        );
346
347        self.vmctx_tables_begin = offset_by_aligned(
348            self.vmctx_imported_globals_begin,
349            self.num_imported_globals,
350            u32::from(self.size_of_vmglobal_import()),
351        );
352        self.vmctx_memories_begin = offset_by_aligned(
353            self.vmctx_tables_begin,
354            self.num_local_tables,
355            u32::from(self.size_of_vmtable_definition()),
356        );
357        self.vmctx_globals_begin = align(
358            offset_by(
359                self.vmctx_memories_begin,
360                self.num_local_memories,
361                u32::from(self.size_of_vmmemory_definition()),
362            ),
363            16,
364        );
365        self.vmctx_builtin_functions_begin = offset_by(
366            self.vmctx_globals_begin,
367            self.num_local_globals,
368            u32::from(self.size_of_vmglobal_local()),
369        );
370        self.vmctx_trap_handler_begin = offset_by(
371            self.vmctx_builtin_functions_begin,
372            VMBuiltinFunctionIndex::builtin_functions_total_number(),
373            u32::from(self.pointer_size),
374        );
375        self.vmctx_gas_limiter_pointer = offset_by(
376            self.vmctx_trap_handler_begin,
377            1,
378            u32::from(self.pointer_size),
379        );
380        self.vmctx_stack_limit_begin = offset_by(
381            self.vmctx_gas_limiter_pointer,
382            1,
383            u32::from(self.pointer_size),
384        );
385        self.vmctx_stack_limit_initial_begin = self.vmctx_stack_limit_begin.checked_add(4).unwrap();
386        self.size_of_vmctx = self.vmctx_stack_limit_begin.checked_add(4).unwrap();
387    }
388}
389
390/// Offsets for `VMFunctionImport`.
391impl VMOffsets {
392    /// The offset of the `body` field.
393    #[allow(clippy::erasing_op)]
394    pub const fn vmfunction_import_body(&self) -> u8 {
395        0 * self.pointer_size
396    }
397
398    /// The offset of the `vmctx` field.
399    #[allow(clippy::identity_op)]
400    pub const fn vmfunction_import_vmctx(&self) -> u8 {
401        1 * self.pointer_size
402    }
403
404    /// The offset of the `handle` field.
405    pub const fn vmfunction_import_handle(&self) -> u8 {
406        2 * self.pointer_size
407    }
408
409    /// Return the size of `VMFunctionImport`.
410    pub const fn size_of_vmfunction_import(&self) -> u8 {
411        3 * self.pointer_size
412    }
413}
414
415/// Offsets for `VMDynamicFunctionContext`.
416impl VMOffsets {
417    /// The offset of the `address` field.
418    #[allow(clippy::erasing_op)]
419    pub const fn vmdynamicfunction_import_context_address(&self) -> u8 {
420        0 * self.pointer_size
421    }
422
423    /// The offset of the `ctx` field.
424    #[allow(clippy::identity_op)]
425    pub const fn vmdynamicfunction_import_context_ctx(&self) -> u8 {
426        1 * self.pointer_size
427    }
428
429    /// Return the size of `VMDynamicFunctionContext`.
430    pub const fn size_of_vmdynamicfunction_import_context(&self) -> u8 {
431        2 * self.pointer_size
432    }
433}
434
435/// Offsets for `*const VMFunctionBody`.
436impl VMOffsets {
437    /// The size of the `current_elements` field.
438    #[allow(clippy::identity_op)]
439    pub const fn size_of_vmfunction_body_ptr(&self) -> u8 {
440        1 * self.pointer_size
441    }
442}
443
444/// Offsets for `VMTableImport`.
445impl VMOffsets {
446    /// The offset of the `definition` field.
447    #[allow(clippy::erasing_op)]
448    pub const fn vmtable_import_definition(&self) -> u8 {
449        0 * self.pointer_size
450    }
451
452    /// The offset of the `handle` field.
453    #[allow(clippy::identity_op)]
454    pub const fn vmtable_import_handle(&self) -> u8 {
455        1 * self.pointer_size
456    }
457
458    /// Return the size of `VMTableImport`.
459    pub const fn size_of_vmtable_import(&self) -> u8 {
460        2 * self.pointer_size
461    }
462}
463
464/// Offsets for `VMTableDefinition`.
465impl VMOffsets {
466    /// The offset of the `base` field.
467    #[allow(clippy::erasing_op)]
468    pub const fn vmtable_definition_base(&self) -> u8 {
469        0 * self.pointer_size
470    }
471
472    /// The offset of the `current_elements` field.
473    #[allow(clippy::identity_op)]
474    pub const fn vmtable_definition_current_elements(&self) -> u8 {
475        1 * self.pointer_size
476    }
477
478    /// The size of the `current_elements` field.
479    pub const fn size_of_vmtable_definition_current_elements(&self) -> u8 {
480        4
481    }
482
483    /// Return the size of `VMTableDefinition`.
484    pub const fn size_of_vmtable_definition(&self) -> u8 {
485        2 * self.pointer_size
486    }
487}
488
489/// Offsets for `VMMemoryImport`.
490impl VMOffsets {
491    /// The offset of the `from` field.
492    #[allow(clippy::erasing_op)]
493    pub const fn vmmemory_import_definition(&self) -> u8 {
494        0 * self.pointer_size
495    }
496
497    /// The offset of the `handle` field.
498    #[allow(clippy::identity_op)]
499    pub const fn vmmemory_import_handle(&self) -> u8 {
500        1 * self.pointer_size
501    }
502
503    /// Return the size of `VMMemoryImport`.
504    pub const fn size_of_vmmemory_import(&self) -> u8 {
505        2 * self.pointer_size
506    }
507}
508
509/// Offsets for `VMMemoryDefinition`.
510impl VMOffsets {
511    /// The offset of the `base` field.
512    #[allow(clippy::erasing_op)]
513    pub const fn vmmemory_definition_base(&self) -> u8 {
514        0 * self.pointer_size
515    }
516
517    /// The offset of the `current_length` field.
518    #[allow(clippy::identity_op)]
519    pub const fn vmmemory_definition_current_length(&self) -> u8 {
520        1 * self.pointer_size
521    }
522
523    /// The size of the `current_length` field.
524    pub const fn size_of_vmmemory_definition_current_length(&self) -> u8 {
525        4
526    }
527
528    /// Return the size of `VMMemoryDefinition`.
529    pub const fn size_of_vmmemory_definition(&self) -> u8 {
530        2 * self.pointer_size
531    }
532}
533
534/// Offsets for `VMGlobalImport`.
535impl VMOffsets {
536    /// The offset of the `definition` field.
537    #[allow(clippy::erasing_op)]
538    pub const fn vmglobal_import_definition(&self) -> u8 {
539        0 * self.pointer_size
540    }
541
542    /// The offset of the `handle` field.
543    #[allow(clippy::identity_op)]
544    pub const fn vmglobal_import_handle(&self) -> u8 {
545        1 * self.pointer_size
546    }
547
548    /// Return the size of `VMGlobalImport`.
549    #[allow(clippy::identity_op)]
550    pub const fn size_of_vmglobal_import(&self) -> u8 {
551        2 * self.pointer_size
552    }
553}
554
555/// Offsets for a non-null pointer to a `VMGlobalDefinition` used as a local global.
556impl VMOffsets {
557    /// Return the size of a pointer to a `VMGlobalDefinition`;
558    ///
559    /// The underlying global itself is the size of the largest value type (i.e. a V128),
560    /// however the size of this type is just the size of a pointer.
561    pub const fn size_of_vmglobal_local(&self) -> u8 {
562        self.pointer_size
563    }
564}
565
566/// Offsets for `VMSharedSignatureIndex`.
567impl VMOffsets {
568    /// Return the size of `VMSharedSignatureIndex`.
569    pub const fn size_of_vmshared_signature_index(&self) -> u8 {
570        4
571    }
572}
573
574/// Offsets for `VMCallerCheckedAnyfunc`.
575impl VMOffsets {
576    /// The offset of the `func_ptr` field.
577    #[allow(clippy::erasing_op)]
578    pub const fn vmcaller_checked_anyfunc_func_ptr(&self) -> u8 {
579        0 * self.pointer_size
580    }
581
582    /// The offset of the `type_index` field.
583    #[allow(clippy::identity_op)]
584    pub const fn vmcaller_checked_anyfunc_type_index(&self) -> u8 {
585        1 * self.pointer_size
586    }
587
588    /// The offset of the `vmctx` field.
589    pub const fn vmcaller_checked_anyfunc_vmctx(&self) -> u8 {
590        2 * self.pointer_size
591    }
592
593    /// The offset of the `call_trampoline` field.
594    pub const fn vmcaller_checked_anyfunc_call_trampoline(&self) -> u8 {
595        3 * self.pointer_size
596    }
597
598    /// Return the size of `VMCallerCheckedAnyfunc`.
599    pub const fn size_of_vmcaller_checked_anyfunc(&self) -> u8 {
600        4 * self.pointer_size
601    }
602}
603
604/// Offsets for `VMFuncRef`.
605impl VMOffsets {
606    /// The offset to the pointer to the anyfunc inside the ref.
607    #[allow(clippy::erasing_op)]
608    pub const fn vm_funcref_anyfunc_ptr(&self) -> u8 {
609        0 * self.pointer_size
610    }
611
612    /// Return the size of `VMFuncRef`.
613    #[allow(clippy::identity_op)]
614    pub const fn size_of_vm_funcref(&self) -> u8 {
615        1 * self.pointer_size
616    }
617}
618
619/// Offsets for `VMSharedTagIndex`.
620impl VMOffsets {
621    /// Return the size of `VMSharedTagIndex`.
622    pub const fn size_of_vmshared_tag_index(&self) -> u8 {
623        4
624    }
625}
626
627/// Offsets for `VMContext`.
628impl VMOffsets {
629    /// The offset of the `signature_ids` array.
630    pub fn vmctx_signature_ids_begin(&self) -> u32 {
631        self.vmctx_signature_ids_begin
632    }
633
634    /// The offset of the `tables` array.
635    #[allow(clippy::erasing_op)]
636    pub fn vmctx_imported_functions_begin(&self) -> u32 {
637        self.vmctx_imported_functions_begin
638    }
639
640    /// The offset of the `tables` array.
641    #[allow(clippy::identity_op)]
642    pub fn vmctx_imported_tables_begin(&self) -> u32 {
643        self.vmctx_imported_tables_begin
644    }
645
646    /// The offset of the `memories` array.
647    pub fn vmctx_imported_memories_begin(&self) -> u32 {
648        self.vmctx_imported_memories_begin
649    }
650
651    /// The offset of the `globals` array.
652    pub fn vmctx_imported_globals_begin(&self) -> u32 {
653        self.vmctx_imported_globals_begin
654    }
655
656    /// The offset of the `tags` array.
657    pub fn vmctx_tag_ids_begin(&self) -> u32 {
658        self.vmctx_tag_ids_begin
659    }
660
661    /// The offset of the `tables` array.
662    pub fn vmctx_tables_begin(&self) -> u32 {
663        self.vmctx_tables_begin
664    }
665
666    /// The offset of the `memories` array.
667    pub fn vmctx_memories_begin(&self) -> u32 {
668        self.vmctx_memories_begin
669    }
670
671    /// The offset of the `globals` array.
672    pub fn vmctx_globals_begin(&self) -> u32 {
673        self.vmctx_globals_begin
674    }
675
676    /// The offset of the builtin functions array.
677    pub fn vmctx_builtin_functions_begin(&self) -> u32 {
678        self.vmctx_builtin_functions_begin
679    }
680
681    /// Return the size of the `VMContext` allocation.
682    pub fn size_of_vmctx(&self) -> u32 {
683        self.size_of_vmctx
684    }
685
686    /// Return the offset to `VMSharedSignatureIndex` index `index`.
687    pub fn vmctx_vmshared_signature_id(&self, index: SignatureIndex) -> u32 {
688        assert_lt!(index.as_u32(), self.num_signature_ids);
689        self.vmctx_signature_ids_begin
690            + index.as_u32() * u32::from(self.size_of_vmshared_signature_index())
691    }
692
693    /// Return the offset to `VMFunctionImport` index `index`.
694    pub fn vmctx_vmfunction_import(&self, index: FunctionIndex) -> u32 {
695        assert_lt!(index.as_u32(), self.num_imported_functions);
696        self.vmctx_imported_functions_begin
697            + index.as_u32() * u32::from(self.size_of_vmfunction_import())
698    }
699
700    /// Return the offset to `VMTableImport` index `index`.
701    pub fn vmctx_vmtable_import(&self, index: TableIndex) -> u32 {
702        assert_lt!(index.as_u32(), self.num_imported_tables);
703        self.vmctx_imported_tables_begin + index.as_u32() * u32::from(self.size_of_vmtable_import())
704    }
705
706    /// Return the offset to `VMMemoryImport` index `index`.
707    pub fn vmctx_vmmemory_import(&self, index: MemoryIndex) -> u32 {
708        assert_lt!(index.as_u32(), self.num_imported_memories);
709        self.vmctx_imported_memories_begin
710            + index.as_u32() * u32::from(self.size_of_vmmemory_import())
711    }
712
713    /// Return the offset to `VMGlobalImport` index `index`.
714    pub fn vmctx_vmglobal_import(&self, index: GlobalIndex) -> u32 {
715        assert_lt!(index.as_u32(), self.num_imported_globals);
716        self.vmctx_imported_globals_begin
717            + index.as_u32() * u32::from(self.size_of_vmglobal_import())
718    }
719
720    /// Return the offset to `VMTableDefinition` index `index`.
721    pub fn vmctx_vmtable_definition(&self, index: LocalTableIndex) -> u32 {
722        assert_lt!(index.as_u32(), self.num_local_tables);
723        self.vmctx_tables_begin + index.as_u32() * u32::from(self.size_of_vmtable_definition())
724    }
725
726    /// Return the offset to `VMMemoryDefinition` index `index`.
727    pub fn vmctx_vmmemory_definition(&self, index: LocalMemoryIndex) -> u32 {
728        assert_lt!(index.as_u32(), self.num_local_memories);
729        self.vmctx_memories_begin + index.as_u32() * u32::from(self.size_of_vmmemory_definition())
730    }
731
732    /// Return the offset to the `VMGlobalDefinition` index `index`.
733    pub fn vmctx_vmglobal_definition(&self, index: LocalGlobalIndex) -> u32 {
734        assert_lt!(index.as_u32(), self.num_local_globals);
735        self.vmctx_globals_begin + index.as_u32() * u32::from(self.size_of_vmglobal_local())
736    }
737
738    /// Return the offset to the `body` field in `*const VMFunctionBody` index `index`.
739    /// Remember updating precompute upon changes
740    pub fn vmctx_vmfunction_import_body(&self, index: FunctionIndex) -> u32 {
741        self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_body())
742    }
743
744    /// Return the offset to the `vmctx` field in `*const VMFunctionBody` index `index`.
745    /// Remember updating precompute upon changes
746    pub fn vmctx_vmfunction_import_vmctx(&self, index: FunctionIndex) -> u32 {
747        self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_vmctx())
748    }
749
750    /// Return the offset to the `definition` field in `VMTableImport` index `index`.
751    /// Remember updating precompute upon changes
752    pub fn vmctx_vmtable_import_definition(&self, index: TableIndex) -> u32 {
753        self.vmctx_vmtable_import(index) + u32::from(self.vmtable_import_definition())
754    }
755
756    /// Return the offset to the `base` field in `VMTableDefinition` index `index`.
757    /// Remember updating precompute upon changes
758    pub fn vmctx_vmtable_definition_base(&self, index: LocalTableIndex) -> u32 {
759        self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_base())
760    }
761
762    /// Return the offset to the `current_elements` field in `VMTableDefinition` index `index`.
763    /// Remember updating precompute upon changes
764    pub fn vmctx_vmtable_definition_current_elements(&self, index: LocalTableIndex) -> u32 {
765        self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_current_elements())
766    }
767
768    /// Return the offset to the `from` field in `VMMemoryImport` index `index`.
769    /// Remember updating precompute upon changes
770    pub fn vmctx_vmmemory_import_definition(&self, index: MemoryIndex) -> u32 {
771        self.vmctx_vmmemory_import(index) + u32::from(self.vmmemory_import_definition())
772    }
773
774    /// Return the offset to the `vmctx` field in `VMMemoryImport` index `index`.
775    /// Remember updating precompute upon changes
776    pub fn vmctx_vmmemory_import_handle(&self, index: MemoryIndex) -> u32 {
777        self.vmctx_vmmemory_import(index) + u32::from(self.vmmemory_import_handle())
778    }
779
780    /// Return the offset to the `base` field in `VMMemoryDefinition` index `index`.
781    /// Remember updating precompute upon changes
782    pub fn vmctx_vmmemory_definition_base(&self, index: LocalMemoryIndex) -> u32 {
783        self.vmctx_vmmemory_definition(index) + u32::from(self.vmmemory_definition_base())
784    }
785
786    /// Return the offset to the `current_length` field in `VMMemoryDefinition` index `index`.
787    /// Remember updating precompute upon changes
788    pub fn vmctx_vmmemory_definition_current_length(&self, index: LocalMemoryIndex) -> u32 {
789        self.vmctx_vmmemory_definition(index) + u32::from(self.vmmemory_definition_current_length())
790    }
791
792    /// Return the offset to the `from` field in `VMGlobalImport` index `index`.
793    /// Remember updating precompute upon changes
794    pub fn vmctx_vmglobal_import_definition(&self, index: GlobalIndex) -> u32 {
795        self.vmctx_vmglobal_import(index) + u32::from(self.vmglobal_import_definition())
796    }
797
798    /// Return the offset to builtin function in `VMBuiltinFunctionsArray` index `index`.
799    /// Remember updating precompute upon changes
800    pub fn vmctx_builtin_function(&self, index: VMBuiltinFunctionIndex) -> u32 {
801        self.vmctx_builtin_functions_begin + index.index() * u32::from(self.pointer_size)
802    }
803}
804
805/// Target specific type for shared signature index.
806#[derive(Debug, Copy, Clone)]
807pub struct TargetSharedSignatureIndex(u32);
808
809impl TargetSharedSignatureIndex {
810    /// Constructs `TargetSharedSignatureIndex`.
811    pub const fn new(value: u32) -> Self {
812        Self(value)
813    }
814
815    /// Returns index value.
816    pub const fn index(self) -> u32 {
817        self.0
818    }
819}
820
821#[cfg(test)]
822mod tests {
823    use crate::vmoffsets::align;
824
825    #[test]
826    fn alignment() {
827        fn is_aligned(x: u32) -> bool {
828            x.is_multiple_of(16)
829        }
830        assert!(is_aligned(align(0, 16)));
831        assert!(is_aligned(align(32, 16)));
832        assert!(is_aligned(align(33, 16)));
833        assert!(is_aligned(align(31, 16)));
834    }
835}