1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
use alloc::vec::Vec;
#[allow(dead_code)]
#[derive(Copy, Clone, Default)]
pub struct GuestInit<'a> {
pub page_size: u32,
pub ro_data: &'a [u8],
pub rw_data: &'a [u8],
pub ro_data_size: u32,
pub rw_data_size: u32,
pub stack_size: u32,
pub aux_data_size: u32,
}
impl<'a> GuestInit<'a> {
pub fn memory_map(&self) -> Result<polkavm_common::abi::MemoryMap, &'static str> {
polkavm_common::abi::MemoryMapBuilder::new(self.page_size)
.ro_data_size(self.ro_data_size)
.rw_data_size(self.rw_data_size)
.stack_size(self.stack_size)
.aux_data_size(self.aux_data_size)
.build()
}
}
pub(crate) struct FlatMap<T, const LAZY_ALLOCATION: bool> {
inner: Vec<Option<T>>,
desired_capacity: u32,
}
impl<T, const LAZY_ALLOCATION: bool> FlatMap<T, LAZY_ALLOCATION>
where
T: Copy,
{
#[inline]
pub fn new(capacity: u32) -> Self {
let mut inner = Vec::new();
if !LAZY_ALLOCATION {
inner.reserve_exact(capacity as usize);
inner.resize_with(capacity as usize, || None);
}
Self {
inner,
desired_capacity: capacity,
}
}
#[inline]
#[allow(dead_code)]
pub fn new_reusing_memory(mut memory: Self, capacity: u32) -> Self {
memory.inner.clear();
memory.inner.resize_with(capacity as usize, || None);
memory.desired_capacity = capacity;
memory
}
#[inline]
pub fn get(&self, key: u32) -> Option<T> {
self.inner.get(key as usize).and_then(|value| *value)
}
#[inline]
#[allow(dead_code)]
pub fn len(&self) -> u32 {
self.inner.len() as u32
}
#[cold]
fn allocate_capacity(&mut self) {
debug_assert!(self.inner.capacity() == 0, "FlatMap should not be allocated yet");
self.inner.reserve_exact(self.desired_capacity as usize);
self.inner.resize_with(self.desired_capacity as usize, || None);
}
#[inline]
pub fn insert(&mut self, key: u32, value: T) {
if self.inner.capacity() == 0 {
self.allocate_capacity();
}
self.inner[key as usize] = Some(value);
}
#[inline]
#[allow(dead_code)]
pub fn clear(&mut self) {
self.inner.clear();
}
#[inline]
pub fn reset(&mut self) {
self.inner.clear();
self.inner.shrink_to_fit();
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
#[non_exhaustive]
pub struct Segfault {
/// The address of the page which was accessed.
pub page_address: u32,
/// The size of the page.
pub page_size: u32,
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum InterruptKind {
/// The execution finished normally.
///
/// This happens when the program jumps to the address `0xffff0000`.
Finished,
/// The execution finished abnormally with a trap.
///
/// This can happen for a few reasons:
/// - if the `trap` instruction is executed,
/// - if an invalid instruction is executed,
/// - if a jump to an invalid address is made,
/// - if a segmentation fault is triggered (when dynamic paging is not enabled for this VM)
Trap,
/// The execution triggered an external call with an `ecalli` instruction.
Ecalli(u32),
/// The execution triggered a segmentation fault.
///
/// This happens when a program accesses a memory page that is not mapped,
/// or tries to write to a read-only page.
///
/// Requires dynamic paging to be enabled with [`ModuleConfig::set_dynamic_paging`](crate::ModuleConfig::set_dynamic_paging), otherwise is never emitted.
Segfault(Segfault),
/// The execution ran out of gas.
///
/// Requires gas metering to be enabled with [`ModuleConfig::set_gas_metering`](crate::ModuleConfig::set_gas_metering), otherwise is never emitted.
NotEnoughGas,
/// Executed a single instruction.
///
/// Requires execution step-tracing to be enabled with [`ModuleConfig::set_step_tracing`](crate::ModuleConfig::set_step_tracing), otherwise is never emitted.
Step,
}
if_compiler_is_supported! {
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Bitness {
B32,
B64,
}
pub trait BitnessT {
const BITNESS: Bitness;
}
pub struct B64;
pub struct B32;
impl BitnessT for B32 {
const BITNESS: Bitness = Bitness::B32;
}
impl BitnessT for B64 {
const BITNESS: Bitness = Bitness::B64;
}
}