From 1ae473383de9374a9bfe92f415673e457c80bb98 Mon Sep 17 00:00:00 2001 From: CPunch Date: Tue, 29 Aug 2023 23:21:52 -0500 Subject: [PATCH] fix more GC bugs --- src/cchunk.c | 8 ++++---- src/clex.c | 6 +++--- src/cmem.c | 22 ++++++++++++---------- src/cmem.h | 33 ++++++++++++++++++++------------- src/cobj.c | 8 ++++---- src/cparse.c | 11 ++++++----- src/cstate.c | 2 +- src/cstate.h | 6 +++--- src/ctable.c | 4 ++-- src/cvalue.c | 4 ++-- 10 files changed, 57 insertions(+), 47 deletions(-) diff --git a/src/cchunk.c b/src/cchunk.c index 4ef4ad6..04db498 100644 --- a/src/cchunk.c +++ b/src/cchunk.c @@ -27,9 +27,9 @@ void initChunk(CState *state, CChunk *chunk, size_t startCapacity) void cleanChunk(CState *state, CChunk *chunk) { // first, free the chunk buffer - cosmoM_freearray(state, INSTRUCTION, chunk->buf, chunk->capacity); + cosmoM_freeArray(state, INSTRUCTION, chunk->buf, chunk->capacity); // then the line info - cosmoM_freearray(state, int, chunk->lineInfo, chunk->capacity); + cosmoM_freeArray(state, int, chunk->lineInfo, chunk->capacity); // free the constants cleanValArray(state, &chunk->constants); } @@ -61,8 +61,8 @@ int addConstant(CState *state, CChunk *chunk, CValue value) void writeu8Chunk(CState *state, CChunk *chunk, INSTRUCTION i, int line) { // does the buffer need to be reallocated? - cosmoM_growarray(state, INSTRUCTION, chunk->buf, chunk->count, chunk->capacity); - cosmoM_growarray(state, int, chunk->lineInfo, chunk->count, chunk->lineCapacity); + cosmoM_growArray(state, INSTRUCTION, chunk->buf, chunk->count, chunk->capacity); + cosmoM_growArray(state, int, chunk->lineInfo, chunk->count, chunk->lineCapacity); // write data to the chunk :) chunk->lineInfo[chunk->count] = line; diff --git a/src/clex.c b/src/clex.c index 811d48e..e2993df 100644 --- a/src/clex.c +++ b/src/clex.c @@ -54,7 +54,7 @@ static void resetBuffer(CLexState *state) // cancels the token heap buffer and frees it static void freeBuffer(CLexState *state) { - cosmoM_freearray(state->cstate, char, state->buffer, state->bufCap); + cosmoM_freeArray(state->cstate, char, state->buffer, state->bufCap); resetBuffer(state); } @@ -62,7 +62,7 @@ static void freeBuffer(CLexState *state) // adds character to buffer static void appendBuffer(CLexState *state, char c) { - cosmoM_growarray(state->cstate, char, state->buffer, state->bufCount, state->bufCap); + cosmoM_growArray(state->cstate, char, state->buffer, state->bufCount, state->bufCap); state->buffer[state->bufCount++] = c; } @@ -90,7 +90,7 @@ static char *cutBuffer(CLexState *state, int *length) resetBuffer(state); // shrink the buffer to only use what we need - return cosmoM_reallocate(state->cstate, buf, cap, count); + return cosmoM_reallocate(state->cstate, buf, cap, count, true); } static CToken makeToken(CLexState *state, CTokenType type) diff --git a/src/cmem.c b/src/cmem.c index c7a6665..71b8514 100644 --- a/src/cmem.c +++ b/src/cmem.c @@ -8,7 +8,7 @@ #include "cvalue.h" // realloc wrapper -void *cosmoM_reallocate(CState *state, void *buf, size_t oldSize, size_t newSize) +void *cosmoM_reallocate(CState *state, void *buf, size_t oldSize, size_t newSize, bool isGC) { if (buf == NULL) oldSize = 0; @@ -34,18 +34,20 @@ void *cosmoM_reallocate(CState *state, void *buf, size_t oldSize, size_t newSize return NULL; } + if (isGC) { #ifdef GC_STRESS - if (!(cosmoM_isFrozen(state)) && newSize > oldSize) { - cosmoM_collectGarbage(state); - } + if (!(cosmoM_isFrozen(state)) && newSize > oldSize) { + cosmoM_collectGarbage(state); + } # ifdef GC_DEBUG - else { - printf("GC event ignored! state frozen! [%d]\n", state->freezeGC); - } + else { + printf("GC event ignored! state frozen! [%d]\n", state->freezeGC); + } # endif #else - cosmoM_checkGarbage(state, 0); + cosmoM_checkGarbage(state, 0); #endif + } // if NULL is passed, realloc() acts like malloc() void *newBuf = realloc(buf, newSize); @@ -206,8 +208,8 @@ static void markObject(CState *state, CObj *obj) return; // we can use cosmoM_growarray because we lock the GC when we entered in cosmoM_collectGarbage - cosmoM_growarray(state, CObj *, state->grayStack.array, state->grayStack.count, - state->grayStack.capacity); + cosmoM_growArrayNonGC(state, CObj *, state->grayStack.array, state->grayStack.count, + state->grayStack.capacity); state->grayStack.array[state->grayStack.count++] = obj; } diff --git a/src/cmem.h b/src/cmem.h index c00aa30..ba38087 100644 --- a/src/cmem.h +++ b/src/cmem.h @@ -12,28 +12,37 @@ #define ARRAY_START 8 #ifdef GC_DEBUG -# define cosmoM_freearray(state, type, buf, capacity) \ +# define cosmoM_freeArray(state, type, buf, capacity) \ printf("freeing array %p [size %lu] at %s:%d\n", buf, sizeof(type) * capacity, __FILE__, \ __LINE__); \ - cosmoM_reallocate(state, buf, sizeof(type) * capacity, 0) + cosmoM_reallocate(state, buf, sizeof(type) * capacity, 0, true) #else -# define cosmoM_freearray(state, type, buf, capacity) \ - cosmoM_reallocate(state, buf, sizeof(type) * capacity, 0) +# define cosmoM_freeArray(state, type, buf, capacity) \ + cosmoM_reallocate(state, buf, sizeof(type) * capacity, 0, true) #endif -#define cosmoM_growarray(state, type, buf, count, capacity) \ +#define cosmoM_growArray(state, type, buf, count, capacity) \ if (count >= capacity || buf == NULL) { \ int old = capacity; \ capacity = old * GROW_FACTOR; \ - buf = (type *)cosmoM_reallocate(state, buf, sizeof(type) * old, sizeof(type) * capacity); \ + buf = (type *)cosmoM_reallocate(state, buf, sizeof(type) * old, sizeof(type) * capacity, \ + true); \ + } + +#define cosmoM_growArrayNonGC(state, type, buf, count, capacity) \ + if (count >= capacity || buf == NULL) { \ + int old = capacity; \ + capacity = old * GROW_FACTOR; \ + buf = (type *)cosmoM_reallocate(state, buf, sizeof(type) * old, sizeof(type) * capacity, \ + false); \ } #ifdef GC_DEBUG # define cosmoM_free(state, type, x) \ printf("freeing %p [size %lu] at %s:%d\n", x, sizeof(type), __FILE__, __LINE__); \ - cosmoM_reallocate(state, x, sizeof(type), 0) + cosmoM_reallocate(state, x, sizeof(type), 0, true) #else -# define cosmoM_free(state, type, x) cosmoM_reallocate(state, x, sizeof(type), 0) +# define cosmoM_free(state, type, x) cosmoM_reallocate(state, x, sizeof(type), 0, true) #endif #define cosmoM_isFrozen(state) (state->freezeGC > 0) @@ -60,7 +69,8 @@ #endif -COSMO_API void *cosmoM_reallocate(CState *state, void *buf, size_t oldSize, size_t newSize); +COSMO_API void *cosmoM_reallocate(CState *state, void *buf, size_t oldSize, size_t newSize, + bool isGC); COSMO_API bool cosmoM_checkGarbage(CState *state, size_t needed); // returns true if GC event was triggered COSMO_API void cosmoM_collectGarbage(CState *state); @@ -76,10 +86,7 @@ COSMO_API void cosmoM_removeRoot(CState *state, CObj *oldRoot); // wrapper for cosmoM_reallocate so we can track our memory usage static inline void *cosmoM_xmalloc(CState *state, size_t sz) { - return cosmoM_reallocate(state, NULL, 0, sz); + return cosmoM_reallocate(state, NULL, 0, sz, true); } -// #define cosmoM_xmalloc(state, sz) \ -// (printf("allocating new buffer at %s:%d of size %ld\n", __FILE__, __LINE__, sz), cosmoM_reallocate(state, NULL, 0, sz)) - #endif diff --git a/src/cobj.c b/src/cobj.c index 6badbdb..81bead8 100644 --- a/src/cobj.c +++ b/src/cobj.c @@ -46,7 +46,7 @@ void cosmoO_free(CState *state, CObj *obj) switch (obj->type) { case COBJ_STRING: { CObjString *objStr = (CObjString *)obj; - cosmoM_freearray(state, char, objStr->str, objStr->length + 1); + cosmoM_freeArray(state, char, objStr->str, objStr->length + 1); cosmoM_free(state, CObjString, objStr); break; } @@ -82,13 +82,13 @@ void cosmoO_free(CState *state, CObj *obj) } case COBJ_ERROR: { CObjError *err = (CObjError *)obj; - cosmoM_freearray(state, CCallFrame, err->frames, err->frameCount); + cosmoM_freeArray(state, CCallFrame, err->frames, err->frameCount); cosmoM_free(state, CObjError, obj); break; } case COBJ_CLOSURE: { CObjClosure *closure = (CObjClosure *)obj; - cosmoM_freearray(state, CObjUpval *, closure->upvalues, closure->upvalueCount); + cosmoM_freeArray(state, CObjUpval *, closure->upvalues, closure->upvalueCount); cosmoM_free(state, CObjClosure, closure); break; } @@ -305,7 +305,7 @@ CObjString *cosmoO_takeString(CState *state, char *str, size_t length) // have we already interned this string? if (lookup != NULL) { - cosmoM_freearray(state, char, str, + cosmoM_freeArray(state, char, str, length + 1); // free our passed character array, it's unneeded! return lookup; } diff --git a/src/cparse.c b/src/cparse.c index 84e4d8b..7bc9cf8 100644 --- a/src/cparse.c +++ b/src/cparse.c @@ -64,9 +64,10 @@ typedef struct CCompilerState *compiler; CObjString *module; // name of the module CToken current; - CToken previous; // token right after the current token - int workingStackCount; // we push CValues of objects we need onto the stack so the garbage collector can see them. - // this is the count of those values so we'll know how many to pop off when we're done + CToken previous; // token right after the current token + int workingStackCount; // we push CValues of objects we need onto the stack so the garbage + // collector can see them. this is the count of those values so we'll + // know how many to pop off when we're done } CParseState; typedef enum @@ -1370,7 +1371,7 @@ static void endLoop(CParseState *pstate) patchJmp(pstate, pstate->compiler->loop.breaks[--pstate->compiler->loop.breakCount]); } - cosmoM_freearray(pstate->state, int, pstate->compiler->loop.breaks, + cosmoM_freeArray(pstate->state, int, pstate->compiler->loop.breaks, pstate->compiler->loop.breakCapacity); } @@ -1659,7 +1660,7 @@ static void breakStatement(CParseState *pstate) pstate->compiler->localCount = savedLocals; // add break to loop - cosmoM_growarray(pstate->state, int, pstate->compiler->loop.breaks, + cosmoM_growArray(pstate->state, int, pstate->compiler->loop.breaks, pstate->compiler->loop.breakCount, pstate->compiler->loop.breakCapacity); pstate->compiler->loop.breaks[pstate->compiler->loop.breakCount++] = writeJmp(pstate, OP_JMP); } diff --git a/src/cstate.c b/src/cstate.c index 6233366..3ed618f 100644 --- a/src/cstate.c +++ b/src/cstate.c @@ -120,7 +120,7 @@ void cosmoV_freeState(CState *state) cosmoT_clearTable(state, &state->strings); // free our gray stack & finally free the state structure - cosmoM_freearray(state, CObj *, state->grayStack.array, state->grayStack.capacity); + cosmoM_freeArray(state, CObj *, state->grayStack.array, state->grayStack.capacity); #ifdef GC_DEBUG if (state->allocatedBytes != 0) { diff --git a/src/cstate.h b/src/cstate.h index df79a86..f895957 100644 --- a/src/cstate.h +++ b/src/cstate.h @@ -54,9 +54,9 @@ struct CState int frameCount; CPanic *panic; - CObj *objects; // tracks all of our allocated objects - CObj *userRoots; // user definable roots, this holds CObjs that should be considered "roots", - // lets the VM know you are holding a reference to a CObj in your code + CObj *objects; // tracks all of our allocated objects + CObj *userRoots; // user definable roots, this holds CObjs that should be considered "roots", + // lets the VM know you are holding a reference to a CObj in your code ArrayCObj grayStack; // keeps track of which objects *haven't yet* been traversed in our GC, but // *have been* found size_t allocatedBytes; diff --git a/src/ctable.c b/src/ctable.c index 8c9a0ff..46a3e6b 100644 --- a/src/ctable.c +++ b/src/ctable.c @@ -61,7 +61,7 @@ void cosmoT_addTable(CState *state, CTable *from, CTable *to) void cosmoT_clearTable(CState *state, CTable *tbl) { - cosmoM_freearray(state, CTableEntry, tbl->table, cosmoT_getCapacity(tbl)); + cosmoM_freeArray(state, CTableEntry, tbl->table, cosmoT_getCapacity(tbl)); } static uint32_t getObjectHash(CObj *obj) @@ -165,7 +165,7 @@ static void resizeTbl(CState *state, CTable *tbl, int newCapacity, bool canShrin } // free the old table - cosmoM_freearray(state, CTableEntry, tbl->table, oldCap); + cosmoM_freeArray(state, CTableEntry, tbl->table, oldCap); tbl->table = entries; tbl->capacityMask = newCapacity - 1; diff --git a/src/cvalue.c b/src/cvalue.c index 52052cc..245436c 100644 --- a/src/cvalue.c +++ b/src/cvalue.c @@ -13,12 +13,12 @@ void initValArray(CState *state, CValueArray *val, size_t startCapacity) void cleanValArray(CState *state, CValueArray *array) { - cosmoM_freearray(state, CValue, array->values, array->capacity); + cosmoM_freeArray(state, CValue, array->values, array->capacity); } void appendValArray(CState *state, CValueArray *array, CValue val) { - cosmoM_growarray(state, CValue, array->values, array->count, array->capacity); + cosmoM_growArray(state, CValue, array->values, array->count, array->capacity); array->values[array->count++] = val; }