2
2
#include "mem.h"
3
3
#include "vm.h"
4
4
5
+ #ifdef DEBUG_LOG_GC
6
+ #include <stdio.h>
7
+ #include "debug.h"
8
+ #endif
9
+
10
+ #define GC_HEAP_GROW_FACTOR 2
11
+
5
12
void * reallocate (void * pointer , size_t oldSize , size_t newSize )
6
13
{
14
+ vm .bytesAllocated += newSize - oldSize ;
15
+ if (newSize > oldSize )
16
+ {
17
+ #ifdef DEBUG_STRESS_GC
18
+ collectGarbage ();
19
+ #endif
20
+ }
21
+ if (vm .bytesAllocated > vm .nextGC )
22
+ {
23
+ collectGarbage ();
24
+ }
25
+
7
26
if (newSize == 0 )
8
27
{
9
28
free (pointer );
@@ -15,8 +34,86 @@ void *reallocate(void *pointer, size_t oldSize, size_t newSize)
15
34
return result ;
16
35
}
17
36
37
+ void markObject (Object * object )
38
+ {
39
+ if (object == NULL )
40
+ return ;
41
+ if (object -> isMarked )
42
+ return ;
43
+ #ifdef DEBUG_LOG_GC
44
+ printf ("%p mark " , (void * )object );
45
+ printValue (OBJ_VAL (object ));
46
+ printf ("\n" );
47
+ #endif
48
+ object -> isMarked = true;
49
+ if (vm .grayCapacity < vm .grayCount + 1 )
50
+ {
51
+ vm .grayCapacity = GROW_ARRAY_SIZE (vm .grayCapacity );
52
+ vm .grayStack = realloc (vm .grayStack ,
53
+ sizeof (Object * ) * vm .grayCapacity );
54
+
55
+ if (vm .grayStack == NULL )
56
+ exit (1 );
57
+ }
58
+
59
+ vm .grayStack [vm .grayCount ++ ] = object ;
60
+ }
61
+
62
+ void markValue (Value value )
63
+ {
64
+ if (!IS_OBJ (value ))
65
+ return ;
66
+ markObject (AS_OBJ (value ));
67
+ }
68
+
69
+ static void markArray (ValueArr * array )
70
+ {
71
+ for (int i = 0 ; i < array -> maxSize ; i ++ )
72
+ {
73
+ markValue (array -> values [i ]);
74
+ }
75
+ }
76
+
77
+ static void blackenObject (Object * object )
78
+ {
79
+ #ifdef DEBUG_LOG_GC
80
+ printf ("%p blacken " , (void * )object );
81
+ printValue (OBJ_VAL (object ));
82
+ printf ("\n" );
83
+ #endif
84
+ switch (object -> t )
85
+ {
86
+ case OBJECT_CLOSURE :
87
+ {
88
+ ObjectClosure * closure = (ObjectClosure * )object ;
89
+ markObject ((Object * )closure -> function );
90
+ for (int i = 0 ; i < closure -> upvalueCount ; i ++ )
91
+ {
92
+ markObject ((Object * )closure -> upvalues [i ]);
93
+ }
94
+ break ;
95
+ }
96
+ case OBJECT_FUNCTION :
97
+ {
98
+ ObjectFunction * function = (ObjectFunction * )object ;
99
+ markObject ((Object * )function -> name );
100
+ markArray (& function -> chunk .constants );
101
+ break ;
102
+ }
103
+ case OBJECT_UPVALUE :
104
+ markValue (((ObjectUpvalue * )object )-> closed );
105
+ break ;
106
+ case OBJECT_NATIVE :
107
+ case OBJECT_STRING :
108
+ break ;
109
+ }
110
+ }
111
+
18
112
static void freeObject (Object * object )
19
113
{
114
+ #ifdef DEBUG_LOG_GC
115
+ printf ("%p free type %d\n" , (void * )object , object -> t );
116
+ #endif
20
117
switch (object -> t )
21
118
{
22
119
case OBJECT_STRING :
@@ -49,6 +146,88 @@ static void freeObject(Object *object)
49
146
}
50
147
}
51
148
149
+ static void markRoots ()
150
+ {
151
+ for (Value * slot = vm .stack ; slot < vm .stackTop ; slot ++ )
152
+ {
153
+ markValue (* slot );
154
+ }
155
+ for (int i = 0 ; i < vm .frameCount ; i ++ )
156
+ {
157
+ markObject ((Object * )vm .frames [i ].closure );
158
+ }
159
+ for (ObjectUpvalue * upvalue = vm .openUpvalues ;
160
+ upvalue != NULL ;
161
+ upvalue = upvalue -> next )
162
+ {
163
+ markObject ((Object * )upvalue );
164
+ }
165
+
166
+ markTable (& vm .globals );
167
+ markCompilerRoots ();
168
+ }
169
+
170
+ static void traceReferences ()
171
+ {
172
+ while (vm .grayCount > 0 )
173
+ {
174
+ Object * object = vm .grayStack [-- vm .grayCount ];
175
+ blackenObject (object );
176
+ }
177
+ }
178
+
179
+ static void sweep ()
180
+ {
181
+ Object * previous = NULL ;
182
+ Object * object = vm .objects ;
183
+ while (object != NULL )
184
+ {
185
+ if (object -> isMarked )
186
+ {
187
+ object -> isMarked = false;
188
+ previous = object ;
189
+ object = object -> next ;
190
+ }
191
+ else
192
+ {
193
+ Object * unreached = object ;
194
+ object = object -> next ;
195
+ if (previous != NULL )
196
+ {
197
+ previous -> next = object ;
198
+ }
199
+ else
200
+ {
201
+ vm .objects = object ;
202
+ }
203
+
204
+ freeObject (unreached );
205
+ }
206
+ }
207
+ }
208
+
209
+ void collectGarbage ()
210
+ {
211
+ #ifdef DEBUG_LOG_GC
212
+ printf ("-- gc begin\n" );
213
+ size_t before = vm .bytesAllocated ;
214
+ #endif
215
+
216
+ markRoots ();
217
+ traceReferences ();
218
+ tableRemoveWhite (& vm .strings );
219
+ sweep ();
220
+
221
+ vm .nextGC = vm .bytesAllocated * GC_HEAP_GROW_FACTOR ;
222
+
223
+ #ifdef DEBUG_LOG_GC
224
+ printf ("-- gc end\n" );
225
+ printf (" collected %ld bytes (from %ld to %ld) next at %ld\n" ,
226
+ before - vm .bytesAllocated , before , vm .bytesAllocated ,
227
+ vm .nextGC );
228
+ #endif
229
+ }
230
+
52
231
void freeObjects ()
53
232
{
54
233
Object * object = vm .objects ;
@@ -58,4 +237,5 @@ void freeObjects()
58
237
freeObject (object );
59
238
object = next ;
60
239
}
240
+ free (vm .grayStack );
61
241
}
0 commit comments