Skip to main content

vihaco_cpu/
data.rs

1// SPDX-FileCopyrightText: 2026 The vihaco Authors
2// SPDX-License-Identifier: MIT
3
4use 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    // TODO, this is wrong to extend the vector, because the stack is push from back, so it should be reversed
154    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}