minor CTable refactoring

This commit is contained in:
CPunch 2023-08-25 19:57:16 -05:00
parent 5c3e24fc39
commit a1c58647ba
6 changed files with 55 additions and 31 deletions

View File

@ -10,6 +10,17 @@
// realloc wrapper // 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)
{ {
#ifdef GC_DEBUG
if (buf) {
if (newSize == 0) {
printf("freeing %p, reclaiming %ld bytes...\n", buf, oldSize);
} else {
printf("realloc %p, byte difference: %ld\n", buf, newSize - oldSize);
}
} else {
printf("allocating new buffer of size %ld\n", newSize - oldSize);
}
#endif
state->allocatedBytes += newSize - oldSize; state->allocatedBytes += newSize - oldSize;
if (newSize == 0) { // it needs to be freed if (newSize == 0) { // it needs to be freed
@ -59,7 +70,7 @@ static void markTable(CState *state, CTable *tbl)
if (tbl->table == NULL) // table is still being initialized if (tbl->table == NULL) // table is still being initialized
return; return;
int cap = tbl->capacityMask + 1; int cap = cosmoT_getCapacity(tbl);
for (int i = 0; i < cap; i++) { for (int i = 0; i < cap; i++) {
CTableEntry *entry = &tbl->table[i]; CTableEntry *entry = &tbl->table[i];
markValue(state, entry->key); markValue(state, entry->key);
@ -67,13 +78,18 @@ static void markTable(CState *state, CTable *tbl)
} }
} }
// frees white members from the table // removes white members from the table
static void tableRemoveWhite(CState *state, CTable *tbl) static void tableRemoveWhite(CState *state, CTable *tbl)
{ {
if (tbl->table == NULL) // table is still being initialized if (tbl->table == NULL) // table is still being initialized
return; return;
int cap = tbl->capacityMask + 1; int cap = cosmoT_getCapacity(tbl);
#ifdef GC_DEBUG
printf("tableRemoveWhite: %p, cap: %d\n", tbl, cap);
#endif
for (int i = 0; i < cap; i++) { for (int i = 0; i < cap; i++) {
CTableEntry *entry = &tbl->table[i]; CTableEntry *entry = &tbl->table[i];
if (IS_REF(entry->key) && if (IS_REF(entry->key) &&
@ -295,7 +311,6 @@ COSMO_API void cosmoM_collectGarbage(CState *state)
printf("-- GC end, reclaimed %ld bytes (started at %ld, ended at %ld), next garbage collection " printf("-- GC end, reclaimed %ld bytes (started at %ld, ended at %ld), next garbage collection "
"scheduled at %ld bytes\n", "scheduled at %ld bytes\n",
start - state->allocatedBytes, start, state->allocatedBytes, state->nextGC); start - state->allocatedBytes, start, state->allocatedBytes, state->nextGC);
getchar(); // pauses execution
#endif #endif
} }

View File

@ -73,10 +73,13 @@ COSMO_API void cosmoM_addRoot(CState *state, CObj *newRoot);
// lets the VM know this root is no longer held in a reference and is able to be freed // lets the VM know this root is no longer held in a reference and is able to be freed
COSMO_API void cosmoM_removeRoot(CState *state, CObj *oldRoot); COSMO_API void cosmoM_removeRoot(CState *state, CObj *oldRoot);
// wrapper for cosmoM_reallocate so we can track our memory usage (it's also safer :P) // wrapper for cosmoM_reallocate so we can track our memory usage
static inline void *cosmoM_xmalloc(CState *state, size_t sz) static inline void *cosmoM_xmalloc(CState *state, size_t sz)
{ {
return cosmoM_reallocate(state, NULL, 0, sz); return cosmoM_reallocate(state, NULL, 0, sz);
} }
// #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 #endif

View File

@ -34,6 +34,7 @@ void cosmoT_initTable(CState *state, CTable *tbl, int startCap)
tbl->capacityMask = startCap - 1; tbl->capacityMask = startCap - 1;
tbl->count = 0; tbl->count = 0;
tbl->tombstones = 0; tbl->tombstones = 0;
tbl->tombThreshold = 32;
tbl->table = NULL; // to let out GC know we're initalizing tbl->table = NULL; // to let out GC know we're initalizing
tbl->table = cosmoM_xmalloc(state, sizeof(CTableEntry) * startCap); tbl->table = cosmoM_xmalloc(state, sizeof(CTableEntry) * startCap);
@ -47,7 +48,7 @@ void cosmoT_initTable(CState *state, CTable *tbl, int startCap)
void cosmoT_addTable(CState *state, CTable *from, CTable *to) void cosmoT_addTable(CState *state, CTable *from, CTable *to)
{ {
CTableEntry *entry; CTableEntry *entry;
int cap = from->capacityMask + 1; int cap = cosmoT_getCapacity(from);
for (int i = 0; i < cap; i++) { for (int i = 0; i < cap; i++) {
entry = &from->table[i]; entry = &from->table[i];
@ -60,7 +61,7 @@ void cosmoT_addTable(CState *state, CTable *from, CTable *to)
void cosmoT_clearTable(CState *state, CTable *tbl) void cosmoT_clearTable(CState *state, CTable *tbl)
{ {
cosmoM_freearray(state, CTableEntry, tbl->table, (tbl->capacityMask + 1)); cosmoM_freearray(state, CTableEntry, tbl->table, cosmoT_getCapacity(tbl));
} }
static uint32_t getObjectHash(CObj *obj) static uint32_t getObjectHash(CObj *obj)
@ -113,10 +114,10 @@ static CTableEntry *findEntry(CState *state, CTableEntry *entries, int mask, CVa
if (IS_NIL(entry->val)) { if (IS_NIL(entry->val)) {
// it's empty! if we found a tombstone, return that so it'll be reused // it's empty! if we found a tombstone, return that so it'll be reused
return tomb != NULL ? tomb : entry; return tomb != NULL ? tomb : entry;
} else { }
// its a tombstone! // its a tombstone!
tomb = entry; tomb = entry;
}
} else if (cosmoV_equal(state, entry->key, key)) { } else if (cosmoV_equal(state, entry->key, key)) {
return entry; return entry;
} }
@ -141,7 +142,7 @@ static void resizeTbl(CState *state, CTable *tbl, int newCapacity, bool canShrin
return; return;
CTableEntry *entries = cosmoM_xmalloc(state, size); CTableEntry *entries = cosmoM_xmalloc(state, size);
oldCap = tbl->capacityMask + 1; oldCap = cosmoT_getCapacity(tbl);
newCount = 0; newCount = 0;
// set all nodes as NIL : NIL // set all nodes as NIL : NIL
@ -176,10 +177,10 @@ bool cosmoT_checkShrink(CState *state, CTable *tbl)
{ {
// if count > 8 and active entries < tombstones // if count > 8 and active entries < tombstones
if (tbl->count > MIN_TABLE_CAPACITY && if (tbl->count > MIN_TABLE_CAPACITY &&
(tbl->count - tbl->tombstones < tbl->tombstones || (tbl->count - tbl->tombstones < tbl->tombstones || tbl->tombstones > tbl->tombThreshold)) {
tbl->tombstones > 50)) { // TODO: 50 should be a threshhold // shrink based on active entries to the next pow of 2
resizeTbl(state, tbl, nextPow2(tbl->count - tbl->tombstones) * GROW_FACTOR, resizeTbl(state, tbl, nextPow2(tbl->count - tbl->tombstones) * GROW_FACTOR, false);
false); // shrink based on active entries to the next pow of 2 tbl->tombThreshold = tbl->count / 4;
return true; return true;
} }
@ -190,7 +191,7 @@ bool cosmoT_checkShrink(CState *state, CTable *tbl)
COSMO_API CValue *cosmoT_insert(CState *state, CTable *tbl, CValue key) COSMO_API CValue *cosmoT_insert(CState *state, CTable *tbl, CValue key)
{ {
// make sure we have enough space allocated // make sure we have enough space allocated
int cap = tbl->capacityMask + 1; int cap = cosmoT_getCapacity(tbl);
if (tbl->count + 1 > (int)(cap * MAX_TABLE_FILL)) { if (tbl->count + 1 > (int)(cap * MAX_TABLE_FILL)) {
// grow table // grow table
int newCap = cap * GROW_FACTOR; int newCap = cap * GROW_FACTOR;
@ -198,8 +199,7 @@ COSMO_API CValue *cosmoT_insert(CState *state, CTable *tbl, CValue key)
} }
// insert into the table // insert into the table
CTableEntry *entry = CTableEntry *entry = findEntry(state, tbl->table, tbl->capacityMask, key);
findEntry(state, tbl->table, tbl->capacityMask, key); // -1 for our capacity mask
if (IS_NIL(entry->key)) { if (IS_NIL(entry->key)) {
if (IS_NIL(entry->val)) // is it empty? if (IS_NIL(entry->val)) // is it empty?
@ -255,9 +255,10 @@ CObjString *cosmoT_lookupString(CTable *tbl, const char *str, int length, uint32
{ {
if (tbl->count == 0) if (tbl->count == 0)
return 0; // sanity check return 0; // sanity check
uint32_t indx =
hash & tbl->capacityMask; // since we know the capacity will *always* be a power of 2, we // since we know the capacity will *always* be a power of 2, we
// can use bitwise & to perform a MUCH faster mod operation // can use bitwise & to perform a MUCH faster mod operation
uint32_t indx = hash & tbl->capacityMask;
// keep looking for an open slot in the entries array // keep looking for an open slot in the entries array
while (true) { while (true) {
@ -280,7 +281,7 @@ CObjString *cosmoT_lookupString(CTable *tbl, const char *str, int length, uint32
void cosmoT_printTable(CTable *tbl, const char *name) void cosmoT_printTable(CTable *tbl, const char *name)
{ {
printf("==== [[%s]] ====\n", name); printf("==== [[%s]] ====\n", name);
int cap = tbl->capacityMask + 1; int cap = cosmoT_getCapacity(tbl);
for (int i = 0; i < cap; i++) { for (int i = 0; i < cap; i++) {
CTableEntry *entry = &tbl->table[i]; CTableEntry *entry = &tbl->table[i];
if (!(IS_NIL(entry->key))) { if (!(IS_NIL(entry->key))) {

View File

@ -18,9 +18,12 @@ typedef struct CTable
int count; int count;
int capacityMask; // +1 to get the capacity int capacityMask; // +1 to get the capacity
int tombstones; int tombstones;
int tombThreshold;
CTableEntry *table; CTableEntry *table;
} CTable; } CTable;
#define cosmoT_getCapacity(tbl) ((tbl)->capacityMask + 1)
COSMO_API void cosmoT_initTable(CState *state, CTable *tbl, int startCap); COSMO_API void cosmoT_initTable(CState *state, CTable *tbl, int startCap);
COSMO_API void cosmoT_clearTable(CState *state, CTable *tbl); COSMO_API void cosmoT_clearTable(CState *state, CTable *tbl);
COSMO_API int cosmoT_count(CTable *tbl); COSMO_API int cosmoT_count(CTable *tbl);

View File

@ -640,7 +640,7 @@ int _tbl__next(CState *state, int nargs, CValue *args)
CObjTable *table = (CObjTable *)cosmoV_readRef(val); CObjTable *table = (CObjTable *)cosmoV_readRef(val);
// while the entry is invalid, go to the next entry // while the entry is invalid, go to the next entry
int cap = table->tbl.capacityMask + 1; int cap = cosmoT_getCapacity(&table->tbl);
CTableEntry *entry; CTableEntry *entry;
do { do {
entry = &table->tbl.table[index++]; entry = &table->tbl.table[index++];
@ -1037,7 +1037,9 @@ int cosmoV_execute(CState *state)
cosmoV_pop(state); // pop the object from the stack cosmoV_pop(state); // pop the object from the stack
cosmoV_pushValue(state, val); cosmoV_pushValue(state, val);
cosmoV_pushRef(state, (CObj *)obj); cosmoV_pushRef(state, (CObj *)obj);
if (!cosmoV_call(state, 1, 1)) // we expect 1 return value on the stack, the iterable object if (!cosmoV_call(
state, 1,
1)) // we expect 1 return value on the stack, the iterable object
return -1; return -1;
StkPtr iObj = cosmoV_getTop(state, 0); StkPtr iObj = cosmoV_getTop(state, 0);