javm_transpiler/
layout.rs1use crate::program::Access;
19
20pub const CODE_CAP_INDEX: u8 = 64;
23pub const STACK_CAP_INDEX: u8 = 65;
25pub const RO_CAP_INDEX: u8 = 66;
27pub const RW_CAP_INDEX: u8 = 67;
29pub const HEAP_CAP_INDEX: u8 = 68;
31pub const PVM_PAGE_SIZE: u32 = 4096;
33
34#[derive(Debug, Clone, Copy)]
37pub struct DataCapEntry {
38 pub cap_index: u8,
39 pub base_page: u32,
40 pub page_count: u32,
41 pub access: Access,
42}
43
44#[derive(Debug, Clone)]
50pub struct ProgramLayout {
51 pub stack: DataCapEntry,
52 pub ro: Option<DataCapEntry>,
53 pub rw: Option<DataCapEntry>,
54 pub heap: Option<DataCapEntry>,
55}
56
57impl ProgramLayout {
58 pub fn compute(stack_pages: u32, ro_pages: u32, rw_pages: u32, heap_pages: u32) -> Self {
63 let mut next_page = 0u32;
64
65 let stack = DataCapEntry {
66 cap_index: STACK_CAP_INDEX,
67 base_page: next_page,
68 page_count: stack_pages,
69 access: Access::RW,
70 };
71 next_page += stack_pages;
72
73 let ro = if ro_pages > 0 {
74 let e = DataCapEntry {
75 cap_index: RO_CAP_INDEX,
76 base_page: next_page,
77 page_count: ro_pages,
78 access: Access::RO,
79 };
80 next_page += ro_pages;
81 Some(e)
82 } else {
83 None
84 };
85
86 let rw = if rw_pages > 0 {
87 let e = DataCapEntry {
88 cap_index: RW_CAP_INDEX,
89 base_page: next_page,
90 page_count: rw_pages,
91 access: Access::RW,
92 };
93 next_page += rw_pages;
94 Some(e)
95 } else {
96 None
97 };
98
99 let heap = if heap_pages > 0 {
100 let e = DataCapEntry {
101 cap_index: HEAP_CAP_INDEX,
102 base_page: next_page,
103 page_count: heap_pages,
104 access: Access::RW,
105 };
106 Some(e)
107 } else {
108 None
109 };
110
111 Self {
112 stack,
113 ro,
114 rw,
115 heap,
116 }
117 }
118
119 pub fn data_caps(&self) -> impl Iterator<Item = &DataCapEntry> + '_ {
122 std::iter::once(&self.stack)
123 .chain(self.ro.iter())
124 .chain(self.rw.iter())
125 .chain(self.heap.iter())
126 }
127
128 pub fn stack_top(&self) -> u64 {
131 (self.stack.base_page + self.stack.page_count) as u64 * PVM_PAGE_SIZE as u64
132 }
133
134 pub fn total_data_pages(&self) -> u32 {
136 self.data_caps().map(|d| d.page_count).sum()
137 }
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143
144 #[test]
145 fn layout_minimal_stack_only() {
146 let l = ProgramLayout::compute(1, 0, 0, 0);
147 assert_eq!(l.stack.cap_index, STACK_CAP_INDEX);
148 assert_eq!(l.stack.base_page, 0);
149 assert_eq!(l.stack.page_count, 1);
150 assert!(l.ro.is_none());
151 assert!(l.rw.is_none());
152 assert!(l.heap.is_none());
153 assert_eq!(l.stack_top(), 4096);
154 assert_eq!(l.total_data_pages(), 1);
155 }
156
157 #[test]
158 fn layout_full_stack_ro_rw_heap() {
159 let l = ProgramLayout::compute(2, 1, 1, 4);
160 assert_eq!(l.stack.base_page, 0);
161 assert_eq!(l.ro.as_ref().unwrap().base_page, 2);
162 assert_eq!(l.rw.as_ref().unwrap().base_page, 3);
163 assert_eq!(l.heap.as_ref().unwrap().base_page, 4);
164 assert_eq!(l.stack_top(), 2 * 4096);
165 assert_eq!(l.total_data_pages(), 2 + 1 + 1 + 4);
166 }
167}