mirror of
https://github.com/CPunch/Cosmo.git
synced 2024-12-04 22:46:31 +00:00
Compare commits
3 Commits
5c3e24fc39
...
9c5270124d
Author | SHA1 | Date | |
---|---|---|---|
9c5270124d | |||
5fc9af5564 | |||
a1c58647ba |
32
src/cmem.c
32
src/cmem.c
@ -10,7 +10,22 @@
|
|||||||
// 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)
|
||||||
{
|
{
|
||||||
|
if (buf == NULL) oldSize = 0;
|
||||||
|
#ifdef GC_DEBUG
|
||||||
|
printf("old allocated bytes: %ld\n", state->allocatedBytes);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
state->allocatedBytes += newSize - oldSize;
|
state->allocatedBytes += newSize - oldSize;
|
||||||
|
#ifdef GC_DEBUG
|
||||||
|
printf("new allocated bytes: %ld\n", state->allocatedBytes);
|
||||||
|
fflush(stdout);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (newSize == 0) { // it needs to be freed
|
if (newSize == 0) { // it needs to be freed
|
||||||
free(buf);
|
free(buf);
|
||||||
@ -33,6 +48,11 @@ void *cosmoM_reallocate(CState *state, void *buf, size_t oldSize, size_t newSize
|
|||||||
// if NULL is passed, realloc() acts like malloc()
|
// if NULL is passed, realloc() acts like malloc()
|
||||||
void *newBuf = realloc(buf, newSize);
|
void *newBuf = realloc(buf, newSize);
|
||||||
|
|
||||||
|
#ifdef GC_DEBUG
|
||||||
|
printf("allocating new buffer of size %ld at %p\n", newSize - oldSize, newBuf);
|
||||||
|
fflush(stdout);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (newBuf == NULL) {
|
if (newBuf == NULL) {
|
||||||
CERROR("failed to allocate memory!");
|
CERROR("failed to allocate memory!");
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -59,7 +79,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 +87,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 +320,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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
20
src/cobj.c
20
src/cobj.c
@ -33,7 +33,7 @@ CObj *cosmoO_allocateBase(CState *state, size_t sz, CObjType type)
|
|||||||
|
|
||||||
obj->nextRoot = NULL;
|
obj->nextRoot = NULL;
|
||||||
#ifdef GC_DEBUG
|
#ifdef GC_DEBUG
|
||||||
printf("allocated %p with OBJ_TYPE %d\n", obj, type);
|
printf("allocated %s %p\n", cosmoO_typeStr(obj), obj);
|
||||||
#endif
|
#endif
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
@ -41,9 +41,7 @@ CObj *cosmoO_allocateBase(CState *state, size_t sz, CObjType type)
|
|||||||
void cosmoO_free(CState *state, CObj *obj)
|
void cosmoO_free(CState *state, CObj *obj)
|
||||||
{
|
{
|
||||||
#ifdef GC_DEBUG
|
#ifdef GC_DEBUG
|
||||||
printf("freeing %p [", obj);
|
printf("freeing %s %p\n", cosmoO_typeStr(obj), obj);
|
||||||
printObject(obj);
|
|
||||||
printf("]\n");
|
|
||||||
#endif
|
#endif
|
||||||
switch (obj->type) {
|
switch (obj->type) {
|
||||||
case COBJ_STRING: {
|
case COBJ_STRING: {
|
||||||
@ -409,9 +407,9 @@ bool cosmoO_getRawObject(CState *state, CObjObject *proto, CValue key, CValue *v
|
|||||||
val)) { // if the field doesn't exist in the object, check the proto
|
val)) { // if the field doesn't exist in the object, check the proto
|
||||||
if (cosmoO_getIString(state, proto, ISTRING_GETTER, val) && IS_TABLE(*val) &&
|
if (cosmoO_getIString(state, proto, ISTRING_GETTER, val) && IS_TABLE(*val) &&
|
||||||
cosmoT_get(state, &cosmoV_readTable(*val)->tbl, key, val)) {
|
cosmoT_get(state, &cosmoV_readTable(*val)->tbl, key, val)) {
|
||||||
cosmoV_pushValue(state, *val); // push function
|
cosmoV_pushValue(state, *val); // push function
|
||||||
cosmoV_pushRef(state, (CObj *)obj); // push object
|
cosmoV_pushRef(state, (CObj *)obj); // push object
|
||||||
if (!cosmoV_call(state, 1, 1)) // call the function with the 1 argument
|
if (!cosmoV_call(state, 1, 1)) // call the function with the 1 argument
|
||||||
return false;
|
return false;
|
||||||
*val = *cosmoV_pop(state); // set value to the return value of __index
|
*val = *cosmoV_pop(state); // set value to the return value of __index
|
||||||
return true;
|
return true;
|
||||||
@ -529,10 +527,10 @@ bool cosmoO_getIString(CState *state, CObjObject *object, int flag, CValue *val)
|
|||||||
bool cosmoO_indexObject(CState *state, CObjObject *object, CValue key, CValue *val)
|
bool cosmoO_indexObject(CState *state, CObjObject *object, CValue key, CValue *val)
|
||||||
{
|
{
|
||||||
if (cosmoO_getIString(state, object, ISTRING_INDEX, val)) {
|
if (cosmoO_getIString(state, object, ISTRING_INDEX, val)) {
|
||||||
cosmoV_pushValue(state, *val); // push function
|
cosmoV_pushValue(state, *val); // push function
|
||||||
cosmoV_pushRef(state, (CObj *)object); // push object
|
cosmoV_pushRef(state, (CObj *)object); // push object
|
||||||
cosmoV_pushValue(state, key); // push key
|
cosmoV_pushValue(state, key); // push key
|
||||||
if (!cosmoV_call(state, 2, 1)) // call the function with the 2 arguments
|
if (!cosmoV_call(state, 2, 1)) // call the function with the 2 arguments
|
||||||
return false;
|
return false;
|
||||||
*val = *cosmoV_pop(state); // set value to the return value of __index
|
*val = *cosmoV_pop(state); // set value to the return value of __index
|
||||||
return true;
|
return true;
|
||||||
|
21
src/cstate.c
21
src/cstate.c
@ -26,7 +26,7 @@ CState *cosmoV_newState()
|
|||||||
state->grayStack.count = 0;
|
state->grayStack.count = 0;
|
||||||
state->grayStack.capacity = 2;
|
state->grayStack.capacity = 2;
|
||||||
state->grayStack.array = NULL;
|
state->grayStack.array = NULL;
|
||||||
state->allocatedBytes = sizeof(CState);
|
state->allocatedBytes = 0;
|
||||||
state->nextGC = 1024 * 8; // threshhold starts at 8kb
|
state->nextGC = 1024 * 8; // threshhold starts at 8kb
|
||||||
|
|
||||||
// init stack
|
// init stack
|
||||||
@ -86,6 +86,12 @@ void cosmoV_freeState(CState *state)
|
|||||||
CObj *objs = state->objects;
|
CObj *objs = state->objects;
|
||||||
while (objs != NULL) {
|
while (objs != NULL) {
|
||||||
CObj *next = objs->next;
|
CObj *next = objs->next;
|
||||||
|
|
||||||
|
#ifdef GC_DEBUG
|
||||||
|
printf("STATE FREEING %p\n", objs);
|
||||||
|
fflush(stdout);
|
||||||
|
#endif
|
||||||
|
|
||||||
cosmoO_free(state, objs);
|
cosmoO_free(state, objs);
|
||||||
objs = next;
|
objs = next;
|
||||||
}
|
}
|
||||||
@ -100,13 +106,12 @@ void cosmoV_freeState(CState *state)
|
|||||||
// free our gray stack & finally free the state structure
|
// 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);
|
||||||
|
|
||||||
// TODO: yeah idk, it looks like im missing 520 bytes somewhere? i'll look into it later
|
#ifdef GC_DEBUG
|
||||||
/*#ifdef GC_DEBUG
|
if (state->allocatedBytes != 0) {
|
||||||
if (state->allocatedBytes != sizeof(CState)) {
|
printf("state->allocatedBytes doesn't match, got %lu\n", state->allocatedBytes);
|
||||||
printf("state->allocatedBytes doesn't match expected value (%lu), got %lu!",
|
}
|
||||||
sizeof(CState), state->allocatedBytes); exit(0);
|
#endif
|
||||||
}
|
|
||||||
#endif*/
|
|
||||||
free(state);
|
free(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
35
src/ctable.c
35
src/ctable.c
@ -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!
|
|
||||||
tomb = entry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// its a tombstone!
|
||||||
|
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))) {
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user