1313#include <stdio.h>
1414#endif
1515
16+ #define GC_HEAP_GROW_FACTOR 2
17+
1618void * reallocate (void * pointer , size_t old_size , size_t new_size )
1719{
20+ vm .bytes_allocated += new_size - old_size ;
21+
1822 if (new_size > old_size )
1923 {
20- #ifdef DEBUG_PRINT_CODE
24+ #ifdef DEBUG_STRESS_GC
2125 collect_garbage ();
2226#endif
27+ if (vm .bytes_allocated > vm .next_GC )
28+ {
29+ collect_garbage ();
30+ }
2331 }
2432 if (new_size == 0 )
2533 {
@@ -37,6 +45,8 @@ void mark_object(Obj* object)
3745{
3846 if (object == NULL )
3947 return ;
48+ if (object -> is_marked )
49+ return ;
4050
4151#ifdef DEBUG_LOG_GC
4252 printf ("%p mark " , (void * )object );
@@ -45,6 +55,16 @@ void mark_object(Obj* object)
4555#endif
4656
4757 object -> is_marked = true;
58+
59+ if (vm .gray_capacity < vm .gray_count + 1 )
60+ {
61+ vm .gray_capacity = GROW_CAPACITY (vm .gray_capacity );
62+ vm .gray_stack = realloc (vm .gray_stack , sizeof (Obj * ) * vm .gray_capacity );
63+
64+ if (vm .gray_stack == NULL )
65+ exit (1 );
66+ }
67+ vm .gray_stack [vm .gray_count ++ ] = object ;
4868}
4969
5070void mark_value (Value value )
@@ -55,6 +75,45 @@ void mark_value(Value value)
5575 mark_object (AS_OBJ (value ));
5676}
5777
78+ static void mark_array (ValueArray * array )
79+ {
80+ for (int i = 0 ; i < array -> count ; i ++ )
81+ {
82+ mark_value (array -> values [i ]);
83+ }
84+ }
85+
86+ static void blacken_object (Obj * object )
87+ {
88+ #ifdef DEBUG_LOG_GC
89+ printf ("%p blacken" , (void * )object );
90+ print_value (OBJ_VAL (object ));
91+ printf ("\n" );
92+ #endif // DEbUG_LOG_GC
93+ switch (object -> type )
94+ {
95+ case OBJ_CLOSURE :
96+ ObjClosure * closure = (ObjClosure * )object ;
97+ mark_object ((Obj * )closure -> function );
98+ for (int i = 0 ; i < closure -> upvalue_count ; i ++ )
99+ {
100+ mark_object ((Obj * )closure -> upvalues [i ]);
101+ }
102+ break ;
103+ case OBJ_FUNCTION :
104+ ObjFunction * function = (ObjFunction * )object ;
105+ mark_object ((Obj * )function -> name );
106+ mark_array (& function -> chunk .constants );
107+ break ;
108+ case OBJ_UPVALUE :
109+ mark_value (((ObjUpvalue * )object )-> closed );
110+ break ;
111+ case OBJ_NATIVE :
112+ case OBJ_STRING :
113+ break ;
114+ }
115+ }
116+
58117static void free_object (Obj * object )
59118{
60119
@@ -107,6 +166,8 @@ void free_objects()
107166 free_object (object );
108167 object = next ;
109168 }
169+
170+ free (vm .gray_stack );
110171}
111172
112173static void mark_roots ()
@@ -131,15 +192,58 @@ static void mark_roots()
131192 mark_compiler_roots ();
132193}
133194
195+ static void trace_references ()
196+ {
197+ while (vm .gray_count > 0 )
198+ {
199+ Obj * object = vm .gray_stack [-- vm .gray_count ];
200+ blacken_object (object );
201+ }
202+ }
203+
204+ static void sweep ()
205+ {
206+ Obj * previous = NULL ;
207+ Obj * object = vm .objects ;
208+
209+ while (object != NULL )
210+ {
211+ if (object -> is_marked )
212+ {
213+ object -> is_marked = false;
214+ previous = object ;
215+ object = object -> next ;
216+ }
217+ else
218+ {
219+ Obj * unreached = object ;
220+ object = object -> next ;
221+ if (previous != NULL )
222+ previous -> next = object ;
223+ else
224+ vm .objects = object ;
225+ free_object (unreached );
226+ }
227+ }
228+ }
229+
134230void collect_garbage ()
135231{
136232#ifdef DEBUG_LOG_GC
137233 printf ("-- GC Begins \n" );
234+ size_t before = vm .bytes_allocated ;
138235#endif
139236
140237 mark_roots ();
238+ trace_references ();
239+ table_remove_white (& vm .strings );
240+ sweep ();
241+
242+ vm .next_GC = vm .bytes_allocated * GC_HEAP_GROW_FACTOR ;
141243
142244#ifdef DEBUG_LOG_GC
143245 printf ("-- GC Ends \n" );
246+ printf (" collected %ld bytes (from %ld to %ld) next at %ld\n" ,
247+ before - vm .bytes_allocated , before , vm .bytes_allocated , vm .next_GC );
144248#endif
145249}
0 commit comments