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