1use vihaco::value::Value;
5use vihaco::{
6 frame::Frame,
7 traits::{FrameMemory, StackFrame, StackMemory},
8};
9
10#[derive(Debug, Clone, Default)]
11pub struct CPU {
12 pub(crate) frames: Vec<Frame>,
13 pub(crate) heap: Heap,
14 pub(crate) stack: Vec<Value>,
15 pub(crate) span: (u32, u32, u32),
16 pub(crate) pending_pc: Option<u32>,
17 pub(crate) current_pc: u32,
18 pub(crate) return_values: Vec<Value>,
19}
20
21type HeapSlot = Option<Box<[Value]>>;
22
23#[derive(Debug, Clone, Default)]
24pub struct Heap {
25 slots: Vec<HeapSlot>,
26 free_list: Vec<u32>,
27}
28
29impl Heap {
30 pub fn alloc(&mut self, values: Box<[Value]>) -> u32 {
31 if let Some(id) = self.free_list.pop() {
32 self.slots[id as usize] = Some(values);
33 id
34 } else {
35 let id = self.slots.len() as u32;
36 self.slots.push(Some(values));
37 id
38 }
39 }
40
41 pub fn dealloc(&mut self, id: u32) -> eyre::Result<()> {
42 match self.slots.get_mut(id as usize) {
43 Some(slot @ Some(_)) => {
44 *slot = None;
45 self.free_list.push(id);
46 Ok(())
47 }
48 Some(None) => Err(eyre::eyre!(
49 "double-free: heap object {} already deallocated",
50 id
51 )),
52 None => Err(eyre::eyre!("invalid heap object id {}", id)),
53 }
54 }
55
56 pub fn get(&self, id: u32) -> eyre::Result<&[Value]> {
57 match self.slots.get(id as usize) {
58 Some(Some(v)) => Ok(v),
59 Some(None) => Err(eyre::eyre!("heap object {} has been deallocated", id)),
60 None => Err(eyre::eyre!("invalid heap object id {}", id)),
61 }
62 }
63
64 pub fn clear(&mut self) {
65 self.slots.clear();
66 self.free_list.clear();
67 }
68
69 #[cfg(test)]
70 pub fn is_empty(&self) -> bool {
71 self.slots.is_empty()
72 }
73}
74
75impl StackMemory for CPU {
76 type Value = Value;
77
78 fn stack(&self) -> &Vec<Self::Value> {
79 &self.stack
80 }
81
82 fn stack_mut(&mut self) -> &mut Vec<Self::Value> {
83 &mut self.stack
84 }
85
86 fn stack_is_empty(&self) -> bool {
87 self.stack.is_empty()
88 }
89
90 fn stack_len(&self) -> usize {
91 self.stack.len()
92 }
93
94 fn stack_get(&self, pos: usize) -> eyre::Result<&Self::Value> {
95 self.stack
96 .get(pos)
97 .ok_or_else(|| eyre::eyre!("stack underflow"))
98 }
99
100 fn stack_get_mut(&mut self, pos: usize) -> eyre::Result<&mut Self::Value> {
101 self.stack
102 .get_mut(pos)
103 .ok_or_else(|| eyre::eyre!("stack underflow"))
104 }
105
106 fn stack_pop(&mut self) -> eyre::Result<Self::Value> {
107 self.stack
108 .pop()
109 .ok_or_else(|| eyre::eyre!("stack underflow"))
110 }
111
112 fn stack_push<T: Into<Self::Value>>(&mut self, v: T) {
113 self.stack.push(v.into());
114 }
115}
116
117impl StackFrame for CPU {
118 fn get_frame(&self) -> eyre::Result<&Frame> {
119 self.frames
120 .last()
121 .ok_or_else(|| eyre::eyre!("no current frame"))
122 }
123
124 fn get_frame_mut(&mut self) -> eyre::Result<&mut Frame> {
125 self.frames
126 .last_mut()
127 .ok_or_else(|| eyre::eyre!("no current frame"))
128 }
129
130 fn push_frame(&mut self, frame: Frame) {
131 self.frames.push(frame);
132 }
133
134 fn pop_frame(&mut self) -> eyre::Result<Frame> {
135 self.frames
136 .pop()
137 .ok_or_else(|| eyre::eyre!("no frame to pop"))
138 }
139}
140
141impl FrameMemory for CPU {
142 fn frame_base(&self) -> eyre::Result<usize> {
143 self.get_frame().map(|f| f.base)
144 }
145
146 fn get_local(&self, index: usize) -> eyre::Result<&Self::Value> {
147 let base = self.frame_base()?;
148 self.stack
149 .get(base + index)
150 .ok_or_else(|| eyre::eyre!("local index out of bounds"))
151 }
152
153 fn get_local_mut(&mut self, index: usize) -> eyre::Result<&mut Self::Value> {
155 let base = self.frame_base()?;
156 let idx = base + index;
157 let len = self.stack.len();
158
159 if len <= idx {
160 self.stack.resize(idx + 1, Value::Undefined);
161 }
162 self.stack
163 .get_mut(idx)
164 .ok_or_else(|| eyre::eyre!("Invalid local address at {:?}, stack size: {:?}", idx, len))
165 }
166}
167
168impl CPU {
169 pub fn push_heap_object(&mut self, values: Box<[Value]>) -> u32 {
170 self.heap.alloc(values)
171 }
172
173 pub fn heap_object(&self, id: u32) -> eyre::Result<&[Value]> {
174 self.heap.get(id)
175 }
176
177 pub fn dealloc_heap_object(&mut self, id: u32) -> eyre::Result<()> {
178 self.heap.dealloc(id)
179 }
180
181 pub fn take_pending_pc(&mut self) -> Option<u32> {
182 self.pending_pc.take()
183 }
184
185 pub fn set_pending_pc(&mut self, pc: u32) {
186 self.pending_pc = Some(pc);
187 }
188
189 pub fn clear_pending_pc(&mut self) {
190 self.pending_pc = None;
191 }
192
193 pub fn set_current_pc(&mut self, pc: u32) {
194 self.current_pc = pc;
195 }
196
197 pub fn return_values(&self) -> &[Value] {
198 &self.return_values
199 }
200
201 pub fn set_return_values(&mut self, values: Vec<Value>) {
202 self.return_values = values;
203 }
204}