1#![deny(rustdoc::broken_intra_doc_links)]
8
9use crate::{
10 FunctionIndex, GlobalIndex, LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryIndex,
11 ModuleInfo, SignatureIndex, TableIndex, TagIndex,
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_throw_index() -> Self {
147 Self(30)
148 }
149
150 pub const fn get_imported_rethrow_index() -> Self {
152 Self(31)
153 }
154
155 pub const fn get_imported_alloc_exception_index() -> Self {
157 Self(32)
158 }
159
160 pub const fn get_imported_delete_exception_index() -> Self {
162 Self(33)
163 }
164
165 pub const fn get_imported_read_exception_index() -> Self {
167 Self(34)
168 }
169
170 pub const fn get_imported_debug_usize_index() -> Self {
172 Self(35)
173 }
174
175 pub const fn builtin_functions_total_number() -> u32 {
177 36
178 }
179
180 pub const fn index(self) -> u32 {
182 self.0
183 }
184}
185
186#[cfg(target_pointer_width = "32")]
187fn cast_to_u32(sz: usize) -> u32 {
188 u32::try_from(sz).unwrap()
189}
190#[cfg(target_pointer_width = "64")]
191fn cast_to_u32(sz: usize) -> u32 {
192 u32::try_from(sz).expect("overflow in cast from usize to u32")
193}
194
195#[inline]
197const fn align(offset: u32, width: u32) -> u32 {
198 (offset + (width - 1)) / width * width
199}
200
201#[derive(Clone, Debug)]
204pub struct VMOffsets {
205 pointer_size: u8,
207 num_signature_ids: u32,
209 num_imported_functions: u32,
211 num_imported_tables: u32,
213 num_imported_memories: u32,
215 num_imported_tags: u32,
217 num_imported_globals: u32,
219 num_local_tables: u32,
221 num_local_memories: u32,
223 num_local_globals: u32,
225
226 vmctx_signature_ids_begin: u32,
227 vmctx_imported_functions_begin: u32,
228 vmctx_imported_tables_begin: u32,
229 vmctx_imported_memories_begin: u32,
230 vmctx_imported_tags_begin: u32,
231 vmctx_imported_globals_begin: u32,
232 vmctx_tables_begin: u32,
233 vmctx_memories_begin: u32,
234 vmctx_globals_begin: u32,
235 vmctx_builtin_functions_begin: u32,
236 vmctx_trap_handler_begin: u32,
237 vmctx_gas_limiter_pointer: u32,
238 vmctx_stack_limit_begin: u32,
239 vmctx_stack_limit_initial_begin: u32,
240 size_of_vmctx: u32,
241}
242
243impl VMOffsets {
244 pub fn new(pointer_size: u8, module: &ModuleInfo) -> Self {
246 let mut ret = Self {
247 pointer_size,
248 num_signature_ids: cast_to_u32(module.signatures.len()),
249 num_imported_functions: cast_to_u32(module.num_imported_functions),
250 num_imported_tables: cast_to_u32(module.num_imported_tables),
251 num_imported_memories: cast_to_u32(module.num_imported_memories),
252 num_imported_tags: cast_to_u32(module.num_imported_tags),
253 num_imported_globals: cast_to_u32(module.num_imported_globals),
254 num_local_tables: cast_to_u32(module.tables.len()),
255 num_local_memories: cast_to_u32(module.memories.len()),
256 num_local_globals: cast_to_u32(module.globals.len()),
257 vmctx_signature_ids_begin: 0,
258 vmctx_imported_functions_begin: 0,
259 vmctx_imported_tables_begin: 0,
260 vmctx_imported_memories_begin: 0,
261 vmctx_imported_tags_begin: 0,
262 vmctx_imported_globals_begin: 0,
263 vmctx_tables_begin: 0,
264 vmctx_memories_begin: 0,
265 vmctx_globals_begin: 0,
266 vmctx_builtin_functions_begin: 0,
267 vmctx_trap_handler_begin: 0,
268 vmctx_gas_limiter_pointer: 0,
269 vmctx_stack_limit_begin: 0,
270 vmctx_stack_limit_initial_begin: 0,
271 size_of_vmctx: 0,
272 };
273 ret.precompute();
274 ret
275 }
276
277 pub fn new_for_trampolines(pointer_size: u8) -> Self {
282 Self {
283 pointer_size,
284 num_signature_ids: 0,
285 num_imported_functions: 0,
286 num_imported_tables: 0,
287 num_imported_memories: 0,
288 num_imported_tags: 0,
289 num_imported_globals: 0,
290 num_local_tables: 0,
291 num_local_memories: 0,
292 num_local_globals: 0,
293 vmctx_signature_ids_begin: 0,
294 vmctx_imported_functions_begin: 0,
295 vmctx_imported_tables_begin: 0,
296 vmctx_imported_memories_begin: 0,
297 vmctx_imported_tags_begin: 0,
298 vmctx_imported_globals_begin: 0,
299 vmctx_tables_begin: 0,
300 vmctx_memories_begin: 0,
301 vmctx_globals_begin: 0,
302 vmctx_builtin_functions_begin: 0,
303 vmctx_trap_handler_begin: 0,
304 vmctx_gas_limiter_pointer: 0,
305 vmctx_stack_limit_begin: 0,
306 vmctx_stack_limit_initial_begin: 0,
307 size_of_vmctx: 0,
308 }
309 }
310
311 pub fn num_local_tables(&self) -> u32 {
313 self.num_local_tables
314 }
315
316 pub fn num_local_memories(&self) -> u32 {
318 self.num_local_memories
319 }
320
321 fn precompute(&mut self) {
322 fn offset_by(base: u32, num_items: u32, item_size: u32) -> u32 {
324 base.checked_add(num_items.checked_mul(item_size).unwrap())
325 .unwrap()
326 }
327 fn offset_by_aligned(base: u32, num_items: u32, item_size: u32) -> u32 {
331 align(
332 base.checked_add(num_items.checked_mul(item_size).unwrap())
333 .unwrap(),
334 size_of::<&u32>() as u32,
335 )
336 }
337
338 self.vmctx_signature_ids_begin = 0;
339 self.vmctx_imported_functions_begin = offset_by_aligned(
340 self.vmctx_signature_ids_begin,
341 self.num_signature_ids,
342 u32::from(self.size_of_vmshared_signature_index()),
343 );
344 self.vmctx_imported_tables_begin = offset_by_aligned(
345 self.vmctx_imported_functions_begin,
346 self.num_imported_functions,
347 u32::from(self.size_of_vmfunction_import()),
348 );
349 self.vmctx_imported_memories_begin = offset_by_aligned(
350 self.vmctx_imported_tables_begin,
351 self.num_imported_tables,
352 u32::from(self.size_of_vmtable_import()),
353 );
354
355 self.vmctx_imported_tags_begin = offset_by_aligned(
356 self.vmctx_imported_memories_begin,
357 self.num_imported_memories,
358 u32::from(self.size_of_vmmemory_import()),
359 );
360
361 self.vmctx_imported_globals_begin = offset_by_aligned(
362 self.vmctx_imported_tags_begin,
363 self.num_imported_tags,
364 u32::from(self.size_of_vmtag_import()),
365 );
366
367 self.vmctx_tables_begin = offset_by_aligned(
368 self.vmctx_imported_globals_begin,
369 self.num_imported_globals,
370 u32::from(self.size_of_vmglobal_import()),
371 );
372 self.vmctx_memories_begin = offset_by_aligned(
373 self.vmctx_tables_begin,
374 self.num_local_tables,
375 u32::from(self.size_of_vmtable_definition()),
376 );
377 self.vmctx_globals_begin = align(
378 offset_by(
379 self.vmctx_memories_begin,
380 self.num_local_memories,
381 u32::from(self.size_of_vmmemory_definition()),
382 ),
383 16,
384 );
385 self.vmctx_builtin_functions_begin = offset_by(
386 self.vmctx_globals_begin,
387 self.num_local_globals,
388 u32::from(self.size_of_vmglobal_local()),
389 );
390 self.vmctx_trap_handler_begin = offset_by(
391 self.vmctx_builtin_functions_begin,
392 VMBuiltinFunctionIndex::builtin_functions_total_number(),
393 u32::from(self.pointer_size),
394 );
395 self.vmctx_gas_limiter_pointer = offset_by(
396 self.vmctx_trap_handler_begin,
397 1,
398 u32::from(self.pointer_size),
399 );
400 self.vmctx_stack_limit_begin = offset_by(
401 self.vmctx_gas_limiter_pointer,
402 1,
403 u32::from(self.pointer_size),
404 );
405 self.vmctx_stack_limit_initial_begin = self.vmctx_stack_limit_begin.checked_add(4).unwrap();
406 self.size_of_vmctx = self.vmctx_stack_limit_begin.checked_add(4).unwrap();
407 }
408}
409
410impl VMOffsets {
412 #[allow(clippy::erasing_op)]
414 pub const fn vmfunction_import_body(&self) -> u8 {
415 0 * self.pointer_size
416 }
417
418 #[allow(clippy::identity_op)]
420 pub const fn vmfunction_import_vmctx(&self) -> u8 {
421 1 * self.pointer_size
422 }
423
424 pub const fn vmfunction_import_handle(&self) -> u8 {
426 2 * self.pointer_size
427 }
428
429 pub const fn size_of_vmfunction_import(&self) -> u8 {
431 3 * self.pointer_size
432 }
433}
434
435impl VMOffsets {
437 #[allow(clippy::erasing_op)]
439 pub const fn vmdynamicfunction_import_context_address(&self) -> u8 {
440 0 * self.pointer_size
441 }
442
443 #[allow(clippy::identity_op)]
445 pub const fn vmdynamicfunction_import_context_ctx(&self) -> u8 {
446 1 * self.pointer_size
447 }
448
449 pub const fn size_of_vmdynamicfunction_import_context(&self) -> u8 {
451 2 * self.pointer_size
452 }
453}
454
455impl VMOffsets {
457 #[allow(clippy::identity_op)]
459 pub const fn size_of_vmfunction_body_ptr(&self) -> u8 {
460 1 * self.pointer_size
461 }
462}
463
464impl VMOffsets {
466 #[allow(clippy::erasing_op)]
468 pub const fn vmtable_import_definition(&self) -> u8 {
469 0 * self.pointer_size
470 }
471
472 #[allow(clippy::identity_op)]
474 pub const fn vmtable_import_handle(&self) -> u8 {
475 1 * self.pointer_size
476 }
477
478 pub const fn size_of_vmtable_import(&self) -> u8 {
480 2 * self.pointer_size
481 }
482}
483
484impl VMOffsets {
486 #[allow(clippy::erasing_op)]
488 pub const fn vmtable_definition_base(&self) -> u8 {
489 0 * self.pointer_size
490 }
491
492 #[allow(clippy::identity_op)]
494 pub const fn vmtable_definition_current_elements(&self) -> u8 {
495 1 * self.pointer_size
496 }
497
498 pub const fn size_of_vmtable_definition_current_elements(&self) -> u8 {
500 4
501 }
502
503 pub const fn size_of_vmtable_definition(&self) -> u8 {
505 2 * self.pointer_size
506 }
507}
508
509impl VMOffsets {
511 #[allow(clippy::erasing_op)]
513 pub const fn vmmemory_import_definition(&self) -> u8 {
514 0 * self.pointer_size
515 }
516
517 #[allow(clippy::identity_op)]
519 pub const fn vmmemory_import_handle(&self) -> u8 {
520 1 * self.pointer_size
521 }
522
523 pub const fn size_of_vmmemory_import(&self) -> u8 {
525 2 * self.pointer_size
526 }
527}
528
529impl VMOffsets {
531 #[allow(clippy::erasing_op)]
533 pub const fn vmmemory_definition_base(&self) -> u8 {
534 0 * self.pointer_size
535 }
536
537 #[allow(clippy::identity_op)]
539 pub const fn vmmemory_definition_current_length(&self) -> u8 {
540 1 * self.pointer_size
541 }
542
543 pub const fn size_of_vmmemory_definition_current_length(&self) -> u8 {
545 4
546 }
547
548 pub const fn size_of_vmmemory_definition(&self) -> u8 {
550 2 * self.pointer_size
551 }
552}
553
554impl VMOffsets {
556 #[allow(clippy::erasing_op)]
558 pub const fn vmglobal_import_definition(&self) -> u8 {
559 0 * self.pointer_size
560 }
561
562 #[allow(clippy::identity_op)]
564 pub const fn vmglobal_import_handle(&self) -> u8 {
565 1 * self.pointer_size
566 }
567
568 #[allow(clippy::identity_op)]
570 pub const fn size_of_vmglobal_import(&self) -> u8 {
571 2 * self.pointer_size
572 }
573}
574
575impl VMOffsets {
577 pub const fn size_of_vmglobal_local(&self) -> u8 {
582 self.pointer_size
583 }
584}
585
586impl VMOffsets {
588 pub const fn size_of_vmshared_signature_index(&self) -> u8 {
590 4
591 }
592}
593
594impl VMOffsets {
596 #[allow(clippy::erasing_op)]
598 pub const fn vmcaller_checked_anyfunc_func_ptr(&self) -> u8 {
599 0 * self.pointer_size
600 }
601
602 #[allow(clippy::identity_op)]
604 pub const fn vmcaller_checked_anyfunc_type_index(&self) -> u8 {
605 1 * self.pointer_size
606 }
607
608 pub const fn vmcaller_checked_anyfunc_vmctx(&self) -> u8 {
610 2 * self.pointer_size
611 }
612
613 pub const fn vmcaller_checked_anyfunc_call_trampoline(&self) -> u8 {
615 3 * self.pointer_size
616 }
617
618 pub const fn size_of_vmcaller_checked_anyfunc(&self) -> u8 {
620 4 * self.pointer_size
621 }
622}
623
624impl VMOffsets {
626 #[allow(clippy::erasing_op)]
628 pub const fn vm_funcref_anyfunc_ptr(&self) -> u8 {
629 0 * self.pointer_size
630 }
631
632 #[allow(clippy::identity_op)]
634 pub const fn size_of_vm_funcref(&self) -> u8 {
635 1 * self.pointer_size
636 }
637}
638
639impl VMOffsets {
641 #[allow(clippy::identity_op)]
643 pub const fn size_of_vmtag_import(&self) -> u8 {
644 1 * self.pointer_size
645 }
646}
647
648impl VMOffsets {
650 pub fn vmctx_signature_ids_begin(&self) -> u32 {
652 self.vmctx_signature_ids_begin
653 }
654
655 #[allow(clippy::erasing_op)]
657 pub fn vmctx_imported_functions_begin(&self) -> u32 {
658 self.vmctx_imported_functions_begin
659 }
660
661 #[allow(clippy::identity_op)]
663 pub fn vmctx_imported_tables_begin(&self) -> u32 {
664 self.vmctx_imported_tables_begin
665 }
666
667 pub fn vmctx_imported_memories_begin(&self) -> u32 {
669 self.vmctx_imported_memories_begin
670 }
671
672 pub fn vmctx_imported_globals_begin(&self) -> u32 {
674 self.vmctx_imported_globals_begin
675 }
676
677 pub fn vmctx_imported_tags_begin(&self) -> u32 {
679 self.vmctx_imported_tags_begin
680 }
681
682 pub fn vmctx_tables_begin(&self) -> u32 {
684 self.vmctx_tables_begin
685 }
686
687 pub fn vmctx_memories_begin(&self) -> u32 {
689 self.vmctx_memories_begin
690 }
691
692 pub fn vmctx_globals_begin(&self) -> u32 {
694 self.vmctx_globals_begin
695 }
696
697 pub fn vmctx_builtin_functions_begin(&self) -> u32 {
699 self.vmctx_builtin_functions_begin
700 }
701
702 pub fn size_of_vmctx(&self) -> u32 {
704 self.size_of_vmctx
705 }
706
707 pub fn vmctx_vmshared_signature_id(&self, index: SignatureIndex) -> u32 {
709 assert_lt!(index.as_u32(), self.num_signature_ids);
710 self.vmctx_signature_ids_begin
711 + index.as_u32() * u32::from(self.size_of_vmshared_signature_index())
712 }
713
714 pub fn vmctx_vmfunction_import(&self, index: FunctionIndex) -> u32 {
716 assert_lt!(index.as_u32(), self.num_imported_functions);
717 self.vmctx_imported_functions_begin
718 + index.as_u32() * u32::from(self.size_of_vmfunction_import())
719 }
720
721 pub fn vmctx_vmtable_import(&self, index: TableIndex) -> u32 {
723 assert_lt!(index.as_u32(), self.num_imported_tables);
724 self.vmctx_imported_tables_begin + index.as_u32() * u32::from(self.size_of_vmtable_import())
725 }
726
727 pub fn vmctx_vmmemory_import(&self, index: MemoryIndex) -> u32 {
729 assert_lt!(index.as_u32(), self.num_imported_memories);
730 self.vmctx_imported_memories_begin
731 + index.as_u32() * u32::from(self.size_of_vmmemory_import())
732 }
733
734 pub fn vmctx_vmtag_import(&self, index: TagIndex) -> u32 {
736 assert_lt!(index.as_u32(), self.num_imported_tags);
737 self.vmctx_imported_tags_begin + index.as_u32() * u32::from(self.size_of_vmtag_import())
738 }
739
740 pub fn vmctx_vmglobal_import(&self, index: GlobalIndex) -> u32 {
742 assert_lt!(index.as_u32(), self.num_imported_globals);
743 self.vmctx_imported_globals_begin
744 + index.as_u32() * u32::from(self.size_of_vmglobal_import())
745 }
746
747 pub fn vmctx_vmtable_definition(&self, index: LocalTableIndex) -> u32 {
749 assert_lt!(index.as_u32(), self.num_local_tables);
750 self.vmctx_tables_begin + index.as_u32() * u32::from(self.size_of_vmtable_definition())
751 }
752
753 pub fn vmctx_vmmemory_definition(&self, index: LocalMemoryIndex) -> u32 {
755 assert_lt!(index.as_u32(), self.num_local_memories);
756 self.vmctx_memories_begin + index.as_u32() * u32::from(self.size_of_vmmemory_definition())
757 }
758
759 pub fn vmctx_vmglobal_definition(&self, index: LocalGlobalIndex) -> u32 {
761 assert_lt!(index.as_u32(), self.num_local_globals);
762 self.vmctx_globals_begin + index.as_u32() * u32::from(self.size_of_vmglobal_local())
763 }
764
765 pub fn vmctx_vmfunction_import_body(&self, index: FunctionIndex) -> u32 {
768 self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_body())
769 }
770
771 pub fn vmctx_vmfunction_import_vmctx(&self, index: FunctionIndex) -> u32 {
774 self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_vmctx())
775 }
776
777 pub fn vmctx_vmtable_import_definition(&self, index: TableIndex) -> u32 {
780 self.vmctx_vmtable_import(index) + u32::from(self.vmtable_import_definition())
781 }
782
783 pub fn vmctx_vmtable_definition_base(&self, index: LocalTableIndex) -> u32 {
786 self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_base())
787 }
788
789 pub fn vmctx_vmtable_definition_current_elements(&self, index: LocalTableIndex) -> u32 {
792 self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_current_elements())
793 }
794
795 pub fn vmctx_vmmemory_import_definition(&self, index: MemoryIndex) -> u32 {
798 self.vmctx_vmmemory_import(index) + u32::from(self.vmmemory_import_definition())
799 }
800
801 pub fn vmctx_vmmemory_import_handle(&self, index: MemoryIndex) -> u32 {
804 self.vmctx_vmmemory_import(index) + u32::from(self.vmmemory_import_handle())
805 }
806
807 pub fn vmctx_vmmemory_definition_base(&self, index: LocalMemoryIndex) -> u32 {
810 self.vmctx_vmmemory_definition(index) + u32::from(self.vmmemory_definition_base())
811 }
812
813 pub fn vmctx_vmmemory_definition_current_length(&self, index: LocalMemoryIndex) -> u32 {
816 self.vmctx_vmmemory_definition(index) + u32::from(self.vmmemory_definition_current_length())
817 }
818
819 pub fn vmctx_vmglobal_import_definition(&self, index: GlobalIndex) -> u32 {
822 self.vmctx_vmglobal_import(index) + u32::from(self.vmglobal_import_definition())
823 }
824
825 pub fn vmctx_builtin_function(&self, index: VMBuiltinFunctionIndex) -> u32 {
828 self.vmctx_builtin_functions_begin + index.index() * u32::from(self.pointer_size)
829 }
830}
831
832#[derive(Debug, Copy, Clone)]
834pub struct TargetSharedSignatureIndex(u32);
835
836impl TargetSharedSignatureIndex {
837 pub const fn new(value: u32) -> Self {
839 Self(value)
840 }
841
842 pub const fn index(self) -> u32 {
844 self.0
845 }
846}
847
848#[cfg(test)]
849mod tests {
850 use crate::vmoffsets::align;
851
852 #[test]
853 fn alignment() {
854 fn is_aligned(x: u32) -> bool {
855 x % 16 == 0
856 }
857 assert!(is_aligned(align(0, 16)));
858 assert!(is_aligned(align(32, 16)));
859 assert!(is_aligned(align(33, 16)));
860 assert!(is_aligned(align(31, 16)));
861 }
862}