1#![deny(rustdoc::broken_intra_doc_links)]
8
9use crate::VMBuiltinFunctionIndex;
10use more_asserts::assert_lt;
11use near_vm_types::{
12 FunctionIndex, GlobalIndex, LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryIndex,
13 ModuleInfo, SignatureIndex, TableIndex,
14};
15use std::convert::TryFrom;
16
17#[cfg(target_pointer_width = "32")]
18fn cast_to_u32(sz: usize) -> u32 {
19 u32::try_from(sz).unwrap()
20}
21#[cfg(target_pointer_width = "64")]
22fn cast_to_u32(sz: usize) -> u32 {
23 u32::try_from(sz).expect("overflow in cast from usize to u32")
24}
25
26#[inline]
28const fn align(offset: u32, width: u32) -> u32 {
29 (offset + (width - 1)) / width * width
30}
31
32#[derive(Clone, Debug)]
38pub struct VMOffsets {
39 pointer_size: u8,
41 num_signature_ids: u32,
43 num_imported_functions: u32,
45 num_imported_tables: u32,
47 num_imported_memories: u32,
49 num_imported_globals: u32,
51 num_local_tables: u32,
53 num_local_memories: u32,
55 num_local_globals: u32,
57 has_trap_handlers: bool,
59
60 vmctx_signature_ids_begin: u32,
61 vmctx_imported_functions_begin: u32,
62 vmctx_imported_tables_begin: u32,
63 vmctx_imported_memories_begin: u32,
64 vmctx_imported_globals_begin: u32,
65 vmctx_tables_begin: u32,
66 vmctx_memories_begin: u32,
67 vmctx_globals_begin: u32,
68 vmctx_builtin_functions_begin: u32,
69 vmctx_trap_handler_begin: u32,
70 vmctx_gas_limiter_pointer: u32,
71 vmctx_stack_limit_begin: u32,
72 vmctx_stack_limit_initial_begin: u32,
73 size_of_vmctx: u32,
74}
75
76impl VMOffsets {
77 pub fn new(pointer_size: u8) -> Self {
82 Self {
83 pointer_size,
84 num_signature_ids: 0,
85 num_imported_functions: 0,
86 num_imported_tables: 0,
87 num_imported_memories: 0,
88 num_imported_globals: 0,
89 num_local_tables: 0,
90 num_local_memories: 0,
91 num_local_globals: 0,
92 has_trap_handlers: false,
93 vmctx_signature_ids_begin: 0,
94 vmctx_imported_functions_begin: 0,
95 vmctx_imported_tables_begin: 0,
96 vmctx_imported_memories_begin: 0,
97 vmctx_imported_globals_begin: 0,
98 vmctx_tables_begin: 0,
99 vmctx_memories_begin: 0,
100 vmctx_globals_begin: 0,
101 vmctx_builtin_functions_begin: 0,
102 vmctx_trap_handler_begin: 0,
103 vmctx_gas_limiter_pointer: 0,
104 vmctx_stack_limit_begin: 0,
105 vmctx_stack_limit_initial_begin: 0,
106 size_of_vmctx: 0,
107 }
108 }
109
110 pub fn for_host() -> Self {
115 Self::new(std::mem::size_of::<*const u8>() as u8)
116 }
117
118 #[tracing::instrument(target = "near_vm", level = "trace", skip_all)]
120 pub fn with_module_info(mut self, module: &ModuleInfo) -> Self {
121 self.num_imported_functions = module.import_counts.functions;
122 self.num_imported_tables = module.import_counts.tables;
123 self.num_imported_memories = module.import_counts.memories;
124 self.num_imported_globals = module.import_counts.globals;
125 self.num_signature_ids = cast_to_u32(module.signatures.len());
126 self.num_local_tables = cast_to_u32(module.tables.len());
128 self.num_local_memories = cast_to_u32(module.memories.len());
129 self.num_local_globals = cast_to_u32(module.globals.len());
130 self.has_trap_handlers = true;
131 self.precompute();
132 self
133 }
134
135 pub fn with_archived_module_info(mut self, module: &rkyv::Archived<ModuleInfo>) -> Self {
137 self.num_imported_functions = module.import_counts.functions.into();
138 self.num_imported_tables = module.import_counts.tables.into();
139 self.num_imported_memories = module.import_counts.memories.into();
140 self.num_imported_globals = module.import_counts.globals.into();
141 self.num_signature_ids = cast_to_u32(module.signatures.len());
142 self.num_local_tables = cast_to_u32(module.tables.len());
144 self.num_local_memories = cast_to_u32(module.memories.len());
145 self.num_local_globals = cast_to_u32(module.globals.len());
146 self.has_trap_handlers = true;
147 self.precompute();
148 self
149 }
150
151 pub fn num_local_tables(&self) -> u32 {
153 self.num_local_tables
154 }
155
156 pub fn num_local_memories(&self) -> u32 {
158 self.num_local_memories
159 }
160
161 fn precompute(&mut self) {
162 use std::mem::align_of;
163
164 fn offset_by(
166 base: u32,
167 num_items: u32,
168 prev_item_size: u32,
169 next_item_align: usize,
170 ) -> u32 {
171 align(
172 base.checked_add(num_items.checked_mul(prev_item_size).unwrap()).unwrap(),
173 next_item_align as u32,
174 )
175 }
176
177 self.vmctx_signature_ids_begin = 0;
178 self.vmctx_imported_functions_begin = offset_by(
179 self.vmctx_signature_ids_begin,
180 self.num_signature_ids,
181 u32::from(self.size_of_vmshared_signature_index()),
182 align_of::<crate::VMFunctionImport>(),
183 );
184 self.vmctx_imported_tables_begin = offset_by(
185 self.vmctx_imported_functions_begin,
186 self.num_imported_functions,
187 u32::from(self.size_of_vmfunction_import()),
188 align_of::<crate::VMTableImport>(),
189 );
190 self.vmctx_imported_memories_begin = offset_by(
191 self.vmctx_imported_tables_begin,
192 self.num_imported_tables,
193 u32::from(self.size_of_vmtable_import()),
194 align_of::<crate::VMMemoryImport>(),
195 );
196 self.vmctx_imported_globals_begin = offset_by(
197 self.vmctx_imported_memories_begin,
198 self.num_imported_memories,
199 u32::from(self.size_of_vmmemory_import()),
200 align_of::<crate::VMGlobalImport>(),
201 );
202 self.vmctx_tables_begin = offset_by(
203 self.vmctx_imported_globals_begin,
204 self.num_imported_globals,
205 u32::from(self.size_of_vmglobal_import()),
206 align_of::<crate::VMTableImport>(),
207 );
208 self.vmctx_memories_begin = offset_by(
209 self.vmctx_tables_begin,
210 self.num_local_tables,
211 u32::from(self.size_of_vmtable_definition()),
212 align_of::<crate::VMMemoryDefinition>(),
213 );
214 self.vmctx_globals_begin = offset_by(
215 self.vmctx_memories_begin,
216 self.num_local_memories,
217 u32::from(self.size_of_vmmemory_definition()),
218 align_of::<crate::VMGlobalDefinition>(),
219 );
220 self.vmctx_builtin_functions_begin = offset_by(
221 self.vmctx_globals_begin,
222 self.num_local_globals,
223 u32::from(self.size_of_vmglobal_local()),
224 align_of::<crate::vmcontext::VMBuiltinFunctionsArray>(),
225 );
226 self.vmctx_trap_handler_begin = offset_by(
227 self.vmctx_builtin_functions_begin,
228 VMBuiltinFunctionIndex::builtin_functions_total_number(),
229 u32::from(self.pointer_size),
230 align_of::<fn()>(),
231 );
232 self.vmctx_gas_limiter_pointer = offset_by(
233 self.vmctx_trap_handler_begin,
234 if self.has_trap_handlers { 1 } else { 0 },
235 u32::from(self.pointer_size),
236 align_of::<*mut near_vm_types::FastGasCounter>(),
237 );
238 self.vmctx_stack_limit_begin = offset_by(
239 self.vmctx_gas_limiter_pointer,
240 1,
241 u32::from(self.pointer_size),
242 align_of::<u32>(),
243 );
244 self.vmctx_stack_limit_initial_begin = self.vmctx_stack_limit_begin.checked_add(4).unwrap();
245 self.size_of_vmctx = self.vmctx_stack_limit_begin.checked_add(4).unwrap();
246 }
247}
248
249impl VMOffsets {
253 #[allow(clippy::erasing_op)]
255 pub const fn vmfunction_import_body(&self) -> u8 {
256 0 * self.pointer_size
257 }
258
259 #[allow(clippy::identity_op)]
261 pub const fn vmfunction_import_vmctx(&self) -> u8 {
262 3 * self.pointer_size
263 }
264
265 pub const fn size_of_vmfunction_import(&self) -> u8 {
269 4 * self.pointer_size
270 }
271}
272
273impl VMOffsets {
277 #[allow(clippy::erasing_op)]
279 pub const fn vmdynamicfunction_import_context_address(&self) -> u8 {
280 0 * self.pointer_size
281 }
282
283 #[allow(clippy::identity_op)]
285 pub const fn vmdynamicfunction_import_context_ctx(&self) -> u8 {
286 1 * self.pointer_size
287 }
288
289 pub const fn size_of_vmdynamicfunction_import_context(&self) -> u8 {
293 2 * self.pointer_size
294 }
295}
296
297impl VMOffsets {
299 #[allow(clippy::identity_op)]
301 pub const fn size_of_vmfunction_body_ptr(&self) -> u8 {
302 1 * self.pointer_size
303 }
304}
305
306impl VMOffsets {
310 #[allow(clippy::erasing_op)]
312 pub const fn vmtable_import_definition(&self) -> u8 {
313 0 * self.pointer_size
314 }
315
316 #[allow(clippy::identity_op)]
318 pub const fn vmtable_import_from(&self) -> u8 {
319 1 * self.pointer_size
320 }
321
322 pub const fn size_of_vmtable_import(&self) -> u8 {
326 3 * self.pointer_size
327 }
328}
329
330impl VMOffsets {
334 #[allow(clippy::erasing_op)]
336 pub const fn vmtable_definition_base(&self) -> u8 {
337 0 * self.pointer_size
338 }
339
340 #[allow(clippy::identity_op)]
342 pub const fn vmtable_definition_current_elements(&self) -> u8 {
343 1 * self.pointer_size
344 }
345
346 pub const fn size_of_vmtable_definition_current_elements(&self) -> u8 {
348 4
349 }
350
351 pub const fn size_of_vmtable_definition(&self) -> u8 {
355 2 * self.pointer_size
356 }
357}
358
359impl VMOffsets {
363 #[allow(clippy::erasing_op)]
365 pub const fn vmmemory_import_definition(&self) -> u8 {
366 0 * self.pointer_size
367 }
368
369 #[allow(clippy::identity_op)]
371 pub const fn vmmemory_import_from(&self) -> u8 {
372 1 * self.pointer_size
373 }
374
375 pub const fn size_of_vmmemory_import(&self) -> u8 {
379 2 * self.pointer_size
380 }
381}
382
383impl VMOffsets {
387 #[allow(clippy::erasing_op)]
389 pub const fn vmmemory_definition_base(&self) -> u8 {
390 0 * self.pointer_size
391 }
392
393 #[allow(clippy::identity_op)]
395 pub const fn vmmemory_definition_current_length(&self) -> u8 {
396 1 * self.pointer_size
397 }
398
399 pub const fn size_of_vmmemory_definition_current_length(&self) -> u8 {
401 4
402 }
403
404 pub const fn size_of_vmmemory_definition(&self) -> u8 {
408 2 * self.pointer_size
409 }
410}
411
412impl VMOffsets {
416 #[allow(clippy::erasing_op)]
418 pub const fn vmglobal_import_definition(&self) -> u8 {
419 0 * self.pointer_size
420 }
421
422 #[allow(clippy::identity_op)]
424 pub const fn vmglobal_import_from(&self) -> u8 {
425 1 * self.pointer_size
426 }
427
428 #[allow(clippy::identity_op)]
432 pub const fn size_of_vmglobal_import(&self) -> u8 {
433 2 * self.pointer_size
434 }
435}
436
437impl VMOffsets {
441 pub const fn size_of_vmglobal_local(&self) -> u8 {
448 self.pointer_size
449 }
450}
451
452impl VMOffsets {
456 pub const fn size_of_vmshared_signature_index(&self) -> u8 {
460 4
461 }
462}
463
464impl VMOffsets {
468 #[allow(clippy::erasing_op)]
470 pub const fn vmcaller_checked_anyfunc_func_ptr(&self) -> u8 {
471 0 * self.pointer_size
472 }
473
474 #[allow(clippy::identity_op)]
476 pub const fn vmcaller_checked_anyfunc_type_index(&self) -> u8 {
477 1 * self.pointer_size
478 }
479
480 pub const fn vmcaller_checked_anyfunc_vmctx(&self) -> u8 {
482 2 * self.pointer_size
483 }
484
485 pub const fn size_of_vmcaller_checked_anyfunc(&self) -> u8 {
489 3 * self.pointer_size
490 }
491}
492
493impl VMOffsets {
497 #[allow(clippy::erasing_op)]
499 pub const fn vm_funcref_anyfunc_ptr(&self) -> u8 {
500 0 * self.pointer_size
501 }
502
503 pub const fn size_of_vm_funcref(&self) -> u8 {
507 self.pointer_size
508 }
509}
510
511impl VMOffsets {
515 #[inline]
517 pub fn vmctx_signature_ids_begin(&self) -> u32 {
518 self.vmctx_signature_ids_begin
519 }
520
521 pub fn vmctx_imported_functions_begin(&self) -> u32 {
523 self.vmctx_imported_functions_begin
524 }
525
526 #[allow(clippy::identity_op)]
528 pub fn vmctx_imported_tables_begin(&self) -> u32 {
529 self.vmctx_imported_tables_begin
530 }
531
532 pub fn vmctx_imported_memories_begin(&self) -> u32 {
534 self.vmctx_imported_memories_begin
535 }
536
537 pub fn vmctx_imported_globals_begin(&self) -> u32 {
539 self.vmctx_imported_globals_begin
540 }
541
542 pub fn vmctx_tables_begin(&self) -> u32 {
544 self.vmctx_tables_begin
545 }
546
547 pub fn vmctx_memories_begin(&self) -> u32 {
549 self.vmctx_memories_begin
550 }
551
552 pub fn vmctx_globals_begin(&self) -> u32 {
554 self.vmctx_globals_begin
555 }
556
557 pub fn vmctx_builtin_functions_begin(&self) -> u32 {
559 self.vmctx_builtin_functions_begin
560 }
561
562 pub fn vmctx_trap_handler_begin(&self) -> u32 {
564 self.vmctx_trap_handler_begin
565 }
566
567 pub fn vmctx_gas_limiter_pointer(&self) -> u32 {
569 self.vmctx_gas_limiter_pointer
570 }
571
572 pub fn vmctx_stack_limit_begin(&self) -> u32 {
574 self.vmctx_stack_limit_begin
575 }
576
577 pub fn vmctx_stack_limit_initial_begin(&self) -> u32 {
579 self.vmctx_stack_limit_initial_begin
580 }
581
582 pub fn size_of_vmctx(&self) -> u32 {
586 self.size_of_vmctx
587 }
588
589 pub fn vmctx_vmshared_signature_id(&self, index: SignatureIndex) -> u32 {
594 assert_lt!(index.as_u32(), self.num_signature_ids);
595 self.vmctx_signature_ids_begin
596 + index.as_u32() * u32::from(self.size_of_vmshared_signature_index())
597 }
598
599 pub fn vmctx_vmfunction_import(&self, index: FunctionIndex) -> u32 {
604 assert_lt!(index.as_u32(), self.num_imported_functions);
605 self.vmctx_imported_functions_begin
606 + index.as_u32() * u32::from(self.size_of_vmfunction_import())
607 }
608
609 pub fn vmctx_vmtable_import(&self, index: TableIndex) -> u32 {
614 assert_lt!(index.as_u32(), self.num_imported_tables);
615 self.vmctx_imported_tables_begin + index.as_u32() * u32::from(self.size_of_vmtable_import())
616 }
617
618 pub fn vmctx_vmmemory_import(&self, index: MemoryIndex) -> u32 {
623 assert_lt!(index.as_u32(), self.num_imported_memories);
624 self.vmctx_imported_memories_begin
625 + index.as_u32() * u32::from(self.size_of_vmmemory_import())
626 }
627
628 pub fn vmctx_vmglobal_import(&self, index: GlobalIndex) -> u32 {
633 assert_lt!(index.as_u32(), self.num_imported_globals);
634 self.vmctx_imported_globals_begin
635 + index.as_u32() * u32::from(self.size_of_vmglobal_import())
636 }
637
638 pub fn vmctx_vmtable_definition(&self, index: LocalTableIndex) -> u32 {
643 assert_lt!(index.as_u32(), self.num_local_tables);
644 self.vmctx_tables_begin + index.as_u32() * u32::from(self.size_of_vmtable_definition())
645 }
646
647 pub fn vmctx_vmmemory_definition(&self, index: LocalMemoryIndex) -> u32 {
652 assert_lt!(index.as_u32(), self.num_local_memories);
653 self.vmctx_memories_begin + index.as_u32() * u32::from(self.size_of_vmmemory_definition())
654 }
655
656 pub fn vmctx_vmglobal_definition(&self, index: LocalGlobalIndex) -> u32 {
661 assert_lt!(index.as_u32(), self.num_local_globals);
662 self.vmctx_globals_begin + index.as_u32() * u32::from(self.size_of_vmglobal_local())
663 }
664
665 pub fn vmctx_vmfunction_import_body(&self, index: FunctionIndex) -> u32 {
668 self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_body())
669 }
670
671 pub fn vmctx_vmfunction_import_vmctx(&self, index: FunctionIndex) -> u32 {
674 self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_vmctx())
675 }
676
677 pub fn vmctx_vmtable_import_definition(&self, index: TableIndex) -> u32 {
682 self.vmctx_vmtable_import(index) + u32::from(self.vmtable_import_definition())
683 }
684
685 pub fn vmctx_vmtable_definition_base(&self, index: LocalTableIndex) -> u32 {
690 self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_base())
691 }
692
693 pub fn vmctx_vmtable_definition_current_elements(&self, index: LocalTableIndex) -> u32 {
698 self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_current_elements())
699 }
700
701 pub fn vmctx_vmmemory_import_definition(&self, index: MemoryIndex) -> u32 {
706 self.vmctx_vmmemory_import(index) + u32::from(self.vmmemory_import_definition())
707 }
708
709 pub fn vmctx_vmmemory_import_from(&self, index: MemoryIndex) -> u32 {
714 self.vmctx_vmmemory_import(index) + u32::from(self.vmmemory_import_from())
715 }
716
717 pub fn vmctx_vmmemory_definition_base(&self, index: LocalMemoryIndex) -> u32 {
722 self.vmctx_vmmemory_definition(index) + u32::from(self.vmmemory_definition_base())
723 }
724
725 pub fn vmctx_vmmemory_definition_current_length(&self, index: LocalMemoryIndex) -> u32 {
730 self.vmctx_vmmemory_definition(index) + u32::from(self.vmmemory_definition_current_length())
731 }
732
733 pub fn vmctx_vmglobal_import_definition(&self, index: GlobalIndex) -> u32 {
738 self.vmctx_vmglobal_import(index) + u32::from(self.vmglobal_import_definition())
739 }
740
741 pub fn vmctx_builtin_function(&self, index: VMBuiltinFunctionIndex) -> u32 {
744 self.vmctx_builtin_functions_begin + index.index() * u32::from(self.pointer_size)
745 }
746
747 pub fn vmctx_trap_handler(&self) -> u32 {
749 assert!(self.has_trap_handlers);
751 self.vmctx_trap_handler_begin
752 }
753}
754
755#[derive(Debug, Copy, Clone)]
757pub struct TargetSharedSignatureIndex(u32);
758
759impl TargetSharedSignatureIndex {
760 pub const fn new(value: u32) -> Self {
762 Self(value)
763 }
764
765 pub const fn index(self) -> u32 {
767 self.0
768 }
769}
770
771#[cfg(test)]
772mod tests {
773 use crate::vmoffsets::align;
774
775 #[test]
776 fn alignment() {
777 fn is_aligned(x: u32) -> bool {
778 x % 16 == 0
779 }
780 assert!(is_aligned(align(0, 16)));
781 assert!(is_aligned(align(32, 16)));
782 assert!(is_aligned(align(33, 16)));
783 assert!(is_aligned(align(31, 16)));
784 }
785}