corevm-engine 0.1.28

CoreVM engine that drives program execution either on the builder or CoreVM service side
Documentation
use core::ops::Range;
use corevm_host::PAGE_SIZE;

/// CoreVM-specific memory map.
pub struct MemoryMap {
	address_ranges: [Range<u32>; 4],
}

impl MemoryMap {
	pub fn new(memory_map: &polkavm::MemoryMap) -> Self {
		let heap_start = memory_map.heap_base().next_multiple_of(PAGE_SIZE);
		let heap_end = heap_start + memory_map.max_heap_size();
		let heap_range = heap_start..heap_end;
		let stack_range = memory_map.stack_range();
		let stack_range = stack_range.start..stack_range.end;
		let ro_data_range = memory_map.ro_data_range();
		let ro_data_range = ro_data_range.start..ro_data_range.end;
		let rw_data_range = memory_map.rw_data_range();
		let rw_data_range = rw_data_range.start..rw_data_range.end;
		Self { address_ranges: [ro_data_range, rw_data_range, stack_range, heap_range] }
	}

	/// Returns the identifier of an address range the `address` belongs to.
	pub fn classify_address(&self, address: u32) -> Option<AddressKind> {
		AddressKind::ALL
			.into_iter()
			.find(|&kind| self.address_ranges[kind as usize].contains(&address))
	}

	/// Returns the identifier of an address range the `page` belongs to.
	pub fn classify_page(&self, page: u32) -> Option<AddressKind> {
		let address = page.checked_mul(PAGE_SIZE)?;
		AddressKind::ALL
			.into_iter()
			.find(|&kind| self.address_ranges[kind as usize].contains(&address))
	}

	pub fn address_range(&self, kind: AddressKind) -> &Range<u32> {
		&self.address_ranges[kind as usize]
	}

	/// Stack address range.
	pub fn stack_range(&self) -> &Range<u32> {
		self.address_range(AddressKind::Stack)
	}

	/// Heap address range.
	pub fn heap_range(&self) -> &Range<u32> {
		self.address_range(AddressKind::Heap)
	}

	/// Read-only data address range.
	pub fn ro_data_range(&self) -> &Range<u32> {
		self.address_range(AddressKind::RoData)
	}

	/// Read/write data address range.
	pub fn rw_data_range(&self) -> &Range<u32> {
		self.address_range(AddressKind::RwData)
	}
}

impl core::fmt::Debug for MemoryMap {
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
		f.debug_struct("MemoryMap")
			.field("ro_data_range", &format_args!("{:#x?}", self.ro_data_range()))
			.field("rw_data_range", &format_args!("{:#x?}", self.rw_data_range()))
			.field("stack_range", &format_args!("{:#x?}", self.stack_range()))
			.field("heap_range", &format_args!("{:#x?}", self.heap_range()))
			.finish_non_exhaustive()
	}
}

/// Address range identifier.
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum AddressKind {
	RoData = 0,
	RwData = 1,
	Stack = 2,
	Heap = 3,
}

impl AddressKind {
	pub const ALL: [Self; 4] = [Self::RoData, Self::RwData, Self::Stack, Self::Heap];

	pub(crate) const fn as_str(self) -> &'static str {
		match self {
			Self::RoData => "ro",
			Self::RwData => "rw",
			Self::Stack => "stack",
			Self::Heap => "heap",
		}
	}
}

impl core::fmt::Debug for AddressKind {
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
		f.write_str(self.as_str())
	}
}