Skip to main content

vihaco_stdlib/execution_state/
execution.rs

1// SPDX-FileCopyrightText: 2026 The vihaco Authors
2// SPDX-License-Identifier: MIT
3
4//! Checked execution of the program dialect, including its PC and halt state.
5
6use super::program;
7use super::{
8    ExecutionState,
9    messages::{BranchMessage, CallMessage},
10};
11
12use vihaco_abi::word::Word;
13use vihaco_module::PopStack;
14use vihaco_runtime::{Execute, NoMessage};
15
16impl ExecutionState {
17    // Direct and indirect calls share checked frame setup and reservation order.
18    fn enter(
19        &mut self,
20        function: usize,
21        arity: usize,
22        locals: usize,
23        target: u32,
24        indirect: bool,
25    ) -> eyre::Result<()> {
26        let required = arity
27            .checked_add(usize::from(indirect))
28            .ok_or_else(|| eyre::eyre!("argument count overflow"))?;
29        self.require_operands(required)?;
30        let ret_pc = self.pc;
31        let base = self.stack.len() - required;
32        let end = base
33            .checked_add(locals)
34            .ok_or_else(|| eyre::eyre!("frame size overflow"))?;
35        self.stack
36            .try_reserve(end.saturating_sub(self.stack.len()))?;
37        self.frames.try_reserve(1)?;
38        if indirect {
39            self.stack.pop();
40        }
41        self.stack.resize(end, 0);
42        self.frames.push(vihaco_abi::frame::Frame {
43            base,
44            local_count: locals,
45            span: (0, 0, 0),
46            function: Some(function),
47            ret_pc,
48        });
49        self.pc = target;
50        Ok(())
51    }
52}
53
54impl Execute<program::ConstI32> for ExecutionState {
55    type Message = NoMessage;
56    type Effect = ();
57    type Error = eyre::Report;
58
59    #[inline]
60    fn execute(&mut self, instruction: &program::ConstI32, _: NoMessage) -> eyre::Result<()> {
61        self.ensure_running()?;
62        self.stack.push(instruction.0);
63        Ok(())
64    }
65}
66
67impl Execute<program::ConstI64> for ExecutionState {
68    type Message = NoMessage;
69    type Effect = ();
70    type Error = eyre::Report;
71
72    #[inline]
73    fn execute(&mut self, instruction: &program::ConstI64, _: NoMessage) -> eyre::Result<()> {
74        self.ensure_running()?;
75        self.stack.push(instruction.0);
76        Ok(())
77    }
78}
79
80impl Execute<program::ConstU32> for ExecutionState {
81    type Message = NoMessage;
82    type Effect = ();
83    type Error = eyre::Report;
84
85    #[inline]
86    fn execute(&mut self, instruction: &program::ConstU32, _: NoMessage) -> eyre::Result<()> {
87        self.ensure_running()?;
88        self.stack.push(instruction.0);
89        Ok(())
90    }
91}
92
93impl Execute<program::ConstU64> for ExecutionState {
94    type Message = NoMessage;
95    type Effect = ();
96    type Error = eyre::Report;
97
98    #[inline]
99    fn execute(&mut self, instruction: &program::ConstU64, _: NoMessage) -> eyre::Result<()> {
100        self.ensure_running()?;
101        self.stack.push(instruction.0);
102        Ok(())
103    }
104}
105
106impl Execute<program::ConstF32> for ExecutionState {
107    type Message = NoMessage;
108    type Effect = ();
109    type Error = eyre::Report;
110
111    #[inline]
112    fn execute(&mut self, instruction: &program::ConstF32, _: NoMessage) -> eyre::Result<()> {
113        self.ensure_running()?;
114        self.stack.push(instruction.0);
115        Ok(())
116    }
117}
118
119impl Execute<program::ConstF64> for ExecutionState {
120    type Message = NoMessage;
121    type Effect = ();
122    type Error = eyre::Report;
123
124    #[inline]
125    fn execute(&mut self, instruction: &program::ConstF64, _: NoMessage) -> eyre::Result<()> {
126        self.ensure_running()?;
127        self.stack.push(instruction.0);
128        Ok(())
129    }
130}
131
132impl Execute<program::ConstBool> for ExecutionState {
133    type Message = NoMessage;
134    type Effect = ();
135    type Error = eyre::Report;
136
137    #[inline]
138    fn execute(&mut self, instruction: &program::ConstBool, _: NoMessage) -> eyre::Result<()> {
139        self.ensure_running()?;
140        self.stack.push(instruction.0);
141        Ok(())
142    }
143}
144
145impl Execute<program::ConstString> for ExecutionState {
146    type Message = NoMessage;
147    type Effect = ();
148    type Error = eyre::Report;
149
150    #[inline]
151    fn execute(&mut self, instruction: &program::ConstString, _: NoMessage) -> eyre::Result<()> {
152        self.ensure_running()?;
153        self.stack.push(instruction.0);
154        Ok(())
155    }
156}
157
158impl Execute<program::ConstFunctionRef> for ExecutionState {
159    type Message = NoMessage;
160    type Effect = ();
161    type Error = eyre::Report;
162
163    #[inline]
164    fn execute(
165        &mut self,
166        instruction: &program::ConstFunctionRef,
167        _: NoMessage,
168    ) -> eyre::Result<()> {
169        self.ensure_running()?;
170        self.stack.push(instruction.0);
171        Ok(())
172    }
173}
174
175impl Execute<program::ConstHeapRef> for ExecutionState {
176    type Message = NoMessage;
177    type Effect = ();
178    type Error = eyre::Report;
179
180    #[inline]
181    fn execute(&mut self, instruction: &program::ConstHeapRef, _: NoMessage) -> eyre::Result<()> {
182        self.ensure_running()?;
183        self.stack.push(instruction.0);
184        Ok(())
185    }
186}
187
188impl Execute<program::LoadI32> for ExecutionState {
189    type Message = NoMessage;
190    type Effect = ();
191    type Error = eyre::Report;
192
193    #[inline]
194    fn execute(&mut self, instruction: &program::LoadI32, _: NoMessage) -> eyre::Result<()> {
195        self.ensure_running()?;
196        let address = self.local_address(instruction.0)?;
197        self.stack.push(self.stack[address]);
198        Ok(())
199    }
200}
201
202impl Execute<program::LoadI64> for ExecutionState {
203    type Message = NoMessage;
204    type Effect = ();
205    type Error = eyre::Report;
206
207    #[inline]
208    fn execute(&mut self, instruction: &program::LoadI64, _: NoMessage) -> eyre::Result<()> {
209        self.ensure_running()?;
210        let address = self.local_address(instruction.0)?;
211        self.stack.push(self.stack[address]);
212        Ok(())
213    }
214}
215
216impl Execute<program::LoadU32> for ExecutionState {
217    type Message = NoMessage;
218    type Effect = ();
219    type Error = eyre::Report;
220
221    #[inline]
222    fn execute(&mut self, instruction: &program::LoadU32, _: NoMessage) -> eyre::Result<()> {
223        self.ensure_running()?;
224        let address = self.local_address(instruction.0)?;
225        self.stack.push(self.stack[address]);
226        Ok(())
227    }
228}
229
230impl Execute<program::LoadU64> for ExecutionState {
231    type Message = NoMessage;
232    type Effect = ();
233    type Error = eyre::Report;
234
235    #[inline]
236    fn execute(&mut self, instruction: &program::LoadU64, _: NoMessage) -> eyre::Result<()> {
237        self.ensure_running()?;
238        let address = self.local_address(instruction.0)?;
239        self.stack.push(self.stack[address]);
240        Ok(())
241    }
242}
243
244impl Execute<program::LoadF32> for ExecutionState {
245    type Message = NoMessage;
246    type Effect = ();
247    type Error = eyre::Report;
248
249    #[inline]
250    fn execute(&mut self, instruction: &program::LoadF32, _: NoMessage) -> eyre::Result<()> {
251        self.ensure_running()?;
252        let address = self.local_address(instruction.0)?;
253        self.stack.push(self.stack[address]);
254        Ok(())
255    }
256}
257
258impl Execute<program::LoadF64> for ExecutionState {
259    type Message = NoMessage;
260    type Effect = ();
261    type Error = eyre::Report;
262
263    #[inline]
264    fn execute(&mut self, instruction: &program::LoadF64, _: NoMessage) -> eyre::Result<()> {
265        self.ensure_running()?;
266        let address = self.local_address(instruction.0)?;
267        self.stack.push(self.stack[address]);
268        Ok(())
269    }
270}
271
272impl Execute<program::LoadBool> for ExecutionState {
273    type Message = NoMessage;
274    type Effect = ();
275    type Error = eyre::Report;
276
277    #[inline]
278    fn execute(&mut self, instruction: &program::LoadBool, _: NoMessage) -> eyre::Result<()> {
279        self.ensure_running()?;
280        let address = self.local_address(instruction.0)?;
281        self.stack.push(self.stack[address]);
282        Ok(())
283    }
284}
285
286impl Execute<program::StoreI32> for ExecutionState {
287    type Message = NoMessage;
288    type Effect = ();
289    type Error = eyre::Report;
290
291    #[inline]
292    fn execute(&mut self, instruction: &program::StoreI32, _: NoMessage) -> eyre::Result<()> {
293        self.ensure_running()?;
294        let address = self.local_address(instruction.0)?;
295        let value = <Self as PopStack<Word>>::pop(self)?;
296        self.stack[address] = value;
297        Ok(())
298    }
299}
300
301impl Execute<program::StoreI64> for ExecutionState {
302    type Message = NoMessage;
303    type Effect = ();
304    type Error = eyre::Report;
305
306    #[inline]
307    fn execute(&mut self, instruction: &program::StoreI64, _: NoMessage) -> eyre::Result<()> {
308        self.ensure_running()?;
309        let address = self.local_address(instruction.0)?;
310        let value = <Self as PopStack<Word>>::pop(self)?;
311        self.stack[address] = value;
312        Ok(())
313    }
314}
315
316impl Execute<program::StoreU32> for ExecutionState {
317    type Message = NoMessage;
318    type Effect = ();
319    type Error = eyre::Report;
320
321    #[inline]
322    fn execute(&mut self, instruction: &program::StoreU32, _: NoMessage) -> eyre::Result<()> {
323        self.ensure_running()?;
324        let address = self.local_address(instruction.0)?;
325        let value = <Self as PopStack<Word>>::pop(self)?;
326        self.stack[address] = value;
327        Ok(())
328    }
329}
330
331impl Execute<program::StoreU64> for ExecutionState {
332    type Message = NoMessage;
333    type Effect = ();
334    type Error = eyre::Report;
335
336    #[inline]
337    fn execute(&mut self, instruction: &program::StoreU64, _: NoMessage) -> eyre::Result<()> {
338        self.ensure_running()?;
339        let address = self.local_address(instruction.0)?;
340        let value = <Self as PopStack<Word>>::pop(self)?;
341        self.stack[address] = value;
342        Ok(())
343    }
344}
345
346impl Execute<program::StoreF32> for ExecutionState {
347    type Message = NoMessage;
348    type Effect = ();
349    type Error = eyre::Report;
350
351    #[inline]
352    fn execute(&mut self, instruction: &program::StoreF32, _: NoMessage) -> eyre::Result<()> {
353        self.ensure_running()?;
354        let address = self.local_address(instruction.0)?;
355        let value = <Self as PopStack<Word>>::pop(self)?;
356        self.stack[address] = value;
357        Ok(())
358    }
359}
360
361impl Execute<program::StoreF64> for ExecutionState {
362    type Message = NoMessage;
363    type Effect = ();
364    type Error = eyre::Report;
365
366    #[inline]
367    fn execute(&mut self, instruction: &program::StoreF64, _: NoMessage) -> eyre::Result<()> {
368        self.ensure_running()?;
369        let address = self.local_address(instruction.0)?;
370        let value = <Self as PopStack<Word>>::pop(self)?;
371        self.stack[address] = value;
372        Ok(())
373    }
374}
375
376impl Execute<program::StoreBool> for ExecutionState {
377    type Message = NoMessage;
378    type Effect = ();
379    type Error = eyre::Report;
380
381    #[inline]
382    fn execute(&mut self, instruction: &program::StoreBool, _: NoMessage) -> eyre::Result<()> {
383        self.ensure_running()?;
384        let address = self.local_address(instruction.0)?;
385        let value = <Self as PopStack<Word>>::pop(self)?;
386        self.stack[address] = value;
387        Ok(())
388    }
389}
390
391impl Execute<program::Dup> for ExecutionState {
392    type Message = NoMessage;
393    type Effect = ();
394    type Error = eyre::Report;
395
396    #[inline]
397    fn execute(&mut self, _instruction: &program::Dup, _: NoMessage) -> eyre::Result<()> {
398        self.ensure_running()?;
399        let value = self.peek_operand()?;
400        self.stack.push(value);
401        Ok(())
402    }
403}
404
405impl Execute<program::Return> for ExecutionState {
406    type Message = NoMessage;
407    type Effect = ();
408    type Error = eyre::Report;
409
410    #[inline]
411    fn execute(&mut self, instruction: &program::Return, _: NoMessage) -> eyre::Result<()> {
412        self.ensure_running()?;
413        let keep = instruction.0 as usize;
414        self.require_operands(keep)?;
415        let frame = *self
416            .frames
417            .last()
418            .ok_or_else(|| eyre::eyre!("no current frame"))?;
419        let len = self.stack.len();
420        self.stack.copy_within(len - keep..len, frame.base);
421        self.stack.truncate(frame.base + keep);
422        self.frames.pop();
423        if self.frames.is_empty() {
424            self.halted = true;
425        } else {
426            self.pc = frame.ret_pc;
427        }
428        Ok(())
429    }
430}
431
432impl Execute<program::Halt> for ExecutionState {
433    type Message = NoMessage;
434    type Effect = ();
435    type Error = eyre::Report;
436
437    #[inline]
438    fn execute(&mut self, _instruction: &program::Halt, _: NoMessage) -> eyre::Result<()> {
439        self.ensure_running()?;
440        self.halted = true;
441        Ok(())
442    }
443}
444
445impl Execute<program::Branch> for ExecutionState {
446    type Message = BranchMessage;
447    type Effect = ();
448    type Error = eyre::Report;
449    #[inline]
450    fn execute(&mut self, _: &program::Branch, message: BranchMessage) -> eyre::Result<()> {
451        self.ensure_running()?;
452        self.pc = message.target;
453        Ok(())
454    }
455}
456
457impl Execute<program::ConditionalBranch> for ExecutionState {
458    type Message = BranchMessage;
459    type Effect = ();
460    type Error = eyre::Report;
461    #[inline]
462    fn execute(
463        &mut self,
464        _: &program::ConditionalBranch,
465        message: BranchMessage,
466    ) -> eyre::Result<()> {
467        self.ensure_running()?;
468        self.pc = message.target;
469        Ok(())
470    }
471}
472
473impl Execute<program::Call> for ExecutionState {
474    type Message = CallMessage;
475    type Effect = ();
476    type Error = eyre::Report;
477    #[inline]
478    fn execute(&mut self, _: &program::Call, message: CallMessage) -> eyre::Result<()> {
479        self.enter(
480            message.function,
481            message.arity,
482            message.locals,
483            message.target,
484            message.indirect,
485        )
486    }
487}
488
489impl Execute<program::IndirectCall> for ExecutionState {
490    type Message = CallMessage;
491    type Effect = ();
492    type Error = eyre::Report;
493    #[inline]
494    fn execute(&mut self, _: &program::IndirectCall, message: CallMessage) -> eyre::Result<()> {
495        self.enter(
496            message.function,
497            message.arity,
498            message.locals,
499            message.target,
500            message.indirect,
501        )
502    }
503}