allow top-level GC to collect all garbage in GC_VISIT_V2

This commit is contained in:
dzaima 2023-02-26 18:37:07 +02:00
parent 418a1c054f
commit 78eb351e10
4 changed files with 37 additions and 24 deletions

View File

@ -356,7 +356,7 @@ void gc_add(B x); // add permanent root object
void gc_addFn(vfn f); // add function that calls mm_visit/mm_visitP for dynamic roots
void gc_add_ref(B* x); // add x as a root reference
bool gc_maybeGC(void); // gc if that seems necessary; returns if did gc
void gc_forceGC(void); // force a gc; who knows what happens if gc is disabled (probably should error)
void gc_forceGC(bool toplevel); // force a gc; who knows what happens if gc is disabled (probably should error)
// some primitive actions
static const B bi_N = b((u64)0x7FF2000000000000ull); // tag(0,TAG_TAG); // make gcc happy

View File

@ -624,7 +624,7 @@ void cbqn_runLine0(char* ln, i64 read) {
e->vars[i] = bi_noVar;
dec(val);
#if ENABLE_GC
if (!gc_depth) gc_forceGC();
if (!gc_depth) gc_forceGC(true);
#endif
return;
}
@ -665,15 +665,21 @@ void cbqn_runLine0(char* ln, i64 read) {
return;
} else if (isCmd(cmdS, &cmdE, "gc ")) {
#if ENABLE_GC
bool toplevel = true;
if (0==*cmdE) {
gc_now:;
if (gc_depth!=0) {
printf("GC is disabled, but forcibly GCing anyway\n");
gc_enable();
gc_forceGC();
gc_disable();
u64 stored_depth = gc_depth;
gc_depth = 0;
gc_forceGC(toplevel);
gc_depth = stored_depth;
} else {
gc_forceGC();
gc_forceGC(toplevel);
}
} else if (strcmp(cmdE,"nontop")==0) {
toplevel = false;
goto gc_now;
} else if (strcmp(cmdE,"on")==0) {
if (gc_depth==0) printf("GC already on\n");
else if (gc_depth>1) printf("GC cannot be enabled\n");
@ -935,7 +941,7 @@ int main(int argc, char* argv[]) {
#ifdef HEAP_VERIFY
heapVerify();
#endif
gc_forceGC();
gc_forceGC(true);
}
}
if (startREPL) {

View File

@ -136,22 +136,29 @@ static void gc_tryFree(Value* v) {
gcv2_storeRemainingEnd(x);
}
static void gc_run() {
visit_mode = GC_DEC_REFC;
mm_forHeap(gcv2_visit);
gcv2_bufS = gcv2_bufC = malloc(1<<20);
gcv2_bufE = gcv2_bufS + ((1<<20) / sizeof(Value*));
mm_forHeap(gcv2_storeRemaining); // incl. unmark
visit_mode = GC_INC_REFC;
mm_forHeap(gcv2_visit);
static void gc_run(bool toplevel) {
if (toplevel) {
mm_forHeap(gc_resetTag);
} else {
visit_mode = GC_DEC_REFC;
mm_forHeap(gcv2_visit);
gcv2_bufS = gcv2_bufC = malloc(1<<20);
gcv2_bufE = gcv2_bufS + ((1<<20) / sizeof(Value*));
mm_forHeap(gcv2_storeRemaining); // incl. unmark
visit_mode = GC_INC_REFC;
mm_forHeap(gcv2_visit);
}
visit_mode = GC_MARK;
gc_visitRoots();
Value** c = gcv2_bufS;
while (c < gcv2_bufC) mm_visitP(*(c++));
free(gcv2_bufS);
if (!toplevel) {
Value** c = gcv2_bufS;
while (c < gcv2_bufC) mm_visitP(*(c++));
free(gcv2_bufS);
}
mm_forHeap(gc_tryFree);
mm_forHeap(gc_freeFreed);
@ -166,7 +173,7 @@ static void gc_tryFree(Value* v) {
#endif
u64 gc_lastAlloc;
void gc_forceGC() {
void gc_forceGC(bool toplevel) {
#if ENABLE_GC
#ifdef LOG_GC
u64 start = nsTime();
@ -175,7 +182,7 @@ void gc_forceGC() {
gc_unkRefsBytes = 0; gc_unkRefsCount = 0;
u64 startSize = mm_heapUsed();
#endif
gc_run();
gc_run(toplevel);
u64 endSize = mm_heapUsed();
#ifdef LOG_GC
fprintf(stderr, "GC kept "N64d"B/"N64d" objs, freed "N64d"B, incl. directly "N64d"B/"N64d" objs", gc_visitBytes, gc_visitCount, startSize-endSize, gc_freedBytes, gc_freedCount);
@ -193,7 +200,7 @@ bool gc_maybeGC() {
if (gc_depth) return false;
u64 used = mm_heapUsed();
if (used > gc_lastAlloc*2) {
gc_forceGC();
gc_forceGC(false);
return true;
}
return false;

View File

@ -51,7 +51,7 @@ static NOINLINE void* BN(allocateMore)(i64 bucket, u8 type, i64 from, i64 to) {
if (mm_heapAlloc+sz >= mm_heapMax) {
#if GC_VISIT_V2
if (!BN(allocMore_rec)) {
gc_forceGC();
gc_forceGC(false);
BN(allocMore_rec) = true;
alloc_rec:;
void* r = BN(allocL)(bucket, type);