1use std::{any::Any, mem};
2
3use crate::Gc;
4
5impl super::VM {
6 fn mark_roots(&mut self) -> Vec<Gc<dyn Any>> {
7 let mut gray_stack = Vec::new();
8
9 for el in &self.stack {
11 el.mark(&mut gray_stack);
12 }
13
14 for val in self.globals.values() {
16 val.mark(&mut gray_stack);
17 }
18
19 for frame in &self.frames {
21 frame.mark(&mut gray_stack);
22 }
23
24 for c in self.open_upvalues.iter() {
26 c.mark();
27 gray_stack.push(c.as_any());
28 }
29
30 for root in &self.compiler_roots {
32 root.mark(&mut gray_stack);
33 }
34
35 gray_stack
36 }
37
38 fn trace_references(gray_stack: &mut Vec<Gc<dyn Any>>) {
39 while let Some(top_obj) = gray_stack.pop() {
40 top_obj.blacken(gray_stack);
41 }
42 }
43
44 fn sweep(&mut self) {
45 let to_drop = self.objects.retain(|obj| {
46 if obj.is_marked() {
47 obj.clear_mark();
48 true
49 } else {
50 false
51 }
52 });
53
54 for ptr in to_drop {
55 self.total_allocations -= mem::size_of_val(&*ptr);
56 ptr.free();
57 }
58 }
59
60 fn collect_garbage(&mut self) {
61 #[cfg(feature = "trace-gc")]
62 let before = self.total_allocations;
63
64 #[cfg(feature = "trace-gc")]
65 log::debug!("gc begin :: total allocations {} bytes", before);
66
67 let mut gray_stack = self.mark_roots();
68 Self::trace_references(&mut gray_stack);
69 self.sweep();
70
71 self.next_gc = self.total_allocations * 2;
73
74 #[cfg(feature = "trace-gc")]
75 log::debug!(
76 "gc end :: collected {} bytes (total was {}, now {}) :: next at {}",
77 before - self.total_allocations,
78 before,
79 self.total_allocations,
80 self.next_gc
81 );
82 }
83
84 fn should_collect(&self) -> bool {
85 cfg!(feature = "stress-test-gc") || self.total_allocations > self.next_gc
86 }
87
88 pub fn alloc<T: Any>(&mut self, obj: T) -> Gc<T> {
97 if self.should_collect() {
98 self.collect_garbage();
99 }
100
101 let size = mem::size_of::<T>();
102 self.total_allocations += size;
103
104 let ptr = Gc::new(obj);
105 self.objects.push(ptr.as_any());
106
107 #[cfg(feature = "trace-gc")]
108 log::debug!(
109 "{:p} allocate {} bytes for {}",
110 ptr,
111 size,
112 std::any::type_name::<T>()
113 );
114
115 ptr
116 }
117}