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_some(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
335 | Opcode::OpNotEqual
336 | Opcode::OpGreaterThan
337 | Opcode::OpLessThan => {
338 self.execute_comparison(opcode)?;
339 }
340 Opcode::OpMinus => {
341 self.execute_minus_operation()?;
342 }
343 Opcode::OpBang => {
344 self.execute_bang_operation()?;
345 }
346 Opcode::OpJump => {
347 let pos = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
348 self.current_frame().ip = pos as i32 - 1;
349 }
350 Opcode::OpJumpNotTruthy => {
351 let pos = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
352 self.current_frame().ip += 2;
353 let condition = self.pop_owned()?;
354 if !is_truthy(&self.heap, condition) {
355 self.current_frame().ip = pos as i32 - 1;
356 }
357 self.heap.free(condition);
358 }
359 Opcode::OpNull => {
360 self.dup_and_push(self.null)?;
361 }
362 Opcode::OpGetGlobal => {
363 let global_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
364 self.current_frame().ip += 2;
365 self.dup_and_push(self.globals[global_index])?;
366 }
367 Opcode::OpSetGlobal => {
368 let global_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
369 self.current_frame().ip += 2;
370 let value = self.pop_owned()?;
371 self.heap.free(self.globals[global_index]);
372 self.globals[global_index] = value;
373 }
374 Opcode::OpArray => {
375 let count = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
376 self.current_frame().ip += 2;
377 let start = self.stack_base_for(count)?;
378 let elements = self.build_array(start, self.sp);
379 let array = alloc_value(&mut self.heap, Value::Array(elements));
380 self.clear_stack_range(start, self.sp);
381 self.sp = start;
382 self.push_raw(array)?;
383 }
384 Opcode::OpHash => {
385 let count = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
386 self.current_frame().ip += 2;
387 let start = self.stack_base_for(count)?;
388 let elements = self.build_hash(start, self.sp)?;
389 let hash = alloc_value(&mut self.heap, Value::Hash(elements));
390 self.clear_stack_range(start, self.sp);
391 self.sp = start;
392 self.push_raw(hash)?;
393 }
394 Opcode::OpIndex => {
395 let (index, left) = self.pop_owned_pair()?;
396 let result = self.execute_index_operation(left, index);
397 self.heap.free(index);
398 self.heap.free(left);
399 result?;
400 }
401 Opcode::OpReturnValue => {
402 let return_value = self.pop_owned()?;
403 if self.frame_index == 1 {
404 self.clear_stack_range(0, self.sp);
407 self.sp = 0;
408 self.heap.free(self.last_popped);
409 self.last_popped = return_value;
410 break;
411 }
412 let frame = self.pop_frame();
413 let new_sp = frame.base_pointer - 1;
414 self.clear_stack_range(new_sp, self.sp);
415 self.sp = new_sp;
416 self.push_raw(return_value)?;
417 }
418 Opcode::OpReturn => {
419 if self.frame_index == 1 {
420 self.clear_stack_range(0, self.sp);
421 self.sp = 0;
422 self.heap.free(self.last_popped);
423 self.last_popped = self.heap.dup(self.null);
424 break;
425 }
426 let frame = self.pop_frame();
427 let new_sp = frame.base_pointer - 1;
428 self.clear_stack_range(new_sp, self.sp);
429 self.sp = new_sp;
430 self.dup_and_push(self.null)?;
431 }
432 Opcode::OpCall => {
433 let num_args = ins[ip + 1] as usize;
434 self.current_frame().ip += 1;
435 self.execute_call(num_args)?;
436 }
437 Opcode::OpSetLocal => {
438 let local_index = ins[ip + 1] as usize;
439 self.current_frame().ip += 1;
440 let base = self.current_frame().base_pointer;
441 let slot = self.local_slot(base, local_index)?;
442 let value = self.pop_owned()?;
443 self.heap.free(self.stack[slot]);
444 self.stack[slot] = value;
445 }
446 Opcode::OpGetLocal => {
447 let local_index = ins[ip + 1] as usize;
448 self.current_frame().ip += 1;
449 let base = self.current_frame().base_pointer;
450 let slot = self.local_slot(base, local_index)?;
451 self.dup_and_push(self.stack[slot])?;
452 }
453 Opcode::OpGetBuiltin => {
454 let built_index = ins[ip + 1] as usize;
455 self.current_frame().ip += 1;
456 let definition = BuiltIns.get(built_index).ok_or_else(|| {
457 self.runtime_error(format!("builtin index {} out of range", built_index))
458 })?;
459 self.alloc_and_push(Value::Builtin(definition.id))?;
460 }
461 Opcode::OpClosure => {
462 let const_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
463 let num_free = ins[ip + 3] as usize;
464 self.current_frame().ip += 3;
465 self.push_closure(const_index, num_free)?;
466 }
467 Opcode::OpGetFree => {
468 let free_index = ins[ip + 1] as usize;
469 self.current_frame().ip += 1;
470 let free_var = self.current_frame().cl.free.get(free_index).copied();
471 let free_var = free_var.ok_or_else(|| {
472 self.runtime_error(format!(
473 "free variable index {} out of range",
474 free_index
475 ))
476 })?;
477 self.dup_and_push(free_var)?;
478 }
479 Opcode::OpCurrentClosure => {
480 let current = self.current_frame().cl.clone();
481 self.alloc_and_push(Value::Closure(current))?;
482 }
483 Opcode::OpClass => {
484 let name_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
485 self.current_frame().ip += 2;
486 let name = self.constant_string(name_index)?;
487 self.alloc_and_push(Value::Class(GcClass {
488 name,
489 constructor: None,
490 methods: HashMap::new(),
491 }))?;
492 }
493 Opcode::OpMethod => {
494 let name_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
495 let kind = ins[ip + 3];
496 self.current_frame().ip += 3;
497 let name = self.constant_string(name_index)?;
498 let method = self.pop_owned()?;
499 if self.sp == 0 {
500 self.heap.free(method);
501 return Err(self.runtime_error("stack underflow"));
502 }
503 let class = self.stack[self.sp - 1];
504 let result = self.install_method(class, name, method, kind == 1);
505 self.heap.free(method);
506 result?;
507 }
508 Opcode::OpGetProperty => {
509 let name_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
510 self.current_frame().ip += 2;
511 let name = self.constant_string(name_index)?;
512 let receiver = self.pop_owned()?;
513 let value = self.get_property(receiver, &name);
514 self.heap.free(receiver);
515 self.push_raw(value?)?;
516 }
517 Opcode::OpSetProperty => {
518 let name_index = BigEndian::read_u16(&ins[ip + 1..ip + 3]) as usize;
519 self.current_frame().ip += 2;
520 let name = self.constant_string(name_index)?;
521 let (value, receiver) = self.pop_owned_pair()?;
522 let result = self.set_property(receiver, name, value);
523 self.heap.free(value);
524 self.heap.free(receiver);
525 result?;
526 }
527 Opcode::OpNew => {
528 let num_args = ins[ip + 1] as usize;
529 self.current_frame().ip += 1;
530 self.execute_new(num_args)?;
531 }
532 }
533 }
534 Ok(())
535 }
536
537 pub fn last_popped_stack_elm(&self) -> Option<GcRef> {
538 Some(self.last_popped)
539 }
540
541 pub fn export_last_result(&self) -> Option<Object> {
542 self.last_popped_stack_elm()
543 .map(|reference| export_object(&self.heap, reference))
544 }
545
546 pub fn try_export_last_result(&self) -> Result<Object, String> {
547 try_export_object(&self.heap, self.last_popped)
548 }
549
550 pub fn last_result_string(&self) -> String {
551 value_to_string(&self.heap, self.last_popped)
552 }
553
554 fn alloc_and_push(&mut self, value: Value) -> Result<(), GcRuntimeError> {
555 let reference = alloc_value(&mut self.heap, value);
556 self.push_raw(reference)
557 }
558
559 fn dup_and_push(&mut self, reference: GcRef) -> Result<(), GcRuntimeError> {
560 let duplicated = self.heap.dup(reference);
561 self.push_raw(duplicated)
562 }
563
564 fn push_raw(&mut self, value: GcRef) -> Result<(), GcRuntimeError> {
565 if self.sp >= STACK_SIZE {
566 let error = self.runtime_error("stack limit exceeded");
567 self.heap.free(value);
568 return Err(error);
569 }
570 let old = self.stack[self.sp];
571 self.stack[self.sp] = value;
572 self.heap.free(old);
573 self.sp += 1;
574 Ok(())
575 }
576
577 fn pop_owned(&mut self) -> Result<GcRef, GcRuntimeError> {
582 if self.sp == 0 {
583 return Err(self.runtime_error("stack underflow"));
584 }
585 self.sp -= 1;
586 let value = self.stack[self.sp];
587 self.stack[self.sp] = self.heap.dup(self.null);
588 Ok(value)
589 }
590
591 fn pop_discard(&mut self) -> Result<(), GcRuntimeError> {
592 let value = self.pop_owned()?;
593 self.heap.free(self.last_popped);
594 self.last_popped = value;
595 Ok(())
596 }
597
598 fn pop_owned_pair(&mut self) -> Result<(GcRef, GcRef), GcRuntimeError> {
601 let top = self.pop_owned()?;
602 match self.pop_owned() {
603 Ok(below) => Ok((top, below)),
604 Err(error) => {
605 self.heap.free(top);
606 Err(error)
607 }
608 }
609 }
610
611 fn stack_base_for(&self, count: usize) -> Result<usize, GcRuntimeError> {
614 self.sp
615 .checked_sub(count)
616 .ok_or_else(|| self.runtime_error("stack underflow"))
617 }
618
619 fn local_slot(&self, base: usize, local_index: usize) -> Result<usize, GcRuntimeError> {
620 let slot = base + local_index;
621 if slot >= STACK_SIZE {
622 return Err(self.runtime_error(format!("local index {} out of range", local_index)));
623 }
624 Ok(slot)
625 }
626
627 fn clear_stack_range(&mut self, start: usize, end: usize) {
628 for index in start..end {
629 let old = self.stack[index];
630 self.stack[index] = self.heap.dup(self.null);
631 self.heap.free(old);
632 }
633 }
634
635 fn execute_binary_operation(&mut self, opcode: Opcode) -> Result<(), GcRuntimeError> {
636 let (right, left) = self.pop_owned_pair()?;
637 let left_value = get_value(&self.heap, left).clone();
638 let right_value = get_value(&self.heap, right).clone();
639 let result = match (&left_value, &right_value) {
640 (Value::Integer(l), Value::Integer(r)) => match opcode {
641 Opcode::OpAdd => Ok(Value::Integer(l + r)),
642 Opcode::OpSub => Ok(Value::Integer(l - r)),
643 Opcode::OpMul => Ok(Value::Integer(l * r)),
644 Opcode::OpDiv if *r != 0 => l
645 .checked_div(*r)
646 .map(Value::Integer)
647 .ok_or_else(|| "integer overflow in division".to_string()),
648 Opcode::OpDiv => Err("division by zero".to_string()),
649 _ => unreachable!(),
650 },
651 (Value::String(l), Value::String(r)) if opcode == Opcode::OpAdd => {
652 Ok(Value::String(l.to_string() + r))
653 }
654 _ => Err(format!(
655 "unsupported binary operation for {} and {}",
656 value_to_string(&self.heap, left),
657 value_to_string(&self.heap, right)
658 )),
659 };
660 self.heap.free(left);
661 self.heap.free(right);
662 match result {
663 Ok(value) => self.alloc_and_push(value),
664 Err(message) => Err(self.runtime_error(message)),
665 }
666 }
667
668 fn execute_comparison(&mut self, opcode: Opcode) -> Result<(), GcRuntimeError> {
669 let (right, left) = self.pop_owned_pair()?;
670 let result = match (get_value(&self.heap, left), get_value(&self.heap, right)) {
671 (Value::Integer(l), Value::Integer(r)) => match opcode {
672 Opcode::OpEqual => Some(l == r),
673 Opcode::OpNotEqual => Some(l != r),
674 Opcode::OpGreaterThan => Some(l > r),
675 Opcode::OpLessThan => Some(l < r),
676 _ => unreachable!(),
677 },
678 (Value::Boolean(l), Value::Boolean(r)) => match opcode {
679 Opcode::OpEqual => Some(l == r),
680 Opcode::OpNotEqual => Some(l != r),
681 _ => None,
682 },
683 (Value::String(l), Value::String(r)) => match opcode {
684 Opcode::OpEqual => Some(l == r),
685 Opcode::OpNotEqual => Some(l != r),
686 _ => None,
687 },
688 (Value::Null, Value::Null) => match opcode {
689 Opcode::OpEqual => Some(true),
690 Opcode::OpNotEqual => Some(false),
691 _ => None,
692 },
693 (Value::Class(_), Value::Class(_))
694 | (Value::Instance(_), Value::Instance(_))
695 | (Value::BoundMethod(_), Value::BoundMethod(_)) => match opcode {
696 Opcode::OpEqual => Some(left == right),
697 Opcode::OpNotEqual => Some(left != right),
698 _ => None,
699 },
700 _ => None,
701 };
702 let message = if result.is_none() {
703 Some(format!(
704 "unsupported comparison for {} and {}",
705 value_to_string(&self.heap, left),
706 value_to_string(&self.heap, right)
707 ))
708 } else {
709 None
710 };
711 self.heap.free(left);
712 self.heap.free(right);
713 if let Some(result) = result {
714 self.alloc_and_push(Value::Boolean(result))
715 } else {
716 Err(self.runtime_error(message.unwrap()))
717 }
718 }
719
720 fn execute_minus_operation(&mut self) -> Result<(), GcRuntimeError> {
721 let operand = self.pop_owned()?;
722 let negated = match get_value(&self.heap, operand) {
723 Value::Integer(value) => Some(-value),
724 _ => None,
725 };
726 let message = negated.is_none().then(|| {
727 format!("unsupported type for negation: {}", value_to_string(&self.heap, operand))
728 });
729 self.heap.free(operand);
730 if let Some(negated) = negated {
731 self.alloc_and_push(Value::Integer(negated))
732 } else {
733 Err(self.runtime_error(message.unwrap()))
734 }
735 }
736
737 fn execute_bang_operation(&mut self) -> Result<(), GcRuntimeError> {
738 let operand = self.pop_owned()?;
739 let result = match get_value(&self.heap, operand) {
740 Value::Boolean(l) => !l,
741 _ => false,
742 };
743 self.heap.free(operand);
744 self.alloc_and_push(Value::Boolean(result))
745 }
746
747 fn build_array(&mut self, start: usize, end: usize) -> Vec<GcRef> {
748 let mut elements = Vec::with_capacity(end - start);
749 for i in start..end {
750 elements.push(self.stack[i]);
751 }
752 elements
753 }
754
755 fn build_hash(
756 &mut self,
757 start: usize,
758 end: usize,
759 ) -> Result<HashMap<HashKey, GcRef>, GcRuntimeError> {
760 let mut elements = HashMap::new();
761 for i in (start..end).step_by(2) {
762 let key_ref = self.stack[i];
763 let key = HashKey::from_value(get_value(&self.heap, key_ref)).ok_or_else(|| {
764 self.runtime_error(format!(
765 "hash key must be hashable, got {}",
766 value_to_string(&self.heap, key_ref)
767 ))
768 })?;
769 elements.insert(key, self.stack[i + 1]);
770 }
771 Ok(elements)
772 }
773
774 fn execute_index_operation(&mut self, left: GcRef, index: GcRef) -> Result<(), GcRuntimeError> {
775 let left_value = get_value(&self.heap, left).clone();
776 let index_value = get_value(&self.heap, index).clone();
777 match (&left_value, &index_value) {
778 (Value::Array(array), Value::Integer(i)) => self.execute_array_index(array, *i),
779 (Value::Hash(hash), _) => self.execute_hash_index(hash, &index_value),
780 _ => Err(self.runtime_error(format!(
781 "unsupported index operation for {} and {}",
782 value_to_string(&self.heap, left),
783 value_to_string(&self.heap, index)
784 ))),
785 }
786 }
787
788 fn execute_array_index(&mut self, array: &[GcRef], index: i64) -> Result<(), GcRuntimeError> {
789 if index < array.len() as i64 && index >= 0 {
790 self.dup_and_push(array[index as usize])
791 } else {
792 self.dup_and_push(self.null)
793 }
794 }
795
796 fn execute_hash_index(
797 &mut self,
798 hash: &HashMap<HashKey, GcRef>,
799 index: &Value,
800 ) -> Result<(), GcRuntimeError> {
801 let key = HashKey::from_value(index)
802 .ok_or_else(|| self.runtime_error("unsupported hash index key"))?;
803 match hash.get(&key) {
804 Some(value) => self.dup_and_push(*value),
805 None => self.dup_and_push(self.null),
806 }
807 }
808
809 fn current_frame(&mut self) -> &mut Frame {
810 &mut self.frames[self.frame_index - 1]
811 }
812
813 fn push_frame(&mut self, frame: Frame) -> Result<(), GcRuntimeError> {
814 if self.frame_index >= MAX_FRAMES {
815 return Err(self.runtime_error("frame limit exceeded"));
816 }
817 self.frames[self.frame_index] = frame;
818 self.frame_index += 1;
819 Ok(())
820 }
821
822 fn pop_frame(&mut self) -> Frame {
823 self.frame_index -= 1;
824 self.frames[self.frame_index].clone()
825 }
826
827 fn execute_call(&mut self, num_args: usize) -> Result<(), GcRuntimeError> {
828 let callee_slot = self.stack_base_for(num_args + 1)?;
829 let callee = self.stack[callee_slot];
830 match callee_kind(&self.heap, callee) {
831 CalleeKind::Closure(closure) => self.call_closure(closure, num_args),
832 CalleeKind::Builtin(builtin) => self.call_builtin(builtin, num_args),
833 CalleeKind::BoundMethod(bound) => self.call_bound_method(bound, num_args),
834 CalleeKind::Class(name) => {
835 Err(self.runtime_error(format!("class {} must be constructed with new", name)))
836 }
837 CalleeKind::Other(value) => Err(self.runtime_error(format!("cannot call {}", value))),
838 }
839 }
840
841 fn call_closure(&mut self, closure: GcClosure, num_args: usize) -> Result<(), GcRuntimeError> {
842 let compiled = match get_value(&self.heap, closure.func) {
843 Value::CompiledFunction(f) => f.clone(),
844 _ => return Err(self.runtime_error("closure without compiled function")),
845 };
846 if compiled.num_parameters != num_args {
847 return Err(self.runtime_error(format!(
848 "wrong number of arguments: want={}, got={}",
849 compiled.num_parameters, num_args
850 )));
851 }
852
853 let frame = Frame::new(closure, compiled.instructions, self.sp - num_args);
854 let next_sp = frame
857 .base_pointer
858 .checked_add(compiled.num_locals)
859 .filter(|next_sp| *next_sp <= STACK_SIZE)
860 .ok_or_else(|| self.runtime_error("stack limit exceeded"))?;
861 self.sp = next_sp;
862 self.push_frame(frame)
863 }
864
865 fn call_builtin(&mut self, builtin: BuiltinId, num_args: usize) -> Result<(), GcRuntimeError> {
866 let base = self.sp - num_args - 1;
867 let args = self.stack[self.sp - num_args..self.sp].to_vec();
868 let result = call_builtin(&mut self.heap, builtin, &args, self.null);
869 self.clear_stack_range(base, self.sp);
870 self.sp = base;
871 self.push_raw(result)
872 }
873
874 fn push_closure(&mut self, const_index: usize, num_free: usize) -> Result<(), GcRuntimeError> {
875 let func = self.constant(const_index)?;
876 if !matches!(get_value(&self.heap, func), Value::CompiledFunction(_)) {
877 return Err(self.runtime_error(format!(
878 "cannot build closure over {}",
879 value_to_string(&self.heap, func)
880 )));
881 }
882 let start = self.stack_base_for(num_free)?;
883 let mut free = Vec::with_capacity(num_free);
884 for i in 0..num_free {
885 free.push(self.stack[start + i]);
886 }
887 let closure = alloc_value(
888 &mut self.heap,
889 Value::Closure(GcClosure {
890 func,
891 free,
892 }),
893 );
894 self.clear_stack_range(start, self.sp);
895 self.sp = start;
896 self.push_raw(closure)
897 }
898
899 fn constant(&self, index: usize) -> Result<GcRef, GcRuntimeError> {
900 self.constants
901 .get(index)
902 .copied()
903 .ok_or_else(|| self.runtime_error(format!("constant index {} out of range", index)))
904 }
905
906 fn constant_string(&self, index: usize) -> Result<String, GcRuntimeError> {
907 let constant = self.constant(index)?;
908 match get_value(&self.heap, constant) {
909 Value::String(value) => Ok(value.clone()),
910 value => Err(self.runtime_error(format!("expected string constant, got {}", value))),
911 }
912 }
913
914 fn install_method(
915 &mut self,
916 class: GcRef,
917 name: String,
918 method: GcRef,
919 constructor: bool,
920 ) -> Result<(), GcRuntimeError> {
921 if !matches!(get_value(&self.heap, class), Value::Class(_)) {
922 return Err(self.runtime_error(format!(
923 "cannot install method on {}",
924 value_to_string(&self.heap, class)
925 )));
926 }
927 let owned_method = self.heap.dup(method);
928 let old_method = match get_value_mut(&mut self.heap, class) {
929 Value::Class(class) => {
930 if constructor {
931 class.constructor.replace(owned_method)
932 } else {
933 class.methods.insert(name, owned_method)
934 }
935 }
936 _ => unreachable!(),
937 };
938 if let Some(old_method) = old_method {
939 self.heap.free(old_method);
940 }
941 Ok(())
942 }
943
944 fn get_property(&mut self, receiver: GcRef, name: &str) -> Result<GcRef, GcRuntimeError> {
945 let (class, field) = match get_value(&self.heap, receiver) {
946 Value::Instance(instance) => (instance.class, instance.fields.get(name).copied()),
947 _ => {
948 return Err(self.runtime_error(format!(
949 "cannot read property '{}' of {}",
950 name,
951 value_to_string(&self.heap, receiver)
952 )))
953 }
954 };
955 if let Some(field) = field {
956 return Ok(self.heap.dup(field));
957 }
958
959 let (class_name, method) = match get_value(&self.heap, class) {
960 Value::Class(class) => (class.name.clone(), class.methods.get(name).copied()),
961 _ => return Err(self.runtime_error("instance has invalid class")),
962 };
963 match method {
964 Some(method) => Ok(alloc_value(
965 &mut self.heap,
966 Value::BoundMethod(GcBoundMethod {
967 receiver,
968 method,
969 name: name.to_string(),
970 }),
971 )),
972 None => {
973 Err(self
974 .runtime_error(format!("property '{}' does not exist on {}", name, class_name)))
975 }
976 }
977 }
978
979 fn set_property(
980 &mut self,
981 receiver: GcRef,
982 name: String,
983 value: GcRef,
984 ) -> Result<(), GcRuntimeError> {
985 if !matches!(get_value(&self.heap, receiver), Value::Instance(_)) {
986 return Err(self.runtime_error(format!(
987 "cannot set property '{}' of {}",
988 name,
989 value_to_string(&self.heap, receiver)
990 )));
991 }
992 let owned_value = self.heap.dup(value);
993 let old_value = match get_value_mut(&mut self.heap, receiver) {
994 Value::Instance(instance) => instance.fields.insert(name, owned_value),
995 _ => unreachable!(),
996 };
997 if let Some(old_value) = old_value {
998 self.heap.free(old_value);
999 }
1000 Ok(())
1001 }
1002
1003 fn execute_new(&mut self, num_args: usize) -> Result<(), GcRuntimeError> {
1004 let base = self.stack_base_for(num_args + 1)?;
1005 let class_reference = self.stack[base];
1006 let (class_name, constructor) = match get_value(&self.heap, class_reference) {
1007 Value::Class(class) => (class.name.clone(), class.constructor),
1008 _ => {
1009 return Err(self.runtime_error(format!(
1010 "cannot construct {}",
1011 value_to_string(&self.heap, class_reference)
1012 )))
1013 }
1014 };
1015
1016 let Some(constructor) = constructor else {
1017 if num_args != 0 {
1018 return Err(self.runtime_error(format!(
1019 "wrong number of arguments for {}.constructor: want=0, got={}",
1020 class_name, num_args
1021 )));
1022 }
1023 let instance = alloc_value(
1024 &mut self.heap,
1025 Value::Instance(GcInstance {
1026 class: class_reference,
1027 fields: HashMap::new(),
1028 }),
1029 );
1030 self.clear_stack_range(base, self.sp);
1031 self.sp = base;
1032 return self.push_raw(instance);
1033 };
1034
1035 let closure = match get_value(&self.heap, constructor) {
1036 Value::Closure(closure) => closure.clone(),
1037 _ => return Err(self.runtime_error("constructor is not a closure")),
1038 };
1039 let compiled = match get_value(&self.heap, closure.func) {
1040 Value::CompiledFunction(function) => function.clone(),
1041 _ => return Err(self.runtime_error("constructor closure has invalid function")),
1042 };
1043 let expected = compiled.num_parameters.saturating_sub(1);
1044 if expected != num_args {
1045 return Err(self.runtime_error(format!(
1046 "wrong number of arguments for {}.constructor: want={}, got={}",
1047 class_name, expected, num_args
1048 )));
1049 }
1050
1051 let instance = alloc_value(
1052 &mut self.heap,
1053 Value::Instance(GcInstance {
1054 class: class_reference,
1055 fields: HashMap::new(),
1056 }),
1057 );
1058 self.rewrite_receiver_call(constructor, instance, num_args)?;
1059 self.call_closure(closure, num_args + 1)
1060 }
1061
1062 fn call_bound_method(
1063 &mut self,
1064 bound: GcBoundMethod,
1065 num_args: usize,
1066 ) -> Result<(), GcRuntimeError> {
1067 let closure = match get_value(&self.heap, bound.method) {
1068 Value::Closure(closure) => closure.clone(),
1069 _ => return Err(self.runtime_error("bound method is not a closure")),
1070 };
1071 let compiled = match get_value(&self.heap, closure.func) {
1072 Value::CompiledFunction(function) => function.clone(),
1073 _ => return Err(self.runtime_error("method closure has invalid function")),
1074 };
1075 let expected = compiled.num_parameters.saturating_sub(1);
1076 if expected != num_args {
1077 let class_name = match get_value(&self.heap, bound.receiver) {
1078 Value::Instance(instance) => match get_value(&self.heap, instance.class) {
1079 Value::Class(class) => class.name.clone(),
1080 _ => "<invalid class>".to_string(),
1081 },
1082 _ => "<invalid receiver>".to_string(),
1083 };
1084 return Err(self.runtime_error(format!(
1085 "wrong number of arguments for {}.{}: want={}, got={}",
1086 class_name, bound.name, expected, num_args
1087 )));
1088 }
1089 let receiver = self.heap.dup(bound.receiver);
1090 self.rewrite_receiver_call(bound.method, receiver, num_args)?;
1091 self.call_closure(closure, num_args + 1)
1092 }
1093
1094 fn rewrite_receiver_call(
1097 &mut self,
1098 callable: GcRef,
1099 receiver: GcRef,
1100 num_args: usize,
1101 ) -> Result<(), GcRuntimeError> {
1102 let base = self.sp - num_args - 1;
1103 if base + num_args + 2 > STACK_SIZE {
1104 let error = self.runtime_error("stack limit exceeded");
1105 self.heap.free(receiver);
1106 return Err(error);
1107 }
1108 let callable = self.heap.dup(callable);
1109 let borrowed_arguments = self.stack[self.sp - num_args..self.sp].to_vec();
1110 let arguments = borrowed_arguments
1111 .into_iter()
1112 .map(|argument| self.heap.dup(argument))
1113 .collect::<Vec<_>>();
1114 self.clear_stack_range(base, self.sp);
1115 self.sp = base;
1116 self.push_raw(callable)?;
1117 self.push_raw(receiver)?;
1118 for argument in arguments {
1119 self.push_raw(argument)?;
1120 }
1121 Ok(())
1122 }
1123}
1124
1125fn is_truthy(heap: &GcHeap, condition: GcRef) -> bool {
1126 match get_value(heap, condition) {
1127 Value::Boolean(b) => *b,
1128 Value::Null => false,
1129 _ => true,
1130 }
1131}
1132
1133fn callee_kind(heap: &GcHeap, reference: GcRef) -> CalleeKind {
1134 match get_value(heap, reference) {
1135 Value::Closure(closure) => CalleeKind::Closure(closure.clone()),
1136 Value::Builtin(builtin) => CalleeKind::Builtin(*builtin),
1137 Value::BoundMethod(bound) => CalleeKind::BoundMethod(bound.clone()),
1138 Value::Class(class) => CalleeKind::Class(class.name.clone()),
1139 _ => CalleeKind::Other(value_to_string(heap, reference)),
1140 }
1141}
1142
1143fn compiled_instructions(heap: &GcHeap, func: GcRef) -> Vec<u8> {
1144 match get_value(heap, func) {
1145 Value::CompiledFunction(f) => f.instructions.clone(),
1146 _ => panic!("expected compiled function"),
1147 }
1148}