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 super::{VmProfileReport, profile::VmProfileState};
12use crate::nan_value::{Arena, NanValue};
13
14/// The Aver bytecode virtual machine.
15pub struct VM {
16    stack: Vec<NanValue>,
17    frames: Vec<CallFrame>,
18    globals: Vec<NanValue>,
19    code: CodeStore,
20    pub arena: Arena,
21    runtime: VmRuntime,
22    profile: Option<VmProfileState>,
23}
24
25enum ReturnControl {
26    Done(NanValue),
27    Resume {
28        result: NanValue,
29        fn_id: u32,
30        ip: usize,
31        bp: usize,
32    },
33}
34
35impl VM {
36    pub fn new(code: CodeStore, globals: Vec<NanValue>, arena: Arena) -> Self {
37        VM {
38            stack: Vec::with_capacity(1024),
39            frames: Vec::with_capacity(64),
40            globals,
41            code,
42            arena,
43            runtime: VmRuntime::new(),
44            profile: None,
45        }
46    }
47
48    pub fn start_profiling(&mut self) {
49        self.profile = Some(VmProfileState::new(self.code.functions.len()));
50    }
51
52    pub fn clear_profile(&mut self) {
53        self.profile = None;
54    }
55
56    pub fn profile_report(&self) -> Option<VmProfileReport> {
57        self.profile
58            .as_ref()
59            .map(|profile| profile.report(&self.code))
60    }
61
62    pub fn profile_top_bigrams(&self, n: usize) -> Vec<((u8, u8), u64)> {
63        self.profile
64            .as_ref()
65            .map(|p| p.top_bigrams(n))
66            .unwrap_or_default()
67    }
68
69    /// Set CLI arguments for Args.get().
70    pub fn set_cli_args(&mut self, args: Vec<String>) {
71        self.runtime.set_cli_args(args);
72    }
73
74    pub fn set_silent_console(&mut self, silent: bool) {
75        self.runtime.set_silent_console(silent);
76    }
77
78    /// Start recording effectful calls.
79    pub fn start_recording(&mut self) {
80        self.runtime.start_recording();
81    }
82
83    /// Start replaying from recorded effects.
84    pub fn start_replay(
85        &mut self,
86        effects: Vec<crate::replay::session::EffectRecord>,
87        validate_args: bool,
88    ) {
89        self.runtime.start_replay(effects, validate_args);
90    }
91
92    pub fn recorded_effects(&self) -> &[crate::replay::session::EffectRecord] {
93        self.runtime.recorded_effects()
94    }
95
96    pub fn replay_progress(&self) -> (usize, usize) {
97        self.runtime.replay_progress()
98    }
99
100    pub fn ensure_replay_consumed(&self) -> Result<(), VmError> {
101        self.runtime.ensure_replay_consumed()
102    }
103
104    pub fn run(&mut self) -> Result<NanValue, VmError> {
105        self.run_top_level()?;
106        self.run_named_function("main", &[])
107    }
108
109    pub fn run_top_level(&mut self) -> Result<(), VmError> {
110        if let Some(top_id) = self.code.find("__top_level__") {
111            let _ = self.call_function(top_id, &[])?;
112        }
113        Ok(())
114    }
115
116    pub fn run_named_function(
117        &mut self,
118        name: &str,
119        args: &[NanValue],
120    ) -> Result<NanValue, VmError> {
121        let fn_id = self
122            .code
123            .symbols
124            .find(name)
125            .and_then(|symbol_id| self.code.symbols.resolve_function(symbol_id))
126            .or_else(|| self.code.find(name))
127            .ok_or_else(|| VmError::Runtime(format!("function '{}' not found", name)))?;
128        self.runtime
129            .set_allowed_effects(self.code.get(fn_id).effects.clone());
130        self.call_function(fn_id, args)
131    }
132
133    pub fn call_function(&mut self, fn_id: u32, args: &[NanValue]) -> Result<NanValue, VmError> {
134        let chunk = self.code.get(fn_id);
135        let caller_depth = self.frames.len();
136        let arena_mark = self.arena.young_len() as u32;
137        let yard_mark = self.arena.yard_len() as u32;
138        let handoff_mark = self.arena.handoff_len() as u32;
139        let bp = self.stack.len() as u32;
140        for arg in args {
141            self.stack.push(*arg);
142        }
143        for _ in args.len()..(chunk.local_count as usize) {
144            self.stack.push(NanValue::UNIT);
145        }
146        self.frames.push(CallFrame {
147            fn_id,
148            ip: 0,
149            bp,
150            local_count: chunk.local_count,
151            arena_mark,
152            yard_base: yard_mark,
153            yard_mark,
154            handoff_mark,
155            globals_dirty: false,
156            yard_dirty: false,
157            handoff_dirty: false,
158            thin: chunk.thin,
159            parent_thin: chunk.parent_thin,
160        });
161        if let Some(profile) = self.profile.as_mut() {
162            profile.record_function_entry(chunk, fn_id);
163        }
164        self.execute_until(caller_depth)
165    }
166}