From fe93a0b715186497427e26b4414f3aa95eb78804 Mon Sep 17 00:00:00 2001 From: CPunch Date: Mon, 2 Nov 2020 22:32:39 -0600 Subject: [PATCH] better GC debugging, added base object for tables --- src/cbaselib.c | 3 +++ src/cmem.c | 7 ++++++- src/cmem.h | 11 +++++++++++ src/cobj.c | 29 ++++++++++++++++++++++++++++- src/cobj.h | 28 ++++++++++++++++++++-------- src/cstate.c | 4 ++-- src/main.c | 1 - 7 files changed, 70 insertions(+), 13 deletions(-) diff --git a/src/cbaselib.c b/src/cbaselib.c index b265914..c02b592 100644 --- a/src/cbaselib.c +++ b/src/cbaselib.c @@ -1,9 +1,12 @@ #include "cbaselib.h" #include "cvalue.h" #include "cobj.h" +#include "cmem.h" void cosmoB_loadlibrary(CState *state) { + cosmoM_freezeGC(state); cosmoV_register(state, "print", cosmoV_newObj(cosmoO_newCFunction(state, cosmoB_print))); + cosmoM_unfreezeGC(state); } int cosmoB_print(CState *state, int nargs, CValue *args) { diff --git a/src/cmem.c b/src/cmem.c index 066a88c..9831621 100644 --- a/src/cmem.c +++ b/src/cmem.c @@ -20,6 +20,11 @@ void *cosmoM_reallocate(CState* state, void *buf, size_t oldSize, size_t newSize if (!(cosmoM_isFrozen(state)) && newSize > oldSize) { cosmoM_collectGarbage(state); } +#ifdef GC_DEBUG + else { + printf("GC event ignored! state frozen! [%d]\n", state->freezeGC); + } +#endif #else // if the state isn't frozen && we've reached the GC event if (!(cosmoM_isFrozen(state)) && state->allocatedBytes > state->nextGC) { @@ -75,12 +80,12 @@ void markArray(CState *state, CValueArray *array) { void blackenObject(CState *state, CObj *obj) { switch (obj->type) { case COBJ_STRING: + case COBJ_TABLE: // TODO: when metatables are added, make sure they're marked case COBJ_CFUNCTION: // stubbed break; case COBJ_UPVALUE: { markValue(state, ((CObjUpval*)obj)->closed); - break; } case COBJ_FUNCTION: { diff --git a/src/cmem.h b/src/cmem.h index bb16ffc..353c628 100644 --- a/src/cmem.h +++ b/src/cmem.h @@ -28,11 +28,22 @@ #define cosmoM_isFrozen(state) \ state->freezeGC > 0 +// if debugging, print the locations of when the state is frozen/unfrozen +#ifdef GC_DEBUG +#define cosmoM_freezeGC(state) \ + state->freezeGC++; \ + printf("freezing state at %s:%d [%d]\n", __FILE__, __LINE__, state->freezeGC) + +#define cosmoM_unfreezeGC(state) \ + state->freezeGC--; \ + printf("unfreezing state at %s:%d [%d]\n", __FILE__, __LINE__, state->freezeGC) +#else #define cosmoM_freezeGC(state) \ state->freezeGC++ #define cosmoM_unfreezeGC(state) \ state->freezeGC-- +#endif COSMO_API void *cosmoM_reallocate(CState* state, void *buf, size_t oldSize, size_t newSize); COSMO_API void cosmoM_collectGarbage(CState* state); diff --git a/src/cobj.c b/src/cobj.c index 90e26bd..959d199 100644 --- a/src/cobj.c +++ b/src/cobj.c @@ -42,6 +42,12 @@ void cosmoO_freeObject(CState *state, CObj* obj) { cosmoM_free(state, CObjString, objStr); break; } + case COBJ_TABLE: { + CObjTable *objTbl = (CObjTable*)obj; + cosmoT_clearTable(state, &objTbl->tbl); + cosmoM_free(state, CObjTable, objTbl); + break; + } case COBJ_UPVALUE: { cosmoM_free(state, CObjUpval, obj); break; @@ -72,11 +78,23 @@ bool cosmoO_equalObject(CObj* obj1, CObj* obj2) { switch (obj1->type) { case COBJ_STRING: return obj1 == obj2; // compare pointers because we already intern all strings :) + case COBJ_CFUNCTION: { + CObjCFunction *cfunc1 = (CObjCFunction*)obj1; + CObjCFunction *cfunc2 = (CObjCFunction*)obj2; + return cfunc1->cfunc == cfunc2->cfunc; + } default: - return false; // they're some unknown type, probably malformed :( + return false; } } +CObjTable *cosmoO_newTable(CState *state) { + CObjTable *tbl = (CObjTable*)cosmoO_allocateObject(state, sizeof(CObjTable), COBJ_TABLE); + + cosmoT_initTable(state, &tbl->tbl, 8); // start the table at 8 + return tbl; +} + CObjFunction *cosmoO_newFunction(CState *state) { CObjFunction *func = (CObjFunction*)cosmoO_allocateObject(state, sizeof(CObjFunction), COBJ_FUNCTION); func->args = 0; @@ -170,6 +188,11 @@ CObjString *cosmoO_toString(CState *state, CObj *val) { CObjFunction *func = (CObjFunction*)val; return func->name != NULL ? func->name : cosmoO_copyString(state, UNNAMEDCHUNK, strlen(UNNAMEDCHUNK)); } + case COBJ_TABLE: { // TODO: maybe not safe?? + char buf[64]; + int sz = sprintf(buf, " %p", val) + 1; // +1 for the null character + return cosmoO_copyString(state, buf, sz); + } default: return cosmoO_copyString(state, "", 6); } @@ -182,6 +205,10 @@ void printObject(CObj *o) { printf("\"%.*s\"", objStr->length, objStr->str); break; } + case COBJ_TABLE: { + printf(" %p", o); + return; + } case COBJ_UPVALUE: { CObjUpval *upval = (CObjUpval*)o; printf(" -> ", upval->val); diff --git a/src/cobj.h b/src/cobj.h index daba240..59150b2 100644 --- a/src/cobj.h +++ b/src/cobj.h @@ -4,15 +4,18 @@ #include "cosmo.h" #include "cchunk.h" #include "cvalue.h" +#include "ctable.h" typedef struct CState CState; typedef enum { COBJ_STRING, - COBJ_UPVALUE, + COBJ_TABLE, COBJ_FUNCTION, COBJ_CFUNCTION, - COBJ_CLOSURE + // internal use + COBJ_CLOSURE, + COBJ_UPVALUE, } CObjType; #define CommonHeader CObj obj; @@ -32,12 +35,11 @@ typedef struct CObjString { uint32_t hash; // for hashtable lookup } CObjString; -typedef struct CObjUpval { +typedef struct CObjTable { CommonHeader; // "is a" CObj - CValue *val; - CValue closed; - struct CObjUpval *next; -} CObjUpval; + CTable tbl; + //struct CObjTable *meta; // metatable, used to describe table behavior +} CObjTable; typedef struct CObjFunction { CommonHeader; // "is a" CObj @@ -53,18 +55,27 @@ typedef struct CObjCFunction { } CObjCFunction; typedef struct CObjClosure { - CommonHeader; + CommonHeader; // "is a" CObj CObjFunction *function; CObjUpval **upvalues; int upvalueCount; } CObjClosure; +typedef struct CObjUpval { + CommonHeader; // "is a" CObj + CValue *val; + CValue closed; + struct CObjUpval *next; +} CObjUpval; + #define IS_STRING(x) isObjType(x, COBJ_STRING) +#define IS_TABLE(x) isObjType(x, COBJ_TABLE) #define IS_FUNCTION(x) isObjType(x, COBJ_FUNCTION) #define IS_CFUNCTION(x) isObjType(x, COBJ_CFUNCTION) #define IS_CLOSURE(x) isObjType(x, COBJ_CLOSURE) #define cosmoV_readString(x) ((CObjString*)cosmoV_readObj(x)) +#define cosmoV_readTable(x) ((CObjTable*)cosmoV_readObj(x)) #define cosmoV_readFunction(x) ((CObjFunction*)cosmoV_readObj(x)) #define cosmoV_readCFunction(x) (((CObjCFunction*)cosmoV_readObj(x))->cfunc) #define cosmoV_readClosure(x) ((CObjClosure*)cosmoV_readObj(x)) @@ -78,6 +89,7 @@ void cosmoO_freeObject(CState *state, CObj* obj); bool cosmoO_equalObject(CObj* obj1, CObj* obj2); +CObjTable *cosmoO_newTable(CState *state); CObjFunction *cosmoO_newFunction(CState *state); CObjCFunction *cosmoO_newCFunction(CState *state, CosmoCFunction func); CObjClosure *cosmoO_newClosure(CState *state, CObjFunction *func); diff --git a/src/cstate.c b/src/cstate.c index 50d9b80..55d68ed 100644 --- a/src/cstate.c +++ b/src/cstate.c @@ -55,10 +55,10 @@ void cosmoV_freeState(CState *state) { void cosmoV_register(CState *state, const char *identifier, CValue val) { // we push the values so the garbage collector can find them - cosmoV_pushValue(state, cosmoV_newObj(cosmoO_copyString(state, identifier, strlen(identifier)))); cosmoV_pushValue(state, val); + cosmoV_pushValue(state, cosmoV_newObj(cosmoO_copyString(state, identifier, strlen(identifier)))); - CValue *oldVal = cosmoT_insert(state, &state->globals, *cosmoV_getTop(state, 1)); + CValue *oldVal = cosmoT_insert(state, &state->globals, *cosmoV_getTop(state, 0)); *oldVal = val; cosmoV_setTop(state, 2); // pops the 2 values off the stack diff --git a/src/main.c b/src/main.c index 96a4167..ed56d19 100644 --- a/src/main.c +++ b/src/main.c @@ -90,7 +90,6 @@ static void runFile(const char* fileName) { char* script = readFile(fileName); CState *state = cosmoV_newState(); - interpret(state, script); cosmoV_freeState(state);