switch to GCv2, various fixes/cleanup

includes:
  fixing some refcounts for FOR_BUILD build •FFI
  moving DEBUG_VM prints to stderr
  fixing heapverify reports of loose shape objects of fillarrs
  regular ol' adding-of-semicolon-after-label for old gcc
  move GC enable to after all initialization, not load_init
This commit is contained in:
dzaima 2023-03-04 20:40:56 +02:00
parent 16274e5952
commit c5aedaa414
18 changed files with 114 additions and 177 deletions

View File

@ -1326,7 +1326,7 @@ B transp_c1(B t, B x) {
void* xp = tyany_ptr(x);
switch(xe) { default: UD;
#if __BMI2__
case el_bit:
case el_bit:;
u64* r0 = rp; TALLOC(u64, r1, BIT_N(h));
for (usz i=0; i<BIT_N(ia); i++) {
u64 v = ((u64*)xp)[i];

View File

@ -2,7 +2,6 @@
#include "h.h"
#include "core/stuff.h"
#include "core/heap.h"
#if MM==0
#include "opt/mm_malloc.h"

View File

@ -52,6 +52,7 @@ DEF_FREE(fillarr) {
for (usz i = 0; i < ia; i++) dec(p[i]);
}
static void fillarr_visit(Value* x) { assert(PTY(x) == t_fillarr);
VISIT_SHAPE(x);
usz ia = PIA((Arr*)x); B* p = ((FillArr*)x)->a;
mm_visit(((FillArr*)x)->fill);
for (usz i = 0; i < ia; i++) mm_visit(p[i]);
@ -60,7 +61,7 @@ static bool fillarr_canStore(B x) { return true; }
static void fillarr_freeT(Value* x) { FillArr* s=(void*)x; dec(s->fill); decSh(x); mm_free(x); }
static void fillslice_visit(Value* x) { FillSlice* s=(void*)x; mm_visitP(s->p); mm_visit(s->fill); }
static void fillslice_visit(Value* x) { FillSlice* s=(void*)x; mm_visitP(s->p); mm_visit(s->fill); VISIT_SHAPE(x); }
static void fillslice_freeO(Value* x) { FillSlice* s=(void*)x; ptr_dec(s->p); dec(s->fill); decSh(x); }
static void fillslice_freeF(Value* x) { fillslice_freeO(x); mm_free(x); }

View File

@ -19,33 +19,14 @@ void heapVerify_checkFn(Value* v) {
void heapVerify_callVisit(Value* v) {
if (TIv(v,isArr) && PRNK(v)>1) heapVerify_visitP(shObjP(v));
TIv(v,visit)(v);
}
void heap_getReferents(Value* v) {
heap_curr = v;
if (TIv(v,isArr) && PRNK(v)>1) heapVerify_visitP(shObjP(v));
TIv(v,visit)(v);
}
void gc_visitRoots(void);
void gcv2_runHeapverify(i32);
void heapVerify() {
void cbqn_heapVerify() {
heap_observed = 0;
#if GC_VISIT_V2
gcv2_runHeapverify(0);
mm_forHeap(heapVerify_checkFn);
gcv2_runHeapverify(1);
#else
heapVerify_mode=0; mm_forHeap(heapVerify_callVisit); gc_visitRoots();
mm_forHeap(heapVerify_checkFn);
heapVerify_mode=1; mm_forHeap(heapVerify_callVisit); gc_visitRoots();
#endif
if (heap_observed) {
printf("refc of last: %d\n", heap_observed->refc);
// heapVerify_mode=2; mm_forHeap(heap_getReferents);
}
gcv2_runHeapverify(0);
mm_forHeap(heapVerify_checkFn);
gcv2_runHeapverify(1);
if (heap_observed) printf("refc of last: %d\n", heap_observed->refc);
heapVerify_mode=-1;
}
@ -97,7 +78,7 @@ void heap_printInfo(bool sizes, bool types, bool freed, bool chain) {
for (i32 i = 2; i < 64; i++) {
for (i32 j = 0; j < MM; j++) {
i32 o = i-j;
ux cf=0, cc=0;
u64 cf=0, cc=0;
if (freed) {
cf = heap_PIFreed[o + j*64];
}

View File

@ -1,23 +0,0 @@
u64 mm_heapUsed(void);
#ifdef HEAP_VERIFY
extern u32 heapVerify_mode;
extern Value* heap_observed;
extern Value* heap_curr;
static bool heapVerify_visit(B x) {
if (heapVerify_mode==-1) return false;
if (isVal(x)) mm_visitP(v(x));
return true;
}
static bool heapVerify_visitP(void* x) {
if(heapVerify_mode==-1) return false;
Value* v = x;
if (heapVerify_mode==0) v->refc--;
else if(heapVerify_mode==1) v->refc++;
else if(heapVerify_mode==2) if (x==heap_observed) { printf("referee: %p ", heap_curr); printI(tag(heap_curr,OBJ_TAG)); putchar('\n'); }
return true;
}
void heapVerify(void);
#endif

View File

@ -44,7 +44,7 @@ NOINLINE B c2F(B f, B w, B x) { dec(w); dec(x);
NOINLINE void value_freeF(Value* x) { value_free(x); }
NOINLINE void decA_F(B x) { dec(x); }
void noop_visit(Value* x) { }
#if HEAP_VERIFY && GC_VISIT_V2
#if HEAP_VERIFY
void arr_visit(Value* x) { VISIT_SHAPE(x); }
#endif
NOINLINE B c1_bad(B f, B x) { thrM("This function can't be called monadically"); }
@ -666,7 +666,7 @@ B bqn_merge(B x) {
usz* rsh = arr_shAlloc(ra, xr+elR);
if (rsh) {
shcpy (rsh , SH(x), xr);
if (elSh)shcpy(rsh+xr, elSh, elR);
if (elSh)shcpy(rsh+xr, elSh, elR);
}
decG(x);
return withFill(taga(ra),fill);

View File

@ -222,7 +222,7 @@ B def_fn_ix(B t, B w, B x);
B def_decompose(B x);
void noop_visit(Value* x);
#if HEAP_VERIFY && GC_VISIT_V2
#if HEAP_VERIFY
void arr_visit(Value* x);
#define VISIT_SHAPE(X) ({ if (PRNK(X)>1) mm_visitP(shObjP(X)); })
#else

View File

@ -939,6 +939,7 @@ void ffi_init(void) {
switch (id) { default: err("bad id");
case 0: {
char* s = toCStr(x);
decG(x);
i32 r = chdir(s);
freeCStr(s);
return m_f64(r);
@ -954,30 +955,34 @@ void ffi_init(void) {
return m_vec2(m_f64(r), m_vec2(m_f64(vs[0]), m_f64(vs[1])));
}
case 3: {
SGetU(x)
int fd = o2i(GetU(x,0));
I8Arr* buf = cpyI8Arr(GetU(x,1));
usz maxlen = o2s(GetU(x,2));
SGet(x)
int fd = o2i(Get(x,0));
I8Arr* buf = cpyI8Arr(Get(x,1));
usz maxlen = o2s(Get(x,2));
decG(x);
assert(PIA(buf)==maxlen);
int res = read(fd, buf->a, maxlen);
return m_vec2(m_f64(res), taga(buf));
}
case 4: {
SGetU(x)
int fd = o2i(GetU(x,0));
I8Arr* buf = cpyI8Arr(GetU(x,1));
usz maxlen = o2s(GetU(x,2));
SGet(x)
int fd = o2i(Get(x,0));
I8Arr* buf = cpyI8Arr(Get(x,1));
usz maxlen = o2s(Get(x,2));
decG(x);
int res = write(fd, buf->a, maxlen);
ptr_dec(buf);
return m_f64(res);
}
case 5: {
return m_f64(close(o2i(x)));
}
case 6: {
SGetU(x)
I16Arr* buf = cpyI16Arr(GetU(x,0)); i16* a = (i16*)buf->a;
int nfds = o2i(GetU(x,1));
int timeout = o2s(GetU(x,2));
SGet(x)
I16Arr* buf = cpyI16Arr(Get(x,0)); i16* a = (i16*)buf->a;
int nfds = o2i(Get(x,1));
int timeout = o2s(Get(x,2));
decG(x);
TALLOC(pollfd, ps, nfds)
for (i32 i = 0; i < nfds; i++) ps[i] = (pollfd){.fd = a[i*4+0]|a[i*4+1]<<16, .events=a[i*4+2]};

View File

@ -46,7 +46,6 @@
#endif
#endif
// #define HEAP_VERIFY // enable usage of heapVerify()
// #define ALLOC_STAT // store basic allocation statistics
// #define ALLOC_SIZES // store per-type allocation size statistics
// #define USE_VALGRIND // whether to mark freed memory for valgrind
@ -357,6 +356,10 @@ void gc_addFn(vfn f); // add function that calls mm_visit/mm_visitP for dynamic
void gc_add_ref(B* x); // add x as a root reference
bool gc_maybeGC(bool toplevel); // gc if that seems necessary; returns if did gc
void gc_forceGC(bool toplevel); // force a gc; who knows what happens if gc is disabled (probably should error)
u64 mm_heapUsed(void);
#if HEAP_VERIFY
void cbqn_heapVerify(void);
#endif
// some primitive actions
static const B bi_N = b((u64)0x7FF2000000000000ull); // tag(0,TAG_TAG); // make gcc happy

View File

@ -512,8 +512,8 @@ void load_init() { // very last init function
printI(interp);
printf("\n");
dec(interp);
#ifdef HEAP_VERIFY
heapVerify();
#if HEAP_VERIFY
cbqn_heapVerify();
#endif
rtWrap_print();
CTR_FOR(CTR_PRINT)
@ -551,7 +551,6 @@ void load_init() { // very last init function
decG(fmtR);
#endif
gc_enable();
#endif // PRECOMP
}
@ -806,6 +805,7 @@ void cbqn_init() {
#define F(X) X##_init();
FOR_INIT(F)
#undef F
cbqn_initialized = true;
cbqn_initialized = true;
gc_enable();
}
#undef FOR_INIT

View File

@ -825,16 +825,16 @@ void cbqn_runLine(char* ln, i64 len) {
fprintf(stderr, "Error: "); printErrMsg(thrownMsg); fputc('\n', stderr);
vm_pst(envCurr+1, envStart+envPrevHeight);
freeThrown();
#ifdef HEAP_VERIFY
heapVerify();
#if HEAP_VERIFY
cbqn_heapVerify();
#endif
gc_maybeGC(true);
return;
}
cbqn_takeInterrupts(true);
cbqn_runLine0(ln, len);
#ifdef HEAP_VERIFY
heapVerify();
#if HEAP_VERIFY
cbqn_heapVerify();
#endif
gc_maybeGC(true);
cbqn_takeInterrupts(false);
@ -983,8 +983,8 @@ int main(int argc, char* argv[]) {
execRes = bqn_execFile(src, args);
}
dec(execRes);
#ifdef HEAP_VERIFY
heapVerify();
#if HEAP_VERIFY
cbqn_heapVerify();
#endif
gc_forceGC(true);
}
@ -1045,8 +1045,8 @@ int main(int argc, char* argv[]) {
}
}
}
#ifdef HEAP_VERIFY
heapVerify();
#if HEAP_VERIFY
cbqn_heapVerify();
#endif
bqn_exit(0);
#undef INIT

View File

@ -1,8 +1,11 @@
#include "gc.h"
void mm_freeFreedAndMerge(void);
#if ENABLE_GC
static void mm_freeFreedAndMerge(void);
#endif
#ifdef LOG_GC
#include "../utils/time.h"
#include "../utils/time.h"
#endif
u64 gc_depth = 1;
@ -73,41 +76,45 @@ static void gc_tryFree(Value* v) {
u64 gc_visitBytes, gc_visitCount, gc_freedBytes, gc_freedCount, gc_unkRefsBytes, gc_unkRefsCount;
#endif
#if GC_VISIT_V2
i32 visit_mode;
enum {
GC_DEC_REFC, // decrement refcount
GC_INC_REFC, // increment refcount
GC_MARK, // if unmarked, mark & visit
GC_LISTBAD, //
};
void gc_onVisit(Value* x) {
switch (visit_mode) { default: UD;
case GC_DEC_REFC: x->refc--; return;
case GC_INC_REFC: x->refc++; return;
case GC_MARK: {
if (x->mmInfo&0x80) return;
x->mmInfo|= 0x80;
#ifdef LOG_GC
gc_visitBytes+= mm_size(x); gc_visitCount++;
#endif
TIv(x,visit)(x);
return;
}
i32 visit_mode;
enum {
GC_DEC_REFC, // decrement refcount
GC_INC_REFC, // increment refcount
GC_MARK, // if unmarked, mark & visit
};
void gc_onVisit(Value* x) {
switch (visit_mode) { default: UD;
case GC_DEC_REFC:
#if DEBUG
if(x->refc==0) err("decrementing refc 0");
#endif
x->refc--;
return;
case GC_INC_REFC: x->refc++; return;
case GC_MARK: {
if (x->mmInfo&0x80) return;
x->mmInfo|= 0x80;
#ifdef LOG_GC
gc_visitBytes+= mm_size(x); gc_visitCount++;
#endif
TIv(x,visit)(x);
return;
}
}
static void gcv2_visit(Value* x) { TIv(x,visit)(x); }
#if HEAP_VERIFY
}
static void gcv2_visit(Value* x) { TIv(x,visit)(x); }
#if HEAP_VERIFY
void gcv2_runHeapverify(i32 mode) {
visit_mode = mode==0? GC_DEC_REFC : GC_INC_REFC;
mm_forHeap(gcv2_visit);
gc_visitRoots();
}
#endif
#endif
#if ENABLE_GC
static Value** gcv2_bufS;
static Value** gcv2_bufC;
static Value** gcv2_bufE;
@ -132,7 +139,7 @@ static void gc_tryFree(Value* v) {
if (gcv2_bufC == gcv2_bufE) return gcv2_storeRemainingR(x);
gcv2_storeRemainingEnd(x);
}
static void gc_run(bool toplevel) {
if (toplevel) {
mm_forHeap(gc_resetTag);
@ -157,13 +164,6 @@ static void gc_tryFree(Value* v) {
free(gcv2_bufS);
}
mm_forHeap(gc_tryFree);
mm_freeFreedAndMerge();
}
#else
static void gc_run(bool toplevel) {
mm_forHeap(gc_resetTag);
gc_visitRoots();
mm_forHeap(gc_tryFree);
mm_freeFreedAndMerge();
}
@ -183,9 +183,7 @@ void gc_forceGC(bool 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);
#if GC_VISIT_V2
fprintf(stderr, "; unknown refs: "N64d"B/"N64d" objs", gc_unkRefsBytes, gc_unkRefsCount);
#endif
fprintf(stderr, "; unknown refs: "N64d"B/"N64d" objs", gc_unkRefsBytes, gc_unkRefsCount);
fprintf(stderr, "; took %.3fms\n", (nsTime()-start)/1e6);
#endif
gc_lastAlloc = endSize;

View File

@ -8,40 +8,10 @@ static void gc_enable() { gc_depth--; }
extern u64 gc_visitBytes, gc_visitCount, gc_freedBytes, gc_freedCount;
#endif
#if GC_VISIT_V2
extern void gc_onVisit(Value*);
static void mm_visit(B x) {
if (isVal(x)) gc_onVisit(v(x));
}
static void mm_visitP(void* xp) {
gc_onVisit(xp);
}
#else
static void mm_visit(B x) {
#ifdef HEAP_VERIFY
if(heapVerify_visit(x)) return;
#endif
if (!isVal(x)) return;
Value* vx = v(x);
if (vx->mmInfo&0x80) return;
vx->mmInfo|= 0x80;
#ifdef LOG_GC
gc_visitBytes+= mm_size(vx); gc_visitCount++;
#endif
TI(x,visit)(vx);
}
static void mm_visitP(void* xp) {
#ifdef HEAP_VERIFY
if(heapVerify_visitP(xp)) return;
#endif
Value* x = (Value*)xp;
if (x->mmInfo&0x80) return;
x->mmInfo|= 0x80;
#ifdef LOG_GC
gc_visitBytes+= mm_size(x); gc_visitCount++;
#endif
TIv(x,visit)(x);
}
#endif
extern void gc_onVisit(Value*);
static void mm_visit(B x) {
if (isVal(x)) gc_onVisit(v(x));
}
static void mm_visitP(void* xp) {
gc_onVisit(xp);
}

View File

@ -47,7 +47,7 @@ void mm_forFreedHeap(V2v f) {
b1_forFreedHeap(f);
b3_forFreedHeap(f);
}
void mm_freeFreedAndMerge() {
static void mm_freeFreedAndMerge() {
b1_freeFreedAndMerge();
b3_freeFreedAndMerge();
}

View File

@ -36,7 +36,7 @@ FORCE_INLINE void BN(splitTo)(EmptyValue* c, i64 from, i64 to, bool notEqual) {
buckets[from] = c;
}
#if GC_VISIT_V2 && !BUDDY_NO_GC
#if !BUDDY_NO_GC && ENABLE_GC
static bool BN(allocMore_rec);
#endif
@ -44,12 +44,12 @@ static NOINLINE void* BN(allocateMore)(i64 bucket, u8 type, i64 from, i64 to) {
u64 sz = BSZ(from);
CHECK_INTERRUPT;
#if GC_VISIT_V2 && !BUDDY_NO_GC
#if !BUDDY_NO_GC && ENABLE_GC
if (gc_maybeGC(false)) goto alloc_rec;
#endif
if (mm_heapAlloc+sz >= mm_heapMax) {
#if GC_VISIT_V2 && !BUDDY_NO_GC
#if !BUDDY_NO_GC && ENABLE_GC
if (!BN(allocMore_rec)) {
gc_forceGC(false);
BN(allocMore_rec) = true;
@ -130,6 +130,7 @@ void BN(forFreedHeap)(V2v f) {
}
}
}
#if !BUDDY_NO_GC && ENABLE_GC
static void BN(freeFreedAndMerge)() {
for (u64 i = 0; i < 64; i++) buckets[i] = NULL;
@ -140,7 +141,7 @@ static void BN(freeFreedAndMerge)() {
Value* e = (Value*)(ci.sz + (u8*)ci.p);
assert(c!=e);
while (true) {
if (vg_def_v(c->type)==t_freed) BN(freeLink)(c, false);
if (vg_def_v(c->type)==t_freed) mm_freeLink(c, false);
Value* next = (Value*)(BSZ(vg_def_v(c->mmInfo)&63) + (u8*)c);
if (vg_def_v(c->type)==t_empty) {
@ -159,6 +160,7 @@ static void BN(freeFreedAndMerge)() {
.mmInfo = MMI(b),
.next = buckets[b]
};
vg_undef_p(cv, sizeof(EmptyValue));
buckets[b] = cv;
emptyStart+= curr*MUL;
@ -175,6 +177,7 @@ static void BN(freeFreedAndMerge)() {
}
}
}
#endif
void writeNum(FILE* f, u64 v, i32 len);
void BN(dumpHeap)(FILE* f) {

View File

@ -23,7 +23,7 @@ static void gc_enable() { }
static void mm_visit(B x) { }
static void mm_visitP(void* x) { }
void gc_maybeGC(bool);
bool gc_maybeGC(bool);
void gc_forceGC(bool);
void mm_forHeap(V2v f);
void mm_dumpHeap(FILE* f);

View File

@ -690,7 +690,7 @@ B evalBC(Body* b, Scope* sc, Block* bl) { // doesn't consume
if (!vmStack) vmStack = malloc(400);
i32 stackNum = bcDepth>>1;
vmStack[stackNum] = -1;
printf("new eval\n");
fprintf(stderr,"new eval\n");
B* origStack = gStack;
#endif
u32* bc = b->bc;
@ -728,9 +728,9 @@ B evalBC(Body* b, Scope* sc, Block* bl) { // doesn't consume
u32* sbc = bc;
i32 bcPos = BCPOS(b,sbc);
vmStack[stackNum] = bcPos;
for(i32 i = 0; i < bcDepth; i++) printf(" ");
print_BC(sbc,20); printf("@%d in: ", bcPos);
for (i32 i = 0; i < lgStack-origStack; i++) { if(i)printf("; "); printI(origStack[i]); } putchar('\n'); fflush(stdout);
for(i32 i = 0; i < bcDepth; i++) fprintf(stderr," ");
print_BC(stderr,sbc,20); fprintf(stderr,"@%d in: ",bcPos);
for (i32 i = 0; i < lgStack-origStack; i++) { if(i)fprintf(stderr,"; "); fprintI(stderr,origStack[i]); } fputc('\n',stderr); fflush(stderr);
bcCtr++;
for (i32 i = 0; i < sc->varAm; i++) VALIDATE(sc->vars[i]);
#endif
@ -930,9 +930,9 @@ B evalBC(Body* b, Scope* sc, Block* bl) { // doesn't consume
#endif
}
#ifdef DEBUG_VM
for(i32 i = 0; i < bcDepth; i++) printf(" ");
print_BC(sbc,20); printf("@%d out: ", BCPOS(b, sbc));
for (i32 i = 0; i < lgStack-origStack; i++) { if(i)printf("; "); printI(origStack[i]); } putchar('\n'); fflush(stdout);
for(i32 i = 0; i < bcDepth; i++) fprintf(stderr," ");
print_BC(stderr,sbc,20); fprintf(stderr,"@%d out: ",BCPOS(b, sbc));
for (i32 i = 0; i < lgStack-origStack; i++) { if(i)fprintf(stderr,"; "); fprintI(stderr,origStack[i]); } fputc('\n',stderr); fflush(stderr);
#endif
}
end:;

View File

@ -3,13 +3,13 @@ if [ "$#" -ne 1 ]; then
echo "Usage: $0 path/to/mlochbaum/BQN"
exit
fi
make && ./BQN -p 2+2 || exit
make single-debug && ./BQN -p 2+2 || exit
make heapverify && ./BQN -p 2+2 || exit
make rtverify && ./BQN -p 2+2 || exit
make rtperf && ./BQN -p 2+2 | head -2 || exit
make f='-DDEBUG -DDEBUG_VM' c && ./BQN -p 2+2 | tail -2 || exit
make f='-DWARN_SLOW' c && ./BQN -p 2+2 2> /dev/null || exit
make && ./BQN -p 2+2 || exit
make single-debug && ./BQN -p 2+2 || exit
make heapverify && ./BQN -p 2+2 || exit
make rtverify && ./BQN -p 2+2 || exit
make rtperf && ./BQN -p 2+2 | head -2 || exit
make f='-DDEBUG -DDEBUG_VM' c && ./BQN -p 2+2 2>&1 | tail -2 || exit
make f='-DWARN_SLOW' c && ./BQN -p 2+2 2> /dev/null || exit
make f='-DMM=0 -DENABLE_GC=0' c && ./BQN -p 2+2 || exit
make f='-DMM=1' c && ./BQN -p 2+2 || exit
make f='-DMM=2' c && ./BQN -p 2+2 || exit