Skip to main content

aver/vm/execute/
mod.rs

1mod boundary;
2mod dispatch;
3mod host;
4mod ops;
5
6#[cfg(test)]
7mod tests;
8
9use super::runtime::VmRuntime;
10use super::types::{CallFrame, CodeStore, VmError};
11use crate::nan_value::{Arena, NanValue};
12
13/// The Aver bytecode virtual machine.
14pub struct VM {
15    stack: Vec<NanValue>,
16    frames: Vec<CallFrame>,
17    globals: Vec<NanValue>,
18    code: CodeStore,
19    pub arena: Arena,
20    runtime: VmRuntime,
21}
22
23enum ReturnControl {
24    Done(NanValue),
25    Resume {
26        result: NanValue,
27        fn_id: u32,
28        ip: usize,
29        bp: usize,
30    },
31}
32
33impl VM {
34    pub fn new(code: CodeStore, globals: Vec<NanValue>, arena: Arena) -> Self {
35        VM {
36            stack: Vec::with_capacity(1024),
37            frames: Vec::with_capacity(64),
38            globals,
39            code,
40            arena,
41            runtime: VmRuntime::new(),
42        }
43    }
44
45    /// Set CLI arguments for Args.get().
46    pub fn set_cli_args(&mut self, args: Vec<String>) {
47        self.runtime.set_cli_args(args);
48    }
49
50    /// Start recording effectful calls.
51    pub fn start_recording(&mut self) {
52        self.runtime.start_recording();
53    }
54
55    /// Start replaying from recorded effects.
56    pub fn start_replay(
57        &mut self,
58        effects: Vec<crate::replay::session::EffectRecord>,
59        validate_args: bool,
60    ) {
61        self.runtime.start_replay(effects, validate_args);
62    }
63
64    pub fn recorded_effects(&self) -> &[crate::replay::session::EffectRecord] {
65        self.runtime.recorded_effects()
66    }
67
68    pub fn replay_progress(&self) -> (usize, usize) {
69        self.runtime.replay_progress()
70    }
71
72    pub fn ensure_replay_consumed(&self) -> Result<(), VmError> {
73        self.runtime.ensure_replay_consumed()
74    }
75
76    pub fn run(&mut self) -> Result<NanValue, VmError> {
77        self.run_top_level()?;
78        self.run_named_function("main", &[])
79    }
80
81    pub fn run_top_level(&mut self) -> Result<(), VmError> {
82        if let Some(top_id) = self.code.find("__top_level__") {
83            let _ = self.call_function(top_id, &[])?;
84        }
85        Ok(())
86    }
87
88    pub fn run_named_function(
89        &mut self,
90        name: &str,
91        args: &[NanValue],
92    ) -> Result<NanValue, VmError> {
93        let fn_id = self
94            .code
95            .find(name)
96            .ok_or_else(|| VmError::Runtime(format!("function '{}' not found", name)))?;
97        self.runtime
98            .set_allowed_effects(self.code.get(fn_id).effects.clone());
99        self.call_function(fn_id, args)
100    }
101
102    pub fn call_function(&mut self, fn_id: u32, args: &[NanValue]) -> Result<NanValue, VmError> {
103        let chunk = self.code.get(fn_id);
104        let caller_depth = self.frames.len();
105        let arena_mark = self.arena.young_len() as u32;
106        let yard_mark = self.arena.yard_len() as u32;
107        let handoff_mark = self.arena.handoff_len() as u32;
108        let bp = self.stack.len() as u32;
109        for arg in args {
110            self.stack.push(*arg);
111        }
112        for _ in args.len()..(chunk.local_count as usize) {
113            self.stack.push(NanValue::UNIT);
114        }
115        self.frames.push(CallFrame {
116            fn_id,
117            ip: 0,
118            bp,
119            local_count: chunk.local_count,
120            arena_mark,
121            yard_base: yard_mark,
122            yard_mark,
123            handoff_mark,
124            globals_dirty: false,
125            yard_dirty: false,
126            handoff_dirty: false,
127            thin: chunk.thin,
128            parent_thin: chunk.parent_thin,
129        });
130        self.execute_until(caller_depth)
131    }
132}