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