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_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 get_imported_debug_str_index() -> Self {
177 Self(36)
178 }
179
180 pub const fn builtin_functions_total_number() -> u32 {
182 37
183 }
184
185 pub const fn index(self) -> u32 {
187 self.0
188 }
189}
190
191#[cfg(target_pointer_width = "32")]
192fn cast_to_u32(sz: usize) -> u32 {
193 u32::try_from(sz).unwrap()
194}
195#[cfg(target_pointer_width = "64")]
196fn cast_to_u32(sz: usize) -> u32 {
197 u32::try_from(sz).expect("overflow in cast from usize to u32")
198}
199
200#[inline]
202const fn align(offset: u32, width: u32) -> u32 {
203 offset.div_ceil(width) * width
204}
205
206#[derive(Clone, Debug)]
209pub struct VMOffsets {
210 pointer_size: u8,
212 num_signature_ids: u32,
214 num_imported_functions: u32,
216 num_imported_tables: u32,
218 num_imported_memories: u32,
220 num_tag_ids: u32,
222 num_imported_globals: u32,
224 num_local_tables: u32,
226 num_local_memories: u32,
228 num_local_globals: u32,
230
231 vmctx_signature_ids_begin: u32,
232 vmctx_imported_functions_begin: u32,
233 vmctx_imported_tables_begin: u32,
234 vmctx_imported_memories_begin: u32,
235 vmctx_tag_ids_begin: u32,
236 vmctx_imported_globals_begin: u32,
237 vmctx_tables_begin: u32,
238 vmctx_memories_begin: u32,
239 vmctx_globals_begin: u32,
240 vmctx_builtin_functions_begin: u32,
241 vmctx_trap_handler_begin: u32,
242 vmctx_gas_limiter_pointer: u32,
243 vmctx_stack_limit_begin: u32,
244 vmctx_stack_limit_initial_begin: u32,
245 size_of_vmctx: u32,
246}
247
248impl VMOffsets {
249 pub fn new(pointer_size: u8, module: &ModuleInfo) -> Self {
251 let mut ret = Self {
252 pointer_size,
253 num_signature_ids: cast_to_u32(module.signatures.len()),
254 num_imported_functions: cast_to_u32(module.num_imported_functions),
255 num_imported_tables: cast_to_u32(module.num_imported_tables),
256 num_imported_memories: cast_to_u32(module.num_imported_memories),
257 num_tag_ids: cast_to_u32(module.tags.len()),
258 num_imported_globals: cast_to_u32(module.num_imported_globals),
259 num_local_tables: cast_to_u32(module.tables.len()),
260 num_local_memories: cast_to_u32(module.memories.len()),
261 num_local_globals: cast_to_u32(module.globals.len()),
262 vmctx_signature_ids_begin: 0,
263 vmctx_imported_functions_begin: 0,
264 vmctx_imported_tables_begin: 0,
265 vmctx_imported_memories_begin: 0,
266 vmctx_tag_ids_begin: 0,
267 vmctx_imported_globals_begin: 0,
268 vmctx_tables_begin: 0,
269 vmctx_memories_begin: 0,
270 vmctx_globals_begin: 0,
271 vmctx_builtin_functions_begin: 0,
272 vmctx_trap_handler_begin: 0,
273 vmctx_gas_limiter_pointer: 0,
274 vmctx_stack_limit_begin: 0,
275 vmctx_stack_limit_initial_begin: 0,
276 size_of_vmctx: 0,
277 };
278 ret.precompute();
279 ret
280 }
281
282 pub fn new_for_trampolines(pointer_size: u8) -> Self {
287 Self {
288 pointer_size,
289 num_signature_ids: 0,
290 num_imported_functions: 0,
291 num_imported_tables: 0,
292 num_imported_memories: 0,
293 num_tag_ids: 0,
294 num_imported_globals: 0,
295 num_local_tables: 0,
296 num_local_memories: 0,
297 num_local_globals: 0,
298 vmctx_signature_ids_begin: 0,
299 vmctx_imported_functions_begin: 0,
300 vmctx_imported_tables_begin: 0,
301 vmctx_imported_memories_begin: 0,
302 vmctx_tag_ids_begin: 0,
303 vmctx_imported_globals_begin: 0,
304 vmctx_tables_begin: 0,
305 vmctx_memories_begin: 0,
306 vmctx_globals_begin: 0,
307 vmctx_builtin_functions_begin: 0,
308 vmctx_trap_handler_begin: 0,
309 vmctx_gas_limiter_pointer: 0,
310 vmctx_stack_limit_begin: 0,
311 vmctx_stack_limit_initial_begin: 0,
312 size_of_vmctx: 0,
313 }
314 }
315
316 pub fn num_local_tables(&self) -> u32 {
318 self.num_local_tables
319 }
320
321 pub fn num_local_memories(&self) -> u32 {
323 self.num_local_memories
324 }
325
326 fn precompute(&mut self) {
327 fn offset_by(base: u32, num_items: u32, item_size: u32) -> u32 {
329 base.checked_add(num_items.checked_mul(item_size).unwrap())
330 .unwrap()
331 }
332 fn 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 size_of::<&u32>() as u32,
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 size_of_vmfunction_import(&self) -> u8 {
436 3 * self.pointer_size
437 }
438}
439
440impl VMOffsets {
442 #[allow(clippy::erasing_op)]
444 pub const fn vmdynamicfunction_import_context_address(&self) -> u8 {
445 0 * self.pointer_size
446 }
447
448 #[allow(clippy::identity_op)]
450 pub const fn vmdynamicfunction_import_context_ctx(&self) -> u8 {
451 1 * self.pointer_size
452 }
453
454 pub const fn size_of_vmdynamicfunction_import_context(&self) -> u8 {
456 2 * self.pointer_size
457 }
458}
459
460impl VMOffsets {
462 #[allow(clippy::identity_op)]
464 pub const fn size_of_vmfunction_body_ptr(&self) -> u8 {
465 1 * self.pointer_size
466 }
467}
468
469impl VMOffsets {
471 #[allow(clippy::erasing_op)]
473 pub const fn vmtable_import_definition(&self) -> u8 {
474 0 * self.pointer_size
475 }
476
477 #[allow(clippy::identity_op)]
479 pub const fn vmtable_import_handle(&self) -> u8 {
480 1 * self.pointer_size
481 }
482
483 pub const fn size_of_vmtable_import(&self) -> u8 {
485 2 * self.pointer_size
486 }
487}
488
489impl VMOffsets {
491 #[allow(clippy::erasing_op)]
493 pub const fn vmtable_definition_base(&self) -> u8 {
494 0 * self.pointer_size
495 }
496
497 #[allow(clippy::identity_op)]
499 pub const fn vmtable_definition_current_elements(&self) -> u8 {
500 1 * self.pointer_size
501 }
502
503 pub const fn size_of_vmtable_definition_current_elements(&self) -> u8 {
505 4
506 }
507
508 pub const fn size_of_vmtable_definition(&self) -> u8 {
510 2 * self.pointer_size
511 }
512}
513
514impl VMOffsets {
516 #[allow(clippy::erasing_op)]
518 pub const fn vmmemory_import_definition(&self) -> u8 {
519 0 * self.pointer_size
520 }
521
522 #[allow(clippy::identity_op)]
524 pub const fn vmmemory_import_handle(&self) -> u8 {
525 1 * self.pointer_size
526 }
527
528 pub const fn size_of_vmmemory_import(&self) -> u8 {
530 2 * self.pointer_size
531 }
532}
533
534impl VMOffsets {
536 #[allow(clippy::erasing_op)]
538 pub const fn vmmemory_definition_base(&self) -> u8 {
539 0 * self.pointer_size
540 }
541
542 #[allow(clippy::identity_op)]
544 pub const fn vmmemory_definition_current_length(&self) -> u8 {
545 1 * self.pointer_size
546 }
547
548 pub const fn size_of_vmmemory_definition_current_length(&self) -> u8 {
550 4
551 }
552
553 pub const fn size_of_vmmemory_definition(&self) -> u8 {
555 2 * self.pointer_size
556 }
557}
558
559impl VMOffsets {
561 #[allow(clippy::erasing_op)]
563 pub const fn vmglobal_import_definition(&self) -> u8 {
564 0 * self.pointer_size
565 }
566
567 #[allow(clippy::identity_op)]
569 pub const fn vmglobal_import_handle(&self) -> u8 {
570 1 * self.pointer_size
571 }
572
573 #[allow(clippy::identity_op)]
575 pub const fn size_of_vmglobal_import(&self) -> u8 {
576 2 * self.pointer_size
577 }
578}
579
580impl VMOffsets {
582 pub const fn size_of_vmglobal_local(&self) -> u8 {
587 self.pointer_size
588 }
589}
590
591impl VMOffsets {
593 pub const fn size_of_vmshared_signature_index(&self) -> u8 {
595 4
596 }
597}
598
599impl VMOffsets {
601 #[allow(clippy::erasing_op)]
603 pub const fn vmcaller_checked_anyfunc_func_ptr(&self) -> u8 {
604 0 * self.pointer_size
605 }
606
607 #[allow(clippy::identity_op)]
609 pub const fn vmcaller_checked_anyfunc_type_index(&self) -> u8 {
610 1 * self.pointer_size
611 }
612
613 pub const fn vmcaller_checked_anyfunc_vmctx(&self) -> u8 {
615 2 * self.pointer_size
616 }
617
618 pub const fn vmcaller_checked_anyfunc_call_trampoline(&self) -> u8 {
620 3 * self.pointer_size
621 }
622
623 pub const fn size_of_vmcaller_checked_anyfunc(&self) -> u8 {
625 4 * self.pointer_size
626 }
627}
628
629impl VMOffsets {
631 #[allow(clippy::erasing_op)]
633 pub const fn vm_funcref_anyfunc_ptr(&self) -> u8 {
634 0 * self.pointer_size
635 }
636
637 #[allow(clippy::identity_op)]
639 pub const fn size_of_vm_funcref(&self) -> u8 {
640 1 * self.pointer_size
641 }
642}
643
644impl VMOffsets {
646 pub const fn size_of_vmshared_tag_index(&self) -> u8 {
648 4
649 }
650}
651
652impl VMOffsets {
654 pub fn vmctx_signature_ids_begin(&self) -> u32 {
656 self.vmctx_signature_ids_begin
657 }
658
659 #[allow(clippy::erasing_op)]
661 pub fn vmctx_imported_functions_begin(&self) -> u32 {
662 self.vmctx_imported_functions_begin
663 }
664
665 #[allow(clippy::identity_op)]
667 pub fn vmctx_imported_tables_begin(&self) -> u32 {
668 self.vmctx_imported_tables_begin
669 }
670
671 pub fn vmctx_imported_memories_begin(&self) -> u32 {
673 self.vmctx_imported_memories_begin
674 }
675
676 pub fn vmctx_imported_globals_begin(&self) -> u32 {
678 self.vmctx_imported_globals_begin
679 }
680
681 pub fn vmctx_tag_ids_begin(&self) -> u32 {
683 self.vmctx_tag_ids_begin
684 }
685
686 pub fn vmctx_tables_begin(&self) -> u32 {
688 self.vmctx_tables_begin
689 }
690
691 pub fn vmctx_memories_begin(&self) -> u32 {
693 self.vmctx_memories_begin
694 }
695
696 pub fn vmctx_globals_begin(&self) -> u32 {
698 self.vmctx_globals_begin
699 }
700
701 pub fn vmctx_builtin_functions_begin(&self) -> u32 {
703 self.vmctx_builtin_functions_begin
704 }
705
706 pub fn size_of_vmctx(&self) -> u32 {
708 self.size_of_vmctx
709 }
710
711 pub fn vmctx_vmshared_signature_id(&self, index: SignatureIndex) -> u32 {
713 assert_lt!(index.as_u32(), self.num_signature_ids);
714 self.vmctx_signature_ids_begin
715 + index.as_u32() * u32::from(self.size_of_vmshared_signature_index())
716 }
717
718 pub fn vmctx_vmfunction_import(&self, index: FunctionIndex) -> u32 {
720 assert_lt!(index.as_u32(), self.num_imported_functions);
721 self.vmctx_imported_functions_begin
722 + index.as_u32() * u32::from(self.size_of_vmfunction_import())
723 }
724
725 pub fn vmctx_vmtable_import(&self, index: TableIndex) -> u32 {
727 assert_lt!(index.as_u32(), self.num_imported_tables);
728 self.vmctx_imported_tables_begin + index.as_u32() * u32::from(self.size_of_vmtable_import())
729 }
730
731 pub fn vmctx_vmmemory_import(&self, index: MemoryIndex) -> u32 {
733 assert_lt!(index.as_u32(), self.num_imported_memories);
734 self.vmctx_imported_memories_begin
735 + index.as_u32() * u32::from(self.size_of_vmmemory_import())
736 }
737
738 pub fn vmctx_vmglobal_import(&self, index: GlobalIndex) -> u32 {
740 assert_lt!(index.as_u32(), self.num_imported_globals);
741 self.vmctx_imported_globals_begin
742 + index.as_u32() * u32::from(self.size_of_vmglobal_import())
743 }
744
745 pub fn vmctx_vmtable_definition(&self, index: LocalTableIndex) -> u32 {
747 assert_lt!(index.as_u32(), self.num_local_tables);
748 self.vmctx_tables_begin + index.as_u32() * u32::from(self.size_of_vmtable_definition())
749 }
750
751 pub fn vmctx_vmmemory_definition(&self, index: LocalMemoryIndex) -> u32 {
753 assert_lt!(index.as_u32(), self.num_local_memories);
754 self.vmctx_memories_begin + index.as_u32() * u32::from(self.size_of_vmmemory_definition())
755 }
756
757 pub fn vmctx_vmglobal_definition(&self, index: LocalGlobalIndex) -> u32 {
759 assert_lt!(index.as_u32(), self.num_local_globals);
760 self.vmctx_globals_begin + index.as_u32() * u32::from(self.size_of_vmglobal_local())
761 }
762
763 pub fn vmctx_vmfunction_import_body(&self, index: FunctionIndex) -> u32 {
766 self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_body())
767 }
768
769 pub fn vmctx_vmfunction_import_vmctx(&self, index: FunctionIndex) -> u32 {
772 self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_vmctx())
773 }
774
775 pub fn vmctx_vmtable_import_definition(&self, index: TableIndex) -> u32 {
778 self.vmctx_vmtable_import(index) + u32::from(self.vmtable_import_definition())
779 }
780
781 pub fn vmctx_vmtable_definition_base(&self, index: LocalTableIndex) -> u32 {
784 self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_base())
785 }
786
787 pub fn vmctx_vmtable_definition_current_elements(&self, index: LocalTableIndex) -> u32 {
790 self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_current_elements())
791 }
792
793 pub fn vmctx_vmmemory_import_definition(&self, index: MemoryIndex) -> u32 {
796 self.vmctx_vmmemory_import(index) + u32::from(self.vmmemory_import_definition())
797 }
798
799 pub fn vmctx_vmmemory_import_handle(&self, index: MemoryIndex) -> u32 {
802 self.vmctx_vmmemory_import(index) + u32::from(self.vmmemory_import_handle())
803 }
804
805 pub fn vmctx_vmmemory_definition_base(&self, index: LocalMemoryIndex) -> u32 {
808 self.vmctx_vmmemory_definition(index) + u32::from(self.vmmemory_definition_base())
809 }
810
811 pub fn vmctx_vmmemory_definition_current_length(&self, index: LocalMemoryIndex) -> u32 {
814 self.vmctx_vmmemory_definition(index) + u32::from(self.vmmemory_definition_current_length())
815 }
816
817 pub fn vmctx_vmglobal_import_definition(&self, index: GlobalIndex) -> u32 {
820 self.vmctx_vmglobal_import(index) + u32::from(self.vmglobal_import_definition())
821 }
822
823 pub fn vmctx_builtin_function(&self, index: VMBuiltinFunctionIndex) -> u32 {
826 self.vmctx_builtin_functions_begin + index.index() * u32::from(self.pointer_size)
827 }
828}
829
830#[derive(Debug, Copy, Clone)]
832pub struct TargetSharedSignatureIndex(u32);
833
834impl TargetSharedSignatureIndex {
835 pub const fn new(value: u32) -> Self {
837 Self(value)
838 }
839
840 pub const fn index(self) -> u32 {
842 self.0
843 }
844}
845
846#[cfg(test)]
847mod tests {
848 use crate::vmoffsets::align;
849
850 #[test]
851 fn alignment() {
852 fn is_aligned(x: u32) -> bool {
853 x % 16 == 0
854 }
855 assert!(is_aligned(align(0, 16)));
856 assert!(is_aligned(align(32, 16)));
857 assert!(is_aligned(align(33, 16)));
858 assert!(is_aligned(align(31, 16)));
859 }
860}