1use std::collections::VecDeque;
2
3use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
4
5#[cfg(debug_assertions)]
6use crate::debug::disassemble_instruction;
7use crate::{
8 BoundIntrinsicObject, BoundMethodObject, ClassHandle, ClosureHandle, HashMapHandle,
9 HeapAllocator, NativeFn, NativeFunctionError, NativeFunctionHandle, NativeFunctionObject,
10 QangProgram, QangRuntimeError, StringHandle, Value, ValueKind,
11 backend::{
12 assembler::{FRAME_MAX, STACK_MAX},
13 chunk::{OpCode, SourceLocation},
14 external_context::ExternalContext,
15 module_resolver::ModuleResolver,
16 object::{ClosureObject, FunctionObject, IntrinsicKind, IntrinsicMethod, UpvalueSlot},
17 qang_std::{
18 qang_array_create, qang_assert, qang_assert_eq, qang_assert_throws, qang_env_cwd,
19 qang_hash, qang_object_assign, qang_object_get, qang_object_set,
20 qang_object_to_entries, qang_print, qang_println, qang_system_time, qang_to_string,
21 qang_typeof,
22 },
23 value::{
24 ARRAY_TYPE_STRING, BOOLEAN_TYPE_STRING, CLASS_TYPE_STRING, FUNCTION_TYPE_STRING,
25 MODULE_TYPE_STRING, NIL_TYPE_STRING, NUMBER_TYPE_STRING, OBJECT_TYPE_STRING,
26 STRING_TYPE_STRING,
27 },
28 },
29 debug_log,
30};
31
32#[derive(Debug, Clone)]
33pub struct BinaryOperationError(pub String);
34
35impl BinaryOperationError {
36 pub fn new(message: &str) -> Self {
37 Self(message.to_string())
38 }
39
40 fn into_qang_error(self, loc: SourceLocation) -> QangRuntimeError {
41 QangRuntimeError::new(self.0, loc)
42 }
43}
44
45impl From<&'_ str> for BinaryOperationError {
46 fn from(value: &'_ str) -> Self {
47 BinaryOperationError::new(value)
48 }
49}
50
51pub type RuntimeResult<T> = Result<T, QangRuntimeError>;
52
53type StackSlot = usize;
54type UpvalueIndex = usize;
55use crate::memory::OpenUpvalueTracker;
56type OpenUpvalueEntry = (StackSlot, OpenUpvalueTracker);
57
58#[derive(Debug, Clone, Copy)]
59pub struct PropertyCache {
60 pub object_type: CachedObjectType,
61 pub property_name: StringHandle,
62 pub table_handle: HashMapHandle,
63 pub generation: u32,
64}
65
66#[derive(Debug, Clone, Copy, PartialEq)]
67pub enum CachedObjectType {
68 Instance(ClassHandle),
69 ObjectLiteral,
70 Module,
71}
72
73impl Default for PropertyCache {
74 fn default() -> Self {
75 Self {
76 object_type: CachedObjectType::ObjectLiteral,
77 property_name: StringHandle::default(),
78 table_handle: HashMapHandle::default(),
79 generation: 0,
80 }
81 }
82}
83
84#[derive(Debug, Clone, Copy)]
85pub struct MethodCache {
86 pub object_type: CachedObjectType,
87 pub method_name: StringHandle,
88 pub table_handle: HashMapHandle,
89 pub cached_method: Value,
90 pub generation: u32,
91}
92
93impl Default for MethodCache {
94 fn default() -> Self {
95 Self {
96 object_type: CachedObjectType::ObjectLiteral,
97 method_name: StringHandle::default(),
98 table_handle: HashMapHandle::default(),
99 cached_method: Value::nil(),
100 generation: 0,
101 }
102 }
103}
104
105#[macro_export]
106macro_rules! push_value {
107 ($vm:expr, $value:expr) => {
108 if $vm.state.stack_top >= STACK_MAX {
109 Err($crate::QangRuntimeError::new(
110 format!(
111 "Stack overflow: maximum stack size of {} exceeded",
112 STACK_MAX
113 ),
114 $vm.state.get_current_loc(),
115 ))
116 } else {
117 $vm.state.stack[$vm.state.stack_top] = $value;
118 $vm.state.stack_top += 1;
119 Ok(())
120 }
121 };
122}
123
124#[macro_export]
125macro_rules! pop_value {
126 ($vm:expr) => {{
127 debug_assert!(
128 $vm.state.stack_top > 0,
129 "Stack underflow: unexpected empty stack."
130 );
131 $vm.state.stack_top -= 1;
132 $vm.state.stack[$vm.state.stack_top]
133 }};
134}
135
136#[macro_export]
137macro_rules! peek_value {
138 ($vm:expr, $distance:expr) => {
139 if $vm.state.stack_top > $distance {
140 $vm.state
141 .stack
142 .get($vm.state.stack_top - 1 - $distance)
143 .copied()
144 .unwrap_or(Value::nil())
145 } else {
146 Value::nil()
147 }
148 };
149}
150
151#[macro_export]
152macro_rules! read_string {
153 ($vm:expr) => {
154 match $vm.state.read_constant().as_string() {
155 Some(handle) => handle,
156 _ => panic!("Expected string constant"),
157 }
158 };
159}
160
161#[macro_export]
162macro_rules! read_string_16 {
163 ($vm:expr) => {
164 match $vm.state.read_constant_16().as_string() {
165 Some(handle) => handle,
166 _ => panic!("Expected string constant"),
167 }
168 };
169}
170
171#[derive(Debug, Clone, Default)]
172pub(crate) struct CallFrame {
173 pub closure: ClosureHandle,
174 pub ip: usize,
175 pub value_slot: usize,
176 pub module_export_target: Option<HashMapHandle>,
177}
178
179#[derive(Debug, Clone)]
180pub(crate) struct VmState {
181 pub stack_top: usize,
182 pub frame_count: usize,
183 pub stack: Vec<Value>,
184 pub frames: [CallFrame; FRAME_MAX],
185 globals: FxHashMap<StringHandle, Value>,
186 intrinsics: FxHashMap<IntrinsicKind, IntrinsicMethod>,
187 open_upvalues: Vec<OpenUpvalueEntry>,
188 current_function_ptr: *const FunctionObject,
189 pub modules: ModuleResolver,
190 function_module_context: Option<HashMapHandle>,
191 property_cache: [PropertyCache; Self::PROPERTY_CACHE_SIZE],
192 method_cache: [MethodCache; Self::METHOD_CACHE_SIZE],
193 cache_generation: u32,
194 pub(crate) arg_buffer: [Value; 256],
195 additional_roots: FxHashSet<Value>,
196}
197
198impl VmState {
199 const PROPERTY_CACHE_SIZE: usize = 256;
200 const METHOD_CACHE_SIZE: usize = 256;
201
202 fn new(
203 globals: FxHashMap<StringHandle, Value>,
204 intrinsics: FxHashMap<IntrinsicKind, IntrinsicMethod>,
205 ) -> Self {
206 Self {
207 frame_count: 0,
208 stack_top: 0,
209 stack: vec![Value::default(); STACK_MAX],
210 frames: std::array::from_fn(|_| CallFrame::default()),
211 globals,
212 intrinsics,
213 open_upvalues: Vec::with_capacity(8),
214 current_function_ptr: std::ptr::null(),
215 modules: ModuleResolver::default(),
216 function_module_context: None,
217 property_cache: [PropertyCache::default(); Self::PROPERTY_CACHE_SIZE],
218 method_cache: [MethodCache::default(); Self::METHOD_CACHE_SIZE],
219 cache_generation: 0,
220 arg_buffer: [Value::default(); 256],
221 additional_roots: FxHashSet::with_capacity_and_hasher(64, FxBuildHasher),
222 }
223 }
224
225 fn invalidate_caches(&mut self) {
226 self.cache_generation = self.cache_generation.wrapping_add(1);
227 }
228
229 fn get_property_cache_index(&self) -> usize {
230 let ip = self.frames[self.frame_count - 1].ip;
231 let closure_handle = self.frames[self.frame_count - 1].closure;
232
233 let cache_key = (ip as u64) ^ closure_handle.as_raw();
234 cache_key as usize % Self::PROPERTY_CACHE_SIZE
235 }
236
237 fn get_method_cache_index(&self) -> usize {
238 let ip = self.frames[self.frame_count - 1].ip;
239 let closure_handle = self.frames[self.frame_count - 1].closure;
240
241 let cache_key = (ip as u64) ^ closure_handle.as_raw();
242 cache_key as usize % Self::METHOD_CACHE_SIZE
243 }
244
245 fn get_current_function(&self) -> &FunctionObject {
246 debug_assert!(
247 !self.current_function_ptr.is_null(),
248 "Function pointer is null"
249 );
250 unsafe { &*self.current_function_ptr }
251 }
252
253 pub fn get_current_loc(&self) -> SourceLocation {
254 self.get_loc_at(self.frames[self.frame_count - 1].ip)
255 }
256
257 pub fn get_previous_loc(&self) -> SourceLocation {
258 if self.frames[self.frame_count - 1].ip > 0 {
259 self.get_loc_at(self.frames[self.frame_count - 1].ip - 1)
260 } else {
261 SourceLocation::default()
262 }
263 }
264
265 pub fn get_loc_at(&self, index: usize) -> SourceLocation {
266 self.get_current_function()
267 .chunk
268 .locs
269 .get(index)
270 .copied()
271 .unwrap_or_default()
272 }
273
274 fn read_byte(&mut self) -> u8 {
275 let frame = unsafe { self.frames.get_unchecked_mut(self.frame_count - 1) };
276 debug_assert!(
277 !self.current_function_ptr.is_null(),
278 "Function pointer is null"
279 );
280
281 let code = unsafe { &(*self.current_function_ptr).chunk.code };
282 debug_assert!(frame.ip < code.len(), "IP out of bounds");
283 let byte = unsafe { *code.get_unchecked(frame.ip) };
284 frame.ip += 1;
285 byte
286 }
287
288 fn read_constant(&mut self) -> Value {
289 let index = self.read_byte() as usize;
290 debug_assert!(
291 !self.current_function_ptr.is_null(),
292 "Function pointer is null"
293 );
294 let constants = unsafe { &(*self.current_function_ptr).chunk.constants };
295 debug_assert!(index < constants.len(), "Constant index out of bounds");
296 constants[index]
297 }
298
299 fn read_constant_16(&mut self) -> Value {
300 let index = self.read_short();
301 debug_assert!(
302 !self.current_function_ptr.is_null(),
303 "Function pointer is null"
304 );
305 let constants = unsafe { &(*self.current_function_ptr).chunk.constants };
306 debug_assert!(index < constants.len(), "Constant index out of bounds");
307 constants[index]
308 }
309
310 fn read_short(&mut self) -> usize {
311 let high_byte = self.read_byte() as usize;
312 let low_byte = self.read_byte() as usize;
313 (high_byte << 8) | low_byte
314 }
315}
316
317#[derive(Debug)]
318pub struct Vm {
319 pub is_debug: bool,
320 pub is_gc_enabled: bool,
321 pub(crate) state: VmState,
322 pub alloc: HeapAllocator,
323 pub external_context: ExternalContext,
324}
325
326impl Vm {
327 pub(crate) fn with_gc_check<T>(&mut self, op: impl FnOnce(&mut HeapAllocator) -> T) -> T {
328 if self.is_gc_enabled && self.alloc.should_collect_garbage() {
329 self.collect_garbage();
330 }
331 op(&mut self.alloc)
332 }
333
334 pub fn new(mut alloc: HeapAllocator) -> Self {
335 let mut globals = FxHashMap::with_capacity_and_hasher(64, FxBuildHasher);
336
337 let nil_type_value_handle = alloc.strings.intern(NIL_TYPE_STRING);
338 globals.insert(
339 alloc.strings.intern("NIL"),
340 Value::string(nil_type_value_handle),
341 );
342 let boolean_type_value_handle = alloc.strings.intern(BOOLEAN_TYPE_STRING);
343 globals.insert(
344 alloc.strings.intern("BOOLEAN"),
345 Value::string(boolean_type_value_handle),
346 );
347 let number_type_value_handle = alloc.strings.intern(NUMBER_TYPE_STRING);
348 globals.insert(
349 alloc.strings.intern("NUMBER"),
350 Value::string(number_type_value_handle),
351 );
352 let string_type_value_handle = alloc.strings.intern(STRING_TYPE_STRING);
353 globals.insert(
354 alloc.strings.intern("STRING"),
355 Value::string(string_type_value_handle),
356 );
357 let function_type_value_handle = alloc.strings.intern(FUNCTION_TYPE_STRING);
358 globals.insert(
359 alloc.strings.intern("FUNCTION"),
360 Value::string(function_type_value_handle),
361 );
362 let class_type_value_handle = alloc.strings.intern(CLASS_TYPE_STRING);
363 globals.insert(
364 alloc.strings.intern("CLASS"),
365 Value::string(class_type_value_handle),
366 );
367 let object_type_value_handle = alloc.strings.intern(OBJECT_TYPE_STRING);
368 globals.insert(
369 alloc.strings.intern("OBJECT"),
370 Value::string(object_type_value_handle),
371 );
372 let array_type_value_handle = alloc.strings.intern(ARRAY_TYPE_STRING);
373 globals.insert(
374 alloc.strings.intern("ARRAY"),
375 Value::string(array_type_value_handle),
376 );
377 let module_type_value_handle = alloc.strings.intern(MODULE_TYPE_STRING);
378 globals.insert(
379 alloc.strings.intern("MODULE"),
380 Value::string(module_type_value_handle),
381 );
382 let mut vm = Self {
383 is_debug: false,
384 is_gc_enabled: true,
385 state: VmState::new(globals, Self::load_intrinsics(&mut alloc)),
386 alloc,
387 external_context: ExternalContext::new(),
388 };
389
390 vm.add_native_function("assert", 2, qang_assert)
391 .add_native_function("assert_eq", 3, qang_assert_eq)
392 .add_native_function("assert_throws", 2, qang_assert_throws)
393 .add_native_function("print", 1, qang_print)
394 .add_native_function("println", 1, qang_println)
395 .add_native_function("system_time", 0, qang_system_time)
396 .add_native_function("typeof", 1, qang_typeof)
397 .add_native_function("to_string", 1, qang_to_string)
398 .add_native_function("hash", 1, qang_hash)
399 .add_native_function("array_of_length", 1, qang_array_create)
400 .add_native_function("env_cwd", 0, qang_env_cwd)
401 .add_native_function("object_to_entries", 1, qang_object_to_entries)
402 .add_native_function("object_get", 2, qang_object_get)
403 .add_native_function("object_set", 3, qang_object_set)
404 .add_native_function("object_assign", 2, qang_object_assign)
405 .with_stdlib()
406 .with_native_filesystem();
407
408 vm
409 }
410
411 pub fn set_debug(mut self, is_debug: bool) -> Self {
412 self.is_debug = is_debug;
413 self
414 }
415
416 pub fn set_gc_status(mut self, is_enabled: bool) -> Self {
417 self.is_gc_enabled = is_enabled;
418 self
419 }
420
421 pub fn add_native_function(
422 &mut self,
423 name: &str,
424 arity: usize,
425 function: NativeFn,
426 ) -> &mut Self {
427 let identifier_handle = self.alloc.strings.intern(name);
428 let native_function = NativeFunctionObject {
429 name_handle: identifier_handle,
430 arity,
431 function,
432 };
433 let handle = self.alloc.allocate_native_function(native_function);
434
435 self.state
436 .globals
437 .insert(identifier_handle, Value::native_function(handle));
438
439 self
440 }
441
442 pub fn add_external_root(&mut self, value: Value) {
443 self.state.additional_roots.insert(value);
444 }
445
446 pub fn remove_external_root(&mut self, value: Value) {
447 self.state.additional_roots.remove(&value);
448 }
449
450 pub fn interpret(&mut self, program: QangProgram) -> RuntimeResult<()> {
451 let function_handle = program.get_handle();
452 self.state.modules = program.into_modules();
453 let upvalue_count = self.alloc.get_function(function_handle).upvalue_count;
454
455 let handle = self.alloc.closures.allocate_closure(ClosureObject::new(
456 function_handle,
457 upvalue_count,
458 None,
459 ));
460 push_value!(self, Value::closure(handle))?;
461 self.call(handle, 0)?;
462
463 #[cfg(feature = "profiler")]
464 coz::scope!("vm_interpret");
465
466 let _ = self
467 .run()
468 .map_err(|e| e.with_stack_trace(self.get_stack_trace()))?;
469
470 #[cfg(feature = "profiler")]
471 coz::progress!("execution_complete");
472
473 Ok(())
474 }
475
476 fn run(&mut self) -> RuntimeResult<Value> {
477 loop {
478 #[cfg(feature = "profiler")]
479 coz::progress!("vm_instructions");
480
481 #[cfg(debug_assertions)]
482 {
483 if self.is_debug {
484 self.debug_print();
485 }
486 }
487
488 let opcode: OpCode = self.state.read_byte().into();
489
490 match opcode {
491 OpCode::Constant => {
492 let constant = self.state.read_constant();
493 push_value!(self, constant)?;
494 }
495 OpCode::Constant16 => {
496 let constant = self.state.read_constant_16();
497 push_value!(self, constant)?;
498 }
499 OpCode::Negate => {
500 if let Some(number) = peek_value!(self, 0).as_number() {
501 if let Some(stack_value) =
502 self.state.stack.get_mut(self.state.stack_top - 1)
503 {
504 *stack_value = Value::number(-number);
505 }
506 } else {
507 return Err(QangRuntimeError::new(
508 "Operand must be a number.".to_string(),
509 self.state.get_previous_loc(),
510 ));
511 }
512 }
513 OpCode::Not => {
514 let value = peek_value!(self, 0);
515 if let Some(stack_value) = self.state.stack.get_mut(self.state.stack_top - 1) {
516 *stack_value = (!value.is_truthy()).into();
517 }
518 }
519 OpCode::True => {
520 push_value!(self, Value::boolean(true))?;
521 }
522 OpCode::False => {
523 push_value!(self, Value::boolean(false))?;
524 }
525 OpCode::Nil => {
526 push_value!(self, Value::nil())?;
527 }
528 OpCode::Add => {
529 self.binary_operation(|a, b, alloc| match (a.kind(), b.kind()) {
530 (ValueKind::Number(num1), ValueKind::Number(num2)) => {
531 Ok(Value::number(num1 + num2))
532 }
533 (ValueKind::String(handle1), ValueKind::String(handle2)) => {
534 #[cfg(feature = "profiler")]
535 coz::scope!("string_concatenation");
536 Ok(Value::string(alloc.strings.concat(handle1, handle2)))
537 }
538 (ValueKind::Array(handle1), ValueKind::Array(handle2)) => {
539 Ok(Value::array(alloc.arrays.concat(handle1, handle2)))
540 }
541 (ValueKind::Number(_), _) => {
542 Err(format!("Cannot add number to {}.", b.to_type_string())
543 .as_str()
544 .into())
545 }
546 (ValueKind::String(_), _) => {
547 Err(format!("Cannot add string to {}.", b.to_type_string())
548 .as_str()
549 .into())
550 }
551 (ValueKind::Array(_), _) => {
552 Err(format!("Cannot add an array to {}.", b.to_type_string())
553 .as_str()
554 .into())
555 }
556 (_, ValueKind::Number(_)) => {
557 Err(format!("Cannot add {} to number.", a.to_type_string())
558 .as_str()
559 .into())
560 }
561 (_, ValueKind::String(_)) => {
562 Err(format!("Cannot add {} to string.", a.to_type_string())
563 .as_str()
564 .into())
565 }
566 (_, ValueKind::Array(_)) => {
567 Err(format!("Cannot add {} to an array.", a.to_type_string())
568 .as_str()
569 .into())
570 }
571 _ => Err("Both operands must be a numbers, strings or arrays.".into()),
572 })?;
573 }
574 OpCode::Subtract => self.binary_operation(|a, b, _allocator| {
575 match (a.as_number(), b.as_number()) {
576 (Some(num1), Some(num2)) => Ok((num1 - num2).into()),
577 _ => Err(BinaryOperationError::new("Both operands must be a number.")),
578 }
579 })?,
580 OpCode::Multiply => self.binary_operation(|a, b, _allocator| {
581 match (a.as_number(), b.as_number()) {
582 (Some(num1), Some(num2)) => Ok((num1 * num2).into()),
583 _ => Err(BinaryOperationError::new("Both operands must be a number.")),
584 }
585 })?,
586 OpCode::Divide => self.binary_operation(|a, b, _allocator| {
587 match (a.as_number(), b.as_number()) {
588 (Some(num1), Some(num2)) => {
589 if num2 == 0.0 {
590 Err(BinaryOperationError::new("Cannot divide by zero."))
591 } else {
592 Ok((num1 / num2).into())
593 }
594 }
595 _ => Err(BinaryOperationError::new("Both operands must be a number.")),
596 }
597 })?,
598 OpCode::Modulo => self.binary_operation(|a, b, _allocator| {
599 match (a.as_number(), b.as_number()) {
600 (Some(num1), Some(num2)) => Ok((num1 % num2).into()),
601 _ => Err(BinaryOperationError::new("Both operands must be a number.")),
602 }
603 })?,
604 OpCode::Equal => self.binary_operation(|a, b, _allocator| Ok((a == b).into()))?,
605 OpCode::Greater => self.binary_operation(|a, b, _allocator| {
606 match (a.as_number(), b.as_number()) {
607 (Some(num1), Some(num2)) => Ok((num1 > num2).into()),
608 _ => Err(BinaryOperationError::new("Both operands must be a number.")),
609 }
610 })?,
611 OpCode::GreaterEqual => self.binary_operation(|a, b, _allocator| {
612 match (a.as_number(), b.as_number()) {
613 (Some(num1), Some(num2)) => Ok((num1 >= num2).into()),
614 _ => Err(BinaryOperationError::new("Both operands must be a number.")),
615 }
616 })?,
617 OpCode::Less => self.binary_operation(|a, b, _allocator| {
618 match (a.as_number(), b.as_number()) {
619 (Some(num1), Some(num2)) => Ok((num1 < num2).into()),
620 _ => Err(BinaryOperationError::new("Both operands must be a number.")),
621 }
622 })?,
623 OpCode::LessEqual => self.binary_operation(|a, b, _allocator| {
624 match (a.as_number(), b.as_number()) {
625 (Some(num1), Some(num2)) => Ok((num1 <= num2).into()),
626 _ => Err(BinaryOperationError::new("Both operands must be a number.")),
627 }
628 })?,
629 OpCode::Is => {
630 let b = pop_value!(self);
631 let a = pop_value!(self);
632
633 let result = match (a.kind(), b.kind()) {
634 (ValueKind::Array(_), ValueKind::String(string_handle)) => {
635 let array_handle = self.alloc.strings.intern("array");
636 array_handle == string_handle
637 }
638 (ValueKind::Number(_), ValueKind::String(string_handle)) => {
639 let number_handle = self.alloc.strings.intern("number");
640 number_handle == string_handle
641 }
642 (ValueKind::String(_), ValueKind::String(string_handle)) => {
643 let other_string_handle = self.alloc.strings.intern("string");
644 other_string_handle == string_handle
645 }
646 (ValueKind::Nil, ValueKind::String(string_handle)) => {
647 let nil_handle = self.alloc.strings.intern("nil");
648 nil_handle == string_handle
649 }
650 (ValueKind::True | ValueKind::False, ValueKind::String(string_handle)) => {
651 let boolean_handle = self.alloc.strings.intern("boolean");
652 boolean_handle == string_handle
653 }
654 (ValueKind::Class(_), ValueKind::String(string_handle)) => {
655 let class_handle = self.alloc.strings.intern("class");
656 class_handle == string_handle
657 }
658 (
659 ValueKind::ObjectLiteral(_) | ValueKind::Instance(_),
660 ValueKind::String(string_handle),
661 ) => {
662 let object_handle = self.alloc.strings.intern("object");
663 object_handle == string_handle
664 }
665 (
666 ValueKind::FunctionDecl(_)
667 | ValueKind::NativeFunction(_)
668 | ValueKind::Closure(_)
669 | ValueKind::BoundMethod(_)
670 | ValueKind::BoundIntrinsic(_),
671 ValueKind::String(string_handle),
672 ) => {
673 let function_handle = self.alloc.strings.intern("function");
674 function_handle == string_handle
675 }
676 (ValueKind::Instance(instance_handle), ValueKind::Class(clazz_handle)) => {
677 let instance_of_handle = self.alloc.get_instance(instance_handle).clazz;
678
679 if instance_of_handle == clazz_handle {
680 true
681 } else {
682 let mut current_handle = instance_of_handle;
683 loop {
684 let current_class = self.alloc.get_class(current_handle);
685 if let Some(super_handle) = current_class.super_clazz {
686 if super_handle == clazz_handle {
687 break true;
688 }
689 current_handle = super_handle;
690 } else {
691 break false;
692 }
693 }
694 }
695 }
696 _ => false,
697 };
698
699 push_value!(self, result.into())?;
700 }
701 OpCode::Pop => {
702 pop_value!(self);
703 }
704 OpCode::DefineGlobal => {
705 let identifier_handle = read_string!(self);
706 let value = pop_value!(self);
707
708 if let Some(module_target) =
709 self.state.frames[self.state.frame_count - 1].module_export_target
710 {
711 self.alloc.tables.insert(
712 module_target,
713 Value::string(identifier_handle),
714 value,
715 );
716 } else {
717 self.state.globals.insert(identifier_handle, value);
718 }
719 }
720
721 OpCode::DefineGlobal16 => {
722 let identifier_handle = read_string_16!(self);
723 let value = pop_value!(self);
724
725 if let Some(module_target) =
726 self.state.frames[self.state.frame_count - 1].module_export_target
727 {
728 self.alloc.tables.insert(
729 module_target,
730 Value::string(identifier_handle),
731 value,
732 );
733 } else {
734 self.state.globals.insert(identifier_handle, value);
735 }
736 }
737 OpCode::SetGlobal => {
738 let identifier_handle = read_string!(self);
739 self.set_global(identifier_handle)?;
740 }
741
742 OpCode::SetGlobal16 => {
743 let identifier_handle = read_string_16!(self);
744 self.set_global(identifier_handle)?;
745 }
746 OpCode::GetGlobal => {
747 let identifier_handle = read_string!(self);
748 let value = self.get_global(identifier_handle)?;
749 push_value!(self, value)?;
750 }
751
752 OpCode::GetGlobal16 => {
753 let identifier_handle = read_string_16!(self);
754 let value = self.get_global(identifier_handle)?;
755 push_value!(self, value)?;
756 }
757 OpCode::GetLocal => {
758 let slot = self.state.read_byte();
759 let absolute_slot =
760 self.state.frames[self.state.frame_count - 1].value_slot + slot as usize;
761 debug_assert!(
762 absolute_slot < STACK_MAX,
763 "Local slot {} out of bounds",
764 absolute_slot
765 );
766
767 let value = self.state.stack[absolute_slot];
768 push_value!(self, value)?;
769 }
770 OpCode::SetLocal => {
771 let slot = self.state.read_byte();
772 let value = peek_value!(self, 0);
773 let absolute_slot =
774 self.state.frames[self.state.frame_count - 1].value_slot + slot as usize;
775
776 self.state.stack[absolute_slot] = value;
777 }
778 OpCode::JumpIfFalse => {
779 let offset = self.state.read_short();
780 if !peek_value!(self, 0).is_truthy() {
781 self.state.frames[self.state.frame_count - 1].ip += offset;
782 }
783 }
784 OpCode::JumpIfNil => {
785 let offset = self.state.read_short();
786 if peek_value!(self, 0).is_nil() {
787 self.state.frames[self.state.frame_count - 1].ip += offset;
788 }
789 }
790 OpCode::Jump => {
791 let offset = self.state.read_short();
792 self.state.frames[self.state.frame_count - 1].ip += offset;
793 }
794 OpCode::Loop => {
795 let offset = self.state.read_short();
796 self.state.frames[self.state.frame_count - 1].ip -= offset;
797 }
798 OpCode::Call => {
799 let arg_count = self.state.read_byte() as usize;
800 let function_value = peek_value!(self, arg_count);
801 self.call_value(function_value, arg_count)?;
802 }
803 OpCode::TailCall => {
804 let arg_count = self.state.read_byte() as usize;
805 let function_value = peek_value!(self, arg_count);
806 self.tail_call_value(function_value, arg_count)?;
807 }
808 OpCode::Closure => {
809 let constant = self.state.read_constant();
810 self.create_closure(constant)?;
811 }
812 OpCode::Closure16 => {
813 let constant = self.state.read_constant_16();
814 self.create_closure(constant)?;
815 }
816 OpCode::GetUpvalue => {
817 let slot = self.state.read_byte() as usize;
818 let current_closure_handle =
819 self.state.frames[self.state.frame_count - 1].closure;
820 let upvalue = self
821 .alloc
822 .closures
823 .get_upvalue(current_closure_handle, slot)
824 .unwrap_or(UpvalueSlot::Open(0));
825
826 match upvalue {
827 UpvalueSlot::Open(stack_slot) => {
828 let value = self.state.stack[stack_slot];
829 push_value!(self, value)?;
830 }
831 UpvalueSlot::Closed(value_handle) => {
832 let value = *self.alloc.get_upvalue(value_handle);
833 push_value!(self, value)?;
834 }
835 }
836 }
837 OpCode::SetUpvalue => {
838 let slot = self.state.read_byte() as usize;
839 let value = peek_value!(self, 0);
840 let current_closure_handle =
841 self.state.frames[self.state.frame_count - 1].closure;
842
843 let upvalue = self
844 .alloc
845 .closures
846 .get_upvalue(current_closure_handle, slot)
847 .unwrap_or(UpvalueSlot::Open(0));
848 match upvalue {
849 UpvalueSlot::Open(stack_slot) => {
850 self.state.stack[stack_slot] = value;
851 }
852 UpvalueSlot::Closed(value_handle) => {
853 *self.alloc.get_upvalue_mut(value_handle) = value;
854 }
855 }
856 }
857 OpCode::CloseUpvalue => {
858 self.close_upvalue(self.state.stack_top - 1);
859 pop_value!(self);
860 }
861 OpCode::Class => {
862 let identifier_handle = read_string!(self);
863 let class_handle: crate::arena::Index =
864 self.with_gc_check(|alloc| alloc.allocate_class(identifier_handle));
865 push_value!(self, Value::class(class_handle))?
866 }
867 OpCode::Class16 => {
868 let identifier_handle = read_string_16!(self);
869 let class_handle: crate::arena::Index =
870 self.with_gc_check(|alloc| alloc.allocate_class(identifier_handle));
871 push_value!(self, Value::class(class_handle))?
872 }
873 OpCode::GetProperty => {
874 let object = peek_value!(self, 0);
875 let identifier = read_string!(self);
876 self.get_property_value(object, false, identifier)?;
877 }
878 OpCode::GetProperty16 => {
879 let object = peek_value!(self, 0);
880 let identifier = read_string_16!(self);
881 self.get_property_value(object, false, identifier)?;
882 }
883 OpCode::SetProperty => {
884 let identifier = read_string!(self);
885 self.set_property(identifier)?
886 }
887 OpCode::SetProperty16 => {
888 let identifier = read_string_16!(self);
889 self.set_property(identifier)?
890 }
891 OpCode::GetOptionalProperty => {
892 let object = peek_value!(self, 0);
893 let identifier = read_string!(self);
894 self.get_property_value(object, true, identifier)?;
895 }
896 OpCode::GetOptionalProperty16 => {
897 let object = peek_value!(self, 0);
898 let identifier = read_string_16!(self);
899 self.get_property_value(object, true, identifier)?;
900 }
901 OpCode::Method => {
902 let identifier_handle = read_string!(self);
903 self.define_method(identifier_handle)?;
904 }
905 OpCode::Method16 => {
906 let identifier_handle = read_string_16!(self);
907 self.define_method(identifier_handle)?;
908 }
909 OpCode::InitField => {
910 let identifier_handle = read_string!(self);
911 let value = pop_value!(self);
912 self.init_field(identifier_handle, value)?;
913 }
914 OpCode::InitField16 => {
915 let identifier_handle = read_string_16!(self);
916 let value = pop_value!(self);
917 self.init_field(identifier_handle, value)?;
918 }
919 OpCode::Invoke => {
920 let method_handle = read_string!(self);
921 let arg_count = self.state.read_byte();
922 self.invoke(method_handle, arg_count as usize)?;
923 }
924 OpCode::Invoke16 => {
925 let method_handle = read_string_16!(self);
926 let arg_count = self.state.read_byte();
927 self.invoke(method_handle, arg_count as usize)?;
928 }
929 OpCode::GetSuper => {
930 let property_handle = read_string!(self);
931 self.get_super(property_handle)?;
932 }
933 OpCode::GetSuper16 => {
934 let property_handle = read_string_16!(self);
935 self.get_super(property_handle)?;
936 }
937 OpCode::SuperInvoke => {
938 let method_handle = read_string!(self);
939 self.invoke_super(method_handle)?;
940 }
941 OpCode::SuperInvoke16 => {
942 let method_handle = read_string_16!(self);
943 self.invoke_super(method_handle)?;
944 }
945 OpCode::Inherit => {
946 let superclass = peek_value!(self, 0);
947 let subclass = peek_value!(self, 1);
948
949 match (superclass.as_class(), subclass.as_class()) {
950 (Some(superclass_handle), Some(subclass_handle)) => {
951 let subclass = self.alloc.get_class_mut(subclass_handle);
952 subclass.super_clazz = Some(superclass_handle);
953 let subclass = self.alloc.get_class(subclass_handle);
954 let superclass = self.alloc.get_class(superclass_handle);
955 let subclass_value_table = subclass.value_table;
956 let superclass_value_table = superclass.value_table;
957 let superclass_method_table = superclass.method_table;
958 let subclass_method_table = subclass.method_table;
959 self.alloc
960 .tables
961 .copy_into(superclass_method_table, subclass_method_table);
962 self.alloc
963 .tables
964 .copy_into(superclass_value_table, subclass_value_table);
965 pop_value!(self);
966 Ok(())
967 }
968 (Some(_), _) => Err(QangRuntimeError::new(
969 "Invalid subclass.".to_string(),
970 self.state.get_previous_loc(),
971 )),
972 (_, Some(_)) => Err(QangRuntimeError::new(
973 "Super class must be a class.".to_string(),
974 self.state.get_previous_loc(),
975 )),
976 _ => Err(QangRuntimeError::new(
977 "Invalid class declaration.".to_string(),
978 self.state.get_previous_loc(),
979 )),
980 }?
981 }
982 OpCode::ArrayLiteral => {
983 let length = self.state.read_byte() as usize;
984 let array = self.with_gc_check(|alloc| alloc.arrays.create_array(length));
985 for i in 0..length {
986 let value = pop_value!(self);
987 self.alloc.arrays.insert(array, i, value);
988 }
989 push_value!(self, Value::array(array))?;
990 }
991 OpCode::GetArrayIndex => {
992 let index = pop_value!(self);
993 match (index.as_number(), peek_value!(self, 0).as_array()) {
994 (Some(index), Some(handle)) => {
995 let value = self.alloc.arrays.get(handle, index.trunc() as isize);
996 pop_value!(self);
997 push_value!(self, value)?;
998 }
999 (_, Some(_)) => {
1000 return Err(QangRuntimeError::new(
1001 "An array can only be indexed by a number.".to_string(),
1002 self.state.get_previous_loc(),
1003 ));
1004 }
1005 (Some(_), _) => {
1006 return Err(QangRuntimeError::new(
1007 "Only arrays can be indexed.".to_string(),
1008 self.state.get_previous_loc(),
1009 ));
1010 }
1011 _ => {
1012 return Err(QangRuntimeError::new(
1013 "Invalid operation.".to_string(),
1014 self.state.get_previous_loc(),
1015 ));
1016 }
1017 }
1018 }
1019 OpCode::SetArrayIndex => {
1020 let value = pop_value!(self);
1021 let index = pop_value!(self);
1022 match (index.as_number(), peek_value!(self, 0).as_array()) {
1023 (Some(index), Some(handle)) => {
1024 let is_within_bounds =
1025 self.alloc
1026 .arrays
1027 .insert(handle, index.trunc() as usize, value);
1028
1029 if !is_within_bounds {
1030 return Err(QangRuntimeError::new(
1031 "Index out of bounds.".to_string(),
1032 self.state.get_previous_loc(),
1033 ));
1034 }
1035 pop_value!(self);
1036 push_value!(self, value)?;
1037 }
1038 (_, Some(_)) => {
1039 return Err(QangRuntimeError::new(
1040 "An array can only be indexed by a number.".to_string(),
1041 self.state.get_previous_loc(),
1042 ));
1043 }
1044 (Some(_), _) => {
1045 return Err(QangRuntimeError::new(
1046 "Only arrays can be indexed.".to_string(),
1047 self.state.get_previous_loc(),
1048 ));
1049 }
1050 _ => {
1051 return Err(QangRuntimeError::new(
1052 "Invalid operation.".to_string(),
1053 self.state.get_previous_loc(),
1054 ));
1055 }
1056 }
1057 }
1058 OpCode::ObjectLiteral => {
1059 let handle = self.alloc.tables.new_hashmap();
1060 let length = self.state.read_byte() as usize;
1061 for _ in 0..length {
1062 let value = pop_value!(self);
1063 let key = pop_value!(self);
1064 self.alloc.tables.insert(handle, key, value);
1065 }
1066 push_value!(self, Value::object_literal(handle))?;
1067 }
1068 OpCode::Module => {
1069 let module_path = read_string!(self);
1070 self.load_module(module_path)?;
1071 }
1072 OpCode::Module16 => {
1073 let module_path = read_string_16!(self);
1074 self.load_module(module_path)?;
1075 }
1076 OpCode::Return => {
1077 let result = pop_value!(self);
1078 let value_slot = self.state.frames[self.state.frame_count - 1].value_slot;
1079
1080 self.close_upvalue(value_slot);
1081 self.state.frame_count -= 1;
1082
1083 #[cfg(feature = "profiler")]
1084 coz::progress!("function_returns");
1085
1086 if self.state.frame_count > 0 {
1087 let prev_closure = self
1088 .alloc
1089 .closures
1090 .get_closure(self.state.frames[self.state.frame_count - 1].closure);
1091 self.state.function_module_context = prev_closure.module_context;
1092 } else {
1093 self.state.function_module_context = None;
1094 }
1095
1096 if self.state.frame_count == 0 {
1097 return Ok(result);
1098 }
1099
1100 let previous_frame = &self.state.frames[self.state.frame_count - 1];
1101 let previous_closure = self.alloc.closures.get_closure(previous_frame.closure);
1102 let previous_function = self.alloc.get_function(previous_closure.function);
1103 self.state.current_function_ptr = previous_function as *const FunctionObject;
1104
1105 self.state.stack_top = value_slot + 1;
1106 self.state.stack[value_slot] = result;
1107 }
1108 OpCode::ModuleReturn => {
1109 let result = pop_value!(self);
1110 let value_slot = self.state.frames[self.state.frame_count - 1].value_slot;
1111
1112 let module_instance =
1113 self.state.frames[self.state.frame_count - 1].module_export_target;
1114
1115 self.close_upvalue(value_slot);
1116 self.state.frame_count -= 1;
1117
1118 #[cfg(feature = "profiler")]
1119 coz::progress!("function_returns");
1120
1121 if let Some(module_instance) = module_instance {
1122 self.state.stack[self.state.stack_top - 1] = Value::module(module_instance);
1123 } else if self.state.frame_count == 0 {
1124 return Ok(result);
1125 }
1126
1127 if self.state.frame_count == 0 {
1128 return Ok(result);
1129 }
1130
1131 let previous_frame = &self.state.frames[self.state.frame_count - 1];
1132 let previous_closure = self.alloc.closures.get_closure(previous_frame.closure);
1133 let previous_function = self.alloc.get_function(previous_closure.function);
1134 self.state.current_function_ptr = previous_function as *const FunctionObject;
1135 }
1136 };
1137 }
1138 }
1139
1140 fn load_module(&mut self, module_path: StringHandle) -> RuntimeResult<()> {
1141 if let Some(instance_handle) = self.state.modules.get_instance_handle(module_path) {
1142 push_value!(self, Value::module(instance_handle))?;
1143 return Ok(());
1144 }
1145
1146 let module_function = self
1147 .state
1148 .modules
1149 .get_module_handle(module_path, self.state.get_previous_loc())?;
1150
1151 let module_instance = self.with_gc_check(|alloc| alloc.tables.new_hashmap());
1152
1153 self.state
1154 .modules
1155 .add_instance(module_path, module_instance);
1156
1157 let module_closure = self.with_gc_check(|alloc| {
1158 alloc
1159 .closures
1160 .allocate_closure(ClosureObject::new(module_function, 0, None))
1161 });
1162
1163 push_value!(self, Value::closure(module_closure))?;
1164 self.call(module_closure, 0)?;
1165
1166 self.state.frames[self.state.frame_count - 1].module_export_target = Some(module_instance);
1167
1168 Ok(())
1169 }
1170
1171 fn create_closure(&mut self, constant: Value) -> RuntimeResult<()> {
1172 let handle = match constant.as_function() {
1173 Some(handle) => handle,
1174 _ => {
1175 return Err(QangRuntimeError::new(
1176 "Expected function.".to_string(),
1177 self.state.get_previous_loc(),
1178 ));
1179 }
1180 };
1181 let upvalue_count = self.alloc.get_function(handle).upvalue_count;
1182 let module_context = if self.state.frame_count > 0 {
1183 self.state.frames[self.state.frame_count - 1].module_export_target
1184 } else {
1185 None
1186 };
1187 let closure_handle = self.with_gc_check(|alloc| {
1188 alloc.closures.allocate_closure(ClosureObject::new(
1189 handle,
1190 upvalue_count,
1191 module_context,
1192 ))
1193 });
1194
1195 push_value!(self, Value::closure(closure_handle))?;
1196
1197 for i in 0..self
1198 .alloc
1199 .closures
1200 .get_closure(closure_handle)
1201 .upvalue_count
1202 {
1203 let is_local = self.state.read_byte() != 0;
1204 let index = self.state.read_byte() as usize;
1205
1206 if is_local {
1207 let stack_slot = self.state.frames[self.state.frame_count - 1].value_slot + index;
1208 self.capture_upvalue(stack_slot, closure_handle, i);
1209 } else {
1210 let current_closure_handle = self.state.frames[self.state.frame_count - 1].closure;
1211 if let Some(current_upvalue) = self
1212 .alloc
1213 .closures
1214 .get_upvalue(current_closure_handle, index)
1215 {
1216 self.alloc
1217 .closures
1218 .set_upvalue(closure_handle, i, current_upvalue);
1219 }
1220 }
1221 }
1222
1223 Ok(())
1224 }
1225
1226 fn define_method(&mut self, name: StringHandle) -> RuntimeResult<()> {
1227 if let Some(method) = peek_value!(self, 0).as_closure()
1228 && let Some(clazz_handle) = peek_value!(self, 1).as_class()
1229 {
1230 let clazz = self.alloc.get_class(clazz_handle);
1231 self.alloc.set_class_method(
1232 clazz.method_table,
1233 Value::string(name),
1234 Value::closure(method),
1235 );
1236 pop_value!(self);
1237 }
1238
1239 Ok(())
1240 }
1241
1242 fn init_field(&mut self, field_name: StringHandle, value: Value) -> RuntimeResult<()> {
1243 if let Some(clazz_handle) = peek_value!(self, 0).as_class() {
1244 let clazz = self.alloc.get_class(clazz_handle);
1245 self.alloc
1246 .set_class_method(clazz.value_table, Value::string(field_name), value);
1247 }
1248
1249 Ok(())
1250 }
1251
1252 fn bind_method(&mut self, clazz_handle: ClassHandle, method_name: Value) -> RuntimeResult<()> {
1253 if let Some(method_handle) = method_name.as_string() {
1254 let init_handle = self.alloc.strings.intern("init");
1255 if method_handle == init_handle {
1256 pop_value!(self);
1257 push_value!(self, Value::nil())?;
1258 return Ok(());
1259 }
1260 }
1261
1262 let clazz = self.alloc.get_class(clazz_handle);
1263 if let Some(closure) = self
1264 .alloc
1265 .get_class_method(clazz.method_table, method_name)
1266 .and_then(|v| v.as_closure())
1267 {
1268 let receiver = peek_value!(self, 0);
1269 let bound = BoundMethodObject::new(receiver, closure);
1270 let handle = self.with_gc_check(|alloc| alloc.allocate_bound_method(bound));
1271 pop_value!(self);
1272 push_value!(self, Value::bound_method(handle))?;
1273 } else {
1274 pop_value!(self);
1275 push_value!(self, Value::nil())?;
1276 }
1277 Ok(())
1278 }
1279
1280 fn bind_intrinsic_method(
1281 &mut self,
1282 method_name: StringHandle,
1283 kind: IntrinsicKind,
1284 receiver: Value,
1285 ) -> RuntimeResult<()> {
1286 let intrinsic = *self.state.intrinsics.get(&kind).ok_or_else(|| {
1287 QangRuntimeError::new(
1288 "invalid method call.".to_string(),
1289 self.state.get_previous_loc(),
1290 )
1291 })?;
1292
1293 let final_intrinsic = if receiver.is_nil() {
1294 match intrinsic {
1295 IntrinsicMethod::Call => IntrinsicMethod::NilSafeCall,
1296 IntrinsicMethod::Apply => IntrinsicMethod::NilSafeApply,
1297 other => other,
1298 }
1299 } else {
1300 intrinsic
1301 };
1302
1303 let bound = BoundIntrinsicObject::new(receiver, final_intrinsic, method_name);
1304 let handle = self.with_gc_check(|alloc| alloc.allocate_bound_intrinsic(bound));
1305 pop_value!(self);
1306 push_value!(self, Value::bound_intrinsic(handle))?;
1307 Ok(())
1308 }
1309
1310 fn bind_super_method(
1311 &mut self,
1312 method_table_handle: HashMapHandle,
1313 method_name: StringHandle,
1314 ) -> RuntimeResult<bool> {
1315 if let Some(closure) = self
1316 .alloc
1317 .get_class_method(method_table_handle, Value::string(method_name))
1318 .and_then(|v| v.as_closure())
1319 {
1320 let receiver = peek_value!(self, 0);
1321 let bound = BoundMethodObject::new(receiver, closure);
1322 let handle = self.with_gc_check(|alloc| alloc.allocate_bound_method(bound));
1323 pop_value!(self); push_value!(self, Value::bound_method(handle))?;
1325 Ok(true)
1326 } else {
1327 Ok(false)
1328 }
1329 }
1330
1331 fn close_upvalue(&mut self, last_slot: StackSlot) {
1332 let mut i = self.state.open_upvalues.len();
1333 while i > 0 {
1334 i -= 1;
1335 let (stack_slot, upvalue_ref) = &self.state.open_upvalues[i];
1336
1337 if *stack_slot >= last_slot {
1338 let value = self.state.stack[*stack_slot];
1339
1340 let value_handle = self.alloc.allocate_upvalue(value);
1341
1342 for (closure_handle, upvalue_index) in
1343 upvalue_ref.iter_all_entries(&self.alloc.upvalue_overflow)
1344 {
1345 self.alloc.closures.set_upvalue(
1346 closure_handle,
1347 upvalue_index,
1348 UpvalueSlot::Closed(value_handle),
1349 );
1350 }
1351
1352 self.state.open_upvalues.remove(i);
1353 }
1354 }
1355 }
1356
1357 fn capture_upvalue(
1358 &mut self,
1359 stack_slot: StackSlot,
1360 closure_handle: ClosureHandle,
1361 upvalue_index: UpvalueIndex,
1362 ) {
1363 for (open_slot, upvalue_ref) in self.state.open_upvalues.iter_mut() {
1364 if *open_slot == stack_slot {
1365 upvalue_ref.add_closure(
1366 closure_handle,
1367 upvalue_index,
1368 &mut self.alloc.upvalue_overflow,
1369 );
1370
1371 self.alloc.closures.set_upvalue(
1372 closure_handle,
1373 upvalue_index,
1374 UpvalueSlot::Open(stack_slot),
1375 );
1376 return;
1377 }
1378 }
1379
1380 let mut upvalue_ref = OpenUpvalueTracker::new();
1381 upvalue_ref.add_closure(
1382 closure_handle,
1383 upvalue_index,
1384 &mut self.alloc.upvalue_overflow,
1385 );
1386
1387 self.alloc.closures.set_upvalue(
1388 closure_handle,
1389 upvalue_index,
1390 UpvalueSlot::Open(stack_slot),
1391 );
1392
1393 self.state.open_upvalues.push((stack_slot, upvalue_ref));
1394 }
1395
1396 fn binary_operation<F>(&mut self, op: F) -> RuntimeResult<()>
1397 where
1398 F: FnOnce(Value, Value, &mut HeapAllocator) -> Result<Value, BinaryOperationError>,
1399 {
1400 #[cfg(feature = "profiler")]
1401 coz::scope!("binary_operation");
1402
1403 let b = pop_value!(self);
1404 let a = pop_value!(self);
1405
1406 let value = op(a, b, &mut self.alloc)
1407 .map_err(|e: BinaryOperationError| e.into_qang_error(self.state.get_previous_loc()))?;
1408
1409 push_value!(self, value)?;
1410 Ok(())
1411 }
1412
1413 pub(crate) fn call_value(&mut self, value: Value, arg_count: usize) -> RuntimeResult<()> {
1414 match value.kind() {
1415 ValueKind::Closure(handle) => self.call(handle, arg_count),
1416 ValueKind::NativeFunction(function) => self.call_native_function(function, arg_count),
1417 ValueKind::Class(handle) => {
1418 let clazz = self.alloc.get_class(handle);
1419 let clazz_method_table = clazz.method_table;
1420 let clazz_value_table = clazz.value_table;
1421 let instance_handle = self.with_gc_check(|alloc| alloc.allocate_instance(handle));
1422 self.state.stack[self.state.stack_top - arg_count - 1] =
1423 Value::instance(instance_handle);
1424 let instance_table = self.alloc.get_instance(instance_handle).table;
1425
1426 self.alloc
1427 .tables
1428 .copy_into(clazz_value_table, instance_table);
1429
1430 let constructor_handle = self.alloc.strings.intern("init");
1431 if let Some(constructor) = self
1432 .alloc
1433 .get_class_method(clazz_method_table, Value::string(constructor_handle))
1434 .and_then(|v| v.as_closure())
1435 {
1436 self.call(constructor, arg_count)?;
1437 } else {
1438 for _ in 0..arg_count {
1440 pop_value!(self);
1441 }
1442 }
1443 Ok(())
1444 }
1445 ValueKind::BoundMethod(handle) => {
1446 let bound_method = self.alloc.get_bound_method(handle);
1447
1448 self.state.stack[self.state.stack_top - arg_count - 1] = bound_method.receiver;
1449 self.call(bound_method.closure, arg_count)
1450 }
1451 ValueKind::BoundIntrinsic(handle) => {
1452 let bound_intrinsic = self.alloc.get_bound_intrinsic(handle);
1453 self.call_intrinsic_method(
1454 bound_intrinsic.receiver,
1455 bound_intrinsic.method,
1456 arg_count,
1457 )
1458 }
1459 _ => {
1460 let value_str = value.to_display_string(&self.alloc);
1461 Err(QangRuntimeError::new(
1462 format!("Identifier '{}' not callable.", value_str).to_string(),
1463 self.state.get_previous_loc(),
1464 ))
1465 }
1466 }
1467 }
1468
1469 fn invoke(&mut self, method_handle: StringHandle, arg_count: usize) -> RuntimeResult<()> {
1470 let receiver = peek_value!(self, arg_count);
1471
1472 match receiver.kind() {
1473 ValueKind::Instance(instance_handle) => {
1474 let clazz = {
1475 let instance = self.alloc.get_instance(instance_handle);
1476
1477 if let Some(value) = self
1478 .alloc
1479 .get_instance_field(instance.table, Value::string(method_handle))
1480 {
1481 self.state.stack[self.state.stack_top - arg_count - 1] = value;
1482 return self.call_value(value, arg_count);
1483 }
1484
1485 instance.clazz
1486 };
1487
1488 let init_handle = self.alloc.strings.intern("init");
1489 if method_handle == init_handle {
1490 return Err(QangRuntimeError::new(
1491 "Cannot call constructor 'init' on an instance.".to_string(),
1492 self.state.get_previous_loc(),
1493 ));
1494 }
1495
1496 self.invoke_from_class_cached(clazz, method_handle, arg_count)
1497 }
1498
1499 ValueKind::ObjectLiteral(handle) => {
1500 let object_type = CachedObjectType::ObjectLiteral;
1501
1502 if let Some(method_value) =
1503 self.get_method_cached(object_type, handle, method_handle)
1504 {
1505 self.state.stack[self.state.stack_top - arg_count - 1] = method_value;
1506 self.call_value(method_value, arg_count)
1507 } else {
1508 Err(QangRuntimeError::new(
1509 format!(
1510 "Property '{}' does not exist on object.",
1511 self.alloc.strings.get(method_handle)
1512 ),
1513 self.state.get_previous_loc(),
1514 ))
1515 }
1516 }
1517
1518 ValueKind::Module(handle) => {
1519 let object_type = CachedObjectType::Module;
1520
1521 if let Some(method_value) =
1522 self.get_method_cached(object_type, handle, method_handle)
1523 {
1524 self.state.stack[self.state.stack_top - arg_count - 1] = method_value;
1525 self.call_value(method_value, arg_count)
1526 } else {
1527 Err(QangRuntimeError::new(
1528 format!(
1529 "Property '{}' does not exist on module.",
1530 self.alloc.strings.get(method_handle)
1531 ),
1532 self.state.get_previous_loc(),
1533 ))
1534 }
1535 }
1536
1537 ValueKind::String(_) => {
1538 let intrinsic = *self
1539 .state
1540 .intrinsics
1541 .get(&IntrinsicKind::String(method_handle))
1542 .ok_or_else(|| {
1543 QangRuntimeError::new(
1544 "invalid method call.".to_string(),
1545 self.state.get_previous_loc(),
1546 )
1547 })?;
1548 self.call_intrinsic_method(receiver, intrinsic, arg_count)
1549 }
1550
1551 ValueKind::Array(_) => {
1552 let intrinsic = *self
1553 .state
1554 .intrinsics
1555 .get(&IntrinsicKind::Array(method_handle))
1556 .ok_or_else(|| {
1557 QangRuntimeError::new(
1558 "invalid method call.".to_string(),
1559 self.state.get_previous_loc(),
1560 )
1561 })?;
1562 self.call_intrinsic_method(receiver, intrinsic, arg_count)
1563 }
1564
1565 ValueKind::Number(_) => {
1566 let intrinsic = *self
1567 .state
1568 .intrinsics
1569 .get(&IntrinsicKind::Number(method_handle))
1570 .ok_or_else(|| {
1571 QangRuntimeError::new(
1572 "invalid method call.".to_string(),
1573 self.state.get_previous_loc(),
1574 )
1575 })?;
1576 self.call_intrinsic_method(receiver, intrinsic, arg_count)
1577 }
1578
1579 ValueKind::Closure(_)
1580 | ValueKind::NativeFunction(_)
1581 | ValueKind::BoundIntrinsic(_)
1582 | ValueKind::BoundMethod(_) => {
1583 let intrinsic = *self
1584 .state
1585 .intrinsics
1586 .get(&IntrinsicKind::Function(method_handle))
1587 .ok_or_else(|| {
1588 QangRuntimeError::new(
1589 "invalid method call.".to_string(),
1590 self.state.get_previous_loc(),
1591 )
1592 })?;
1593 self.call_intrinsic_method(receiver, intrinsic, arg_count)
1594 }
1595
1596 _ => Err(QangRuntimeError::new(
1597 format!(
1598 "Cannot invoke {}, no methods exist.",
1599 receiver.to_type_string()
1600 ),
1601 self.state.get_previous_loc(),
1602 )),
1603 }
1604 }
1605
1606 fn call(&mut self, closure_handle: ClosureHandle, arg_count: usize) -> RuntimeResult<()> {
1607 #[cfg(feature = "profiler")]
1608 coz::scope!("call_function");
1609
1610 #[cfg(feature = "profiler")]
1611 coz::progress!("before_call");
1612
1613 let closure = self.alloc.closures.get_closure(closure_handle);
1614 let function = self.alloc.get_function(closure.function);
1615
1616 let final_arg_count = {
1617 if arg_count < function.arity {
1618 let arity = function.arity;
1619 for _ in arg_count..arity {
1620 push_value!(self, Value::nil())?;
1621 }
1622 arity
1623 } else {
1624 arg_count
1625 }
1626 };
1627
1628 if self.state.frame_count >= FRAME_MAX {
1629 let loc = if self.state.frame_count > 0 {
1630 self.state.get_previous_loc()
1631 } else {
1632 SourceLocation::default()
1633 };
1634 return Err(QangRuntimeError::new(
1635 "Maximum call depth exceeded.".to_string(),
1636 loc,
1637 ));
1638 }
1639
1640 self.state.frame_count += 1;
1641
1642 let value_slot = self.state.stack_top - final_arg_count - 1;
1643 let call_frame = &mut self.state.frames[self.state.frame_count - 1];
1644
1645 call_frame.value_slot = value_slot;
1646 call_frame.closure = closure_handle;
1647 call_frame.ip = 0;
1648 call_frame.module_export_target = None;
1649 self.state.current_function_ptr = function as *const FunctionObject;
1650
1651 if let Some(module_context) = closure.module_context {
1652 self.state.function_module_context = Some(module_context);
1653 }
1654
1655 #[cfg(feature = "profiler")]
1656 coz::progress!("after_call");
1657
1658 Ok(())
1659 }
1660
1661 fn tail_call_value(&mut self, callee: Value, arg_count: usize) -> RuntimeResult<()> {
1662 match callee.kind() {
1663 ValueKind::Closure(closure_handle) => self.tail_call(closure_handle, arg_count),
1664 ValueKind::NativeFunction(handle) => self.call_native_function(handle, arg_count),
1665 ValueKind::Class(_handle) => {
1666 panic!("Cannot tail call optimize class instancing.")
1667 }
1668 ValueKind::BoundMethod(handle) => {
1669 let bound_method = self.alloc.get_bound_method(handle);
1670 self.state.stack[self.state.stack_top - arg_count - 1] = bound_method.receiver;
1671 self.tail_call(bound_method.closure, arg_count)
1672 }
1673 ValueKind::BoundIntrinsic(handle) => {
1674 let bound_intrinsic = self.alloc.get_bound_intrinsic(handle);
1675 self.call_intrinsic_method(
1676 bound_intrinsic.receiver,
1677 bound_intrinsic.method,
1678 arg_count,
1679 )
1680 }
1681 _ => {
1682 let value_str = callee.to_display_string(&self.alloc);
1683 Err(QangRuntimeError::new(
1684 format!("Identifier '{}' not callable.", value_str).to_string(),
1685 self.state.get_previous_loc(),
1686 ))
1687 }
1688 }
1689 }
1690
1691 fn tail_call(&mut self, closure_handle: ClosureHandle, arg_count: usize) -> RuntimeResult<()> {
1692 let closure = self.alloc.closures.get_closure(closure_handle);
1693 let function_handle = closure.function;
1694 let function_arity = self.alloc.get_function(function_handle).arity;
1695
1696 let final_arg_count = if arg_count < function_arity {
1698 for _ in arg_count..function_arity {
1699 push_value!(self, Value::nil())?;
1700 }
1701 function_arity
1702 } else {
1703 arg_count
1704 };
1705
1706 let current_frame = &self.state.frames[self.state.frame_count - 1];
1708 let current_value_slot = current_frame.value_slot;
1709
1710 self.close_upvalue(current_value_slot + 1);
1714
1715 let new_func_pos = self.state.stack_top - final_arg_count - 1;
1718
1719 for i in 0..=final_arg_count {
1721 self.state.stack[current_value_slot + i] = self.state.stack[new_func_pos + i];
1723 }
1724
1725 self.state.stack_top = current_value_slot + final_arg_count + 1;
1727
1728 let current_frame = &mut self.state.frames[self.state.frame_count - 1];
1730 current_frame.closure = closure_handle;
1731 current_frame.ip = 0;
1732
1733 let function = self.alloc.get_function(function_handle);
1735 self.state.current_function_ptr = function as *const FunctionObject;
1736
1737 Ok(())
1738 }
1739
1740 pub fn call_function(&mut self, handle: ClosureHandle, args: &[Value]) -> RuntimeResult<Value> {
1741 let saved_stack_top = self.state.stack_top;
1742 let saved_frame_count = self.state.frame_count;
1743 let saved_function_ptr = self.state.current_function_ptr;
1744
1745 push_value!(self, Value::closure(handle))?;
1746
1747 for value in args {
1748 push_value!(self, *value)?;
1749 }
1750
1751 self.call(handle, args.len())?;
1752
1753 let result = self.run();
1754
1755 self.state.stack_top = saved_stack_top;
1756 self.state.frame_count = saved_frame_count;
1757 self.state.current_function_ptr = saved_function_ptr;
1758
1759 result
1760 }
1761
1762 pub fn get_function_args(&self, arg_count: usize) -> &[Value] {
1763 &self.state.arg_buffer[..arg_count]
1764 }
1765
1766 fn call_native_function(
1767 &mut self,
1768 handle: NativeFunctionHandle,
1769 arg_count: usize,
1770 ) -> RuntimeResult<()> {
1771 let function = self.alloc.get_native_function(handle);
1772
1773 for i in (0..arg_count).rev() {
1774 if i < function.arity {
1775 self.state.arg_buffer[i] = pop_value!(self);
1776 } else {
1777 pop_value!(self); }
1779 }
1780
1781 pop_value!(self); let value = (function.function)(arg_count, self)
1784 .map_err(|e: NativeFunctionError| {
1785 let loc = self.state.get_previous_loc();
1786 e.into_qang_error(loc)
1787 })?
1788 .unwrap_or_default();
1789
1790 push_value!(self, value)?;
1791 self.state.arg_buffer.fill(Value::default());
1792
1793 Ok(())
1794 }
1795
1796 fn call_intrinsic_method(
1797 &mut self,
1798 receiver: Value,
1799 method: IntrinsicMethod,
1800 arg_count: usize,
1801 ) -> RuntimeResult<()> {
1802 match method {
1803 IntrinsicMethod::Native { function, arity } => {
1804 for i in (0..arg_count).rev() {
1805 if i < arity {
1806 self.state.arg_buffer[i] = pop_value!(self);
1807 } else {
1808 pop_value!(self); }
1810 }
1811
1812 pop_value!(self); self.state.additional_roots.insert(receiver);
1816
1817 let value = function(receiver, arg_count, self)
1818 .map_err(|e: NativeFunctionError| {
1819 let loc = self.state.get_previous_loc();
1820 e.into_qang_error(loc)
1821 })?
1822 .unwrap_or_default();
1823
1824 self.state.additional_roots.remove(&receiver);
1826
1827 push_value!(self, value)?;
1828 self.state.arg_buffer.fill(Value::default());
1829
1830 Ok(())
1831 }
1832 IntrinsicMethod::Apply => self.handle_function_intrinsic_apply(receiver, arg_count),
1833 IntrinsicMethod::Call => self.handle_function_intrinsic_call(receiver, arg_count),
1834 IntrinsicMethod::Iter => self.handle_array_intrinsic_iter(receiver, arg_count),
1835 IntrinsicMethod::ToNumber => {
1836 self.handle_string_intrinsic_to_number(receiver, arg_count)
1837 }
1838 IntrinsicMethod::NilSafeCall | IntrinsicMethod::NilSafeApply => {
1839 for _ in 0..arg_count {
1841 pop_value!(self);
1842 }
1843 pop_value!(self); push_value!(self, Value::nil())?;
1845 Ok(())
1846 }
1847 }
1848 }
1849
1850 fn invoke_from_class(
1851 &mut self,
1852 clazz_handle: ClassHandle,
1853 method_handle: StringHandle,
1854 arg_count: usize,
1855 ) -> RuntimeResult<()> {
1856 let clazz = self.alloc.get_class(clazz_handle);
1857 if let Some(method) = self
1858 .alloc
1859 .get_class_method(clazz.method_table, Value::string(method_handle))
1860 .and_then(|v| v.as_closure())
1861 {
1862 self.call(method, arg_count)
1863 } else {
1864 let init_handle = self.alloc.strings.intern("init");
1866 if method_handle == init_handle {
1867 for _ in 0..arg_count {
1869 pop_value!(self);
1870 }
1871 push_value!(self, Value::nil())?;
1873 Ok(())
1874 } else {
1875 Err(QangRuntimeError::new(
1876 format!(
1877 "{} does not exist on class {}.",
1878 Value::string(method_handle).to_display_string(&self.alloc),
1879 Value::class(clazz_handle).to_display_string(&self.alloc),
1880 ),
1881 self.state.get_previous_loc(),
1882 ))
1883 }
1884 }
1885 }
1886
1887 fn invoke_from_class_cached(
1888 &mut self,
1889 clazz_handle: ClassHandle,
1890 method_handle: StringHandle,
1891 arg_count: usize,
1892 ) -> RuntimeResult<()> {
1893 let clazz = self.alloc.get_class(clazz_handle);
1894 let object_type = CachedObjectType::Instance(clazz_handle);
1895
1896 if let Some(method_value) =
1897 self.get_method_cached(object_type, clazz.method_table, method_handle)
1898 {
1899 if let Some(method) = method_value.as_closure() {
1900 self.call(method, arg_count)
1901 } else {
1902 Err(QangRuntimeError::new(
1903 format!(
1904 "{} is not a method on class {}.",
1905 Value::string(method_handle).to_display_string(&self.alloc),
1906 Value::class(clazz_handle).to_display_string(&self.alloc),
1907 ),
1908 self.state.get_previous_loc(),
1909 ))
1910 }
1911 } else {
1912 let init_handle = self.alloc.strings.intern("init");
1913 if method_handle == init_handle {
1914 for _ in 0..arg_count {
1915 pop_value!(self);
1916 }
1917 push_value!(self, Value::nil())?;
1919 Ok(())
1920 } else {
1921 Err(QangRuntimeError::new(
1922 format!(
1923 "{} does not exist on class {}.",
1924 Value::string(method_handle).to_display_string(&self.alloc),
1925 Value::class(clazz_handle).to_display_string(&self.alloc),
1926 ),
1927 self.state.get_previous_loc(),
1928 ))
1929 }
1930 }
1931 }
1932
1933 fn get_property_cached(
1934 &mut self,
1935 object_type: CachedObjectType,
1936 table_handle: HashMapHandle,
1937 property_name: StringHandle,
1938 ) -> Option<Value> {
1939 let cache_index = self.state.get_property_cache_index();
1940
1941 if let Some(cached) = self.state.property_cache.get(cache_index)
1942 && cached.object_type == object_type
1943 && cached.property_name == property_name
1944 && cached.table_handle == table_handle
1945 && cached.generation == self.state.cache_generation
1946 {
1947 let key = Value::string(property_name);
1948 return self.alloc.tables.get(cached.table_handle, &key);
1949 }
1950
1951 let key = Value::string(property_name);
1952 let value = self.alloc.tables.get(table_handle, &key);
1953
1954 if let Some(cache_entry) = self.state.property_cache.get_mut(cache_index) {
1955 *cache_entry = PropertyCache {
1956 object_type,
1957 property_name,
1958 table_handle,
1959 generation: self.state.cache_generation,
1960 };
1961 }
1962
1963 value
1964 }
1965
1966 fn get_method_cached(
1967 &mut self,
1968 object_type: CachedObjectType,
1969 table_handle: HashMapHandle,
1970 method_name: StringHandle,
1971 ) -> Option<Value> {
1972 let cache_index = self.state.get_method_cache_index();
1973
1974 if let Some(cached) = self.state.method_cache.get(cache_index)
1975 && cached.object_type == object_type
1976 && cached.method_name == method_name
1977 && cached.table_handle == table_handle
1978 && cached.generation == self.state.cache_generation
1979 {
1980 return Some(cached.cached_method);
1981 }
1982
1983 let key = Value::string(method_name);
1984 if let Some(method_value) = self.alloc.tables.get(table_handle, &key) {
1985 if let Some(cache_entry) = self.state.method_cache.get_mut(cache_index) {
1986 *cache_entry = MethodCache {
1987 object_type,
1988 method_name,
1989 table_handle,
1990 cached_method: method_value,
1991 generation: self.state.cache_generation,
1992 };
1993 }
1994 Some(method_value)
1995 } else {
1996 None
1997 }
1998 }
1999
2000 fn get_property_value(
2001 &mut self,
2002 object: Value,
2003 optional: bool,
2004 identifier: StringHandle,
2005 ) -> RuntimeResult<()> {
2006 match object.kind() {
2007 ValueKind::Instance(instance_handle) => {
2008 let instance = self.alloc.get_instance(instance_handle);
2009 let clazz = instance.clazz;
2010 let object_type = CachedObjectType::Instance(clazz);
2011 let instance_table = instance.table;
2012
2013 if let Some(value) =
2014 self.get_property_cached(object_type, instance_table, identifier)
2015 {
2016 pop_value!(self);
2017 push_value!(self, value)?;
2018 } else {
2019 let key = Value::string(identifier);
2020 self.bind_method(clazz, key)?;
2021 }
2022 }
2023
2024 ValueKind::ObjectLiteral(handle) => {
2025 let object_type = CachedObjectType::ObjectLiteral;
2026
2027 let value = self
2028 .get_property_cached(object_type, handle, identifier)
2029 .unwrap_or_default();
2030 pop_value!(self);
2031 push_value!(self, value)?;
2032 }
2033
2034 ValueKind::Module(handle) => {
2035 let object_type = CachedObjectType::Module;
2036
2037 let value = self.get_property_cached(object_type, handle, identifier);
2038
2039 pop_value!(self);
2040 match value {
2041 Some(val) => push_value!(self, val)?,
2042 None => {
2043 if optional {
2044 push_value!(self, Value::nil())?;
2045 } else {
2046 return Err(QangRuntimeError::new(
2047 format!(
2048 "Property '{}' does not exist on module.",
2049 self.alloc.strings.get(identifier)
2050 ),
2051 self.state.get_previous_loc(),
2052 ));
2053 }
2054 }
2055 }
2056 }
2057
2058 ValueKind::Nil => {
2059 let call_handle = self.alloc.strings.intern("call");
2060 let apply_handle = self.alloc.strings.intern("apply");
2061
2062 if identifier == call_handle || identifier == apply_handle {
2063 let method = if identifier == call_handle {
2064 IntrinsicMethod::NilSafeCall
2065 } else {
2066 IntrinsicMethod::NilSafeApply
2067 };
2068 let bound = BoundIntrinsicObject::new(object, method, identifier);
2069 let handle = self.with_gc_check(|alloc| alloc.allocate_bound_intrinsic(bound));
2070 pop_value!(self);
2071 push_value!(self, Value::bound_intrinsic(handle))?;
2072 } else if optional {
2073 pop_value!(self);
2074 push_value!(self, Value::nil())?;
2075 } else {
2076 return Err(QangRuntimeError::new(
2077 format!("Cannot access property on {}.", object.to_type_string()),
2078 self.state.get_previous_loc(),
2079 ));
2080 }
2081 }
2082
2083 ValueKind::String(_) => {
2084 self.bind_intrinsic_method(identifier, IntrinsicKind::String(identifier), object)?;
2085 }
2086
2087 ValueKind::Array(_) => {
2088 self.bind_intrinsic_method(identifier, IntrinsicKind::Array(identifier), object)?;
2089 }
2090
2091 ValueKind::Number(_) => {
2092 self.bind_intrinsic_method(identifier, IntrinsicKind::Number(identifier), object)?;
2093 }
2094
2095 ValueKind::Closure(_) | ValueKind::BoundMethod(_) => {
2096 self.bind_intrinsic_method(
2097 identifier,
2098 IntrinsicKind::Function(identifier),
2099 object,
2100 )?;
2101 }
2102
2103 _ => {
2104 if optional {
2105 pop_value!(self);
2106 push_value!(self, Value::nil())?;
2107 } else {
2108 return Err(QangRuntimeError::new(
2109 format!("Cannot access property on {}", object.to_type_string()),
2110 self.state.get_previous_loc(),
2111 ));
2112 }
2113 }
2114 }
2115 Ok(())
2116 }
2117
2118 fn set_property(&mut self, identifier: StringHandle) -> RuntimeResult<()> {
2119 let instance = peek_value!(self, 1);
2120 match instance.kind() {
2121 ValueKind::Instance(instance_handle) => {
2122 let instance_obj = self.alloc.get_instance(instance_handle);
2123 let table_handle = instance_obj.table;
2124 let constant = Value::string(identifier);
2125 let value = peek_value!(self, 0);
2126
2127 self.with_gc_check(|alloc| alloc.set_instance_field(table_handle, constant, value));
2128
2129 let value = pop_value!(self);
2130 pop_value!(self);
2131 push_value!(self, value)?;
2132 }
2133
2134 ValueKind::ObjectLiteral(obj_handle) => {
2135 let constant = Value::string(identifier);
2136 let value = peek_value!(self, 0);
2137
2138 self.with_gc_check(|alloc| alloc.tables.insert(obj_handle, constant, value));
2139
2140 let value = pop_value!(self);
2141 pop_value!(self);
2142 push_value!(self, value)?;
2143 }
2144
2145 _ => {
2146 return Err(QangRuntimeError::new(
2147 format!("Cannot set property on {}.", instance.to_type_string()),
2148 self.state.get_previous_loc(),
2149 ));
2150 }
2151 }
2152 Ok(())
2153 }
2154
2155 fn get_global(&self, identifier_handle: StringHandle) -> RuntimeResult<Value> {
2156 let key = Value::string(identifier_handle);
2157
2158 if let Some(function_context) = self.state.function_module_context
2159 && let Some(value) = self.try_get_from_table(function_context, &key)
2160 {
2161 return Ok(value);
2162 }
2163
2164 if self.state.frame_count > 0
2165 && let Some(module_target) =
2166 self.state.frames[self.state.frame_count - 1].module_export_target
2167 && let Some(value) = self.try_get_from_table(module_target, &key)
2168 {
2169 return Ok(value);
2170 }
2171
2172 if self.has_module_context() {
2173 Ok(self.get_from_globals_or_nil(identifier_handle))
2174 } else {
2175 self.try_get_from_globals_strict(identifier_handle)
2176 }
2177 }
2178
2179 fn try_get_from_table(&self, table_handle: HashMapHandle, key: &Value) -> Option<Value> {
2180 self.alloc.tables.get(table_handle, key)
2181 }
2182
2183 fn has_module_context(&self) -> bool {
2184 let has_frame_module_context = if self.state.frame_count > 0 {
2185 self.state.frames[self.state.frame_count - 1]
2186 .module_export_target
2187 .is_some()
2188 } else {
2189 false
2190 };
2191 self.state.function_module_context.is_some() || has_frame_module_context
2192 }
2193
2194 fn get_from_globals_or_nil(&self, identifier_handle: StringHandle) -> Value {
2195 self.state
2196 .globals
2197 .get(&identifier_handle)
2198 .copied()
2199 .unwrap_or(Value::nil())
2200 }
2201
2202 fn try_get_from_globals_strict(&self, identifier_handle: StringHandle) -> RuntimeResult<Value> {
2203 self.state
2204 .globals
2205 .get(&identifier_handle)
2206 .copied()
2207 .ok_or_else(|| {
2208 let loc = self.state.get_previous_loc();
2209 let identifier_name = self.alloc.strings.get(identifier_handle);
2210 QangRuntimeError::new(format!("Undefined variable: {}.", identifier_name), loc)
2211 })
2212 }
2213
2214 fn set_global(&mut self, identifier_handle: StringHandle) -> RuntimeResult<()> {
2215 let value = peek_value!(self, 0);
2216 let key = Value::string(identifier_handle);
2217
2218 if let Some(function_context) = self.state.function_module_context
2219 && self.try_set_in_table(function_context, &key, value)
2220 {
2221 return Ok(());
2222 }
2223
2224 if self.state.frame_count > 0
2225 && let Some(module_target) =
2226 self.state.frames[self.state.frame_count - 1].module_export_target
2227 && self.try_set_in_table(module_target, &key, value)
2228 {
2229 return Ok(());
2230 }
2231
2232 if self.try_set_in_globals(identifier_handle, value) {
2233 return Ok(());
2234 }
2235
2236 self.undefined_variable_error(identifier_handle)
2237 }
2238
2239 fn try_set_in_table(&mut self, table_handle: HashMapHandle, key: &Value, value: Value) -> bool {
2240 if self.alloc.tables.get(table_handle, key).is_some() {
2241 self.alloc.tables.insert(table_handle, *key, value);
2242 true
2243 } else {
2244 false
2245 }
2246 }
2247
2248 fn try_set_in_globals(&mut self, identifier_handle: StringHandle, value: Value) -> bool {
2249 if let std::collections::hash_map::Entry::Occupied(mut e) =
2250 self.state.globals.entry(identifier_handle)
2251 {
2252 e.insert(value);
2253 true
2254 } else {
2255 false
2256 }
2257 }
2258
2259 fn undefined_variable_error(&self, identifier_handle: StringHandle) -> RuntimeResult<()> {
2260 let identifier_name = self.alloc.strings.get(identifier_handle);
2261 let loc = self.state.get_previous_loc();
2262 Err(QangRuntimeError::new(
2263 format!("Undefined variable: {}.", identifier_name),
2264 loc,
2265 ))
2266 }
2267
2268 fn invoke_super(&mut self, method_handle: StringHandle) -> RuntimeResult<()> {
2269 let arg_count = self.state.read_byte() as usize;
2270 let superclass = pop_value!(self);
2271
2272 if let Some(superclass_handle) = superclass.as_class() {
2273 self.invoke_from_class(superclass_handle, method_handle, arg_count)
2274 } else {
2275 Err(QangRuntimeError::new(
2276 "Super class must be a class.".to_string(),
2277 self.state.get_previous_loc(),
2278 ))
2279 }
2280 }
2281
2282 fn get_super(&mut self, property_handle: StringHandle) -> RuntimeResult<()> {
2283 let superclass = pop_value!(self);
2284
2285 if let Some(superclass_handle) = superclass.as_class() {
2286 let superclass_obj = self.alloc.get_class(superclass_handle);
2287
2288 if let Some(field_value) = self
2289 .alloc
2290 .get_class_method(superclass_obj.value_table, Value::string(property_handle))
2291 {
2292 self.state.stack[self.state.stack_top - 1] = field_value; } else if !self.bind_super_method(superclass_obj.method_table, property_handle)? {
2294 pop_value!(self); push_value!(self, Value::nil())?;
2296 }
2297
2298 Ok(())
2299 } else {
2300 Err(QangRuntimeError::new(
2301 "Super class must be a class.".to_string(),
2302 self.state.get_previous_loc(),
2303 ))
2304 }
2305 }
2306
2307 pub fn gather_roots(&mut self) -> VecDeque<Value> {
2308 let capacity = self.state.stack_top
2309 + self.globals().len()
2310 + self.state.frame_count
2311 + self.state.open_upvalues.len()
2312 + self.state.modules.count()
2313 + self.state.arg_buffer.len()
2314 + self.state.additional_roots.len();
2315 let mut roots = VecDeque::with_capacity(capacity);
2316 roots.extend(&self.state.stack[..self.state.stack_top]);
2317 roots.extend(self.globals().values());
2318
2319 for frame in &self.state.frames[..self.state.frame_count] {
2320 roots.push_back(Value::closure(frame.closure));
2321 }
2322
2323 for (_, upvalue_ref) in &self.state.open_upvalues {
2324 for (closure_handle, _) in upvalue_ref.iter() {
2325 roots.push_back(Value::closure(closure_handle));
2326 }
2327 }
2328 roots.extend(&self.state.arg_buffer);
2329
2330 self.state.modules.gather_roots(&mut roots);
2331
2332 roots.extend(self.state.additional_roots.iter());
2333
2334 roots
2335 }
2336
2337 pub fn collect_garbage(&mut self) {
2338 debug_log!(self.is_debug, "--gc begin");
2339
2340 self.state.invalidate_caches();
2341
2342 for (_, upvalue_ref) in &self.state.open_upvalues {
2343 upvalue_ref.mark_overflow_chunks(&mut self.alloc.upvalue_overflow);
2344 }
2345
2346 let roots = self.gather_roots();
2347 self.alloc.collect_garbage(roots);
2348 debug_log!(self.is_debug, "--gc end");
2349 }
2350
2351 pub fn globals(&self) -> &FxHashMap<StringHandle, Value> {
2352 &self.state.globals
2353 }
2354
2355 #[cfg(debug_assertions)]
2356 fn debug_print(&self) {
2357 print!(" ");
2358 for i in 0..self.state.stack_top {
2359 if let Some(value) = self.state.stack.get(i) {
2360 value.print(&self.alloc);
2361 print!(" ");
2362 }
2363 }
2364 println!();
2365
2366 disassemble_instruction(
2367 &self.state.get_current_function().chunk,
2368 &self.alloc,
2369 self.state.frames[self.state.frame_count - 1].ip,
2370 );
2371 }
2372}