1use std::collections::{HashMap, HashSet};
2
3use byteorder::{BigEndian, ByteOrder};
4use compiler::compiler::{Bytecode, DebugInfo};
5use compiler::op_code::Opcode;
6use object::builtins::{BuiltIns, BuiltinId};
7use object::Object;
8use parser::lexer::token::Span;
9use serde::Serialize;
10
11use crate::frame::Frame;
12use crate::report::{
13 empty_value_kind_counts, select_global_roots, summarize_gc_object, GcCollectionReport,
14 GlobalRoot,
15};
16use crate::value::{
17 alloc_value, call_builtin, export_object, get_value, get_value_mut, import_object,
18 try_export_object, value_to_string, GcBoundMethod, GcClass, GcClosure, GcInstance, HashKey,
19 Value,
20};
21use crate::{GcHeap, GcId, GcRef};
22
23const STACK_SIZE: usize = 2048;
24pub const GLOBAL_SIZE: usize = 65536;
25const MAX_FRAMES: usize = 1024;
26pub const DEFAULT_INSTRUCTION_BUDGET: usize = 100_000;
27
28#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
29#[serde(rename_all = "camelCase")]
30pub struct GcRuntimeError {
31 pub message: String,
32 pub span: Option<Span>,
33}
34
35enum CalleeKind {
36 Closure(GcClosure),
37 Builtin(BuiltinId),
38 BoundMethod(GcBoundMethod),
39 Class(String),
40 Other(String),
41}
42
43pub struct GcVM {
44 heap: GcHeap,
45 constants: Vec<GcRef>,
46 stack: Vec<GcRef>,
47 sp: usize,
48 globals: Vec<GcRef>,
49 global_names: Vec<(String, usize)>,
50 frames: Vec<Frame>,
51 frame_index: usize,
52 null: GcRef,
53 last_popped: GcRef,
54 main_debug_info: DebugInfo,
55 function_debug_info: HashMap<GcRef, DebugInfo>,
56}
57
58impl GcVM {
59 pub fn new(bytecode: Bytecode) -> Self {
60 let Bytecode {
61 instructions,
62 constants: object_constants,
63 debug_info: main_debug_info,
64 function_debug_info: object_function_debug_info,
65 } = bytecode;
66 let mut heap = GcHeap::new();
67 let null = alloc_value(&mut heap, Value::Null);
68 let constants = object_constants
69 .iter()
70 .map(|constant| import_object(&mut heap, constant))
71 .collect::<Vec<_>>();
72 let function_debug_info = object_function_debug_info
73 .into_iter()
74 .filter_map(|(index, debug_info)| {
75 constants
76 .get(index)
77 .copied()
78 .map(|reference| (reference, debug_info))
79 })
80 .collect();
81
82 let main_fn = alloc_value(
83 &mut heap,
84 Value::CompiledFunction(object::CompiledFunction {
85 name: String::new(),
86 instructions: instructions.data,
87 num_locals: 0,
88 num_parameters: 0,
89 }),
90 );
91 let main_instructions = compiled_instructions(&heap, main_fn);
92 let main_frame = Frame::new(
95 GcClosure {
96 func: main_fn,
97 free: vec![],
98 },
99 main_instructions,
100 0,
101 );
102
103 let empty_frame = Frame::new(
104 GcClosure {
105 func: main_fn,
106 free: vec![],
107 },
108 vec![],
109 0,
110 );
111
112 let mut frames = vec![empty_frame; MAX_FRAMES];
113 frames[0] = main_frame;
114
115 let stack = (0..STACK_SIZE).map(|_| heap.dup(null)).collect();
116 let globals = (0..GLOBAL_SIZE).map(|_| heap.dup(null)).collect();
117 let last_popped = heap.dup(null);
118
119 GcVM {
120 heap,
121 constants,
122 stack,
123 sp: 0,
124 globals,
125 global_names: Vec::new(),
126 frames,
127 frame_index: 1,
128 null,
129 last_popped,
130 main_debug_info,
131 function_debug_info,
132 }
133 }
134
135 pub fn load_bytecode(&mut self, bytecode: Bytecode) {
141 let Bytecode {
142 instructions,
143 constants: object_constants,
144 debug_info: main_debug_info,
145 function_debug_info: object_function_debug_info,
146 } = bytecode;
147
148 self.clear_stack_range(0, self.sp);
149 self.sp = 0;
150
151 self.heap.free(self.last_popped);
154 self.last_popped = self.heap.dup(self.null);
155
156 for reference in self.constants.drain(..) {
157 self.heap.free(reference);
158 }
159 self.function_debug_info.clear();
160
161 let old_main = self.frames[0].cl.func;
162 self.heap.free(old_main);
163
164 self.constants = object_constants
165 .iter()
166 .map(|constant| import_object(&mut self.heap, constant))
167 .collect::<Vec<_>>();
168 self.function_debug_info = object_function_debug_info
169 .into_iter()
170 .filter_map(|(index, debug_info)| {
171 self.constants
172 .get(index)
173 .copied()
174 .map(|reference| (reference, debug_info))
175 })
176 .collect();
177 self.main_debug_info = main_debug_info;
178
179 let main_fn = alloc_value(
180 &mut self.heap,
181 Value::CompiledFunction(object::CompiledFunction {
182 name: String::new(),
183 instructions: instructions.data,
184 num_locals: 0,
185 num_parameters: 0,
186 }),
187 );
188 let main_instructions = compiled_instructions(&self.heap, main_fn);
189 let main_frame = Frame::new(
190 GcClosure {
191 func: main_fn,
192 free: vec![],
193 },
194 main_instructions,
195 0,
196 );
197 let empty_frame = Frame::new(
198 GcClosure {
199 func: main_fn,
200 free: vec![],
201 },
202 vec![],
203 0,
204 );
205 self.frames = vec![empty_frame; MAX_FRAMES];
206 self.frames[0] = main_frame;
207 self.frame_index = 1;
208 }
209
210 pub fn heap(&self) -> &GcHeap {
211 &self.heap
212 }
213
214 pub fn heap_mut(&mut self) -> &mut GcHeap {
215 &mut self.heap
216 }
217
218 pub fn set_global_names(&mut self, names: Vec<(String, usize)>) {
221 self.global_names = names;
222 }
223
224 pub fn collect_garbage(&mut self) -> GcCollectionReport {
225 let global_roots = self
228 .global_names
229 .iter()
230 .filter(|(_, index)| *index < self.globals.len())
231 .map(|(name, index)| GlobalRoot {
232 name: name.clone(),
233 object_id: self.globals[*index].0,
234 })
235 .collect();
236 let before_kinds = self.heap.value_kinds_by_id();
237 let before = self.heap.snapshot();
238 let diagnostics = self.heap.run_gc_with_stats_bundle();
239 let after = self.heap.snapshot();
240 let mut collected_by_value_kind = empty_value_kind_counts();
241 for (id, kind) in before_kinds {
242 if !self.heap.runtime().object_exists(id) {
243 *collected_by_value_kind.entry(kind).or_default() += 1;
244 }
245 }
246 let mut objects = diagnostics.objects;
247 let cataloged: HashSet<GcId> = objects.iter().map(|object| object.id).collect();
248 let (global_roots, omitted_global_roots) = select_global_roots(global_roots, &cataloged);
249 let mut uncataloged: Vec<GcId> = global_roots
254 .iter()
255 .map(|root| root.object_id)
256 .filter(|id| !cataloged.contains(id))
257 .collect();
258 uncataloged.sort_unstable();
259 uncataloged.dedup();
260 for id in uncataloged {
261 objects.push(summarize_gc_object(self.heap.runtime(), id));
262 }
263 objects.sort_unstable_by_key(|object| object.id);
264 GcCollectionReport {
265 before,
266 after,
267 objects,
268 global_roots,
269 omitted_global_roots,
270 phases: diagnostics.phases,
271 collected_by_value_kind,
272 }
273 }
274
275 fn runtime_error(&self, message: impl Into<String>) -> GcRuntimeError {
276 let frame = &self.frames[self.frame_index - 1];
277 let debug_info = if self.frame_index == 1 {
278 Some(&self.main_debug_info)
279 } else {
280 self.function_debug_info.get(&frame.cl.func)
281 };
282 let span = debug_info.and_then(|debug_info| {
283 (frame.ip >= 0)
284 .then(|| frame.ip as usize)
285 .and_then(|pc| debug_info.span_for_pc(pc).cloned())
286 });
287 GcRuntimeError {
288 message: message.into(),
289 span,
290 }
291 }
292
293 pub fn run(&mut self) {
294 self.run_with_budget(usize::MAX)
295 .expect("GC VM execution failed");
296 }
297
298 pub fn run_with_budget(&mut self, instruction_budget: usize) -> Result<(), GcRuntimeError> {
299 let mut executed = 0;
300 while self.current_frame().ip < self.current_frame().instructions.len() as i32 - 1 {
301 self.current_frame().ip += 1;
302 let ip = self.current_frame().ip as usize;
303 if executed >= instruction_budget {
304 return Err(self.runtime_error(format!(
305 "instruction limit exceeded (budget: {})",
306 instruction_budget
307 )));
308 }
309 executed += 1;
310 let ins = self.current_frame().instructions.clone();
311 let op = *ins.get(ip).unwrap();
312 let opcode = Opcode::from_repr(op)
313 .ok_or_else(|| self.runtime_error(format!("unknown opcode 0x{:02x}", op)))?;
314
315 match opcode {
316 Opcode::OpConst => {
317 let const_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
318 self.current_frame().ip += 2;
319 let constant = self.constant(const_index)?;
320 self.dup_and_push(constant)?;
321 }
322 Opcode::OpAdd | Opcode::OpSub | Opcode::OpMul | Opcode::OpDiv => {
323 self.execute_binary_operation(opcode)?;
324 }
325 Opcode::OpPop => {
326 self.pop_discard()?;
327 }
328 Opcode::OpTrue => {
329 self.alloc_and_push(Value::Boolean(true))?;
330 }
331 Opcode::OpFalse => {
332 self.alloc_and_push(Value::Boolean(false))?;
333 }
334 Opcode::OpEqual | Opcode::OpNotEqual | Opcode::OpGreaterThan => {
335 self.execute_comparison(opcode)?;
336 }
337 Opcode::OpMinus => {
338 self.execute_minus_operation()?;
339 }
340 Opcode::OpBang => {
341 self.execute_bang_operation()?;
342 }
343 Opcode::OpJump => {
344 let pos = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
345 self.current_frame().ip = pos as i32 - 1;
346 }
347 Opcode::OpJumpNotTruthy => {
348 let pos = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
349 self.current_frame().ip += 2;
350 let condition = self.pop_owned()?;
351 if !is_truthy(&self.heap, condition) {
352 self.current_frame().ip = pos as i32 - 1;
353 }
354 self.heap.free(condition);
355 }
356 Opcode::OpNull => {
357 self.dup_and_push(self.null)?;
358 }
359 Opcode::OpGetGlobal => {
360 let global_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
361 self.current_frame().ip += 2;
362 self.dup_and_push(self.globals[global_index])?;
363 }
364 Opcode::OpSetGlobal => {
365 let global_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
366 self.current_frame().ip += 2;
367 let value = self.pop_owned()?;
368 self.heap.free(self.globals[global_index]);
369 self.globals[global_index] = value;
370 }
371 Opcode::OpArray => {
372 let count = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
373 self.current_frame().ip += 2;
374 let start = self.stack_base_for(count)?;
375 let elements = self.build_array(start, self.sp);
376 let array = alloc_value(&mut self.heap, Value::Array(elements));
377 self.clear_stack_range(start, self.sp);
378 self.sp = start;
379 self.push_raw(array)?;
380 }
381 Opcode::OpHash => {
382 let count = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
383 self.current_frame().ip += 2;
384 let start = self.stack_base_for(count)?;
385 let elements = self.build_hash(start, self.sp)?;
386 let hash = alloc_value(&mut self.heap, Value::Hash(elements));
387 self.clear_stack_range(start, self.sp);
388 self.sp = start;
389 self.push_raw(hash)?;
390 }
391 Opcode::OpIndex => {
392 let (index, left) = self.pop_owned_pair()?;
393 let result = self.execute_index_operation(left, index);
394 self.heap.free(index);
395 self.heap.free(left);
396 result?;
397 }
398 Opcode::OpReturnValue => {
399 let return_value = self.pop_owned()?;
400 if self.frame_index == 1 {
401 self.clear_stack_range(0, self.sp);
404 self.sp = 0;
405 self.heap.free(self.last_popped);
406 self.last_popped = return_value;
407 break;
408 }
409 let frame = self.pop_frame();
410 let new_sp = frame.base_pointer - 1;
411 self.clear_stack_range(new_sp, self.sp);
412 self.sp = new_sp;
413 self.push_raw(return_value)?;
414 }
415 Opcode::OpReturn => {
416 if self.frame_index == 1 {
417 self.clear_stack_range(0, self.sp);
418 self.sp = 0;
419 self.heap.free(self.last_popped);
420 self.last_popped = self.heap.dup(self.null);
421 break;
422 }
423 let frame = self.pop_frame();
424 let new_sp = frame.base_pointer - 1;
425 self.clear_stack_range(new_sp, self.sp);
426 self.sp = new_sp;
427 self.dup_and_push(self.null)?;
428 }
429 Opcode::OpCall => {
430 let num_args = ins[ip + 1] as usize;
431 self.current_frame().ip += 1;
432 self.execute_call(num_args)?;
433 }
434 Opcode::OpSetLocal => {
435 let local_index = ins[ip + 1] as usize;
436 self.current_frame().ip += 1;
437 let base = self.current_frame().base_pointer;
438 let slot = self.local_slot(base, local_index)?;
439 let value = self.pop_owned()?;
440 self.heap.free(self.stack[slot]);
441 self.stack[slot] = value;
442 }
443 Opcode::OpGetLocal => {
444 let local_index = ins[ip + 1] as usize;
445 self.current_frame().ip += 1;
446 let base = self.current_frame().base_pointer;
447 let slot = self.local_slot(base, local_index)?;
448 self.dup_and_push(self.stack[slot])?;
449 }
450 Opcode::OpGetBuiltin => {
451 let built_index = ins[ip + 1] as usize;
452 self.current_frame().ip += 1;
453 let definition = BuiltIns.get(built_index).ok_or_else(|| {
454 self.runtime_error(format!("builtin index {} out of range", built_index))
455 })?;
456 self.alloc_and_push(Value::Builtin(definition.id))?;
457 }
458 Opcode::OpClosure => {
459 let const_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
460 let num_free = ins[ip + 3] as usize;
461 self.current_frame().ip += 3;
462 self.push_closure(const_index, num_free)?;
463 }
464 Opcode::OpGetFree => {
465 let free_index = ins[ip + 1] as usize;
466 self.current_frame().ip += 1;
467 let free_var = self.current_frame().cl.free.get(free_index).copied();
468 let free_var = free_var.ok_or_else(|| {
469 self.runtime_error(format!(
470 "free variable index {} out of range",
471 free_index
472 ))
473 })?;
474 self.dup_and_push(free_var)?;
475 }
476 Opcode::OpCurrentClosure => {
477 let current = self.current_frame().cl.clone();
478 self.alloc_and_push(Value::Closure(current))?;
479 }
480 Opcode::OpClass => {
481 let name_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
482 self.current_frame().ip += 2;
483 let name = self.constant_string(name_index)?;
484 self.alloc_and_push(Value::Class(GcClass {
485 name,
486 constructor: None,
487 methods: HashMap::new(),
488 }))?;
489 }
490 Opcode::OpMethod => {
491 let name_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
492 let kind = ins[ip + 3];
493 self.current_frame().ip += 3;
494 let name = self.constant_string(name_index)?;
495 let method = self.pop_owned()?;
496 if self.sp == 0 {
497 self.heap.free(method);
498 return Err(self.runtime_error("stack underflow"));
499 }
500 let class = self.stack[self.sp - 1];
501 let result = self.install_method(class, name, method, kind == 1);
502 self.heap.free(method);
503 result?;
504 }
505 Opcode::OpGetProperty => {
506 let name_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
507 self.current_frame().ip += 2;
508 let name = self.constant_string(name_index)?;
509 let receiver = self.pop_owned()?;
510 let value = self.get_property(receiver, &name);
511 self.heap.free(receiver);
512 self.push_raw(value?)?;
513 }
514 Opcode::OpSetProperty => {
515 let name_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
516 self.current_frame().ip += 2;
517 let name = self.constant_string(name_index)?;
518 let (value, receiver) = self.pop_owned_pair()?;
519 let result = self.set_property(receiver, name, value);
520 self.heap.free(value);
521 self.heap.free(receiver);
522 result?;
523 }
524 Opcode::OpNew => {
525 let num_args = ins[ip + 1] as usize;
526 self.current_frame().ip += 1;
527 self.execute_new(num_args)?;
528 }
529 }
530 }
531 Ok(())
532 }
533
534 pub fn last_popped_stack_elm(&self) -> Option<GcRef> {
535 Some(self.last_popped)
536 }
537
538 pub fn export_last_result(&self) -> Option<Object> {
539 self.last_popped_stack_elm()
540 .map(|reference| export_object(&self.heap, reference))
541 }
542
543 pub fn try_export_last_result(&self) -> Result<Object, String> {
544 try_export_object(&self.heap, self.last_popped)
545 }
546
547 pub fn last_result_string(&self) -> String {
548 value_to_string(&self.heap, self.last_popped)
549 }
550
551 fn alloc_and_push(&mut self, value: Value) -> Result<(), GcRuntimeError> {
552 let reference = alloc_value(&mut self.heap, value);
553 self.push_raw(reference)
554 }
555
556 fn dup_and_push(&mut self, reference: GcRef) -> Result<(), GcRuntimeError> {
557 let duplicated = self.heap.dup(reference);
558 self.push_raw(duplicated)
559 }
560
561 fn push_raw(&mut self, value: GcRef) -> Result<(), GcRuntimeError> {
562 if self.sp >= STACK_SIZE {
563 let error = self.runtime_error("stack limit exceeded");
564 self.heap.free(value);
565 return Err(error);
566 }
567 let old = self.stack[self.sp];
568 self.stack[self.sp] = value;
569 self.heap.free(old);
570 self.sp += 1;
571 Ok(())
572 }
573
574 fn pop_owned(&mut self) -> Result<GcRef, GcRuntimeError> {
579 if self.sp == 0 {
580 return Err(self.runtime_error("stack underflow"));
581 }
582 self.sp -= 1;
583 let value = self.stack[self.sp];
584 self.stack[self.sp] = self.heap.dup(self.null);
585 Ok(value)
586 }
587
588 fn pop_discard(&mut self) -> Result<(), GcRuntimeError> {
589 let value = self.pop_owned()?;
590 self.heap.free(self.last_popped);
591 self.last_popped = value;
592 Ok(())
593 }
594
595 fn pop_owned_pair(&mut self) -> Result<(GcRef, GcRef), GcRuntimeError> {
598 let top = self.pop_owned()?;
599 match self.pop_owned() {
600 Ok(below) => Ok((top, below)),
601 Err(error) => {
602 self.heap.free(top);
603 Err(error)
604 }
605 }
606 }
607
608 fn stack_base_for(&self, count: usize) -> Result<usize, GcRuntimeError> {
611 self.sp
612 .checked_sub(count)
613 .ok_or_else(|| self.runtime_error("stack underflow"))
614 }
615
616 fn local_slot(&self, base: usize, local_index: usize) -> Result<usize, GcRuntimeError> {
617 let slot = base + local_index;
618 if slot >= STACK_SIZE {
619 return Err(self.runtime_error(format!("local index {} out of range", local_index)));
620 }
621 Ok(slot)
622 }
623
624 fn clear_stack_range(&mut self, start: usize, end: usize) {
625 for index in start..end {
626 let old = self.stack[index];
627 self.stack[index] = self.heap.dup(self.null);
628 self.heap.free(old);
629 }
630 }
631
632 fn execute_binary_operation(&mut self, opcode: Opcode) -> Result<(), GcRuntimeError> {
633 let (right, left) = self.pop_owned_pair()?;
634 let left_value = get_value(&self.heap, left).clone();
635 let right_value = get_value(&self.heap, right).clone();
636 let result = match (&left_value, &right_value) {
637 (Value::Integer(l), Value::Integer(r)) => match opcode {
638 Opcode::OpAdd => Ok(Value::Integer(l + r)),
639 Opcode::OpSub => Ok(Value::Integer(l - r)),
640 Opcode::OpMul => Ok(Value::Integer(l * r)),
641 Opcode::OpDiv if *r != 0 => l
642 .checked_div(*r)
643 .map(Value::Integer)
644 .ok_or_else(|| "integer overflow in division".to_string()),
645 Opcode::OpDiv => Err("division by zero".to_string()),
646 _ => unreachable!(),
647 },
648 (Value::String(l), Value::String(r)) if opcode == Opcode::OpAdd => {
649 Ok(Value::String(l.to_string() + r))
650 }
651 _ => Err(format!(
652 "unsupported binary operation for {} and {}",
653 value_to_string(&self.heap, left),
654 value_to_string(&self.heap, right)
655 )),
656 };
657 self.heap.free(left);
658 self.heap.free(right);
659 match result {
660 Ok(value) => self.alloc_and_push(value),
661 Err(message) => Err(self.runtime_error(message)),
662 }
663 }
664
665 fn execute_comparison(&mut self, opcode: Opcode) -> Result<(), GcRuntimeError> {
666 let (right, left) = self.pop_owned_pair()?;
667 let result = match (get_value(&self.heap, left), get_value(&self.heap, right)) {
668 (Value::Integer(l), Value::Integer(r)) => match opcode {
669 Opcode::OpEqual => Some(l == r),
670 Opcode::OpNotEqual => Some(l != r),
671 Opcode::OpGreaterThan => Some(l > r),
672 _ => unreachable!(),
673 },
674 (Value::Boolean(l), Value::Boolean(r)) => match opcode {
675 Opcode::OpEqual => Some(l == r),
676 Opcode::OpNotEqual => Some(l != r),
677 _ => None,
678 },
679 (Value::String(l), Value::String(r)) => match opcode {
680 Opcode::OpEqual => Some(l == r),
681 Opcode::OpNotEqual => Some(l != r),
682 _ => None,
683 },
684 (Value::Null, Value::Null) => match opcode {
685 Opcode::OpEqual => Some(true),
686 Opcode::OpNotEqual => Some(false),
687 _ => None,
688 },
689 (Value::Class(_), Value::Class(_))
690 | (Value::Instance(_), Value::Instance(_))
691 | (Value::BoundMethod(_), Value::BoundMethod(_)) => match opcode {
692 Opcode::OpEqual => Some(left == right),
693 Opcode::OpNotEqual => Some(left != right),
694 _ => None,
695 },
696 _ => None,
697 };
698 let message = if result.is_none() {
699 Some(format!(
700 "unsupported comparison for {} and {}",
701 value_to_string(&self.heap, left),
702 value_to_string(&self.heap, right)
703 ))
704 } else {
705 None
706 };
707 self.heap.free(left);
708 self.heap.free(right);
709 if let Some(result) = result {
710 self.alloc_and_push(Value::Boolean(result))
711 } else {
712 Err(self.runtime_error(message.unwrap()))
713 }
714 }
715
716 fn execute_minus_operation(&mut self) -> Result<(), GcRuntimeError> {
717 let operand = self.pop_owned()?;
718 let negated = match get_value(&self.heap, operand) {
719 Value::Integer(value) => Some(-value),
720 _ => None,
721 };
722 let message = negated.is_none().then(|| {
723 format!("unsupported type for negation: {}", value_to_string(&self.heap, operand))
724 });
725 self.heap.free(operand);
726 if let Some(negated) = negated {
727 self.alloc_and_push(Value::Integer(negated))
728 } else {
729 Err(self.runtime_error(message.unwrap()))
730 }
731 }
732
733 fn execute_bang_operation(&mut self) -> Result<(), GcRuntimeError> {
734 let operand = self.pop_owned()?;
735 let result = match get_value(&self.heap, operand) {
736 Value::Boolean(l) => !l,
737 _ => false,
738 };
739 self.heap.free(operand);
740 self.alloc_and_push(Value::Boolean(result))
741 }
742
743 fn build_array(&mut self, start: usize, end: usize) -> Vec<GcRef> {
744 let mut elements = Vec::with_capacity(end - start);
745 for i in start..end {
746 elements.push(self.stack[i]);
747 }
748 elements
749 }
750
751 fn build_hash(
752 &mut self,
753 start: usize,
754 end: usize,
755 ) -> Result<HashMap<HashKey, GcRef>, GcRuntimeError> {
756 let mut elements = HashMap::new();
757 for i in (start..end).step_by(2) {
758 let key_ref = self.stack[i];
759 let key = HashKey::from_value(get_value(&self.heap, key_ref)).ok_or_else(|| {
760 self.runtime_error(format!(
761 "hash key must be hashable, got {}",
762 value_to_string(&self.heap, key_ref)
763 ))
764 })?;
765 elements.insert(key, self.stack[i + 1]);
766 }
767 Ok(elements)
768 }
769
770 fn execute_index_operation(&mut self, left: GcRef, index: GcRef) -> Result<(), GcRuntimeError> {
771 let left_value = get_value(&self.heap, left).clone();
772 let index_value = get_value(&self.heap, index).clone();
773 match (&left_value, &index_value) {
774 (Value::Array(array), Value::Integer(i)) => self.execute_array_index(array, *i),
775 (Value::Hash(hash), _) => self.execute_hash_index(hash, &index_value),
776 _ => Err(self.runtime_error(format!(
777 "unsupported index operation for {} and {}",
778 value_to_string(&self.heap, left),
779 value_to_string(&self.heap, index)
780 ))),
781 }
782 }
783
784 fn execute_array_index(&mut self, array: &[GcRef], index: i64) -> Result<(), GcRuntimeError> {
785 if index < array.len() as i64 && index >= 0 {
786 self.dup_and_push(array[index as usize])
787 } else {
788 self.dup_and_push(self.null)
789 }
790 }
791
792 fn execute_hash_index(
793 &mut self,
794 hash: &HashMap<HashKey, GcRef>,
795 index: &Value,
796 ) -> Result<(), GcRuntimeError> {
797 let key = HashKey::from_value(index)
798 .ok_or_else(|| self.runtime_error("unsupported hash index key"))?;
799 match hash.get(&key) {
800 Some(value) => self.dup_and_push(*value),
801 None => self.dup_and_push(self.null),
802 }
803 }
804
805 fn current_frame(&mut self) -> &mut Frame {
806 &mut self.frames[self.frame_index - 1]
807 }
808
809 fn push_frame(&mut self, frame: Frame) -> Result<(), GcRuntimeError> {
810 if self.frame_index >= MAX_FRAMES {
811 return Err(self.runtime_error("frame limit exceeded"));
812 }
813 self.frames[self.frame_index] = frame;
814 self.frame_index += 1;
815 Ok(())
816 }
817
818 fn pop_frame(&mut self) -> Frame {
819 self.frame_index -= 1;
820 self.frames[self.frame_index].clone()
821 }
822
823 fn execute_call(&mut self, num_args: usize) -> Result<(), GcRuntimeError> {
824 let callee_slot = self.stack_base_for(num_args + 1)?;
825 let callee = self.stack[callee_slot];
826 match callee_kind(&self.heap, callee) {
827 CalleeKind::Closure(closure) => self.call_closure(closure, num_args),
828 CalleeKind::Builtin(builtin) => self.call_builtin(builtin, num_args),
829 CalleeKind::BoundMethod(bound) => self.call_bound_method(bound, num_args),
830 CalleeKind::Class(name) => {
831 Err(self.runtime_error(format!("class {} must be constructed with new", name)))
832 }
833 CalleeKind::Other(value) => Err(self.runtime_error(format!("cannot call {}", value))),
834 }
835 }
836
837 fn call_closure(&mut self, closure: GcClosure, num_args: usize) -> Result<(), GcRuntimeError> {
838 let compiled = match get_value(&self.heap, closure.func) {
839 Value::CompiledFunction(f) => f.clone(),
840 _ => return Err(self.runtime_error("closure without compiled function")),
841 };
842 if compiled.num_parameters != num_args {
843 return Err(self.runtime_error(format!(
844 "wrong number of arguments: want={}, got={}",
845 compiled.num_parameters, num_args
846 )));
847 }
848
849 let frame = Frame::new(closure, compiled.instructions, self.sp - num_args);
850 let next_sp = frame
853 .base_pointer
854 .checked_add(compiled.num_locals)
855 .filter(|next_sp| *next_sp <= STACK_SIZE)
856 .ok_or_else(|| self.runtime_error("stack limit exceeded"))?;
857 self.sp = next_sp;
858 self.push_frame(frame)
859 }
860
861 fn call_builtin(&mut self, builtin: BuiltinId, num_args: usize) -> Result<(), GcRuntimeError> {
862 let base = self.sp - num_args - 1;
863 let args = self.stack[self.sp - num_args..self.sp].to_vec();
864 let result = call_builtin(&mut self.heap, builtin, &args, self.null);
865 self.clear_stack_range(base, self.sp);
866 self.sp = base;
867 self.push_raw(result)
868 }
869
870 fn push_closure(&mut self, const_index: usize, num_free: usize) -> Result<(), GcRuntimeError> {
871 let func = self.constant(const_index)?;
872 if !matches!(get_value(&self.heap, func), Value::CompiledFunction(_)) {
873 return Err(self.runtime_error(format!(
874 "cannot build closure over {}",
875 value_to_string(&self.heap, func)
876 )));
877 }
878 let start = self.stack_base_for(num_free)?;
879 let mut free = Vec::with_capacity(num_free);
880 for i in 0..num_free {
881 free.push(self.stack[start + i]);
882 }
883 let closure = alloc_value(
884 &mut self.heap,
885 Value::Closure(GcClosure {
886 func,
887 free,
888 }),
889 );
890 self.clear_stack_range(start, self.sp);
891 self.sp = start;
892 self.push_raw(closure)
893 }
894
895 fn constant(&self, index: usize) -> Result<GcRef, GcRuntimeError> {
896 self.constants
897 .get(index)
898 .copied()
899 .ok_or_else(|| self.runtime_error(format!("constant index {} out of range", index)))
900 }
901
902 fn constant_string(&self, index: usize) -> Result<String, GcRuntimeError> {
903 let constant = self.constant(index)?;
904 match get_value(&self.heap, constant) {
905 Value::String(value) => Ok(value.clone()),
906 value => Err(self.runtime_error(format!("expected string constant, got {}", value))),
907 }
908 }
909
910 fn install_method(
911 &mut self,
912 class: GcRef,
913 name: String,
914 method: GcRef,
915 constructor: bool,
916 ) -> Result<(), GcRuntimeError> {
917 if !matches!(get_value(&self.heap, class), Value::Class(_)) {
918 return Err(self.runtime_error(format!(
919 "cannot install method on {}",
920 value_to_string(&self.heap, class)
921 )));
922 }
923 let owned_method = self.heap.dup(method);
924 let old_method = match get_value_mut(&mut self.heap, class) {
925 Value::Class(class) => {
926 if constructor {
927 class.constructor.replace(owned_method)
928 } else {
929 class.methods.insert(name, owned_method)
930 }
931 }
932 _ => unreachable!(),
933 };
934 if let Some(old_method) = old_method {
935 self.heap.free(old_method);
936 }
937 Ok(())
938 }
939
940 fn get_property(&mut self, receiver: GcRef, name: &str) -> Result<GcRef, GcRuntimeError> {
941 let (class, field) = match get_value(&self.heap, receiver) {
942 Value::Instance(instance) => (instance.class, instance.fields.get(name).copied()),
943 _ => {
944 return Err(self.runtime_error(format!(
945 "cannot read property '{}' of {}",
946 name,
947 value_to_string(&self.heap, receiver)
948 )))
949 }
950 };
951 if let Some(field) = field {
952 return Ok(self.heap.dup(field));
953 }
954
955 let (class_name, method) = match get_value(&self.heap, class) {
956 Value::Class(class) => (class.name.clone(), class.methods.get(name).copied()),
957 _ => return Err(self.runtime_error("instance has invalid class")),
958 };
959 match method {
960 Some(method) => Ok(alloc_value(
961 &mut self.heap,
962 Value::BoundMethod(GcBoundMethod {
963 receiver,
964 method,
965 name: name.to_string(),
966 }),
967 )),
968 None => {
969 Err(self
970 .runtime_error(format!("property '{}' does not exist on {}", name, class_name)))
971 }
972 }
973 }
974
975 fn set_property(
976 &mut self,
977 receiver: GcRef,
978 name: String,
979 value: GcRef,
980 ) -> Result<(), GcRuntimeError> {
981 if !matches!(get_value(&self.heap, receiver), Value::Instance(_)) {
982 return Err(self.runtime_error(format!(
983 "cannot set property '{}' of {}",
984 name,
985 value_to_string(&self.heap, receiver)
986 )));
987 }
988 let owned_value = self.heap.dup(value);
989 let old_value = match get_value_mut(&mut self.heap, receiver) {
990 Value::Instance(instance) => instance.fields.insert(name, owned_value),
991 _ => unreachable!(),
992 };
993 if let Some(old_value) = old_value {
994 self.heap.free(old_value);
995 }
996 Ok(())
997 }
998
999 fn execute_new(&mut self, num_args: usize) -> Result<(), GcRuntimeError> {
1000 let base = self.stack_base_for(num_args + 1)?;
1001 let class_reference = self.stack[base];
1002 let (class_name, constructor) = match get_value(&self.heap, class_reference) {
1003 Value::Class(class) => (class.name.clone(), class.constructor),
1004 _ => {
1005 return Err(self.runtime_error(format!(
1006 "cannot construct {}",
1007 value_to_string(&self.heap, class_reference)
1008 )))
1009 }
1010 };
1011
1012 let Some(constructor) = constructor else {
1013 if num_args != 0 {
1014 return Err(self.runtime_error(format!(
1015 "wrong number of arguments for {}.constructor: want=0, got={}",
1016 class_name, num_args
1017 )));
1018 }
1019 let instance = alloc_value(
1020 &mut self.heap,
1021 Value::Instance(GcInstance {
1022 class: class_reference,
1023 fields: HashMap::new(),
1024 }),
1025 );
1026 self.clear_stack_range(base, self.sp);
1027 self.sp = base;
1028 return self.push_raw(instance);
1029 };
1030
1031 let closure = match get_value(&self.heap, constructor) {
1032 Value::Closure(closure) => closure.clone(),
1033 _ => return Err(self.runtime_error("constructor is not a closure")),
1034 };
1035 let compiled = match get_value(&self.heap, closure.func) {
1036 Value::CompiledFunction(function) => function.clone(),
1037 _ => return Err(self.runtime_error("constructor closure has invalid function")),
1038 };
1039 let expected = compiled.num_parameters.saturating_sub(1);
1040 if expected != num_args {
1041 return Err(self.runtime_error(format!(
1042 "wrong number of arguments for {}.constructor: want={}, got={}",
1043 class_name, expected, num_args
1044 )));
1045 }
1046
1047 let instance = alloc_value(
1048 &mut self.heap,
1049 Value::Instance(GcInstance {
1050 class: class_reference,
1051 fields: HashMap::new(),
1052 }),
1053 );
1054 self.rewrite_receiver_call(constructor, instance, num_args)?;
1055 self.call_closure(closure, num_args + 1)
1056 }
1057
1058 fn call_bound_method(
1059 &mut self,
1060 bound: GcBoundMethod,
1061 num_args: usize,
1062 ) -> Result<(), GcRuntimeError> {
1063 let closure = match get_value(&self.heap, bound.method) {
1064 Value::Closure(closure) => closure.clone(),
1065 _ => return Err(self.runtime_error("bound method is not a closure")),
1066 };
1067 let compiled = match get_value(&self.heap, closure.func) {
1068 Value::CompiledFunction(function) => function.clone(),
1069 _ => return Err(self.runtime_error("method closure has invalid function")),
1070 };
1071 let expected = compiled.num_parameters.saturating_sub(1);
1072 if expected != num_args {
1073 let class_name = match get_value(&self.heap, bound.receiver) {
1074 Value::Instance(instance) => match get_value(&self.heap, instance.class) {
1075 Value::Class(class) => class.name.clone(),
1076 _ => "<invalid class>".to_string(),
1077 },
1078 _ => "<invalid receiver>".to_string(),
1079 };
1080 return Err(self.runtime_error(format!(
1081 "wrong number of arguments for {}.{}: want={}, got={}",
1082 class_name, bound.name, expected, num_args
1083 )));
1084 }
1085 let receiver = self.heap.dup(bound.receiver);
1086 self.rewrite_receiver_call(bound.method, receiver, num_args)?;
1087 self.call_closure(closure, num_args + 1)
1088 }
1089
1090 fn rewrite_receiver_call(
1093 &mut self,
1094 callable: GcRef,
1095 receiver: GcRef,
1096 num_args: usize,
1097 ) -> Result<(), GcRuntimeError> {
1098 let base = self.sp - num_args - 1;
1099 if base + num_args + 2 > STACK_SIZE {
1100 let error = self.runtime_error("stack limit exceeded");
1101 self.heap.free(receiver);
1102 return Err(error);
1103 }
1104 let callable = self.heap.dup(callable);
1105 let borrowed_arguments = self.stack[self.sp - num_args..self.sp].to_vec();
1106 let arguments = borrowed_arguments
1107 .into_iter()
1108 .map(|argument| self.heap.dup(argument))
1109 .collect::<Vec<_>>();
1110 self.clear_stack_range(base, self.sp);
1111 self.sp = base;
1112 self.push_raw(callable)?;
1113 self.push_raw(receiver)?;
1114 for argument in arguments {
1115 self.push_raw(argument)?;
1116 }
1117 Ok(())
1118 }
1119}
1120
1121fn is_truthy(heap: &GcHeap, condition: GcRef) -> bool {
1122 match get_value(heap, condition) {
1123 Value::Boolean(b) => *b,
1124 Value::Null => false,
1125 _ => true,
1126 }
1127}
1128
1129fn callee_kind(heap: &GcHeap, reference: GcRef) -> CalleeKind {
1130 match get_value(heap, reference) {
1131 Value::Closure(closure) => CalleeKind::Closure(closure.clone()),
1132 Value::Builtin(builtin) => CalleeKind::Builtin(*builtin),
1133 Value::BoundMethod(bound) => CalleeKind::BoundMethod(bound.clone()),
1134 Value::Class(class) => CalleeKind::Class(class.name.clone()),
1135 _ => CalleeKind::Other(value_to_string(heap, reference)),
1136 }
1137}
1138
1139fn compiled_instructions(heap: &GcHeap, func: GcRef) -> Vec<u8> {
1140 match get_value(heap, func) {
1141 Value::CompiledFunction(f) => f.instructions.clone(),
1142 _ => panic!("expected compiled function"),
1143 }
1144}