aboutsummaryrefslogtreecommitdiffstats
path: root/clox/src/memory.c
diff options
context:
space:
mode:
authorGravatar Tom Willemse2022-06-04 22:00:27 -0700
committerGravatar Tom Willemse2022-06-04 22:00:27 -0700
commit14b3866ac09c80b8f34d79227d743eabb2da0f2a (patch)
tree62eb3137f016ceaec9d0c88e527a663372927d59 /clox/src/memory.c
parent57ed9226c06b5fbe016e62857fe9662c51da3dfd (diff)
downloadcrafting-interpreters-14b3866ac09c80b8f34d79227d743eabb2da0f2a.tar.gz
crafting-interpreters-14b3866ac09c80b8f34d79227d743eabb2da0f2a.zip
Chapter 26.1, 26.2, 26.3, and 26.4
Diffstat (limited to 'clox/src/memory.c')
-rw-r--r--clox/src/memory.c121
1 files changed, 121 insertions, 0 deletions
diff --git a/clox/src/memory.c b/clox/src/memory.c
index 1db1c61..7d403d1 100644
--- a/clox/src/memory.c
+++ b/clox/src/memory.c
@@ -1,9 +1,21 @@
#include <stdlib.h>
+#include "compiler.h"
#include "memory.h"
#include "vm.h"
+#ifdef DEBUG_LOG_GC
+#include "debug.h"
+#include <stdio.h>
+#endif
+
void *reallocate(void *pointer, size_t oldSize, size_t newSize) {
+ if (newSize > oldSize) {
+#ifdef DEBUG_STRESS_GC
+ collectGarbage();
+#endif
+ }
+
if (newSize == 0) {
free(pointer);
return NULL;
@@ -15,7 +27,76 @@ void *reallocate(void *pointer, size_t oldSize, size_t newSize) {
return result;
}
+void markObject(Obj *object) {
+ if (object == NULL)
+ return;
+ if (object->isMarked)
+ return;
+
+#ifdef DEBUG_LOG_GC
+ printf("%p mark ", (void *)object);
+ printValue(OBJ_VAL(object));
+ printf("\n");
+#endif
+ object->isMarked = true;
+
+ if (vm.grayCapacity < vm.grayCount + 1) {
+ vm.grayCapacity = GROW_CAPACITY(vm.grayCapacity);
+ vm.grayStack =
+ (Obj **)realloc(vm.grayStack, sizeof(Obj *) * vm.grayCapacity);
+ if (vm.grayStack == NULL)
+ exit(1);
+ }
+
+ vm.grayStack[vm.grayCount++] = object;
+}
+
+void markValue(Value value) {
+ if (IS_OBJ(value))
+ markObject(AS_OBJ(value));
+}
+
+static void markArray(ValueArray *array) {
+ for (int i = 0; i < array->count; i++) {
+ markValue(array->values[i]);
+ }
+}
+
+static void blackenObject(Obj *object) {
+#ifdef DEBUG_LOG_GC
+ printf("%p blacken ", (void *)object);
+ printValue(OBJ_VAL(object));
+ printf("\n");
+#endif
+ switch (object->type) {
+ case OBJ_CLOSURE: {
+ ObjClosure *closure = (ObjClosure *)object;
+ markObject((Obj *)closure->function);
+ for (int i = 0; i < closure->upvalueCount; i++) {
+ markObject((Obj *)closure->upvalues[i]);
+ }
+ break;
+ }
+ case OBJ_FUNCTION: {
+ ObjFunction *function = (ObjFunction *)object;
+ markObject((Obj *)function->name);
+ markArray(&function->chunk.constants);
+ break;
+ }
+ case OBJ_UPVALUE:
+ markValue(((ObjUpvalue *)object)->closed);
+ break;
+ case OBJ_NATIVE:
+ case OBJ_STRING:
+ break;
+ }
+}
+
static void freeObject(Obj *object) {
+#ifdef DEBUG_LOG_GC
+ printf("%p free type %d\n", (void *)object, object->type);
+#endif // DEBUG_LOG_GC
+
switch (object->type) {
case OBJ_CLOSURE: {
ObjClosure *closure = (ObjClosure *)object;
@@ -44,6 +125,44 @@ static void freeObject(Obj *object) {
}
}
+static void markRoots() {
+ for (Value *slot = vm.stack; slot < vm.stackTop; slot++) {
+ markValue(*slot);
+ }
+
+ for (int i = 0; i < vm.frameCount; i++) {
+ markObject((Obj *)vm.frames[i].closure);
+ }
+
+ for (ObjUpvalue *upvalue = vm.openUpvalues; upvalue != NULL;
+ upvalue = upvalue->next) {
+ markObject((Obj *)upvalue);
+ }
+
+ markTable(&vm.globals);
+ markCompilerRoots();
+}
+
+static void traceReferences() {
+ while (vm.grayCount > 0) {
+ Obj *object = vm.grayStack[--vm.grayCount];
+ blackenObject(object);
+ }
+}
+
+void collectGarbage() {
+#ifdef DEBUG_LOG_GC
+ printf("-- gc begin\n");
+#endif
+
+ markRoots();
+ traceReferences();
+
+#ifdef DEBUG_LOG_GC
+ printf("-- gd end\n");
+#endif
+}
+
void freeObjects() {
Obj *object = vm.objects;
while (object != NULL) {
@@ -51,4 +170,6 @@ void freeObjects() {
freeObject(object);
object = next;
}
+
+ free(vm.grayStack);
}