Skip to main content

vihaco_cpu/execute/values/
heap.rs

1// SPDX-FileCopyrightText: 2026 The vihaco Authors
2// SPDX-License-Identifier: MIT
3
4use crate::{CPU, Word, cpu};
5use vihaco_runtime::{Execute, InputCount, PopFromStack, PushToStack, StackBatch, StackInputCount};
6
7impl StackInputCount<cpu::HeapAlloc> for CPU {
8    fn input_count(instruction: &cpu::HeapAlloc) -> eyre::Result<InputCount> {
9        Ok(InputCount::Immediate(usize::try_from(instruction.0)?))
10    }
11}
12
13impl Execute<cpu::HeapAlloc> for CPU {
14    type Message = PopFromStack<StackBatch<Word>>;
15    type Effect = PushToStack<(u32,)>;
16    type Error = eyre::Report;
17    fn execute(
18        &mut self,
19        _: &cpu::HeapAlloc,
20        PopFromStack(values): Self::Message,
21    ) -> eyre::Result<Self::Effect> {
22        // The heap object outlives this message and owns a separate allocation.
23        Ok(PushToStack((self
24            .heap
25            .alloc(values.into_iter().collect::<Vec<_>>()),)))
26    }
27}
28
29impl Execute<cpu::GetItem> for CPU {
30    type Message = PopFromStack<(u32, u64)>;
31    type Effect = PushToStack<(Word,)>;
32    type Error = eyre::Report;
33    fn execute(
34        &mut self,
35        _: &cpu::GetItem,
36        PopFromStack((id, index)): Self::Message,
37    ) -> eyre::Result<Self::Effect> {
38        let index = usize::try_from(index)?;
39        let value = *self
40            .heap
41            .get(id)?
42            .get(index)
43            .ok_or_else(|| eyre::eyre!("heap index {} out of bounds", index))?;
44        Ok(PushToStack((value,)))
45    }
46}
47
48impl Execute<cpu::HeapDealloc> for CPU {
49    type Message = PopFromStack<(u32,)>;
50    type Effect = PushToStack<()>;
51    type Error = eyre::Report;
52    fn execute(
53        &mut self,
54        _: &cpu::HeapDealloc,
55        PopFromStack((id,)): Self::Message,
56    ) -> eyre::Result<Self::Effect> {
57        self.heap.dealloc(id)?;
58        Ok(PushToStack(()))
59    }
60}
61
62impl Execute<cpu::HeapReserve> for CPU {
63    type Message = PopFromStack<(u64,)>;
64    type Effect = PushToStack<(u32,)>;
65    type Error = eyre::Report;
66    fn execute(
67        &mut self,
68        _: &cpu::HeapReserve,
69        PopFromStack((capacity,)): Self::Message,
70    ) -> eyre::Result<Self::Effect> {
71        Ok(PushToStack((self
72            .heap
73            .reserve(usize::try_from(capacity)?)?,)))
74    }
75}
76
77impl Execute<cpu::HeapPush> for CPU {
78    type Message = PopFromStack<(Word, Word)>;
79    type Effect = PushToStack<(Word,)>;
80    type Error = eyre::Report;
81    fn execute(
82        &mut self,
83        _: &cpu::HeapPush,
84        PopFromStack((id, value)): Self::Message,
85    ) -> eyre::Result<Self::Effect> {
86        self.heap.push(crate::word::decode_heap_ref(id), value)?;
87        Ok(PushToStack((id,)))
88    }
89}
90
91impl Execute<cpu::HeapLen> for CPU {
92    type Message = PopFromStack<(u32,)>;
93    type Effect = PushToStack<(u64,)>;
94    type Error = eyre::Report;
95    fn execute(
96        &mut self,
97        _: &cpu::HeapLen,
98        PopFromStack((id,)): Self::Message,
99    ) -> eyre::Result<Self::Effect> {
100        Ok(PushToStack((u64::try_from(self.heap.get(id)?.len())?,)))
101    }
102}