mirror of
https://github.com/CPunch/Cosmo.git
synced 2024-11-22 07:20:05 +00:00
added cosmoM_addRoot & cosmoM_removeRoot
This commit is contained in:
parent
aff011a8d1
commit
f8a062919f
54
src/cmem.c
54
src/cmem.c
@ -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) {
|
void markRoots(CState *state) {
|
||||||
// mark all values on the stack
|
// mark all values on the stack
|
||||||
for (StkPtr value = state->stack; value < state->top; value++) {
|
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++)
|
for (int i = 0; i < ISTRING_MAX; i++)
|
||||||
markObject(state, (CObj*)state->iStrings[i]);
|
markObject(state, (CObj*)state->iStrings[i]);
|
||||||
|
|
||||||
|
// mark the user defined roots
|
||||||
|
markUserRoots(state);
|
||||||
|
|
||||||
// mark our proto object
|
// mark our proto object
|
||||||
markObject(state, (CObj*)state->protoObj);
|
markObject(state, (CObj*)state->protoObj);
|
||||||
traceGrays(state);
|
traceGrays(state);
|
||||||
@ -234,7 +247,7 @@ COSMO_API void cosmoM_collectGarbage(CState *state) {
|
|||||||
// set our next GC event
|
// set our next GC event
|
||||||
cosmoM_updateThreshhold(state);
|
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
|
#ifdef GC_DEBUG
|
||||||
printf("-- GC end, reclaimed %ld bytes (started at %ld, ended at %ld), next garbage collection scheduled at %ld bytes\n",
|
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);
|
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) {
|
COSMO_API void cosmoM_updateThreshhold(CState *state) {
|
||||||
state->nextGC = state->allocatedBytes * HEAP_GROW_FACTOR;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
13
src/cmem.h
13
src/cmem.h
@ -39,9 +39,12 @@
|
|||||||
printf("unfreezing state at %s:%d [%d]\n", __FILE__, __LINE__, state->freezeGC); \
|
printf("unfreezing state at %s:%d [%d]\n", __FILE__, __LINE__, state->freezeGC); \
|
||||||
cosmoM_checkGarbage(state, 0)
|
cosmoM_checkGarbage(state, 0)
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
// freeze's the garbage collector until cosmoM_unfreezeGC is called
|
||||||
#define cosmoM_freezeGC(state) \
|
#define cosmoM_freezeGC(state) \
|
||||||
state->freezeGC++
|
state->freezeGC++
|
||||||
|
|
||||||
|
// unfreeze's the garbage collector and tries to run a garbage collection cycle
|
||||||
#define cosmoM_unfreezeGC(state) \
|
#define cosmoM_unfreezeGC(state) \
|
||||||
state->freezeGC--; \
|
state->freezeGC--; \
|
||||||
cosmoM_checkGarbage(state, 0)
|
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_collectGarbage(CState *state);
|
||||||
COSMO_API void cosmoM_updateThreshhold(CState *state);
|
COSMO_API void cosmoM_updateThreshhold(CState *state);
|
||||||
|
|
||||||
/*
|
// lets the VM know you are holding a reference to a CObj and to not free it
|
||||||
wrapper for cosmoM_reallocate so we can track our memory usage (it's also safer :P)
|
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) {
|
static inline void *cosmoM_xmalloc(CState *state, size_t sz) {
|
||||||
return cosmoM_reallocate(state, NULL, 0, sz);
|
return cosmoM_reallocate(state, NULL, 0, sz);
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,8 @@ CObj *cosmoO_allocateBase(CState *state, size_t sz, CObjType type) {
|
|||||||
|
|
||||||
obj->next = state->objects;
|
obj->next = state->objects;
|
||||||
state->objects = obj;
|
state->objects = obj;
|
||||||
|
|
||||||
|
obj->nextRoot = NULL;
|
||||||
#ifdef GC_DEBUG
|
#ifdef GC_DEBUG
|
||||||
printf("allocated %p with OBJ_TYPE %d\n", obj, type);
|
printf("allocated %p with OBJ_TYPE %d\n", obj, type);
|
||||||
#endif
|
#endif
|
||||||
|
@ -31,6 +31,7 @@ typedef struct CObj {
|
|||||||
CObjType type;
|
CObjType type;
|
||||||
bool isMarked; // for the GC
|
bool isMarked; // for the GC
|
||||||
struct CObj *next;
|
struct CObj *next;
|
||||||
|
struct CObj *nextRoot; // for the root linked list
|
||||||
} CObj;
|
} CObj;
|
||||||
|
|
||||||
typedef struct CObjString {
|
typedef struct CObjString {
|
||||||
|
@ -20,6 +20,7 @@ CState *cosmoV_newState() {
|
|||||||
|
|
||||||
// GC
|
// GC
|
||||||
state->objects = NULL;
|
state->objects = NULL;
|
||||||
|
state->userRoots = NULL;
|
||||||
state->grayStack.count = 0;
|
state->grayStack.count = 0;
|
||||||
state->grayStack.capacity = 2;
|
state->grayStack.capacity = 2;
|
||||||
state->grayStack.array = NULL;
|
state->grayStack.array = NULL;
|
||||||
|
@ -32,6 +32,7 @@ typedef struct CState {
|
|||||||
bool panic;
|
bool panic;
|
||||||
int freezeGC; // when > 0, GC events will be ignored (for internal use)
|
int freezeGC; // when > 0, GC events will be ignored (for internal use)
|
||||||
CObj *objects; // tracks all of our allocated objects
|
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
|
ArrayCObj grayStack; // keeps track of which objects *haven't yet* been traversed in our GC, but *have been* found
|
||||||
size_t allocatedBytes;
|
size_t allocatedBytes;
|
||||||
size_t nextGC; // when allocatedBytes reaches this threshhold, trigger a GC event
|
size_t nextGC; // when allocatedBytes reaches this threshhold, trigger a GC event
|
||||||
|
@ -18,13 +18,15 @@ typedef double cosmo_Number;
|
|||||||
|
|
||||||
#ifdef NAN_BOXXED
|
#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:
|
two articles:
|
||||||
|
|
||||||
https://leonardschuetz.ch/blog/nan-boxing/ and https://piotrduperas.com/posts/nan-boxing/
|
https://leonardschuetz.ch/blog/nan-boxing/ and https://piotrduperas.com/posts/nan-boxing/
|
||||||
|
|
||||||
both are great resources :)
|
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.
|
TL;DR: we can store payloads in the NaN value in the IEEE 754 standard.
|
||||||
*/
|
*/
|
||||||
typedef union CValue {
|
typedef union CValue {
|
||||||
|
@ -30,7 +30,6 @@ CValue cosmoB_input(CState *state, int nargs, CValue *args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void interpret(CState *state, const char* script) {
|
static void interpret(CState *state, const char* script) {
|
||||||
|
|
||||||
// cosmoP_compileString pushes the result onto the stack (NIL or COBJ_FUNCTION)
|
// cosmoP_compileString pushes the result onto the stack (NIL or COBJ_FUNCTION)
|
||||||
CObjFunction* func = cosmoP_compileString(state, script);
|
CObjFunction* func = cosmoP_compileString(state, script);
|
||||||
if (func != NULL) {
|
if (func != NULL) {
|
||||||
|
Loading…
Reference in New Issue
Block a user