Skip to main content

compiler/
vm.rs

1use std::cell::RefCell;
2use std::collections::HashMap;
3use std::rc::Rc;
4
5use byteorder::{BigEndian, ByteOrder};
6use object::builtins::BuiltIns;
7
8use object::Object::ClosureObj;
9use object::{BoundMethodObject, BuiltinFunc, ClassObject, Closure, InstanceObject, Object};
10
11use crate::compiler::Bytecode;
12use crate::frame::Frame;
13use crate::op_code::Opcode;
14
15const STACK_SIZE: usize = 2048;
16pub const GLOBAL_SIZE: usize = 65536;
17const MAX_FRAMES: usize = 1024;
18
19pub struct VM {
20    constants: Vec<Rc<Object>>,
21
22    stack: Vec<Rc<Object>>,
23    sp: usize, // stack pointer. Always point to the next value. Top of the stack is stack[sp -1]
24
25    pub globals: Vec<Rc<Object>>,
26
27    frames: Vec<Frame>,
28    frame_index: usize,
29}
30
31impl VM {
32    pub fn new(bytecode: Bytecode) -> VM {
33        // it's rust, it's verbose. You can't just grow your vector size.
34        let empty_frame = Frame::new(
35            Closure {
36                func: Rc::from(object::CompiledFunction {
37                    name: String::new(),
38                    instructions: vec![],
39                    num_locals: 0,
40                    num_parameters: 0,
41                }),
42                free: vec![],
43            },
44            0,
45        );
46
47        let main_fn = Rc::from(object::CompiledFunction {
48            name: String::new(),
49            instructions: bytecode.instructions.data,
50            num_locals: 0,
51            num_parameters: 0,
52        });
53        let main_closure = Closure {
54            func: main_fn,
55            free: vec![],
56        };
57        let main_frame = Frame::new(main_closure, 0);
58        let mut frames = vec![empty_frame; MAX_FRAMES];
59        frames[0] = main_frame;
60
61        return VM {
62            constants: bytecode.constants,
63            stack: vec![Rc::new(Object::Null); STACK_SIZE],
64            sp: 0,
65            globals: vec![Rc::new(Object::Null); GLOBAL_SIZE],
66            frames,
67            frame_index: 1,
68        };
69    }
70
71    pub fn new_with_global_store(bytecode: Bytecode, globals: Vec<Rc<Object>>) -> VM {
72        let mut vm = VM::new(bytecode);
73        vm.globals = globals;
74        return vm;
75    }
76
77    pub fn run(&mut self) {
78        let mut ip = 0;
79        let mut ins: Vec<u8>;
80        while self.current_frame().ip
81            < self.current_frame().instructions().data.clone().len() as i32 - 1
82        {
83            self.current_frame().ip += 1;
84            ip = self.current_frame().ip as usize;
85            ins = self.current_frame().instructions().data.clone();
86
87            let op: u8 = *ins.get(ip).unwrap();
88            let opcode = Opcode::from_repr(op).expect("unknown opcode in compiled bytecode");
89
90            match opcode {
91                Opcode::OpConst => {
92                    let const_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
93                    self.current_frame().ip += 2;
94                    self.push(Rc::clone(&self.constants[const_index]))
95                }
96                Opcode::OpAdd | Opcode::OpSub | Opcode::OpMul | Opcode::OpDiv => {
97                    self.execute_binary_operation(opcode);
98                }
99                Opcode::OpPop => {
100                    self.pop();
101                }
102                Opcode::OpTrue => {
103                    self.push(Rc::new(Object::Boolean(true)));
104                }
105                Opcode::OpFalse => {
106                    self.push(Rc::new(Object::Boolean(false)));
107                }
108                Opcode::OpEqual | Opcode::OpNotEqual | Opcode::OpGreaterThan => {
109                    self.execute_comparison(opcode);
110                }
111                Opcode::OpMinus => {
112                    self.execute_minus_operation(opcode);
113                }
114                Opcode::OpBang => {
115                    self.execute_bang_operation();
116                }
117                Opcode::OpJump => {
118                    let pos = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
119                    self.current_frame().ip = pos as i32 - 1;
120                }
121                Opcode::OpJumpNotTruthy => {
122                    let pos = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
123                    self.current_frame().ip += 2;
124                    let condition = self.pop();
125                    if !self.is_truthy(condition) {
126                        self.current_frame().ip = pos as i32 - 1;
127                    }
128                }
129                Opcode::OpNull => {
130                    self.push(Rc::new(Object::Null));
131                }
132                Opcode::OpGetGlobal => {
133                    let global_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
134                    self.current_frame().ip += 2;
135                    self.push(Rc::clone(&self.globals[global_index]));
136                }
137                Opcode::OpSetGlobal => {
138                    let global_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
139                    self.current_frame().ip += 2;
140                    self.globals[global_index] = self.pop();
141                }
142                Opcode::OpArray => {
143                    let count = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
144                    self.current_frame().ip += 2;
145                    let elements = self.build_array(self.sp - count, self.sp);
146                    self.sp = self.sp - count;
147                    self.push(Rc::new(Object::Array(elements)));
148                }
149                Opcode::OpHash => {
150                    let count = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
151                    self.current_frame().ip += 2;
152                    let elements = self.build_hash(self.sp - count, self.sp);
153                    self.sp = self.sp - count;
154                    self.push(Rc::new(Object::Hash(elements)));
155                }
156                Opcode::OpIndex => {
157                    let index = self.pop();
158                    let left = self.pop();
159                    self.execute_index_operation(left, index);
160                }
161                Opcode::OpReturnValue => {
162                    let return_value = self.pop();
163                    if self.frame_index == 1 {
164                        // A top-level return ends the program with this value
165                        // as its result, matching the interpreter backend.
166                        self.stack[0] = return_value;
167                        self.sp = 0;
168                        break;
169                    }
170                    let frame = self.pop_frame();
171                    self.sp = frame.base_pointer - 1;
172                    self.push(return_value);
173                }
174                Opcode::OpReturn => {
175                    if self.frame_index == 1 {
176                        self.stack[0] = Rc::new(object::Object::Null);
177                        self.sp = 0;
178                        break;
179                    }
180                    let frame = self.pop_frame();
181                    self.sp = frame.base_pointer - 1;
182                    self.push(Rc::new(object::Object::Null));
183                }
184                Opcode::OpCall => {
185                    let num_args = ins[ip + 1] as usize;
186                    self.current_frame().ip += 1;
187                    self.execute_call(num_args);
188                }
189                Opcode::OpSetLocal => {
190                    let local_index = ins[ip + 1] as usize;
191                    self.current_frame().ip += 1;
192                    let base = self.current_frame().base_pointer;
193                    self.stack[base + local_index] = self.pop();
194                }
195                Opcode::OpGetLocal => {
196                    let local_index = ins[ip + 1] as usize;
197                    self.current_frame().ip += 1;
198                    let base = self.current_frame().base_pointer;
199                    self.push(Rc::clone(&self.stack[base + local_index]));
200                }
201                Opcode::OpGetBuiltin => {
202                    let built_index = ins[ip + 1] as usize;
203                    self.current_frame().ip += 1;
204                    let definition = BuiltIns.get(built_index).unwrap().function;
205                    self.push(Rc::new(Object::Builtin(definition)));
206                }
207                Opcode::OpClosure => {
208                    let const_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
209                    let num_free = ins[ip + 3] as usize;
210                    self.current_frame().ip += 3;
211                    self.push_closure(const_index, num_free);
212                }
213                Opcode::OpGetFree => {
214                    let free_index = ins[ip + 1] as usize;
215                    self.current_frame().ip += 1;
216                    let current_closure = self.current_frame().cl.clone();
217                    self.push(current_closure.free[free_index].clone());
218                }
219                Opcode::OpCurrentClosure => {
220                    let current_closure = self.current_frame().cl.clone();
221                    self.push(Rc::new(Object::ClosureObj(current_closure)));
222                }
223                Opcode::OpClass => {
224                    let name_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
225                    self.current_frame().ip += 2;
226                    let name = self.constant_string(name_index);
227                    self.push(Rc::new(Object::Class(Rc::new(RefCell::new(ClassObject {
228                        name,
229                        constructor: None,
230                        methods: HashMap::new(),
231                    })))));
232                }
233                Opcode::OpMethod => {
234                    let name_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
235                    let kind = ins[ip + 3];
236                    self.current_frame().ip += 3;
237                    let name = self.constant_string(name_index);
238                    let method = self.pop();
239                    let class = match &*self.stack[self.sp - 1] {
240                        Object::Class(class) => Rc::clone(class),
241                        value => panic!("cannot install method on {}", value),
242                    };
243                    if kind == 1 {
244                        class.borrow_mut().constructor = Some(method);
245                    } else {
246                        class.borrow_mut().methods.insert(name, method);
247                    }
248                }
249                Opcode::OpGetProperty => {
250                    let name_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
251                    self.current_frame().ip += 2;
252                    let name = self.constant_string(name_index);
253                    let receiver = self.pop();
254                    let value = self.get_property(&receiver, &name);
255                    self.push(value);
256                }
257                Opcode::OpSetProperty => {
258                    let name_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
259                    self.current_frame().ip += 2;
260                    let name = self.constant_string(name_index);
261                    let value = self.pop();
262                    let receiver = self.pop();
263                    self.set_property(&receiver, name, value);
264                }
265                Opcode::OpNew => {
266                    let num_args = ins[ip + 1] as usize;
267                    self.current_frame().ip += 1;
268                    self.execute_new(num_args);
269                }
270            }
271        }
272    }
273
274    fn execute_binary_operation(&mut self, opcode: Opcode) {
275        let right = self.pop();
276        let left = self.pop();
277        match (left.as_ref(), right.as_ref()) {
278            (Object::Integer(l), Object::Integer(r)) => {
279                let result = match opcode {
280                    Opcode::OpAdd => l + r,
281                    Opcode::OpSub => l - r,
282                    Opcode::OpMul => l * r,
283                    Opcode::OpDiv => l / r,
284                    _ => panic!("Unknown opcode for int"),
285                };
286                self.push(Rc::from(Object::Integer(result)));
287            }
288            (Object::String(l), Object::String(r)) => {
289                let result = match opcode {
290                    Opcode::OpAdd => l.to_string() + &r.to_string(),
291                    _ => panic!("Unknown opcode for string"),
292                };
293                self.push(Rc::from(Object::String(result)));
294            }
295            _ => {
296                panic!("unsupported add for those types")
297            }
298        }
299    }
300
301    fn execute_comparison(&mut self, opcode: Opcode) {
302        let right = self.pop();
303        let left = self.pop();
304        if opcode == Opcode::OpEqual || opcode == Opcode::OpNotEqual {
305            let equal = left.as_ref() == right.as_ref();
306            self.push(Rc::new(Object::Boolean(if opcode == Opcode::OpEqual {
307                equal
308            } else {
309                !equal
310            })));
311            return;
312        }
313        match (left.as_ref(), right.as_ref()) {
314            (Object::Integer(l), Object::Integer(r)) => {
315                let result = match opcode {
316                    Opcode::OpGreaterThan => l > r,
317                    _ => panic!("Unknown opcode for comparing int"),
318                };
319                self.push(Rc::from(Object::Boolean(result)));
320            }
321            _ => {
322                panic!("unsupported comparison for those types")
323            }
324        }
325    }
326
327    fn execute_minus_operation(&mut self, opcode: Opcode) {
328        let operand = self.pop();
329        match operand.as_ref() {
330            Object::Integer(l) => {
331                self.push(Rc::from(Object::Integer(-*l)));
332            }
333            _ => {
334                panic!("unsupported types for negation {:?}", opcode)
335            }
336        }
337    }
338    fn execute_bang_operation(&mut self) {
339        let operand = self.pop();
340        match operand.as_ref() {
341            Object::Boolean(l) => {
342                self.push(Rc::from(Object::Boolean(!*l)));
343            }
344            _ => {
345                self.push(Rc::from(Object::Boolean(false)));
346            }
347        }
348    }
349
350    pub fn last_popped_stack_elm(&self) -> Option<Rc<Object>> {
351        self.stack.get(self.sp).cloned()
352    }
353
354    fn pop(&mut self) -> Rc<Object> {
355        let o = Rc::clone(&self.stack[self.sp - 1]);
356        self.sp -= 1;
357        return o;
358    }
359
360    fn push(&mut self, o: Rc<Object>) {
361        if self.sp >= STACK_SIZE {
362            panic!("Stack overflow");
363        };
364        self.stack[self.sp] = o;
365        self.sp += 1;
366    }
367    fn is_truthy(&self, condition: Rc<Object>) -> bool {
368        match condition.as_ref() {
369            Object::Boolean(b) => *b,
370            Object::Null => false,
371            _ => true,
372        }
373    }
374    fn build_array(&self, start: usize, end: usize) -> Vec<Rc<Object>> {
375        let mut elements = Vec::with_capacity(end - start);
376        for i in start..end {
377            elements.push(Rc::clone(&self.stack[i]));
378        }
379        return elements;
380    }
381
382    fn build_hash(&self, start: usize, end: usize) -> HashMap<Rc<Object>, Rc<Object>> {
383        let mut elements = HashMap::new();
384        for i in (start..end).step_by(2) {
385            let key = Rc::clone(&self.stack[i]);
386            let value = Rc::clone(&self.stack[i + 1]);
387            elements.insert(key, value);
388        }
389        return elements;
390    }
391
392    fn execute_index_operation(&mut self, left: Rc<Object>, index: Rc<Object>) {
393        match (left.as_ref(), index.as_ref()) {
394            (Object::Array(l), Object::Integer(i)) => {
395                self.execute_array_index(l, *i);
396            }
397            (Object::Hash(l), _) => {
398                self.execute_hash_index(l, index);
399            }
400            _ => {
401                panic!("unsupported index operation for those types")
402            }
403        }
404    }
405
406    fn execute_array_index(&mut self, array: &Vec<Rc<Object>>, index: i64) {
407        if index < array.len() as i64 && index >= 0 {
408            self.push(Rc::clone(&array[index as usize]));
409        } else {
410            self.push(Rc::new(Object::Null));
411        }
412    }
413
414    fn execute_hash_index(&mut self, hash: &HashMap<Rc<Object>, Rc<Object>>, index: Rc<Object>) {
415        match &*index {
416            Object::Integer(_) | Object::Boolean(_) | Object::String(_) => match hash.get(&index) {
417                Some(el) => {
418                    self.push(Rc::clone(el));
419                }
420                None => {
421                    self.push(Rc::new(Object::Null));
422                }
423            },
424            _ => {
425                panic!("unsupported hash index operation for those types {}", index)
426            }
427        }
428    }
429
430    fn current_frame(&mut self) -> &mut Frame {
431        &mut self.frames[self.frame_index - 1]
432    }
433
434    fn push_frame(&mut self, frame: Frame) {
435        self.frames[self.frame_index] = frame;
436        self.frame_index += 1;
437    }
438
439    fn pop_frame(&mut self) -> Frame {
440        self.frame_index -= 1;
441        return self.frames[self.frame_index].clone();
442    }
443
444    fn execute_call(&mut self, num_args: usize) {
445        let callee = Rc::clone(&self.stack[self.sp - 1 - num_args]);
446        match &*callee {
447            Object::ClosureObj(cf) => {
448                self.call_closure(cf.clone(), num_args);
449            }
450            Object::Builtin(bt) => {
451                self.call_builtin(bt.clone(), num_args);
452            }
453            Object::BoundMethod(bound) => {
454                self.call_bound_method(bound.clone(), num_args);
455            }
456            Object::Class(class) => {
457                panic!("class {} must be constructed with new", class.borrow().name)
458            }
459            _ => {
460                panic!("calling non-closure")
461            }
462        }
463    }
464    fn call_closure(&mut self, cl: Closure, num_args: usize) {
465        if cl.func.num_parameters != num_args {
466            panic!("wrong number of arguments: want={}, got={}", cl.func.num_parameters, num_args);
467        }
468
469        let frame = Frame::new(cl.clone(), self.sp - num_args);
470        self.sp = frame.base_pointer + cl.func.num_locals;
471        self.push_frame(frame);
472    }
473
474    fn call_builtin(&mut self, bt: BuiltinFunc, num_args: usize) {
475        let args = self.stack[self.sp - num_args..self.sp].to_vec();
476        let result = bt(args);
477        self.sp = self.sp - num_args - 1;
478        self.push(result);
479    }
480
481    fn push_closure(&mut self, const_index: usize, num_free: usize) {
482        match &*self.constants[const_index] {
483            Object::CompiledFunction(f) => {
484                let mut free = Vec::with_capacity(num_free);
485                for i in 0..num_free {
486                    let f = self.stack[self.sp - num_free + i].clone();
487                    free.push(f);
488                }
489                self.sp = self.sp - num_free;
490                let closure = ClosureObj(Closure {
491                    func: f.clone(),
492                    free,
493                });
494                self.push(Rc::new(closure));
495            }
496            o => {
497                panic!("not a function {}", o);
498            }
499        }
500    }
501
502    fn constant_string(&self, index: usize) -> String {
503        match &*self.constants[index] {
504            Object::String(value) => value.clone(),
505            value => panic!("expected string constant, got {}", value),
506        }
507    }
508
509    fn get_property(&self, receiver: &Rc<Object>, name: &str) -> Rc<Object> {
510        let Object::Instance(instance) = &**receiver else {
511            panic!("cannot read property '{}' of {}", name, receiver);
512        };
513        if let Some(value) = instance.borrow().fields.get(name).cloned() {
514            return value;
515        }
516        let (class_name, method) = {
517            let instance_object = instance.borrow();
518            let class = instance_object.class.borrow();
519            (class.name.clone(), class.methods.get(name).cloned())
520        };
521        match method {
522            Some(method) => Rc::new(Object::BoundMethod(Rc::new(BoundMethodObject {
523                receiver: Rc::clone(instance),
524                method,
525                name: name.to_string(),
526            }))),
527            None => panic!("property '{}' does not exist on {}", name, class_name),
528        }
529    }
530
531    fn set_property(&self, receiver: &Rc<Object>, name: String, value: Rc<Object>) {
532        let Object::Instance(instance) = &**receiver else {
533            panic!("cannot set property '{}' of {}", name, receiver);
534        };
535        instance.borrow_mut().fields.insert(name, value);
536    }
537
538    fn execute_new(&mut self, num_args: usize) {
539        let base = self.sp - num_args - 1;
540        let class = match &*self.stack[base] {
541            Object::Class(class) => Rc::clone(class),
542            value => panic!("cannot construct {}", value),
543        };
544        let instance = Rc::new(RefCell::new(InstanceObject {
545            class: Rc::clone(&class),
546            fields: HashMap::new(),
547        }));
548        let instance_value = Rc::new(Object::Instance(instance));
549        let constructor = class.borrow().constructor.clone();
550        let Some(constructor) = constructor else {
551            if num_args != 0 {
552                panic!(
553                    "wrong number of arguments for {}.constructor: want=0, got={}",
554                    class.borrow().name,
555                    num_args
556                );
557            }
558            self.sp = base;
559            self.push(instance_value);
560            return;
561        };
562
563        let closure = match &*constructor {
564            Object::ClosureObj(closure) => closure.clone(),
565            value => panic!("constructor is not a closure: {}", value),
566        };
567        let expected = closure.func.num_parameters.saturating_sub(1);
568        if expected != num_args {
569            panic!(
570                "wrong number of arguments for {}.constructor: want={}, got={}",
571                class.borrow().name,
572                expected,
573                num_args
574            );
575        }
576        self.rewrite_receiver_call(constructor, instance_value, num_args);
577        self.call_closure(closure, num_args + 1);
578    }
579
580    fn call_bound_method(&mut self, bound: Rc<BoundMethodObject>, num_args: usize) {
581        let closure = match &*bound.method {
582            Object::ClosureObj(closure) => closure.clone(),
583            value => panic!("bound method is not a closure: {}", value),
584        };
585        let expected = closure.func.num_parameters.saturating_sub(1);
586        if expected != num_args {
587            let class_name = bound.receiver.borrow().class.borrow().name.clone();
588            panic!(
589                "wrong number of arguments for {}.{}: want={}, got={}",
590                class_name, bound.name, expected, num_args
591            );
592        }
593        let receiver = Rc::new(Object::Instance(Rc::clone(&bound.receiver)));
594        self.rewrite_receiver_call(Rc::clone(&bound.method), receiver, num_args);
595        self.call_closure(closure, num_args + 1);
596    }
597
598    fn rewrite_receiver_call(
599        &mut self,
600        callable: Rc<Object>,
601        receiver: Rc<Object>,
602        num_args: usize,
603    ) {
604        let base = self.sp - num_args - 1;
605        for index in (base + 1..self.sp).rev() {
606            self.stack[index + 1] = Rc::clone(&self.stack[index]);
607        }
608        self.stack[base] = callable;
609        self.stack[base + 1] = receiver;
610        self.sp += 1;
611    }
612}