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