Skip to main content

zksync_vm2/
fat_pointer.rs

1use std::ptr;
2
3use primitive_types::U256;
4use zksync_vm2_interface::HeapId;
5
6/// Fat pointer to a heap location.
7#[derive(Debug)]
8#[repr(C)]
9pub struct FatPointer {
10    /// Additional pointer offset inside the `start..(start + length)` range.
11    pub offset: u32,
12    /// ID of the heap this points to.
13    pub memory_page: HeapId,
14    /// 0-based index of the pointer start byte at the `memory` page.
15    pub start: u32,
16    /// Length of the pointed slice in bytes.
17    pub length: u32,
18}
19
20// The `FatPointer <-> U256`/`u128` conversions below reinterpret memory, so they rely on the
21// exact layout of `FatPointer` (and, for the `&mut U256` cast, on `U256` being a little-endian
22// `[u64; 4]`). These assertions fail to compile if that layout ever drifts, turning silent UB
23// into a build error. `HeapId` is `#[repr(transparent)]` so `memory_page` is laid out as a `u32`.
24const _: () = assert!(std::mem::size_of::<FatPointer>() == 16);
25const _: () = assert!(std::mem::size_of::<FatPointer>() == std::mem::size_of::<u128>());
26const _: () = assert!(std::mem::size_of::<HeapId>() == std::mem::size_of::<u32>());
27// The `&mut U256 -> &mut FatPointer` cast reinterprets `U256` storage in place, so `FatPointer`
28// must fit within a `U256` (size) and be no more aligned than it (alignment) to stay in bounds.
29const _: () = assert!(std::mem::size_of::<FatPointer>() <= std::mem::size_of::<U256>());
30const _: () = assert!(std::mem::align_of::<FatPointer>() <= std::mem::align_of::<U256>());
31
32#[cfg(target_endian = "little")]
33impl From<&mut U256> for &mut FatPointer {
34    fn from(value: &mut U256) -> Self {
35        unsafe { &mut *ptr::from_mut(value).cast() }
36    }
37}
38
39#[cfg(target_endian = "little")]
40impl From<U256> for FatPointer {
41    fn from(value: U256) -> Self {
42        unsafe { std::mem::transmute(value.low_u128()) }
43    }
44}
45
46impl FatPointer {
47    /// Converts this pointer into a `U256` word.
48    #[cfg(target_endian = "little")]
49    pub fn into_u256(self) -> U256 {
50        U256::zero() + unsafe { std::mem::transmute::<FatPointer, u128>(self) }
51    }
52}