| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- #include "memory.h"
- #include "vm.h"
- #ifdef DEBUG_LOG_GC
- #include "debug.h"
- #include <stdlib.h>
- #endif
- // oldSize newSize Operation
- // 0 Non‑zero Allocate new block.
- // Non‑zero 0 Free allocation.
- // Non‑zero Smaller than oldSize Shrink existing allocation.
- // Non‑zero Larger than oldSize Grow existing allocation.
- 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;
- }
- /*
- The realloc() function tries to change the size of the allocation pointed
- to by ptr to size, and returns ptr. If there is not enough room to
- enlarge the memory allocation pointed to by ptr, realloc() creates a new
- allocation, copies as much of the old data pointed to by ptr as will fit
- to the new allocation, frees the old allocation, and returns a pointer to
- the allocated memory. If ptr is NULL, realloc() is identical to a call
- to malloc() for size bytes. If size is zero and ptr is not NULL, a new,
- minimum sized object is allocated and the original object is freed. When
- extending a region allocated with calloc(3), realloc(3) does not guaran-
- tee that the additional memory is also zero-filled
- */
- void *result = realloc(pointer, newSize);
- if (result == NULL) exit(1);
- return result;
- }
- static void freeObject(Obj *object) {
- #ifdef DEBUG_LOG_GC
- printf("%p free type %d\n", (void *) object, object->type);
- #endif
- switch (object->type) {
- case OBJ_NATIVE:
- FREE(ObjNative, object);
- break;
- case OBJ_FUNCTION: {
- ObjFunction *function = (ObjFunction *) object;
- freeChunk(&function->chunk);
- FREE(ObjFunction, object);
- break;
- }
- case OBJ_STRING:
- FREE_ARRAY(char, ((ObjString *) object)->chars, ((ObjString *) object)->length + 1);
- FREE(ObjString, object);
- break;
- case OBJ_CLOSURE: {
- ObjClosure *closure = (ObjClosure *) object;
- FREE_ARRAY(ObjUpvalue *, closure->upvalues, closure->upvalueCount);
- FREE(ObjClosure, object);
- break;
- }
- case OBJ_UPVALUE:
- FREE(ObjUpvalue, object);
- break;
- }
- }
- void freeObjects() {
- Obj *object = vm.objects;
- while (object != NULL) {
- Obj *next = object->next;
- freeObject(object);
- object = next;
- }
- }
- 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();
- }
- void collectGarbage() {
- #ifdef DEBUG_LOG_GC
- printf("-- gc begin\n");
- #endif
- markRoots();
- #ifdef DEBUG_LOG_GC
- printf("-- gc end\n");
- #endif
- }
- void markValue(Value value) {
- if (IS_OBJ(value)) markObject(AS_OBJ(value));
- }
- void markObject(Obj *object) {
- if (object == NULL) return;
- #ifdef DEBUG_LOG_GC
- printf("%p mark ", (void *) object);
- printValue(OBJ_VAL(object));
- printf("\n");
- #endif
- object->isMarked = true;
- }
|