1#![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#[derive(Copy, Clone, Debug)]
19pub struct VMBuiltinFunctionIndex(u32);
20
21impl VMBuiltinFunctionIndex {
22    pub const fn get_memory32_grow_index() -> Self {
24        Self(0)
25    }
26    pub const fn get_imported_memory32_grow_index() -> Self {
28        Self(1)
29    }
30    pub const fn get_memory32_size_index() -> Self {
32        Self(2)
33    }
34    pub const fn get_imported_memory32_size_index() -> Self {
36        Self(3)
37    }
38    pub const fn get_table_copy_index() -> Self {
41        Self(4)
42    }
43    pub const fn get_table_init_index() -> Self {
45        Self(5)
46    }
47    pub const fn get_elem_drop_index() -> Self {
49        Self(6)
50    }
51    pub const fn get_memory_copy_index() -> Self {
53        Self(7)
54    }
55    pub const fn get_imported_memory_copy_index() -> Self {
57        Self(8)
58    }
59    pub const fn get_memory_fill_index() -> Self {
61        Self(9)
62    }
63    pub const fn get_imported_memory_fill_index() -> Self {
65        Self(10)
66    }
67    pub const fn get_memory_init_index() -> Self {
69        Self(11)
70    }
71    pub const fn get_data_drop_index() -> Self {
73        Self(12)
74    }
75    pub const fn get_raise_trap_index() -> Self {
77        Self(13)
78    }
79    pub const fn get_table_size_index() -> Self {
81        Self(14)
82    }
83    pub const fn get_imported_table_size_index() -> Self {
85        Self(15)
86    }
87    pub const fn get_table_grow_index() -> Self {
89        Self(16)
90    }
91    pub const fn get_imported_table_grow_index() -> Self {
93        Self(17)
94    }
95    pub const fn get_table_get_index() -> Self {
97        Self(18)
98    }
99    pub const fn get_imported_table_get_index() -> Self {
101        Self(19)
102    }
103    pub const fn get_table_set_index() -> Self {
105        Self(20)
106    }
107    pub const fn get_imported_table_set_index() -> Self {
109        Self(21)
110    }
111    pub const fn get_func_ref_index() -> Self {
113        Self(22)
114    }
115    pub const fn get_table_fill_index() -> Self {
117        Self(23)
118    }
119    pub const fn get_memory_atomic_wait32_index() -> Self {
121        Self(24)
122    }
123    pub const fn get_imported_memory_atomic_wait32_index() -> Self {
125        Self(25)
126    }
127    pub const fn get_memory_atomic_wait64_index() -> Self {
129        Self(26)
130    }
131    pub const fn get_imported_memory_atomic_wait64_index() -> Self {
133        Self(27)
134    }
135    pub const fn get_memory_atomic_notify_index() -> Self {
137        Self(28)
138    }
139
140    pub const fn get_imported_memory_atomic_notify_index() -> Self {
142        Self(29)
143    }
144
145    pub const fn get_imported_debug_usize_index() -> Self {
147        Self(30)
148    }
149
150    pub const fn get_imported_debug_str_index() -> Self {
152        Self(31)
153    }
154
155    pub const fn builtin_functions_total_number() -> u32 {
157        32
158    }
159
160    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#[inline]
177const fn align(offset: u32, width: u32) -> u32 {
178    offset.div_ceil(width) * width
179}
180
181#[derive(Clone, Debug)]
184pub struct VMOffsets {
185    pointer_size: u8,
187    num_signature_ids: u32,
189    num_imported_functions: u32,
191    num_imported_tables: u32,
193    num_imported_memories: u32,
195    num_tag_ids: u32,
197    num_imported_globals: u32,
199    num_local_tables: u32,
201    num_local_memories: u32,
203    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    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    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    pub fn num_local_tables(&self) -> u32 {
293        self.num_local_tables
294    }
295
296    pub fn num_local_memories(&self) -> u32 {
298        self.num_local_memories
299    }
300
301    fn precompute(&mut self) {
302        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        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
390impl VMOffsets {
392    #[allow(clippy::erasing_op)]
394    pub const fn vmfunction_import_body(&self) -> u8 {
395        0 * self.pointer_size
396    }
397
398    #[allow(clippy::identity_op)]
400    pub const fn vmfunction_import_vmctx(&self) -> u8 {
401        1 * self.pointer_size
402    }
403
404    pub const fn vmfunction_import_handle(&self) -> u8 {
406        2 * self.pointer_size
407    }
408
409    pub const fn size_of_vmfunction_import(&self) -> u8 {
411        3 * self.pointer_size
412    }
413}
414
415impl VMOffsets {
417    #[allow(clippy::erasing_op)]
419    pub const fn vmdynamicfunction_import_context_address(&self) -> u8 {
420        0 * self.pointer_size
421    }
422
423    #[allow(clippy::identity_op)]
425    pub const fn vmdynamicfunction_import_context_ctx(&self) -> u8 {
426        1 * self.pointer_size
427    }
428
429    pub const fn size_of_vmdynamicfunction_import_context(&self) -> u8 {
431        2 * self.pointer_size
432    }
433}
434
435impl VMOffsets {
437    #[allow(clippy::identity_op)]
439    pub const fn size_of_vmfunction_body_ptr(&self) -> u8 {
440        1 * self.pointer_size
441    }
442}
443
444impl VMOffsets {
446    #[allow(clippy::erasing_op)]
448    pub const fn vmtable_import_definition(&self) -> u8 {
449        0 * self.pointer_size
450    }
451
452    #[allow(clippy::identity_op)]
454    pub const fn vmtable_import_handle(&self) -> u8 {
455        1 * self.pointer_size
456    }
457
458    pub const fn size_of_vmtable_import(&self) -> u8 {
460        2 * self.pointer_size
461    }
462}
463
464impl VMOffsets {
466    #[allow(clippy::erasing_op)]
468    pub const fn vmtable_definition_base(&self) -> u8 {
469        0 * self.pointer_size
470    }
471
472    #[allow(clippy::identity_op)]
474    pub const fn vmtable_definition_current_elements(&self) -> u8 {
475        1 * self.pointer_size
476    }
477
478    pub const fn size_of_vmtable_definition_current_elements(&self) -> u8 {
480        4
481    }
482
483    pub const fn size_of_vmtable_definition(&self) -> u8 {
485        2 * self.pointer_size
486    }
487}
488
489impl VMOffsets {
491    #[allow(clippy::erasing_op)]
493    pub const fn vmmemory_import_definition(&self) -> u8 {
494        0 * self.pointer_size
495    }
496
497    #[allow(clippy::identity_op)]
499    pub const fn vmmemory_import_handle(&self) -> u8 {
500        1 * self.pointer_size
501    }
502
503    pub const fn size_of_vmmemory_import(&self) -> u8 {
505        2 * self.pointer_size
506    }
507}
508
509impl VMOffsets {
511    #[allow(clippy::erasing_op)]
513    pub const fn vmmemory_definition_base(&self) -> u8 {
514        0 * self.pointer_size
515    }
516
517    #[allow(clippy::identity_op)]
519    pub const fn vmmemory_definition_current_length(&self) -> u8 {
520        1 * self.pointer_size
521    }
522
523    pub const fn size_of_vmmemory_definition_current_length(&self) -> u8 {
525        4
526    }
527
528    pub const fn size_of_vmmemory_definition(&self) -> u8 {
530        2 * self.pointer_size
531    }
532}
533
534impl VMOffsets {
536    #[allow(clippy::erasing_op)]
538    pub const fn vmglobal_import_definition(&self) -> u8 {
539        0 * self.pointer_size
540    }
541
542    #[allow(clippy::identity_op)]
544    pub const fn vmglobal_import_handle(&self) -> u8 {
545        1 * self.pointer_size
546    }
547
548    #[allow(clippy::identity_op)]
550    pub const fn size_of_vmglobal_import(&self) -> u8 {
551        2 * self.pointer_size
552    }
553}
554
555impl VMOffsets {
557    pub const fn size_of_vmglobal_local(&self) -> u8 {
562        self.pointer_size
563    }
564}
565
566impl VMOffsets {
568    pub const fn size_of_vmshared_signature_index(&self) -> u8 {
570        4
571    }
572}
573
574impl VMOffsets {
576    #[allow(clippy::erasing_op)]
578    pub const fn vmcaller_checked_anyfunc_func_ptr(&self) -> u8 {
579        0 * self.pointer_size
580    }
581
582    #[allow(clippy::identity_op)]
584    pub const fn vmcaller_checked_anyfunc_type_index(&self) -> u8 {
585        1 * self.pointer_size
586    }
587
588    pub const fn vmcaller_checked_anyfunc_vmctx(&self) -> u8 {
590        2 * self.pointer_size
591    }
592
593    pub const fn vmcaller_checked_anyfunc_call_trampoline(&self) -> u8 {
595        3 * self.pointer_size
596    }
597
598    pub const fn size_of_vmcaller_checked_anyfunc(&self) -> u8 {
600        4 * self.pointer_size
601    }
602}
603
604impl VMOffsets {
606    #[allow(clippy::erasing_op)]
608    pub const fn vm_funcref_anyfunc_ptr(&self) -> u8 {
609        0 * self.pointer_size
610    }
611
612    #[allow(clippy::identity_op)]
614    pub const fn size_of_vm_funcref(&self) -> u8 {
615        1 * self.pointer_size
616    }
617}
618
619impl VMOffsets {
621    pub const fn size_of_vmshared_tag_index(&self) -> u8 {
623        4
624    }
625}
626
627impl VMOffsets {
629    pub fn vmctx_signature_ids_begin(&self) -> u32 {
631        self.vmctx_signature_ids_begin
632    }
633
634    #[allow(clippy::erasing_op)]
636    pub fn vmctx_imported_functions_begin(&self) -> u32 {
637        self.vmctx_imported_functions_begin
638    }
639
640    #[allow(clippy::identity_op)]
642    pub fn vmctx_imported_tables_begin(&self) -> u32 {
643        self.vmctx_imported_tables_begin
644    }
645
646    pub fn vmctx_imported_memories_begin(&self) -> u32 {
648        self.vmctx_imported_memories_begin
649    }
650
651    pub fn vmctx_imported_globals_begin(&self) -> u32 {
653        self.vmctx_imported_globals_begin
654    }
655
656    pub fn vmctx_tag_ids_begin(&self) -> u32 {
658        self.vmctx_tag_ids_begin
659    }
660
661    pub fn vmctx_tables_begin(&self) -> u32 {
663        self.vmctx_tables_begin
664    }
665
666    pub fn vmctx_memories_begin(&self) -> u32 {
668        self.vmctx_memories_begin
669    }
670
671    pub fn vmctx_globals_begin(&self) -> u32 {
673        self.vmctx_globals_begin
674    }
675
676    pub fn vmctx_builtin_functions_begin(&self) -> u32 {
678        self.vmctx_builtin_functions_begin
679    }
680
681    pub fn size_of_vmctx(&self) -> u32 {
683        self.size_of_vmctx
684    }
685
686    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    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    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    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    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    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    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    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    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    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    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    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    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    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    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    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    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    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    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#[derive(Debug, Copy, Clone)]
807pub struct TargetSharedSignatureIndex(u32);
808
809impl TargetSharedSignatureIndex {
810    pub const fn new(value: u32) -> Self {
812        Self(value)
813    }
814
815    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}