added cosmoM_addRoot & cosmoM_removeRoot

This commit is contained in:
CPunch 2020-12-07 15:53:23 -06:00
parent aff011a8d1
commit f8a062919f
8 changed files with 71 additions and 6 deletions

View File

@ -191,6 +191,16 @@ void sweep(CState *state) {
}
}
void markUserRoots(CState *state) {
CObj *root = state->userRoots;
// traverse userRoots and mark all the object
while (root != NULL) {
markObject(state, root);
root = root->nextRoot;
}
}
void markRoots(CState *state) {
// mark all values on the stack
for (StkPtr value = state->stack; value < state->top; value++) {
@ -213,6 +223,9 @@ void markRoots(CState *state) {
for (int i = 0; i < ISTRING_MAX; i++)
markObject(state, (CObj*)state->iStrings[i]);
// mark the user defined roots
markUserRoots(state);
// mark our proto object
markObject(state, (CObj*)state->protoObj);
traceGrays(state);
@ -234,7 +247,7 @@ COSMO_API void cosmoM_collectGarbage(CState *state) {
// set our next GC event
cosmoM_updateThreshhold(state);
cosmoM_unfreezeGC(state);
state->freezeGC--; // we don't want to use cosmoM_unfreezeGC because that might trigger a GC event
#ifdef GC_DEBUG
printf("-- GC end, reclaimed %ld bytes (started at %ld, ended at %ld), next garbage collection scheduled at %ld bytes\n",
start - state->allocatedBytes, start, state->allocatedBytes, state->nextGC);
@ -244,4 +257,43 @@ COSMO_API void cosmoM_collectGarbage(CState *state) {
COSMO_API void cosmoM_updateThreshhold(CState *state) {
state->nextGC = state->allocatedBytes * HEAP_GROW_FACTOR;
}
COSMO_API void cosmoM_addRoot(CState *state, CObj *newRoot) {
// first, check and make sure this root doesn't already exist in the list
CObj *root = state->userRoots;
while (root != NULL) {
if (root == newRoot) // found in the list, abort
return;
root = root->nextRoot;
}
// adds root to userRoot linked list
newRoot->nextRoot = state->userRoots;
state->userRoots = newRoot;
}
COSMO_API void cosmoM_removeRoot(CState *state, CObj *oldRoot) {
CObj *prev = NULL;
CObj *root = state->userRoots;
// traverse the userRoot linked list
while (root != NULL) {
if (root == oldRoot) { // found root in list
// remove from the linked list
if (prev == NULL) {
state->userRoots = root->nextRoot;
} else {
prev->nextRoot = root->nextRoot;
}
root->nextRoot = NULL;
break;
}
prev = root;
root = root->nextRoot;
}
}

View File

@ -39,9 +39,12 @@
printf("unfreezing state at %s:%d [%d]\n", __FILE__, __LINE__, state->freezeGC); \
cosmoM_checkGarbage(state, 0)
#else
// freeze's the garbage collector until cosmoM_unfreezeGC is called
#define cosmoM_freezeGC(state) \
state->freezeGC++
// unfreeze's the garbage collector and tries to run a garbage collection cycle
#define cosmoM_unfreezeGC(state) \
state->freezeGC--; \
cosmoM_checkGarbage(state, 0)
@ -53,9 +56,13 @@ COSMO_API bool cosmoM_checkGarbage(CState *state, size_t needed); // returns tru
COSMO_API void cosmoM_collectGarbage(CState *state);
COSMO_API void cosmoM_updateThreshhold(CState *state);
/*
wrapper for cosmoM_reallocate so we can track our memory usage (it's also safer :P)
*/
// lets the VM know you are holding a reference to a CObj and to not free it
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 free'd
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)
static inline void *cosmoM_xmalloc(CState *state, size_t sz) {
return cosmoM_reallocate(state, NULL, 0, sz);
}

View File

@ -24,6 +24,8 @@ CObj *cosmoO_allocateBase(CState *state, size_t sz, CObjType type) {
obj->next = state->objects;
state->objects = obj;
obj->nextRoot = NULL;
#ifdef GC_DEBUG
printf("allocated %p with OBJ_TYPE %d\n", obj, type);
#endif

View File

@ -31,6 +31,7 @@ typedef struct CObj {
CObjType type;
bool isMarked; // for the GC
struct CObj *next;
struct CObj *nextRoot; // for the root linked list
} CObj;
typedef struct CObjString {

View File

@ -20,6 +20,7 @@ CState *cosmoV_newState() {
// GC
state->objects = NULL;
state->userRoots = NULL;
state->grayStack.count = 0;
state->grayStack.capacity = 2;
state->grayStack.array = NULL;

View File

@ -32,6 +32,7 @@ typedef struct CState {
bool panic;
int freezeGC; // when > 0, GC events will be ignored (for internal use)
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;
size_t nextGC; // when allocatedBytes reaches this threshhold, trigger a GC event

View File

@ -18,13 +18,15 @@ typedef double cosmo_Number;
#ifdef NAN_BOXXED
/*
NaN box, this is great for performance on x86_64 or ARM64 architectures. If you don't know how this works please reference these
NaN box, this is great for fitting more in the cpu cache on x86_64 or ARM64 architectures. If you don't know how this works please reference these
two articles:
https://leonardschuetz.ch/blog/nan-boxing/ and https://piotrduperas.com/posts/nan-boxing/
both are great resources :)
Performance notes: this can actually degrade performance, so only enable if you know what you're doing.
TL;DR: we can store payloads in the NaN value in the IEEE 754 standard.
*/
typedef union CValue {

View File

@ -30,7 +30,6 @@ CValue cosmoB_input(CState *state, int nargs, CValue *args) {
}
static void interpret(CState *state, const char* script) {
// cosmoP_compileString pushes the result onto the stack (NIL or COBJ_FUNCTION)
CObjFunction* func = cosmoP_compileString(state, script);
if (func != NULL) {