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 pub const fn get_imported_memory_atomic_notify_index() -> Self {
141 Self(29)
142 }
143 pub const fn builtin_functions_total_number() -> u32 {
145 30
146 }
147
148 pub const fn index(self) -> u32 {
150 self.0
151 }
152}
153
154#[cfg(target_pointer_width = "32")]
155fn cast_to_u32(sz: usize) -> u32 {
156 u32::try_from(sz).unwrap()
157}
158#[cfg(target_pointer_width = "64")]
159fn cast_to_u32(sz: usize) -> u32 {
160 u32::try_from(sz).expect("overflow in cast from usize to u32")
161}
162
163#[inline]
165const fn align(offset: u32, width: u32) -> u32 {
166 (offset + (width - 1)) / width * width
167}
168
169#[derive(Clone, Debug)]
172pub struct VMOffsets {
173 pointer_size: u8,
175 num_signature_ids: u32,
177 num_imported_functions: u32,
179 num_imported_tables: u32,
181 num_imported_memories: u32,
183 num_imported_globals: u32,
185 num_local_tables: u32,
187 num_local_memories: u32,
189 num_local_globals: u32,
191
192 vmctx_signature_ids_begin: u32,
193 vmctx_imported_functions_begin: u32,
194 vmctx_imported_tables_begin: u32,
195 vmctx_imported_memories_begin: u32,
196 vmctx_imported_globals_begin: u32,
197 vmctx_tables_begin: u32,
198 vmctx_memories_begin: u32,
199 vmctx_globals_begin: u32,
200 vmctx_builtin_functions_begin: u32,
201 vmctx_trap_handler_begin: u32,
202 vmctx_gas_limiter_pointer: u32,
203 vmctx_stack_limit_begin: u32,
204 vmctx_stack_limit_initial_begin: u32,
205 size_of_vmctx: u32,
206}
207
208impl VMOffsets {
209 pub fn new(pointer_size: u8, module: &ModuleInfo) -> Self {
211 let mut ret = Self {
212 pointer_size,
213 num_signature_ids: cast_to_u32(module.signatures.len()),
214 num_imported_functions: cast_to_u32(module.num_imported_functions),
215 num_imported_tables: cast_to_u32(module.num_imported_tables),
216 num_imported_memories: cast_to_u32(module.num_imported_memories),
217 num_imported_globals: cast_to_u32(module.num_imported_globals),
218 num_local_tables: cast_to_u32(module.tables.len()),
219 num_local_memories: cast_to_u32(module.memories.len()),
220 num_local_globals: cast_to_u32(module.globals.len()),
221 vmctx_signature_ids_begin: 0,
222 vmctx_imported_functions_begin: 0,
223 vmctx_imported_tables_begin: 0,
224 vmctx_imported_memories_begin: 0,
225 vmctx_imported_globals_begin: 0,
226 vmctx_tables_begin: 0,
227 vmctx_memories_begin: 0,
228 vmctx_globals_begin: 0,
229 vmctx_builtin_functions_begin: 0,
230 vmctx_trap_handler_begin: 0,
231 vmctx_gas_limiter_pointer: 0,
232 vmctx_stack_limit_begin: 0,
233 vmctx_stack_limit_initial_begin: 0,
234 size_of_vmctx: 0,
235 };
236 ret.precompute();
237 ret
238 }
239
240 pub fn new_for_trampolines(pointer_size: u8) -> Self {
245 Self {
246 pointer_size,
247 num_signature_ids: 0,
248 num_imported_functions: 0,
249 num_imported_tables: 0,
250 num_imported_memories: 0,
251 num_imported_globals: 0,
252 num_local_tables: 0,
253 num_local_memories: 0,
254 num_local_globals: 0,
255 vmctx_signature_ids_begin: 0,
256 vmctx_imported_functions_begin: 0,
257 vmctx_imported_tables_begin: 0,
258 vmctx_imported_memories_begin: 0,
259 vmctx_imported_globals_begin: 0,
260 vmctx_tables_begin: 0,
261 vmctx_memories_begin: 0,
262 vmctx_globals_begin: 0,
263 vmctx_builtin_functions_begin: 0,
264 vmctx_trap_handler_begin: 0,
265 vmctx_gas_limiter_pointer: 0,
266 vmctx_stack_limit_begin: 0,
267 vmctx_stack_limit_initial_begin: 0,
268 size_of_vmctx: 0,
269 }
270 }
271
272 pub fn num_local_tables(&self) -> u32 {
274 self.num_local_tables
275 }
276
277 pub fn num_local_memories(&self) -> u32 {
279 self.num_local_memories
280 }
281
282 fn precompute(&mut self) {
283 fn offset_by(base: u32, num_items: u32, item_size: u32) -> u32 {
285 base.checked_add(num_items.checked_mul(item_size).unwrap())
286 .unwrap()
287 }
288 fn offset_by_aligned(base: u32, num_items: u32, item_size: u32) -> u32 {
292 align(
293 base.checked_add(num_items.checked_mul(item_size).unwrap())
294 .unwrap(),
295 size_of::<&u32>() as u32,
296 )
297 }
298
299 self.vmctx_signature_ids_begin = 0;
300 self.vmctx_imported_functions_begin = offset_by_aligned(
301 self.vmctx_signature_ids_begin,
302 self.num_signature_ids,
303 u32::from(self.size_of_vmshared_signature_index()),
304 );
305 self.vmctx_imported_tables_begin = offset_by_aligned(
306 self.vmctx_imported_functions_begin,
307 self.num_imported_functions,
308 u32::from(self.size_of_vmfunction_import()),
309 );
310 self.vmctx_imported_memories_begin = offset_by_aligned(
311 self.vmctx_imported_tables_begin,
312 self.num_imported_tables,
313 u32::from(self.size_of_vmtable_import()),
314 );
315 self.vmctx_imported_globals_begin = offset_by_aligned(
316 self.vmctx_imported_memories_begin,
317 self.num_imported_memories,
318 u32::from(self.size_of_vmmemory_import()),
319 );
320 self.vmctx_tables_begin = offset_by_aligned(
321 self.vmctx_imported_globals_begin,
322 self.num_imported_globals,
323 u32::from(self.size_of_vmglobal_import()),
324 );
325 self.vmctx_memories_begin = offset_by_aligned(
326 self.vmctx_tables_begin,
327 self.num_local_tables,
328 u32::from(self.size_of_vmtable_definition()),
329 );
330 self.vmctx_globals_begin = align(
331 offset_by(
332 self.vmctx_memories_begin,
333 self.num_local_memories,
334 u32::from(self.size_of_vmmemory_definition()),
335 ),
336 16,
337 );
338 self.vmctx_builtin_functions_begin = offset_by(
339 self.vmctx_globals_begin,
340 self.num_local_globals,
341 u32::from(self.size_of_vmglobal_local()),
342 );
343 self.vmctx_trap_handler_begin = offset_by(
344 self.vmctx_builtin_functions_begin,
345 VMBuiltinFunctionIndex::builtin_functions_total_number(),
346 u32::from(self.pointer_size),
347 );
348 self.vmctx_gas_limiter_pointer = offset_by(
349 self.vmctx_trap_handler_begin,
350 1,
351 u32::from(self.pointer_size),
352 );
353 self.vmctx_stack_limit_begin = offset_by(
354 self.vmctx_gas_limiter_pointer,
355 1,
356 u32::from(self.pointer_size),
357 );
358 self.vmctx_stack_limit_initial_begin = self.vmctx_stack_limit_begin.checked_add(4).unwrap();
359 self.size_of_vmctx = self.vmctx_stack_limit_begin.checked_add(4).unwrap();
360 }
361}
362
363impl VMOffsets {
365 #[allow(clippy::erasing_op)]
367 pub const fn vmfunction_import_body(&self) -> u8 {
368 0 * self.pointer_size
369 }
370
371 #[allow(clippy::identity_op)]
373 pub const fn vmfunction_import_vmctx(&self) -> u8 {
374 1 * self.pointer_size
375 }
376
377 pub const fn vmfunction_import_handle(&self) -> u8 {
379 2 * self.pointer_size
380 }
381
382 pub const fn size_of_vmfunction_import(&self) -> u8 {
384 3 * self.pointer_size
385 }
386}
387
388impl VMOffsets {
390 #[allow(clippy::erasing_op)]
392 pub const fn vmdynamicfunction_import_context_address(&self) -> u8 {
393 0 * self.pointer_size
394 }
395
396 #[allow(clippy::identity_op)]
398 pub const fn vmdynamicfunction_import_context_ctx(&self) -> u8 {
399 1 * self.pointer_size
400 }
401
402 pub const fn size_of_vmdynamicfunction_import_context(&self) -> u8 {
404 2 * self.pointer_size
405 }
406}
407
408impl VMOffsets {
410 #[allow(clippy::identity_op)]
412 pub const fn size_of_vmfunction_body_ptr(&self) -> u8 {
413 1 * self.pointer_size
414 }
415}
416
417impl VMOffsets {
419 #[allow(clippy::erasing_op)]
421 pub const fn vmtable_import_definition(&self) -> u8 {
422 0 * self.pointer_size
423 }
424
425 #[allow(clippy::identity_op)]
427 pub const fn vmtable_import_handle(&self) -> u8 {
428 1 * self.pointer_size
429 }
430
431 pub const fn size_of_vmtable_import(&self) -> u8 {
433 2 * self.pointer_size
434 }
435}
436
437impl VMOffsets {
439 #[allow(clippy::erasing_op)]
441 pub const fn vmtable_definition_base(&self) -> u8 {
442 0 * self.pointer_size
443 }
444
445 #[allow(clippy::identity_op)]
447 pub const fn vmtable_definition_current_elements(&self) -> u8 {
448 1 * self.pointer_size
449 }
450
451 pub const fn size_of_vmtable_definition_current_elements(&self) -> u8 {
453 4
454 }
455
456 pub const fn size_of_vmtable_definition(&self) -> u8 {
458 2 * self.pointer_size
459 }
460}
461
462impl VMOffsets {
464 #[allow(clippy::erasing_op)]
466 pub const fn vmmemory_import_definition(&self) -> u8 {
467 0 * self.pointer_size
468 }
469
470 #[allow(clippy::identity_op)]
472 pub const fn vmmemory_import_handle(&self) -> u8 {
473 1 * self.pointer_size
474 }
475
476 pub const fn size_of_vmmemory_import(&self) -> u8 {
478 2 * self.pointer_size
479 }
480}
481
482impl VMOffsets {
484 #[allow(clippy::erasing_op)]
486 pub const fn vmmemory_definition_base(&self) -> u8 {
487 0 * self.pointer_size
488 }
489
490 #[allow(clippy::identity_op)]
492 pub const fn vmmemory_definition_current_length(&self) -> u8 {
493 1 * self.pointer_size
494 }
495
496 pub const fn size_of_vmmemory_definition_current_length(&self) -> u8 {
498 4
499 }
500
501 pub const fn size_of_vmmemory_definition(&self) -> u8 {
503 2 * self.pointer_size
504 }
505}
506
507impl VMOffsets {
509 #[allow(clippy::erasing_op)]
511 pub const fn vmglobal_import_definition(&self) -> u8 {
512 0 * self.pointer_size
513 }
514
515 #[allow(clippy::identity_op)]
517 pub const fn vmglobal_import_handle(&self) -> u8 {
518 1 * self.pointer_size
519 }
520
521 #[allow(clippy::identity_op)]
523 pub const fn size_of_vmglobal_import(&self) -> u8 {
524 2 * self.pointer_size
525 }
526}
527
528impl VMOffsets {
530 pub const fn size_of_vmglobal_local(&self) -> u8 {
535 self.pointer_size
536 }
537}
538
539impl VMOffsets {
541 pub const fn size_of_vmshared_signature_index(&self) -> u8 {
543 4
544 }
545}
546
547impl VMOffsets {
549 #[allow(clippy::erasing_op)]
551 pub const fn vmcaller_checked_anyfunc_func_ptr(&self) -> u8 {
552 0 * self.pointer_size
553 }
554
555 #[allow(clippy::identity_op)]
557 pub const fn vmcaller_checked_anyfunc_type_index(&self) -> u8 {
558 1 * self.pointer_size
559 }
560
561 pub const fn vmcaller_checked_anyfunc_vmctx(&self) -> u8 {
563 2 * self.pointer_size
564 }
565
566 pub const fn vmcaller_checked_anyfunc_call_trampoline(&self) -> u8 {
568 3 * self.pointer_size
569 }
570
571 pub const fn size_of_vmcaller_checked_anyfunc(&self) -> u8 {
573 4 * self.pointer_size
574 }
575}
576
577impl VMOffsets {
579 #[allow(clippy::erasing_op)]
581 pub const fn vm_funcref_anyfunc_ptr(&self) -> u8 {
582 0 * self.pointer_size
583 }
584
585 #[allow(clippy::identity_op)]
587 pub const fn size_of_vm_funcref(&self) -> u8 {
588 1 * self.pointer_size
589 }
590}
591
592impl VMOffsets {
594 pub fn vmctx_signature_ids_begin(&self) -> u32 {
596 self.vmctx_signature_ids_begin
597 }
598
599 #[allow(clippy::erasing_op)]
601 pub fn vmctx_imported_functions_begin(&self) -> u32 {
602 self.vmctx_imported_functions_begin
603 }
604
605 #[allow(clippy::identity_op)]
607 pub fn vmctx_imported_tables_begin(&self) -> u32 {
608 self.vmctx_imported_tables_begin
609 }
610
611 pub fn vmctx_imported_memories_begin(&self) -> u32 {
613 self.vmctx_imported_memories_begin
614 }
615
616 pub fn vmctx_imported_globals_begin(&self) -> u32 {
618 self.vmctx_imported_globals_begin
619 }
620
621 pub fn vmctx_tables_begin(&self) -> u32 {
623 self.vmctx_tables_begin
624 }
625
626 pub fn vmctx_memories_begin(&self) -> u32 {
628 self.vmctx_memories_begin
629 }
630
631 pub fn vmctx_globals_begin(&self) -> u32 {
633 self.vmctx_globals_begin
634 }
635
636 pub fn vmctx_builtin_functions_begin(&self) -> u32 {
638 self.vmctx_builtin_functions_begin
639 }
640
641 pub fn size_of_vmctx(&self) -> u32 {
643 self.size_of_vmctx
644 }
645
646 pub fn vmctx_vmshared_signature_id(&self, index: SignatureIndex) -> u32 {
648 assert_lt!(index.as_u32(), self.num_signature_ids);
649 self.vmctx_signature_ids_begin
650 + index.as_u32() * u32::from(self.size_of_vmshared_signature_index())
651 }
652
653 pub fn vmctx_vmfunction_import(&self, index: FunctionIndex) -> u32 {
655 assert_lt!(index.as_u32(), self.num_imported_functions);
656 self.vmctx_imported_functions_begin
657 + index.as_u32() * u32::from(self.size_of_vmfunction_import())
658 }
659
660 pub fn vmctx_vmtable_import(&self, index: TableIndex) -> u32 {
662 assert_lt!(index.as_u32(), self.num_imported_tables);
663 self.vmctx_imported_tables_begin + index.as_u32() * u32::from(self.size_of_vmtable_import())
664 }
665
666 pub fn vmctx_vmmemory_import(&self, index: MemoryIndex) -> u32 {
668 assert_lt!(index.as_u32(), self.num_imported_memories);
669 self.vmctx_imported_memories_begin
670 + index.as_u32() * u32::from(self.size_of_vmmemory_import())
671 }
672
673 pub fn vmctx_vmglobal_import(&self, index: GlobalIndex) -> u32 {
675 assert_lt!(index.as_u32(), self.num_imported_globals);
676 self.vmctx_imported_globals_begin
677 + index.as_u32() * u32::from(self.size_of_vmglobal_import())
678 }
679
680 pub fn vmctx_vmtable_definition(&self, index: LocalTableIndex) -> u32 {
682 assert_lt!(index.as_u32(), self.num_local_tables);
683 self.vmctx_tables_begin + index.as_u32() * u32::from(self.size_of_vmtable_definition())
684 }
685
686 pub fn vmctx_vmmemory_definition(&self, index: LocalMemoryIndex) -> u32 {
688 assert_lt!(index.as_u32(), self.num_local_memories);
689 self.vmctx_memories_begin + index.as_u32() * u32::from(self.size_of_vmmemory_definition())
690 }
691
692 pub fn vmctx_vmglobal_definition(&self, index: LocalGlobalIndex) -> u32 {
694 assert_lt!(index.as_u32(), self.num_local_globals);
695 self.vmctx_globals_begin + index.as_u32() * u32::from(self.size_of_vmglobal_local())
696 }
697
698 pub fn vmctx_vmfunction_import_body(&self, index: FunctionIndex) -> u32 {
701 self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_body())
702 }
703
704 pub fn vmctx_vmfunction_import_vmctx(&self, index: FunctionIndex) -> u32 {
707 self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_vmctx())
708 }
709
710 pub fn vmctx_vmtable_import_definition(&self, index: TableIndex) -> u32 {
713 self.vmctx_vmtable_import(index) + u32::from(self.vmtable_import_definition())
714 }
715
716 pub fn vmctx_vmtable_definition_base(&self, index: LocalTableIndex) -> u32 {
719 self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_base())
720 }
721
722 pub fn vmctx_vmtable_definition_current_elements(&self, index: LocalTableIndex) -> u32 {
725 self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_current_elements())
726 }
727
728 pub fn vmctx_vmmemory_import_definition(&self, index: MemoryIndex) -> u32 {
731 self.vmctx_vmmemory_import(index) + u32::from(self.vmmemory_import_definition())
732 }
733
734 pub fn vmctx_vmmemory_import_handle(&self, index: MemoryIndex) -> u32 {
737 self.vmctx_vmmemory_import(index) + u32::from(self.vmmemory_import_handle())
738 }
739
740 pub fn vmctx_vmmemory_definition_base(&self, index: LocalMemoryIndex) -> u32 {
743 self.vmctx_vmmemory_definition(index) + u32::from(self.vmmemory_definition_base())
744 }
745
746 pub fn vmctx_vmmemory_definition_current_length(&self, index: LocalMemoryIndex) -> u32 {
749 self.vmctx_vmmemory_definition(index) + u32::from(self.vmmemory_definition_current_length())
750 }
751
752 pub fn vmctx_vmglobal_import_definition(&self, index: GlobalIndex) -> u32 {
755 self.vmctx_vmglobal_import(index) + u32::from(self.vmglobal_import_definition())
756 }
757
758 pub fn vmctx_builtin_function(&self, index: VMBuiltinFunctionIndex) -> u32 {
761 self.vmctx_builtin_functions_begin + index.index() * u32::from(self.pointer_size)
762 }
763}
764
765#[derive(Debug, Copy, Clone)]
767pub struct TargetSharedSignatureIndex(u32);
768
769impl TargetSharedSignatureIndex {
770 pub const fn new(value: u32) -> Self {
772 Self(value)
773 }
774
775 pub const fn index(self) -> u32 {
777 self.0
778 }
779}
780
781#[cfg(test)]
782mod tests {
783 use crate::vmoffsets::align;
784
785 #[test]
786 fn alignment() {
787 fn is_aligned(x: u32) -> bool {
788 x % 16 == 0
789 }
790 assert!(is_aligned(align(0, 16)));
791 assert!(is_aligned(align(32, 16)));
792 assert!(is_aligned(align(33, 16)));
793 assert!(is_aligned(align(31, 16)));
794 }
795}