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;
15
16#[derive(Copy, Clone, Debug)]
18pub struct VMBuiltinFunctionIndex(u32);
19
20impl VMBuiltinFunctionIndex {
21 pub const fn get_memory32_grow_index() -> Self {
23 Self(0)
24 }
25 pub const fn get_imported_memory32_grow_index() -> Self {
27 Self(1)
28 }
29 pub const fn get_memory32_size_index() -> Self {
31 Self(2)
32 }
33 pub const fn get_imported_memory32_size_index() -> Self {
35 Self(3)
36 }
37 pub const fn get_table_copy_index() -> Self {
40 Self(4)
41 }
42 pub const fn get_table_init_index() -> Self {
44 Self(5)
45 }
46 pub const fn get_elem_drop_index() -> Self {
48 Self(6)
49 }
50 pub const fn get_memory_copy_index() -> Self {
52 Self(7)
53 }
54 pub const fn get_imported_memory_copy_index() -> Self {
56 Self(8)
57 }
58 pub const fn get_memory_fill_index() -> Self {
60 Self(9)
61 }
62 pub const fn get_imported_memory_fill_index() -> Self {
64 Self(10)
65 }
66 pub const fn get_memory_init_index() -> Self {
68 Self(11)
69 }
70 pub const fn get_data_drop_index() -> Self {
72 Self(12)
73 }
74 pub const fn get_raise_trap_index() -> Self {
76 Self(13)
77 }
78 pub const fn get_table_size_index() -> Self {
80 Self(14)
81 }
82 pub const fn get_imported_table_size_index() -> Self {
84 Self(15)
85 }
86 pub const fn get_table_grow_index() -> Self {
88 Self(16)
89 }
90 pub const fn get_imported_table_grow_index() -> Self {
92 Self(17)
93 }
94 pub const fn get_table_get_index() -> Self {
96 Self(18)
97 }
98 pub const fn get_imported_table_get_index() -> Self {
100 Self(19)
101 }
102 pub const fn get_table_set_index() -> Self {
104 Self(20)
105 }
106 pub const fn get_imported_table_set_index() -> Self {
108 Self(21)
109 }
110 pub const fn get_func_ref_index() -> Self {
112 Self(22)
113 }
114 pub const fn get_table_fill_index() -> Self {
116 Self(23)
117 }
118 pub const fn get_memory_atomic_wait32_index() -> Self {
120 Self(24)
121 }
122 pub const fn get_imported_memory_atomic_wait32_index() -> Self {
124 Self(25)
125 }
126 pub const fn get_memory_atomic_wait64_index() -> Self {
128 Self(26)
129 }
130 pub const fn get_imported_memory_atomic_wait64_index() -> Self {
132 Self(27)
133 }
134 pub const fn get_memory_atomic_notify_index() -> Self {
136 Self(28)
137 }
138
139 pub const fn get_imported_memory_atomic_notify_index() -> Self {
141 Self(29)
142 }
143
144 pub const fn get_imported_debug_usize_index() -> Self {
146 Self(30)
147 }
148
149 pub const fn get_imported_debug_str_index() -> Self {
151 Self(31)
152 }
153
154 pub const fn get_imported_personality2_index() -> Self {
156 Self(32)
157 }
158
159 pub const fn get_imported_alloc_exception_index() -> Self {
161 Self(33)
162 }
163
164 pub const fn get_imported_throw_index() -> Self {
166 Self(34)
167 }
168
169 pub const fn get_imported_read_exnref_index() -> Self {
171 Self(35)
172 }
173
174 pub const fn get_imported_exception_into_exnref_index() -> Self {
176 Self(36)
177 }
178
179 pub const fn builtin_functions_total_number() -> u32 {
181 37
182 }
183
184 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#[inline]
201const fn align(offset: u32, width: u32) -> u32 {
202 offset.div_ceil(width) * width
203}
204
205#[derive(Clone, Debug)]
208pub struct VMOffsets {
209 pointer_size: u8,
211 num_signature_ids: u32,
213 num_imported_functions: u32,
215 num_imported_tables: u32,
217 num_imported_memories: u32,
219 num_tag_ids: u32,
221 num_imported_globals: u32,
223 num_local_tables: u32,
225 num_local_memories: u32,
227 num_local_globals: u32,
229
230 vmctx_signature_ids_begin: u32,
231 vmctx_imported_functions_begin: u32,
232 vmctx_imported_tables_begin: u32,
233 vmctx_imported_memories_begin: u32,
234 vmctx_tag_ids_begin: u32,
235 vmctx_imported_globals_begin: u32,
236 vmctx_tables_begin: u32,
237 vmctx_memories_begin: u32,
238 vmctx_globals_begin: u32,
239 vmctx_builtin_functions_begin: u32,
240 vmctx_trap_handler_begin: u32,
241 vmctx_gas_limiter_pointer: u32,
242 vmctx_stack_limit_begin: u32,
243 vmctx_stack_limit_initial_begin: u32,
244 size_of_vmctx: u32,
245}
246
247impl VMOffsets {
248 pub fn new(pointer_size: u8, module: &ModuleInfo) -> Self {
250 let mut ret = Self {
251 pointer_size,
252 num_signature_ids: cast_to_u32(module.signatures.len()),
253 num_imported_functions: cast_to_u32(module.num_imported_functions),
254 num_imported_tables: cast_to_u32(module.num_imported_tables),
255 num_imported_memories: cast_to_u32(module.num_imported_memories),
256 num_tag_ids: cast_to_u32(module.tags.len()),
257 num_imported_globals: cast_to_u32(module.num_imported_globals),
258 num_local_tables: cast_to_u32(module.tables.len()),
259 num_local_memories: cast_to_u32(module.memories.len()),
260 num_local_globals: cast_to_u32(module.globals.len()),
261 vmctx_signature_ids_begin: 0,
262 vmctx_imported_functions_begin: 0,
263 vmctx_imported_tables_begin: 0,
264 vmctx_imported_memories_begin: 0,
265 vmctx_tag_ids_begin: 0,
266 vmctx_imported_globals_begin: 0,
267 vmctx_tables_begin: 0,
268 vmctx_memories_begin: 0,
269 vmctx_globals_begin: 0,
270 vmctx_builtin_functions_begin: 0,
271 vmctx_trap_handler_begin: 0,
272 vmctx_gas_limiter_pointer: 0,
273 vmctx_stack_limit_begin: 0,
274 vmctx_stack_limit_initial_begin: 0,
275 size_of_vmctx: 0,
276 };
277 ret.precompute();
278 ret
279 }
280
281 pub fn new_for_trampolines(pointer_size: u8) -> Self {
286 Self {
287 pointer_size,
288 num_signature_ids: 0,
289 num_imported_functions: 0,
290 num_imported_tables: 0,
291 num_imported_memories: 0,
292 num_tag_ids: 0,
293 num_imported_globals: 0,
294 num_local_tables: 0,
295 num_local_memories: 0,
296 num_local_globals: 0,
297 vmctx_signature_ids_begin: 0,
298 vmctx_imported_functions_begin: 0,
299 vmctx_imported_tables_begin: 0,
300 vmctx_imported_memories_begin: 0,
301 vmctx_tag_ids_begin: 0,
302 vmctx_imported_globals_begin: 0,
303 vmctx_tables_begin: 0,
304 vmctx_memories_begin: 0,
305 vmctx_globals_begin: 0,
306 vmctx_builtin_functions_begin: 0,
307 vmctx_trap_handler_begin: 0,
308 vmctx_gas_limiter_pointer: 0,
309 vmctx_stack_limit_begin: 0,
310 vmctx_stack_limit_initial_begin: 0,
311 size_of_vmctx: 0,
312 }
313 }
314
315 pub fn num_local_tables(&self) -> u32 {
317 self.num_local_tables
318 }
319
320 pub fn num_local_memories(&self) -> u32 {
322 self.num_local_memories
323 }
324
325 fn precompute(&mut self) {
326 fn offset_by(base: u32, num_items: u32, item_size: u32) -> u32 {
328 base.checked_add(num_items.checked_mul(item_size).unwrap())
329 .unwrap()
330 }
331 let pointer_size = self.pointer_size as u32;
335 let offset_by_aligned = |base: u32, num_items: u32, item_size: u32| -> u32 {
336 align(
337 base.checked_add(num_items.checked_mul(item_size).unwrap())
338 .unwrap(),
339 pointer_size,
340 )
341 };
342
343 self.vmctx_signature_ids_begin = 0;
344 self.vmctx_imported_functions_begin = offset_by_aligned(
345 self.vmctx_signature_ids_begin,
346 self.num_signature_ids,
347 u32::from(self.size_of_vmshared_signature_index()),
348 );
349 self.vmctx_imported_tables_begin = offset_by_aligned(
350 self.vmctx_imported_functions_begin,
351 self.num_imported_functions,
352 u32::from(self.size_of_vmfunction_import()),
353 );
354 self.vmctx_imported_memories_begin = offset_by_aligned(
355 self.vmctx_imported_tables_begin,
356 self.num_imported_tables,
357 u32::from(self.size_of_vmtable_import()),
358 );
359
360 self.vmctx_tag_ids_begin = offset_by_aligned(
361 self.vmctx_imported_memories_begin,
362 self.num_imported_memories,
363 u32::from(self.size_of_vmmemory_import()),
364 );
365
366 self.vmctx_imported_globals_begin = offset_by_aligned(
367 self.vmctx_tag_ids_begin,
368 self.num_tag_ids,
369 u32::from(self.size_of_vmshared_tag_index()),
370 );
371
372 self.vmctx_tables_begin = offset_by_aligned(
373 self.vmctx_imported_globals_begin,
374 self.num_imported_globals,
375 u32::from(self.size_of_vmglobal_import()),
376 );
377 self.vmctx_memories_begin = offset_by_aligned(
378 self.vmctx_tables_begin,
379 self.num_local_tables,
380 u32::from(self.size_of_vmtable_definition()),
381 );
382 self.vmctx_globals_begin = align(
383 offset_by(
384 self.vmctx_memories_begin,
385 self.num_local_memories,
386 u32::from(self.size_of_vmmemory_definition()),
387 ),
388 16,
389 );
390 self.vmctx_builtin_functions_begin = offset_by(
391 self.vmctx_globals_begin,
392 self.num_local_globals,
393 u32::from(self.size_of_vmglobal_local()),
394 );
395 self.vmctx_trap_handler_begin = offset_by(
396 self.vmctx_builtin_functions_begin,
397 VMBuiltinFunctionIndex::builtin_functions_total_number(),
398 u32::from(self.pointer_size),
399 );
400 self.vmctx_gas_limiter_pointer = offset_by(
401 self.vmctx_trap_handler_begin,
402 1,
403 u32::from(self.pointer_size),
404 );
405 self.vmctx_stack_limit_begin = offset_by(
406 self.vmctx_gas_limiter_pointer,
407 1,
408 u32::from(self.pointer_size),
409 );
410 self.vmctx_stack_limit_initial_begin = self.vmctx_stack_limit_begin.checked_add(4).unwrap();
411 self.size_of_vmctx = self.vmctx_stack_limit_begin.checked_add(4).unwrap();
412 }
413}
414
415impl VMOffsets {
417 #[allow(clippy::erasing_op)]
419 pub const fn vmfunction_import_body(&self) -> u8 {
420 0 * self.pointer_size
421 }
422
423 #[allow(clippy::identity_op)]
425 pub const fn vmfunction_import_vmctx(&self) -> u8 {
426 1 * self.pointer_size
427 }
428
429 pub const fn vmfunction_import_handle(&self) -> u8 {
431 2 * self.pointer_size
432 }
433
434 pub const fn vmfunction_import_include_m0_param(&self) -> u8 {
436 3 * self.pointer_size
437 }
438
439 pub const fn size_of_vmfunction_import(&self) -> u8 {
441 4 * self.pointer_size
442 }
443}
444
445impl VMOffsets {
447 #[allow(clippy::erasing_op)]
449 pub const fn vmdynamicfunction_import_context_address(&self) -> u8 {
450 0 * self.pointer_size
451 }
452
453 #[allow(clippy::identity_op)]
455 pub const fn vmdynamicfunction_import_context_ctx(&self) -> u8 {
456 1 * self.pointer_size
457 }
458
459 pub const fn size_of_vmdynamicfunction_import_context(&self) -> u8 {
461 2 * self.pointer_size
462 }
463}
464
465impl VMOffsets {
467 #[allow(clippy::identity_op)]
469 pub const fn size_of_vmfunction_body_ptr(&self) -> u8 {
470 1 * self.pointer_size
471 }
472}
473
474impl VMOffsets {
476 #[allow(clippy::erasing_op)]
478 pub const fn vmtable_import_definition(&self) -> u8 {
479 0 * self.pointer_size
480 }
481
482 #[allow(clippy::identity_op)]
484 pub const fn vmtable_import_handle(&self) -> u8 {
485 1 * self.pointer_size
486 }
487
488 pub const fn size_of_vmtable_import(&self) -> u8 {
490 2 * self.pointer_size
491 }
492}
493
494impl VMOffsets {
496 #[allow(clippy::erasing_op)]
498 pub const fn vmtable_definition_base(&self) -> u8 {
499 0 * self.pointer_size
500 }
501
502 #[allow(clippy::identity_op)]
504 pub const fn vmtable_definition_current_elements(&self) -> u8 {
505 1 * self.pointer_size
506 }
507
508 pub const fn size_of_vmtable_definition_current_elements(&self) -> u8 {
510 4
511 }
512
513 pub const fn size_of_vmtable_definition(&self) -> u8 {
515 2 * self.pointer_size
516 }
517}
518
519impl VMOffsets {
521 #[allow(clippy::erasing_op)]
523 pub const fn vmmemory_import_definition(&self) -> u8 {
524 0 * self.pointer_size
525 }
526
527 #[allow(clippy::identity_op)]
529 pub const fn vmmemory_import_handle(&self) -> u8 {
530 1 * self.pointer_size
531 }
532
533 pub const fn size_of_vmmemory_import(&self) -> u8 {
535 2 * self.pointer_size
536 }
537}
538
539impl VMOffsets {
541 #[allow(clippy::erasing_op)]
543 pub const fn vmmemory_definition_base(&self) -> u8 {
544 0 * self.pointer_size
545 }
546
547 #[allow(clippy::identity_op)]
549 pub const fn vmmemory_definition_current_length(&self) -> u8 {
550 1 * self.pointer_size
551 }
552
553 pub const fn size_of_vmmemory_definition_current_length(&self) -> u8 {
555 4
556 }
557
558 pub const fn size_of_vmmemory_definition(&self) -> u8 {
560 2 * self.pointer_size
561 }
562}
563
564impl VMOffsets {
566 #[allow(clippy::erasing_op)]
568 pub const fn vmglobal_import_definition(&self) -> u8 {
569 0 * self.pointer_size
570 }
571
572 #[allow(clippy::identity_op)]
574 pub const fn vmglobal_import_handle(&self) -> u8 {
575 1 * self.pointer_size
576 }
577
578 #[allow(clippy::identity_op)]
580 pub const fn size_of_vmglobal_import(&self) -> u8 {
581 2 * self.pointer_size
582 }
583}
584
585impl VMOffsets {
587 pub const fn size_of_vmglobal_local(&self) -> u8 {
592 self.pointer_size
593 }
594}
595
596impl VMOffsets {
598 pub const fn size_of_vmshared_signature_index(&self) -> u8 {
600 4
601 }
602}
603
604impl VMOffsets {
606 #[allow(clippy::erasing_op)]
608 pub const fn vmcaller_checked_anyfunc_func_ptr(&self) -> u8 {
609 0 * self.pointer_size
610 }
611
612 #[allow(clippy::identity_op)]
614 pub const fn vmcaller_checked_anyfunc_type_index(&self) -> u8 {
615 1 * self.pointer_size
616 }
617
618 pub const fn vmcaller_checked_anyfunc_vmctx(&self) -> u8 {
620 2 * self.pointer_size
621 }
622
623 pub const fn vmcaller_checked_anyfunc_call_trampoline(&self) -> u8 {
625 3 * self.pointer_size
626 }
627
628 pub const fn size_of_vmcaller_checked_anyfunc(&self) -> u8 {
630 4 * self.pointer_size
631 }
632}
633
634impl VMOffsets {
636 #[allow(clippy::erasing_op)]
638 pub const fn vm_funcref_anyfunc_ptr(&self) -> u8 {
639 0 * self.pointer_size
640 }
641
642 #[allow(clippy::identity_op)]
644 pub const fn size_of_vm_funcref(&self) -> u8 {
645 1 * self.pointer_size
646 }
647}
648
649impl VMOffsets {
651 pub const fn size_of_vmshared_tag_index(&self) -> u8 {
653 4
654 }
655}
656
657impl VMOffsets {
659 pub fn vmctx_signature_ids_begin(&self) -> u32 {
661 self.vmctx_signature_ids_begin
662 }
663
664 #[allow(clippy::erasing_op)]
666 pub fn vmctx_imported_functions_begin(&self) -> u32 {
667 self.vmctx_imported_functions_begin
668 }
669
670 #[allow(clippy::identity_op)]
672 pub fn vmctx_imported_tables_begin(&self) -> u32 {
673 self.vmctx_imported_tables_begin
674 }
675
676 pub fn vmctx_imported_memories_begin(&self) -> u32 {
678 self.vmctx_imported_memories_begin
679 }
680
681 pub fn vmctx_imported_globals_begin(&self) -> u32 {
683 self.vmctx_imported_globals_begin
684 }
685
686 pub fn vmctx_tag_ids_begin(&self) -> u32 {
688 self.vmctx_tag_ids_begin
689 }
690
691 pub fn vmctx_tables_begin(&self) -> u32 {
693 self.vmctx_tables_begin
694 }
695
696 pub fn vmctx_memories_begin(&self) -> u32 {
698 self.vmctx_memories_begin
699 }
700
701 pub fn vmctx_globals_begin(&self) -> u32 {
703 self.vmctx_globals_begin
704 }
705
706 pub fn vmctx_builtin_functions_begin(&self) -> u32 {
708 self.vmctx_builtin_functions_begin
709 }
710
711 pub fn size_of_vmctx(&self) -> u32 {
713 self.size_of_vmctx
714 }
715
716 pub fn vmctx_vmshared_signature_id(&self, index: SignatureIndex) -> u32 {
718 assert_lt!(index.as_u32(), self.num_signature_ids);
719 self.vmctx_signature_ids_begin
720 + index.as_u32() * u32::from(self.size_of_vmshared_signature_index())
721 }
722
723 pub fn vmctx_vmfunction_import(&self, index: FunctionIndex) -> u32 {
725 assert_lt!(index.as_u32(), self.num_imported_functions);
726 self.vmctx_imported_functions_begin
727 + index.as_u32() * u32::from(self.size_of_vmfunction_import())
728 }
729
730 pub fn vmctx_vmtable_import(&self, index: TableIndex) -> u32 {
732 assert_lt!(index.as_u32(), self.num_imported_tables);
733 self.vmctx_imported_tables_begin + index.as_u32() * u32::from(self.size_of_vmtable_import())
734 }
735
736 pub fn vmctx_vmmemory_import(&self, index: MemoryIndex) -> u32 {
738 assert_lt!(index.as_u32(), self.num_imported_memories);
739 self.vmctx_imported_memories_begin
740 + index.as_u32() * u32::from(self.size_of_vmmemory_import())
741 }
742
743 pub fn vmctx_vmglobal_import(&self, index: GlobalIndex) -> u32 {
745 assert_lt!(index.as_u32(), self.num_imported_globals);
746 self.vmctx_imported_globals_begin
747 + index.as_u32() * u32::from(self.size_of_vmglobal_import())
748 }
749
750 pub fn vmctx_vmtable_definition(&self, index: LocalTableIndex) -> u32 {
752 assert_lt!(index.as_u32(), self.num_local_tables);
753 self.vmctx_tables_begin + index.as_u32() * u32::from(self.size_of_vmtable_definition())
754 }
755
756 pub fn vmctx_vmmemory_definition(&self, index: LocalMemoryIndex) -> u32 {
758 assert_lt!(index.as_u32(), self.num_local_memories);
759 self.vmctx_memories_begin + index.as_u32() * u32::from(self.size_of_vmmemory_definition())
760 }
761
762 pub fn vmctx_vmglobal_definition(&self, index: LocalGlobalIndex) -> u32 {
764 assert_lt!(index.as_u32(), self.num_local_globals);
765 self.vmctx_globals_begin + index.as_u32() * u32::from(self.size_of_vmglobal_local())
766 }
767
768 pub fn vmctx_vmfunction_import_body(&self, index: FunctionIndex) -> u32 {
771 self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_body())
772 }
773
774 pub fn vmctx_vmfunction_import_vmctx(&self, index: FunctionIndex) -> u32 {
777 self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_vmctx())
778 }
779
780 pub fn vmctx_vmtable_import_definition(&self, index: TableIndex) -> u32 {
783 self.vmctx_vmtable_import(index) + u32::from(self.vmtable_import_definition())
784 }
785
786 pub fn vmctx_vmtable_definition_base(&self, index: LocalTableIndex) -> u32 {
789 self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_base())
790 }
791
792 pub fn vmctx_vmtable_definition_current_elements(&self, index: LocalTableIndex) -> u32 {
795 self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_current_elements())
796 }
797
798 pub fn vmctx_vmmemory_import_definition(&self, index: MemoryIndex) -> u32 {
801 self.vmctx_vmmemory_import(index) + u32::from(self.vmmemory_import_definition())
802 }
803
804 pub fn vmctx_vmmemory_import_handle(&self, index: MemoryIndex) -> u32 {
807 self.vmctx_vmmemory_import(index) + u32::from(self.vmmemory_import_handle())
808 }
809
810 pub fn vmctx_vmmemory_definition_base(&self, index: LocalMemoryIndex) -> u32 {
813 self.vmctx_vmmemory_definition(index) + u32::from(self.vmmemory_definition_base())
814 }
815
816 pub fn vmctx_vmmemory_definition_current_length(&self, index: LocalMemoryIndex) -> u32 {
819 self.vmctx_vmmemory_definition(index) + u32::from(self.vmmemory_definition_current_length())
820 }
821
822 pub fn vmctx_vmglobal_import_definition(&self, index: GlobalIndex) -> u32 {
825 self.vmctx_vmglobal_import(index) + u32::from(self.vmglobal_import_definition())
826 }
827
828 pub fn vmctx_builtin_function(&self, index: VMBuiltinFunctionIndex) -> u32 {
831 self.vmctx_builtin_functions_begin + index.index() * u32::from(self.pointer_size)
832 }
833}
834
835#[derive(Debug, Copy, Clone)]
837pub struct TargetSharedSignatureIndex(u32);
838
839impl TargetSharedSignatureIndex {
840 pub const fn new(value: u32) -> Self {
842 Self(value)
843 }
844
845 pub const fn index(self) -> u32 {
847 self.0
848 }
849}
850
851#[cfg(test)]
852mod tests {
853 use crate::vmoffsets::align;
854
855 #[test]
856 fn alignment() {
857 fn is_aligned(x: u32) -> bool {
858 x.is_multiple_of(16)
859 }
860 assert!(is_aligned(align(0, 16)));
861 assert!(is_aligned(align(32, 16)));
862 assert!(is_aligned(align(33, 16)));
863 assert!(is_aligned(align(31, 16)));
864 }
865}