sphinx/runtime/
vm.rs

1use core::cell::Cell;
2use core::ops::Deref;
3use crate::runtime::{Variant, HashMap};
4use crate::runtime::gc::{Gc, GcWeak, GcTrace, gc_collect};
5use crate::runtime::function::{Call, Function, Upvalue, UpvalueIndex, Closure};
6use crate::runtime::module::Module;
7use crate::runtime::errors::ExecResult;
8use crate::debug::traceback::TraceSite;
9use crate::debug::snapshot::{VMSnapshot, VMFrameSnapshot};
10
11mod callframe;
12mod instruction;
13
14use callframe::VMCallFrame;
15
16
17// Helpers
18
19// data used to set up a new call
20struct CallInfo {
21    stack_frame: usize,
22    local_frame: usize,
23    call: Call,
24    site: TraceSite,
25}
26
27enum Control {
28    Next,            // keep executing
29    Call(CallInfo),  // setup a call
30    Return(Variant), // return from call
31    Exit(Variant),   // stop execution
32}
33
34
35#[derive(Debug, Clone, Copy)]
36struct UpvalueRef {
37    fun: Gc<Function>,
38    index: UpvalueIndex,
39}
40
41impl UpvalueRef {
42    fn mark_trace(&self) {
43        self.fun.mark_trace()
44    }
45    
46    fn weakref(&self) -> UpvalueWeakRef {
47        UpvalueWeakRef {
48            fun: self.fun.weakref(),
49            index: self.index,
50        }
51    }
52}
53
54impl Deref for UpvalueRef {
55    type Target = Upvalue;
56    
57    #[inline(always)]
58    fn deref(&self) -> &Self::Target {
59        &self.fun.upvalues()[usize::from(self.index)]
60    }
61}
62
63impl Gc<Function> {
64    #[inline(always)]
65    fn upvalue(self, index: UpvalueIndex) -> UpvalueRef {
66        UpvalueRef {
67            fun: self,
68            index
69        }
70    }
71}
72
73
74#[derive(Debug, Clone, Copy)]
75struct UpvalueWeakRef {
76    fun: GcWeak<Function>,
77    index: UpvalueIndex,
78}
79
80impl UpvalueWeakRef {
81    #[inline(always)]
82    fn try_deref(&self) -> Option<&Upvalue> {
83        self.fun.try_deref()
84            .map(|fun| &fun.upvalues()[usize::from(self.index)])
85    }
86    
87    fn is_valid(&self) -> bool {
88        self.fun.is_valid()
89    }
90    
91    fn mark_trace(&self) {
92        self.fun.mark_trace()
93    }
94}
95
96
97
98
99// struct UpvalueWeakRef
100
101
102// Stack-based Virtual Machine
103#[derive(Debug)]
104pub struct VirtualMachine<'c> {
105    traceback: Vec<TraceSite>,
106    
107    frame: VMCallFrame<'c>,  // the active call frame
108    calls: Vec<VMCallFrame<'c>>,
109    locals: ValueStack,
110    stack: ValueStack,
111    upvalues: OpenUpvalues,
112}
113
114impl<'c> VirtualMachine<'c> {
115    /// Create a new VM with the specified root module and an empty main chunk
116    pub fn new(main_module: Gc<Module>, main_chunk: &'c [u8]) -> Self {
117        Self {
118            traceback: Vec::new(),
119            calls: Vec::new(),
120            locals: ValueStack::new(),
121            stack: ValueStack::new(),
122            frame: VMCallFrame::main_chunk(main_module, main_chunk),
123            upvalues: OpenUpvalues::new(),
124        }
125    }
126    
127    pub fn frame(&self) -> &VMCallFrame<'_> { &self.frame }
128    
129    // the return value is mostly of interest to the REPL
130    pub fn run(mut self) -> ExecResult<Variant> {
131        loop {
132            if let Control::Exit(value) = self.exec_next()? {
133                return Ok(value)
134            }
135        }
136    }
137    
138    pub fn run_steps(self) -> impl Iterator<Item=ExecResult<VMSnapshot>> + 'c {
139        VMStepper::from(self)
140    }
141    
142    #[inline]
143    fn exec_next(&mut self) -> ExecResult<Control> {
144        let control = self.frame.exec_next(&mut self.stack, &mut self.locals, &mut self.upvalues)
145            .map_err(|error| error.extend_trace(self.traceback.iter().rev().cloned()))?;
146        
147        match &control {
148            Control::Exit(..) => return Ok(control),
149            
150            Control::Return(value) if self.calls.is_empty() =>
151                return Ok(Control::Exit(*value)),
152            
153            Control::Return(value) => self.return_call(*value),
154            Control::Call(info) => self.setup_call(info)?,
155            
156            Control::Next => { }
157        }
158        
159        self.upvalues.prune_invalid();
160        gc_collect(self);
161        
162        Ok(control)
163    }
164    
165    fn setup_call(&mut self, callinfo: &CallInfo) -> ExecResult<()> {
166        self.traceback.push(callinfo.site.clone());
167        
168        match callinfo.call {
169            Call::Native { func, nargs } => {
170                let args = self.stack.peek_many(nargs)
171                    .iter().copied().collect::<Vec<Variant>>();
172                
173                let retval = func.exec_fun(self, &args)?;
174                self.stack.truncate(callinfo.stack_frame);
175                self.locals.truncate(callinfo.local_frame);
176                self.stack.push(retval);
177                self.traceback.pop();
178            },
179            
180            Call::Chunk { module, chunk_id } => {
181                let mut frame = VMCallFrame::call_frame(
182                    module, chunk_id, callinfo.stack_frame, callinfo.local_frame
183                );
184                core::mem::swap(&mut self.frame, &mut frame);
185                self.calls.push(frame);
186                
187                log::debug!(
188                    "Setup call: {{ stack: {}, locals: {} }}", 
189                    self.frame.stack_frame(), self.frame.local_frame()
190                );
191            },
192        }
193        
194        Ok(())
195    }
196    
197    fn return_call(&mut self, retval: Variant) {
198        let stack_idx = self.frame.stack_frame();
199        let local_idx = self.frame.local_frame();
200        
201        let mut frame = self.calls.pop().expect("empty call stack");
202        core::mem::swap(&mut self.frame, &mut frame);
203        
204        self.stack.truncate(stack_idx);
205        self.locals.truncate(local_idx);
206        self.stack.push(retval);
207        self.traceback.pop();
208        
209        log::debug!(
210            "Return call: {{ stack: {}, locals: {} }}", 
211            self.frame.stack_frame(), self.frame.local_frame()
212        );
213    }
214}
215
216// trace through all Gc roots
217unsafe impl GcTrace for VirtualMachine<'_> {
218    fn trace(&self) {
219        // trace through the value stack
220        self.stack.trace();
221        self.locals.trace();
222        
223        // trace through the active frame and all calls
224        self.frame.trace();
225        for frame in self.calls.iter() {
226            frame.trace();
227        }
228        
229        // traceback
230        for site in self.traceback.iter() {
231            site.trace();
232        }
233        
234        // open upvalues
235        for upval_ref in self.upvalues.iter_refs() {
236            upval_ref.mark_trace();
237        }
238    }
239}
240
241
242// Stack Manipulation
243#[derive(Debug)]
244struct ValueStack {
245    stack: Vec<Variant>,
246}
247
248impl ValueStack {
249    fn new() -> Self {
250        Self { stack: Vec::new() }
251    }
252    
253    fn take(self) -> Vec<Variant> {
254        self.stack
255    }
256    
257    #[inline(always)]
258    fn trace(&self) {
259        self.stack.iter().for_each(Variant::trace)
260    }
261    
262    #[inline(always)]
263    fn len(&self) -> usize {
264        self.stack.len()
265    }
266    
267    #[inline(always)]
268    fn is_empty(&self) -> bool {
269        self.stack.len() == 0
270    }
271    
272    #[inline(always)]
273    fn clear(&mut self) {
274        self.stack.clear()
275    }
276    
277    #[inline(always)]
278    fn pop(&mut self) -> Variant {
279        self.stack.pop().expect("empty stack")
280    }
281    
282    #[inline(always)]
283    fn pop_many(&mut self, count: usize) -> Vec<Variant> {
284        self.stack.split_off(self.stack.len() - count)
285    }
286
287    #[inline(always)]
288    fn truncate(&mut self, index: usize) {
289        self.stack.truncate(index)
290    }
291    
292    #[inline(always)]
293    fn discard(&mut self, count: usize) {
294        self.stack.truncate(self.stack.len() - count)
295    }
296    
297    #[inline(always)]
298    fn discard_at(&mut self, index: usize, count: usize) {
299        let discard_range = index..(index + count);
300        self.stack.splice(discard_range, core::iter::empty());
301    }
302    
303    #[inline(always)]
304    fn push(&mut self, value: Variant) {
305        self.stack.push(value)
306    }
307    
308    #[inline(always)]
309    fn insert(&mut self, index: usize, value: Variant) {
310        self.stack.insert(index, value);
311    }
312    
313    #[inline(always)]
314    fn extend(&mut self, values: &[Variant]) {
315        self.stack.extend(values)
316    }
317    
318    #[inline(always)]
319    fn replace(&mut self, value: Variant) {
320        *self.stack.last_mut().expect("empty stack") = value;
321    }
322    
323    #[inline(always)]
324    fn replace_many(&mut self, count: usize, value: Variant) {
325        let replace_range = (self.stack.len()-count).. ;
326        self.stack.splice(replace_range, core::iter::once(value));
327    }
328    
329    #[inline(always)]
330    fn replace_at(&mut self, index: usize, value: Variant) {
331        let item = self.stack.get_mut(index)
332            .expect("index out of bounds");
333        *item = value;
334    }
335    
336    #[inline(always)]
337    fn swap_last(&mut self, index: usize) {
338        let len = self.stack.len();
339        self.stack.swap(index, len - 1)
340    }
341    
342    #[inline(always)]
343    fn peek(&self) -> &Variant {
344        self.stack.last().expect("empty stack")
345    }
346    
347    #[inline(always)]
348    fn peek_at(&self, index: usize) -> &Variant {
349        self.stack.get(index)
350            .expect("index out of bounds")
351    }
352    
353    #[inline(always)]
354    fn peek_many(&self, count: usize) -> &[Variant] {
355        let (_, peek) = self.stack.as_slice().split_at(self.stack.len() - count);
356        peek
357    }
358    
359    #[inline]
360    fn get_closure(&self, closure: &Closure) -> Variant {
361        match closure {
362            Closure::Open(index) => *self.peek_at(*index),
363            Closure::Closed(cell) => cell.get(),
364        }
365    }
366    
367    #[inline]
368    fn set_closure(&mut self, closure: &Closure, value: Variant) {
369        match closure {
370            Closure::Open(index) => self.replace_at(*index, value),
371            Closure::Closed(cell) => cell.set(value),
372        }
373    }
374}
375
376// Tracking open upvalues
377
378#[derive(Debug)]
379struct OpenUpvalues {
380    upvalues: HashMap<usize, Vec<UpvalueWeakRef>>,
381}
382
383impl OpenUpvalues {
384    fn new() -> Self {
385        Self {
386            upvalues: HashMap::with_hasher(Default::default())
387        }
388    }
389    
390    fn iter_refs(&self) -> impl Iterator<Item=&UpvalueWeakRef> {
391        self.upvalues.values().flat_map(|refs| refs.iter())
392    }
393    
394    fn prune_invalid(&mut self) {
395        self.upvalues.retain(|_, upvals| {
396            upvals.retain(UpvalueWeakRef::is_valid);
397            !upvals.is_empty()
398        })
399    }
400    
401    /// Enter all of a function's upvalues into the upvalue registry
402    fn register(&mut self, function: Gc<Function>) {
403        for (index, upval) in function.upvalues().iter().enumerate() {
404            if upval.closure().is_open() {
405                let upval_ref = function.upvalue(index.try_into().unwrap());
406                self.insert_ref(upval_ref);
407            }
408        }
409    }
410    
411    fn insert_ref(&mut self, upval_ref: UpvalueRef) {
412        let index = match upval_ref.closure() {
413            Closure::Open(index) => index,
414            _ => panic!("insert non-open upvalue"),
415        };
416        
417        let weak_ref = upval_ref.weakref();
418        self.upvalues.entry(index)
419            .and_modify(|refs| refs.push(weak_ref))
420            .or_insert_with(|| vec![ weak_ref ]);
421    }
422    
423    fn close_upvalues(&mut self, index: usize, value: Variant) {
424        if let Some(upvalues) = self.upvalues.remove(&index) {
425            let gc_cell = Gc::new(Cell::new(value));
426            for weak_ref in upvalues.iter() {
427                if let Some(upvalue) = weak_ref.try_deref() {
428                    upvalue.close(gc_cell)
429                }
430            }
431        }
432    }
433}
434
435
436// For debugging
437
438
439impl From<&VirtualMachine<'_>> for VMSnapshot {
440    fn from (vm: &VirtualMachine) -> Self {
441        Self {
442            calls: vm.calls.iter().map(VMFrameSnapshot::from).collect(),
443            stack: vm.stack.stack.clone(),
444            locals: vm.locals.stack.clone(),
445            frame: (&vm.frame).into(),
446        }
447    }
448}
449
450
451struct VMStepper<'m> {
452    vm: VirtualMachine<'m>,
453    start: bool,
454    stop: bool,
455}
456
457impl<'m> From<VirtualMachine<'m>> for VMStepper<'m> {
458    fn from(vm: VirtualMachine<'m>) -> Self {
459        Self {
460            vm, 
461            start: false,
462            stop: false,
463        }
464    }
465}
466
467impl<'m> Iterator for VMStepper<'m> {
468    type Item = ExecResult<VMSnapshot>;
469    
470    fn next(&mut self) -> Option<Self::Item> {
471        if !self.start {
472            self.start = true;
473            return Some(Ok(VMSnapshot::from(&self.vm)))
474        }
475        
476        if !self.stop {
477            let status = self.vm.exec_next();
478            if let Err(error) = status {
479                self.stop = true;
480                return Some(Err(error));
481            }
482            if let Ok(Control::Exit(..)) = status {
483                self.stop = true;
484            }
485            return Some(Ok(VMSnapshot::from(&self.vm)))
486        }
487        
488        None
489    }
490}