Chapter 26.1, 26.2, 26.3, and 26.4
This commit is contained in:
parent
57ed9226c0
commit
14b3866ac0
11 changed files with 160 additions and 0 deletions
|
@ -8,6 +8,9 @@
|
||||||
#define DEBUG_PRINT_CODE
|
#define DEBUG_PRINT_CODE
|
||||||
#define DEBUG_TRACE_EXECUTION
|
#define DEBUG_TRACE_EXECUTION
|
||||||
|
|
||||||
|
#define DEBUG_STRESS_GC
|
||||||
|
#define DEBUG_LOG_GC
|
||||||
|
|
||||||
#define UINT8_COUNT (UINT8_MAX + 1)
|
#define UINT8_COUNT (UINT8_MAX + 1)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
|
#include "memory.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
|
|
||||||
#ifdef DEBUG_PRINT_CODE
|
#ifdef DEBUG_PRINT_CODE
|
||||||
|
@ -827,3 +828,11 @@ ObjFunction *compile(const char *source) {
|
||||||
ObjFunction *function = endCompiler();
|
ObjFunction *function = endCompiler();
|
||||||
return parser.hadError ? NULL : function;
|
return parser.hadError ? NULL : function;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void markCompilerRoots() {
|
||||||
|
Compiler *compiler = current;
|
||||||
|
while (compiler != NULL) {
|
||||||
|
markObject((Obj *)compiler->function);
|
||||||
|
compiler = compiler->enclosing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,5 +5,6 @@
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
|
|
||||||
ObjFunction *compile(const char *source);
|
ObjFunction *compile(const char *source);
|
||||||
|
void markCompilerRoots();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,9 +1,21 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "compiler.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "vm.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) {
|
void *reallocate(void *pointer, size_t oldSize, size_t newSize) {
|
||||||
|
if (newSize > oldSize) {
|
||||||
|
#ifdef DEBUG_STRESS_GC
|
||||||
|
collectGarbage();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
if (newSize == 0) {
|
if (newSize == 0) {
|
||||||
free(pointer);
|
free(pointer);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -15,7 +27,76 @@ void *reallocate(void *pointer, size_t oldSize, size_t newSize) {
|
||||||
return result;
|
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) {
|
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) {
|
switch (object->type) {
|
||||||
case OBJ_CLOSURE: {
|
case OBJ_CLOSURE: {
|
||||||
ObjClosure *closure = (ObjClosure *)object;
|
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() {
|
void freeObjects() {
|
||||||
Obj *object = vm.objects;
|
Obj *object = vm.objects;
|
||||||
while (object != NULL) {
|
while (object != NULL) {
|
||||||
|
@ -51,4 +170,6 @@ void freeObjects() {
|
||||||
freeObject(object);
|
freeObject(object);
|
||||||
object = next;
|
object = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(vm.grayStack);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,9 @@
|
||||||
reallocate(pointer, sizeof(type) * (oldCount), 0)
|
reallocate(pointer, sizeof(type) * (oldCount), 0)
|
||||||
|
|
||||||
void *reallocate(void *pointer, size_t oldSize, size_t newSize);
|
void *reallocate(void *pointer, size_t oldSize, size_t newSize);
|
||||||
|
void markObject(Obj *object);
|
||||||
|
void markValue(Value value);
|
||||||
|
void collectGarbage();
|
||||||
void freeObjects();
|
void freeObjects();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -13,9 +13,15 @@
|
||||||
static Obj *allocateObject(size_t size, ObjType type) {
|
static Obj *allocateObject(size_t size, ObjType type) {
|
||||||
Obj *object = (Obj *)reallocate(NULL, 0, size);
|
Obj *object = (Obj *)reallocate(NULL, 0, size);
|
||||||
object->type = type;
|
object->type = type;
|
||||||
|
object->isMarked = false;
|
||||||
|
|
||||||
object->next = vm.objects;
|
object->next = vm.objects;
|
||||||
vm.objects = object;
|
vm.objects = object;
|
||||||
|
|
||||||
|
#ifdef DEBUG_LOG_GC
|
||||||
|
printf("%p allocate %zu for %d", (void *)object, size, type);
|
||||||
|
#endif
|
||||||
|
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ typedef enum {
|
||||||
|
|
||||||
struct Obj {
|
struct Obj {
|
||||||
ObjType type;
|
ObjType type;
|
||||||
|
bool isMarked;
|
||||||
struct Obj *next;
|
struct Obj *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -140,3 +140,11 @@ ObjString *tableFindString(Table *table, const char *chars, int length,
|
||||||
index = (index + 1) % table->capacity;
|
index = (index + 1) % table->capacity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void markTable(Table *table) {
|
||||||
|
for (int i = 0; i < table->capacity; i++) {
|
||||||
|
Entry *entry = &table->entries[i];
|
||||||
|
markObject((Obj *)entry->key);
|
||||||
|
markValue(entry->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -23,5 +23,6 @@ bool tableDelete(Table *table, ObjString *key);
|
||||||
void tableAddAll(Table *from, Table *to);
|
void tableAddAll(Table *from, Table *to);
|
||||||
ObjString *tableFindString(Table *talbe, const char *chars, int length,
|
ObjString *tableFindString(Table *talbe, const char *chars, int length,
|
||||||
uint32_t hash);
|
uint32_t hash);
|
||||||
|
void markTable(Table *table);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -56,6 +56,10 @@ void initVM() {
|
||||||
resetStack();
|
resetStack();
|
||||||
vm.objects = NULL;
|
vm.objects = NULL;
|
||||||
|
|
||||||
|
vm.grayCount = 0;
|
||||||
|
vm.grayCapacity = 0;
|
||||||
|
vm.grayStack = NULL;
|
||||||
|
|
||||||
initTable(&vm.globals);
|
initTable(&vm.globals);
|
||||||
initTable(&vm.strings);
|
initTable(&vm.strings);
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,9 @@ typedef struct {
|
||||||
Table strings;
|
Table strings;
|
||||||
ObjUpvalue *openUpvalues;
|
ObjUpvalue *openUpvalues;
|
||||||
Obj *objects;
|
Obj *objects;
|
||||||
|
int grayCount;
|
||||||
|
int grayCapacity;
|
||||||
|
Obj **grayStack;
|
||||||
} VM;
|
} VM;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
Loading…
Reference in a new issue