diff --git a/build b/build index 294a39ab..27a938ff 100755 --- a/build +++ b/build @@ -1,2 +1,2 @@ #!/usr/bin/env bash -clang -std=gnu11 -O3 -Wall -Wno-microsoft-anon-tag -fms-extensions -o BQN -lm src/main.c +clang -std=gnu11 -O3 -Wall -Wno-microsoft-anon-tag -fms-extensions -o BQN src/main.c -lm diff --git a/debugBuild b/debugBuild index ea2a4b0a..171c0067 100755 --- a/debugBuild +++ b/debugBuild @@ -1,2 +1,3 @@ #!/usr/bin/env bash -clang -DDEBUG -std=gnu11 -g -Wall -Wno-microsoft-anon-tag -fms-extensions -o BQN -lm src/main.c +clang -DDEBUG -std=gnu11 -g -Wall -Wno-microsoft-anon-tag -fms-extensions -o BQN src/main.c -lm +# clang -DDEBUG -std=gnu11 -g -Wall -Wno-microsoft-anon-tag -fms-extensions -o BQN -lm src/main.c diff --git a/src/arith.c b/src/arith.c index 1ce55f1c..5912051c 100644 --- a/src/arith.c +++ b/src/arith.c @@ -32,7 +32,7 @@ ffnx(log_c2, log(x.f)/log(w.f), {}) B decp_c1(B t, B x); B eq_c2(B t, B w, B x) { if(isF64(w)&isF64(x)) return m_i32(w.f==x.f); - if (w.u==x.u) return m_i32(1); + if (w.u==x.u) { dec(w);dec(x); return m_i32(1); } // doesn't handle int=float if (!isVal(w) | !isVal(x)) { dec(w);dec(x); return m_i32(0); } if (v(w)->type!=v(x)->type) { dec(w);dec(x); return m_i32(0); } @@ -61,9 +61,9 @@ B eq_c1(B t, B x) { B r = m_i32(isArr(x)? rnk(x) : 0); decR(x); return r; } -#define ba(NAME) bi_##NAME = mm_alloc(sizeof(Fun), t_fun_def, ftag(FUN_TAG)); c(Fun,bi_##NAME)->c2 = NAME##_c2; c(Fun,bi_##NAME)->c1 = NAME##_c1 ; c(Fun,bi_##NAME)->extra=pf_##NAME; -#define bd(NAME) bi_##NAME = mm_alloc(sizeof(Fun), t_fun_def, ftag(FUN_TAG)); c(Fun,bi_##NAME)->c2 = NAME##_c2; c(Fun,bi_##NAME)->c1 = c1_invalid; c(Fun,bi_##NAME)->extra=pf_##NAME; -#define bm(NAME) bi_##NAME = mm_alloc(sizeof(Fun), t_fun_def, ftag(FUN_TAG)); c(Fun,bi_##NAME)->c2 = c2_invalid;c(Fun,bi_##NAME)->c1 = NAME##_c1 ; c(Fun,bi_##NAME)->extra=pf_##NAME; +#define ba(NAME) bi_##NAME = mm_alloc(sizeof(Fun), t_fun_def, ftag(FUN_TAG)); c(Fun,bi_##NAME)->c2 = NAME##_c2; c(Fun,bi_##NAME)->c1 = NAME##_c1 ; c(Fun,bi_##NAME)->extra=pf_##NAME; gc_add(bi_##NAME); +#define bd(NAME) bi_##NAME = mm_alloc(sizeof(Fun), t_fun_def, ftag(FUN_TAG)); c(Fun,bi_##NAME)->c2 = NAME##_c2; c(Fun,bi_##NAME)->c1 = c1_invalid; c(Fun,bi_##NAME)->extra=pf_##NAME; gc_add(bi_##NAME); +#define bm(NAME) bi_##NAME = mm_alloc(sizeof(Fun), t_fun_def, ftag(FUN_TAG)); c(Fun,bi_##NAME)->c2 = c2_invalid;c(Fun,bi_##NAME)->c1 = NAME##_c1 ; c(Fun,bi_##NAME)->extra=pf_##NAME; gc_add(bi_##NAME); B bi_add, bi_sub, bi_mul, bi_div, bi_pow, bi_floor, bi_eq, bi_le, bi_log; void arith_init() { ba(add) ba(sub) ba(mul) ba(div) ba(pow) bm(floor) ba(eq) bd(le) ba(log) } diff --git a/src/c32arr.c b/src/c32arr.c index 1938708a..2092993f 100644 --- a/src/c32arr.c +++ b/src/c32arr.c @@ -71,8 +71,11 @@ bool eqStr(B w, u32* x) { void c32arr_init() { ti[t_c32arr].get = c32arr_get; ti[t_c32slice].get = c32slice_get; + ti[t_c32arr].getU = c32arr_get; ti[t_c32slice].getU = c32slice_get; ti[t_c32arr].slice = c32arr_slice; ti[t_c32slice].slice = c32slice_slice; ti[t_c32arr].free = c32arr_free; ti[t_c32slice].free = slice_free; + ti[t_c32arr].visit = do_nothing; ti[t_c32slice].visit = slice_visit; ti[t_c32arr].print = arr_print; ti[t_c32slice].print = arr_print; + ti[t_c32arr].isArr = true; ti[t_c32slice].isArr = true; ti[t_c32arr].canStore = c32arr_canStore; } diff --git a/src/derv.c b/src/derv.c index 1c71271a..9123ebcd 100644 --- a/src/derv.c +++ b/src/derv.c @@ -30,6 +30,12 @@ void md2H_free(B x) { dec(c(Md2H,x)->m2); dec(c(Md2H,x)->g); void fork_free(B x) { dec(c(Fork,x)->f ); dec(c(Fork,x)->g); dec(c(Fork,x)->h); } void atop_free(B x) { dec(c(Atop,x)->g); dec(c(Atop,x)->h); } +void md1D_visit(B x) { mm_visit(c(Md1D,x)->m1); mm_visit(c(Md1D,x)->f); } +void md2D_visit(B x) { mm_visit(c(Md2D,x)->m2); mm_visit(c(Md2D,x)->f); mm_visit(c(Md2D,x)->g); } +void md2H_visit(B x) { mm_visit(c(Md2H,x)->m2); mm_visit(c(Md2H,x)->g); } +void fork_visit(B x) { mm_visit(c(Fork,x)->f ); mm_visit(c(Fork,x)->g); mm_visit(c(Fork,x)->h); } +void atop_visit(B x) { mm_visit(c(Atop,x)->g); mm_visit(c(Atop,x)->h); } + void md1D_print(B x) { printf("(md1D ");print(c(Md1D,x)->f);printf(" ");print(c(Md1D,x)->m1); printf(")"); } void md2D_print(B x) { printf("(md2D ");print(c(Md2D,x)->f);printf(" ");print(c(Md2D,x)->m2);printf(" ");print(c(Md2D,x)->g);printf(")"); } void md2H_print(B x) { printf("(md2H "); print(c(Md2H,x)->m2);printf(" ");print(c(Md2H,x)->g);printf(")"); } @@ -68,11 +74,11 @@ B m2_h(B m, B g) { return m_md2H(m, g); } void derv_init() { - ti[t_md1D].free = md1D_free; ti[t_md1D].print = md1D_print; ti[t_md1D].decompose = md1D_decompose; - ti[t_md2D].free = md2D_free; ti[t_md2D].print = md2D_print; ti[t_md2D].decompose = md2D_decompose; - ti[t_md2H].free = md2H_free; ti[t_md2H].print = md2H_print; ti[t_md2H].decompose = md2H_decompose; - ti[t_fork].free = fork_free; ti[t_fork].print = fork_print; ti[t_fork].decompose = fork_decompose; - ti[t_atop].free = atop_free; ti[t_atop].print = atop_print; ti[t_atop].decompose = atop_decompose; + ti[t_md1D].free = md1D_free; ti[t_md1D].visit = md1D_visit; ti[t_md1D].print = md1D_print; ti[t_md1D].decompose = md1D_decompose; + ti[t_md2D].free = md2D_free; ti[t_md2D].visit = md2D_visit; ti[t_md2D].print = md2D_print; ti[t_md2D].decompose = md2D_decompose; + ti[t_md2H].free = md2H_free; ti[t_md2H].visit = md2H_visit; ti[t_md2H].print = md2H_print; ti[t_md2H].decompose = md2H_decompose; + ti[t_fork].free = fork_free; ti[t_fork].visit = fork_visit; ti[t_fork].print = fork_print; ti[t_fork].decompose = fork_decompose; + ti[t_atop].free = atop_free; ti[t_atop].visit = atop_visit; ti[t_atop].print = atop_print; ti[t_atop].decompose = atop_decompose; ti[t_md1_def].m1_d = m_md1D; ti[t_md2_def].m2_d = m_md2D; } diff --git a/src/fillarr.c b/src/fillarr.c index eed3a043..ed9248c7 100644 --- a/src/fillarr.c +++ b/src/fillarr.c @@ -22,29 +22,6 @@ B asFill(B x) { // consumes dec(x); return bi_noFill; } -B withFill(B x, B fill) { // consumes both - assert(isArr(x)); - switch(v(x)->type) { - case t_i32arr : case t_i32slice : if(fill.u == m_i32(0 ).u) return x; break; - case t_c32arr : case t_c32slice : if(fill.u == m_c32(' ').u) return x; break; - case t_fillarr: case t_fillslice: if (equal(c(FillArr,x)->fill, fill)) { dec(fill); return x; } - if (reusable(x)) { - dec(c(FillArr, x)->fill); - c(FillArr, x)->fill = fill; - return x; - } - break; - } - B r = m_arr(fsizeof(FillArr,a,B,a(x)->ia), t_fillarr); - arr_shCopy(r, x); - c(FillArr,r)->fill = fill; - B* a = c(FillArr,r)->a; - usz ia = a(x)->ia; - BS2B xget = TI(x).get; - for (usz i = 0; i < ia; i++) a[i] = xget(x,i); - dec(x); - return r; -} B getFill(B x) { // consumes if (isArr(x)) { u8 t = v(x)->type; @@ -77,20 +54,56 @@ B fillarr_slice (B x, usz s) {return m_fillslice(x , c(Fill B fillslice_slice(B x, usz s) { B r = m_fillslice(inc(c(FillSlice,x)->p), c(FillSlice,x)->a+s); dec(x); return r; } -B fillarr_get (B x, usz n) { VT(x,t_fillarr ); return inc(c(FillArr ,x)->a[n]); } -B fillslice_get(B x, usz n) { VT(x,t_fillslice); return inc(c(FillSlice,x)->a[n]); } +B fillarr_get (B x, usz n) { VT(x,t_fillarr ); return inc(c(FillArr ,x)->a[n]); } +B fillslice_get (B x, usz n) { VT(x,t_fillslice); return inc(c(FillSlice,x)->a[n]); } +B fillarr_getU (B x, usz n) { VT(x,t_fillarr ); return c(FillArr ,x)->a[n] ; } +B fillslice_getU(B x, usz n) { VT(x,t_fillslice); return c(FillSlice,x)->a[n] ; } void fillarr_free(B x) { decSh(x); B* p = c(FillArr, x)->a; + dec(c(FillArr, x)->fill); usz ia = a(x)->ia; for (usz i = 0; i < ia; i++) dec(p[i]); } +void fillarr_visit(B x) { + usz ia = a(x)->ia; B* p = fillarr_ptr(x); + mm_visit(c(FillArr,x)->fill); + for (usz i = 0; i < ia; i++) mm_visit(p[i]); +} bool fillarr_canStore(B x) { return true; } void fillarr_init() { ti[t_fillarr].get = fillarr_get; ti[t_fillslice].get = fillslice_get; + ti[t_fillarr].getU = fillarr_getU; ti[t_fillslice].getU = fillslice_getU; ti[t_fillarr].slice = fillarr_slice; ti[t_fillslice].slice = fillslice_slice; ti[t_fillarr].free = fillarr_free; ti[t_fillslice].free = slice_free; + ti[t_fillarr].visit = fillarr_visit; ti[t_fillslice].visit = slice_visit; ti[t_fillarr].print = arr_print; ti[t_fillslice].print = arr_print; + ti[t_fillarr].isArr = true; ti[t_fillslice].isArr = true; ti[t_fillarr].canStore = fillarr_canStore; } + +B withFill(B x, B fill) { // consumes both + assert(isArr(x)); + switch(v(x)->type) { + case t_i32arr : case t_i32slice : if(fill.u == m_i32(0 ).u) return x; break; + case t_c32arr : case t_c32slice : if(fill.u == m_c32(' ').u) return x; break; + case t_fillslice: if (equal(c(FillArr,c(Slice,x)->p)->fill, fill)) { dec(fill); return x; } break; + case t_fillarr: if (equal(c(FillArr,x)->fill, fill)) { dec(fill); return x; } + if (reusable(x)) { + dec(c(FillArr, x)->fill); + c(FillArr, x)->fill = fill; + return x; + } + break; + } + B r = m_arr(fsizeof(FillArr,a,B,a(x)->ia), t_fillarr); + arr_shCopy(r, x); + c(FillArr,r)->fill = fill; + B* a = c(FillArr,r)->a; + usz ia = a(x)->ia; + BS2B xget = TI(x).get; + for (usz i = 0; i < ia; i++) a[i] = xget(x,i); + dec(x); + return r; +} \ No newline at end of file diff --git a/src/gc.c b/src/gc.c new file mode 100644 index 00000000..12e888da --- /dev/null +++ b/src/gc.c @@ -0,0 +1,99 @@ +#pragma once +#include "h.h" + + +u64 gc_depth = 1; +void gc_disable() { gc_depth++; } +void gc_enable() { gc_depth--; } + +vfn gc_roots[16]; +u32 gc_rootSz; +void gc_addFn(vfn f) { + if (gc_rootSz>=16) err("Too many GC roots"); + gc_roots[gc_rootSz++] = f; +} +B gc_rootObjs[256]; +u32 gc_rootObjSz; +void gc_add(B x) { + if (gc_rootObjSz>=256) err("Too many GC root objects"); + gc_rootObjs[gc_rootObjSz++] = x; +} + +#ifdef LOG_GC +u64 gc_visitBytes, gc_visitCount, gc_freedBytes, gc_freedCount; +#endif + +u8 gc_tagCurr = 0x80; // if no gc is running, this is what all objects will have +u8 gc_tagNew = 0x00; +void mm_visit(B x) { + #ifdef HEAP_VERIFY + if(heapVerify_visit(x)) return; + #endif + + if (!isVal(x)) return; + u8 p = v(x)->mmInfo; + if ((p&0x80)==gc_tagNew) return; + v(x)->mmInfo = p^0x80; + #ifdef LOG_GC + gc_visitBytes+= mm_size(v(x)); gc_visitCount++; + #endif + TI(x).visit(x); +} +void mm_visitP(void* xp) { + #ifdef HEAP_VERIFY + if(heapVerify_visitP(xp)) return; + #endif + + Value* x = (Value*)xp; + u8 p = x->mmInfo; + if ((p&0x80)==gc_tagNew) return; + x->mmInfo = p^0x80; + #ifdef LOG_GC + gc_visitBytes+= mm_size(x); gc_visitCount++; + #endif + ti[x->type].visit(tag(x, OBJ_TAG)); +} +void gc_tryFree(Value* v) { + u8 t = v->type; + #ifdef DEBUG + if (t==t_freed) err("GC found t_freed\n"); + #endif + if (t!=t_empty & (v->mmInfo&0x80)==gc_tagCurr) { + if (t==t_shape) return; + #ifdef DONT_FREE + v->flags = t; + #endif + #ifdef LOG_GC + gc_freedBytes+= mm_size(v); gc_freedCount++; + #endif + v->type = t_freed; + ti[t].free(tag(v, OBJ_TAG)); + // Object may not be immediately freed if it's not a part of a cycle, but instead a descendant of one. + // It will be freed when the cycle is freed, and the t_freed type ensures it doesn't double-free itself + } +} + + +void gc_visitRoots() { + for (u32 i = 0; i < gc_rootSz; i++) gc_roots[i](); + for (u32 i = 0; i < gc_rootObjSz; i++) mm_visit(gc_rootObjs[i]); +} +void gc_forceGC() { + #ifdef LOG_GC + u64 start = nsTime(); + gc_visitBytes = 0; gc_freedBytes = 0; + gc_visitCount = 0; gc_freedCount = 0; + #endif + gc_visitRoots(); + mm_forHeap(gc_tryFree); + gc_tagNew = gc_tagCurr; + gc_tagCurr^= 0x80; + #ifdef LOG_GC + fprintf(stderr, "GC kept %ldB from %ld objects, freed %ldB from %ld objects; took %.3fms\n", gc_visitBytes, gc_visitCount, gc_freedBytes, gc_freedCount, (nsTime()-start)/1e6); + #endif +} + + +void gc_maybeGC() { + if (!gc_depth) gc_forceGC(); +} \ No newline at end of file diff --git a/src/h.h b/src/h.h index b6f22bd6..f5c44bb6 100644 --- a/src/h.h +++ b/src/h.h @@ -34,10 +34,10 @@ CTR_FOR(CTR_DEF) #define VALIDATE(x) validate(x) // preferred validating level #else #define assert(x) {if (!(x)) __builtin_unreachable();} - #define VALIDATE(x) x + #define VALIDATE(x) (x) #endif -#define fsizeof(T,F,E,n) (offsetof(T, F) + sizeof(E)*n) // type; FAM name; FAM type; amount +#define fsizeof(T,F,E,n) (offsetof(T, F) + sizeof(E)*(n)) // type; FAM name; FAM type; amount #define ftag(x) ((u64)(x) << 48) #define tag(v, t) b(((u64)(v)) | ftag(t)) // .111111111110000000000000000000000000000000000000000000000000000 infinity @@ -61,7 +61,7 @@ enum Type { /* 1*/ t_fun_def, t_fun_block, /* 3*/ t_md1_def, t_md1_block, /* 5*/ t_md2_def, t_md2_block, - /* 7*/ t_noGC, // doesn't get visited, shouldn't be unallocated by gc + /* 7*/ t_shape, // doesn't get visited, shouldn't be unallocated by gc /* 8*/ t_fork, t_atop, /*10*/ t_md1D, t_md2D, t_md2H, @@ -70,12 +70,12 @@ enum Type { /*17*/ t_hslice, t_i32slice, t_fillslice, t_c32slice, /*21*/ t_comp, t_block, t_body, t_scope, - + /*25*/ t_freed, Type_MAX }; char* format_type(u8 u) { switch(u) { default: return"(unknown type)"; - case t_empty:return"empty"; case t_noGC:return"noGC"; + case t_empty:return"empty"; case t_shape:return"shape"; case t_fun_def:return"fun_def"; case t_fun_block:return"fun_block"; case t_md1_def:return"md1_def"; case t_md1_block:return"md1_block"; case t_md2_def:return"md2_def"; case t_md2_block:return"md2_block"; @@ -84,6 +84,7 @@ char* format_type(u8 u) { case t_harr :return"harr" ; case t_i32arr :return"i32arr" ; case t_fillarr :return"fillarr" ; case t_c32arr :return"c32arr" ; case t_hslice:return"hslice"; case t_i32slice:return"i32slice"; case t_fillslice:return"fillslice"; case t_c32slice:return"c32slice"; case t_comp:return"comp"; case t_block:return"block"; case t_body:return"body"; case t_scope:return"scope"; + case t_freed:return"(freed by GC)"; } } @@ -100,7 +101,7 @@ char* format_pf(u8 u) { case pf_add:return"+"; case pf_sub:return"-"; case pf_mul:return"×"; case pf_div:return"÷"; case pf_pow:return"⋆"; case pf_floor:return"⌊"; case pf_eq:return"="; case pf_le:return"≤"; case pf_log:return"⋆⁼"; case pf_shape:return"⥊"; case pf_pick:return"⊑"; case pf_ud:return"↕"; case pf_pair:return"{𝕨‿𝕩}"; case pf_fne:return"≢"; case pf_feq:return"≡"; case pf_lt:return"⊣"; case pf_rt:return"⊢"; case pf_fmtF:case pf_fmtN:return"⍕"; case pf_fork:return"(fork)"; case pf_atop:return"(atop)"; case pf_md1d:return"(derived 1-modifier)"; case pf_md2d:return"(derived 2-modifier)"; - case pf_type:return"•Type"; case pf_decp:return"Decompose"; case pf_primInd:return"•PrimInd"; case pf_glyph:return"•Glyph"; case pf_fill:return"•FillFn"; + case pf_type:return"•Type"; case pf_decp:return"•Decompose"; case pf_primInd:return"•PrimInd"; case pf_glyph:return"•Glyph"; case pf_fill:return"•FillFn"; case pf_grLen:return"•GroupLen"; case pf_grOrd:return"•groupOrd"; case pf_asrt:return"!"; case pf_sys:return"•getsys"; case pf_internal:return"•Internal"; } } @@ -114,6 +115,25 @@ char* format_pm1(u8 u) { case pm1_tbl: return"⌜"; case pm1_scan: return"`"; } } +enum PrimMd2 { + pm2_none, + pm2_val, pm2_fillBy, // md2.c +}; +char* format_pm2(u8 u) { + switch(u) { + default: case pf_none: return"(unknown 1-modifier)"; + case pm2_val: return"⊘"; case pm2_fillBy: return"•_fillBy_"; + } +} + + +#ifdef USE_VALGRIND +#include +#include +void pst(char* msg) { + VALGRIND_PRINTF_BACKTRACE("%s", msg); +} +#endif typedef union B { u64 u; @@ -128,6 +148,9 @@ typedef struct Value { u8 flags; // is sorted/a permutation/whatever in the future, currently primitive index for self-hosted runtime u8 type; // access into TypeInfo among generally knowing what type of object this is ur extra; // whatever object-specific stuff. Rank for arrays, id for functions + #ifdef OBJ_COUNTER + u64 uid; + #endif } Value; typedef struct Arr { struct Value; @@ -137,13 +160,25 @@ typedef struct Arr { // memory manager typedef void (*V2v)(Value*); +typedef void (*vfn)(); +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_disable(); // gc starts disabled +void gc_enable(); // can be nested (e.g. gc_disable(); gc_disable(); gc_enable(); will keep gc disabled until another gc_enable(); ) +void gc_maybeGC(); // gc if that seems necessary +void gc_forceGC(); // force a gc; who knows what happens if gc is disabled (probably should error) +void gc_visitRoots(); void* mm_allocN(usz sz, u8 type); void mm_free(Value* x); void mm_visit(B x); +void mm_visitP(void* x); u64 mm_round(usz x); u64 mm_size(Value* x); -u64 mm_totalAllocated(); + +u64 mm_heapAllocated(); +u64 mm_heapUsed(); + void mm_forHeap(V2v f); B mm_alloc(usz sz, u8 type, u64 tag) { assert(tag>1LL<<16 || tag==0); // make sure it's `ftag`ged :| @@ -174,8 +209,8 @@ void print_vmStack(); B validate(B x); B recvalidate(B x); #else - #define validate(x) x - #define recvalidate(x) x + #define validate(x) (x) + #define recvalidate(x) (x) #endif B err(char* s) { puts(s); fflush(stdout); @@ -211,11 +246,6 @@ typedef struct ShArr { struct Value; usz a[]; } ShArr; -usz* allocSh(ur r) { - assert(r>0); - B x = mm_alloc(fsizeof(ShArr, a, usz, r), t_noGC, ftag(OBJ_TAG)); - return ((ShArr*)v(x))->a; -} ShArr* shObj(B x) { return (ShArr*)((u64)a(x)->sh-offsetof(ShArr,a)); } void decSh(B x) { if (rnk(x)>1) ptr_dec(shObj(x)); } @@ -227,7 +257,7 @@ void arr_shVec(B x, usz ia) { usz* arr_shAlloc(B x, usz ia, usz r) { a(x)->ia = ia; srnk(x,r); - if (r>1) return a(x)->sh = allocSh(r); + if (r>1) return a(x)->sh = c(ShArr,mm_alloc(fsizeof(ShArr, a, usz, r), t_shape, ftag(OBJ_TAG)))->a; a(x)->sh = &a(x)->ia; return 0; } @@ -282,6 +312,7 @@ typedef struct Slice { B p; } Slice; void slice_free(B x) { dec(c(Slice,x)->p); decSh(x); } +void slice_visit(B x) { mm_visit(c(Slice,x)->p); } void slice_print(B x) { arr_print(x); } @@ -297,24 +328,30 @@ typedef B (*BBBBB2B)(B, B, B, B, B); typedef bool (*B2b)(B); typedef struct TypeInfo { - B2v free; // expects refc==0 + B2v free; // expects refc==0, type may be cleared to t_empty for garbage collection BS2B get; // increments result, doesn't consume arg; TODO figure out if this should never allocate, so GC wouldn't happen + BS2B getU; // like get, but doesn't increment result (mostly equivalent to `B t=get(…); dec(t); t`) BB2B m1_d; // consume all args; (m, f) BBB2B m2_d; // consume all args; (m, f, g) BS2B slice; // consumes; create slice from given starting position; add ia, rank, shape yourself B2b canStore; // doesn't consume B2v print; // doesn't consume - B2v visit; // for GC when that comes around + B2v visit; // call mm_visit for all referents B2B decompose; // consumes; must return a HArr + bool isArr; } TypeInfo; TypeInfo ti[Type_MAX]; #define TI(x) (ti[v(x)->type]) void do_nothing(B x) { } -void def_print(B x) { printf("(type %d)", v(x)->type); } -B get_self(B x, usz n) { return x; } +void empty_free(B x) { err("FREEING EMPTY\n"); } +void builtin_free(B x) { err("FREEING BUILTIN\n"); } +void def_visit(B x) { printf("(no visit for %d=%s)\n", v(x)->type, format_type(v(x)->type)); } +void def_print(B x) { printf("(%d=%s)", v(x)->type, format_type(v(x)->type)); } +B def_get (B x, usz n) { return inc(x); } +B def_getU(B x, usz n) { return x; } B def_m1_d(B m, B f ) { return err("cannot derive this"); } B def_m2_d(B m, B f, B g) { return err("cannot derive this"); } B def_slice(B x, usz s) { return err("cannot slice non-array!"); } @@ -322,16 +359,24 @@ B def_decompose(B x) { return m_v2(m_i32((isFun(x)|isMd(x))? 0 : -1),x); } bool def_canStore(B x) { return false; } B bi_nothing, bi_noVar, bi_badHdr, bi_optOut, bi_noFill; void hdr_init() { - for (i32 i = 0; i < Type_MAX; ++i) { - ti[i].visit = ti[i].free = do_nothing; - ti[i].get = get_self; + for (i32 i = 0; i < Type_MAX; i++) { + ti[i].free = do_nothing; + ti[i].visit = def_visit; + ti[i].get = def_get; + ti[i].getU = def_get; ti[i].print = def_print; - ti[i].m1_d = def_m1_d; - ti[i].m2_d = def_m2_d; + ti[i].m1_d = def_m1_d; + ti[i].m2_d = def_m2_d; + ti[i].isArr = false; ti[i].decompose = def_decompose; - ti[i].slice = def_slice; - ti[i].canStore = def_canStore; + ti[i].slice = def_slice; + ti[i].canStore = def_canStore; } + ti[t_empty].free = empty_free; + ti[t_freed].free = do_nothing; + ti[t_shape].visit = do_nothing; + ti[t_fun_def].visit = ti[t_md1_def].visit = ti[t_md2_def].visit = do_nothing; + ti[t_fun_def].free = ti[t_md1_def].free = ti[t_md2_def].free = builtin_free; bi_nothing = tag(0, TAG_TAG); bi_noVar = tag(1, TAG_TAG); bi_badHdr = tag(2, TAG_TAG); @@ -363,7 +408,8 @@ void ptr_dec(void* x) { if(!--((Value*)x)->refc) value_free(tag(x, OBJ_TAG), x); void ptr_inc(void* x) { ((Value*)x)->refc++; } void ptr_decR(void* x) { if(!--((Value*)x)->refc) value_freeR1(x); } void decR(B x) { - if (!isVal(x)) return; Value* vx = v(x); + if (!isVal(x)) return; + Value* vx = v(x); if(!--vx->refc) value_freeR2(vx, x); } bool reusable(B x) { return v(x)->refc==1; } @@ -377,12 +423,20 @@ void print(B x) { printf("%g", x.f); } else if (isC32(x)) { if ((u32)x.u>=32) { printf("'"); printUTF8((u32)x.u); printf("'"); } - else printf("\\x%x", (u32)x.u); + else if((u32)x.u>15) printf("\\x%x", (u32)x.u); + else printf("\\x0%x", (u32)x.u); } else if (isI32(x)) { printf("%d", (i32)x.u); } else if (isVal(x)) { #ifdef DEBUG - if (isVal(x) && v(x)->refc<0) {printf("(FREED)"); exit(1);} else + if (isVal(x) && (v(x)->type==t_freed || v(x)->type==t_empty)) { + u8 t = v(x)->type; + v(x)->type = v(x)->flags; + printf(t==t_freed?"FREED:":"EMPTY:"); + TI(x).print(x); + v(x)->type = t; + return; + } #endif TI(x).print(x); } @@ -458,7 +512,6 @@ B c2(B f, B w, B x) { // BQN-call f dyadically; consumes w,x } - typedef struct Md1 { struct Value; BB2B c1; // f(md1d{this,f}, x); consumes x @@ -475,14 +528,14 @@ B m_md2H(B m, B g); B m_fork(B f, B g, B h); B m_atop( B g, B h); -void arr_print(B x) { +void arr_print(B x) { // should accept refc=0 arguments for debugging purposes usz r = rnk(x); - BS2B xget = TI(x).get; + BS2B xgetU = TI(x).getU; usz ia = a(x)->ia; if (r!=1) { if (r==0) { printf("<"); - print(xget(x,0)); + print(xgetU(x,0)); return; } usz* sh = a(x)->sh; @@ -493,13 +546,11 @@ void arr_print(B x) { printf("⥊"); } else if (ia>0) { for (usz i = 0; i < ia; i++) { - B c = xget(x,i); - bool is = isC32(c); - dec(c); - if (!is) goto reg; + B c = xgetU(x,i); + if (!isC32(c) || (u32)c.u=='\n') goto reg; } printf("\""); - for (usz i = 0; i < ia; i++) printUTF8((u32)xget(x,i).u); // c32, no need to decrement + for (usz i = 0; i < ia; i++) printUTF8((u32)xgetU(x,i).u); // c32, no need to decrement printf("\""); return; } @@ -507,14 +558,19 @@ void arr_print(B x) { printf("⟨"); for (usz i = 0; i < ia; i++) { if (i!=0) printf(", "); - B c = xget(x,i); - print(c); - dec(c); + print(xgetU(x,i)); } printf("⟩"); } +#include +u64 nsTime() { + struct timespec t; + timespec_get(&t, TIME_UTC); + return t.tv_sec*1000000000ull + t.tv_nsec; +} + #ifdef DEBUG B validate(B x) { if (!isVal(x)) return x; @@ -523,7 +579,7 @@ void arr_print(B x) { print(x); puts(""); fflush(stdout); err(""); } - if (isArr(x)) { + if (isArr(x) && v(x)->type!=t_freed) { ur r = rnk(x); if (r<=1) assert(a(x)->sh == &a(x)->ia); else validate(tag(shObj(x),OBJ_TAG)); @@ -556,7 +612,7 @@ u32** actrs; #endif #endif -static void onAlloc(usz sz, u8 type) { +static inline void onAlloc(usz sz, u8 type) { #ifdef ALLOC_STAT if (!ctr_a) { #ifdef ALLOC_SIZES @@ -574,11 +630,14 @@ static void onAlloc(usz sz, u8 type) { talloc+= sz; #endif } -static void onFree(Value* x) { +static inline void onFree(Value* x) { #ifdef ALLOC_STAT ctr_f[x->type]++; #endif #ifdef DEBUG - x->refc = 0x61616161; + // u32 undef; + // x->refc = undef; + x->refc = -1431655000; #endif + // x->refc = 0x61616161; } \ No newline at end of file diff --git a/src/harr.c b/src/harr.c index 08548c4d..b5af3db4 100644 --- a/src/harr.c +++ b/src/harr.c @@ -59,6 +59,7 @@ B m_caf64(usz sz, f64* a) { return r.b; } +// consumes all B m_v1(B a ) { HArr_p r = m_harrv(1); r.a[0] = a; return r.b; } B m_v2(B a, B b ) { HArr_p r = m_harrv(2); r.a[0] = a; r.a[1] = b; return r.b; } B m_v3(B a, B b, B c ) { HArr_p r = m_harrv(3); r.a[0] = a; r.a[1] = b; r.a[2] = c; return r.b; } @@ -80,20 +81,29 @@ B harr_slice (B x, usz s) {return m_hslice(x , c(HArr ,x)->a+ B hslice_slice(B x, usz s) { B r = m_hslice(inc(c(HSlice,x)->p), c(HSlice,x)->a+s); dec(x); return r; } -B harr_get (B x, usz n) { VT(x,t_harr ); return inc(c(HArr ,x)->a[n]); } -B hslice_get(B x, usz n) { VT(x,t_hslice); return inc(c(HSlice,x)->a[n]); } +B harr_get (B x, usz n) { VT(x,t_harr ); return inc(c(HArr ,x)->a[n]); } +B hslice_get (B x, usz n) { VT(x,t_hslice); return inc(c(HSlice,x)->a[n]); } +B harr_getU (B x, usz n) { VT(x,t_harr ); return c(HArr ,x)->a[n] ; } +B hslice_getU(B x, usz n) { VT(x,t_hslice); return c(HSlice,x)->a[n] ; } void harr_free(B x) { decSh(x); - B* p = harr_ptr(x); + B* p = c(HArr,x)->a; // don't use harr_ptr so type isn't checked usz ia = a(x)->ia; for (usz i = 0; i < ia; i++) dec(p[i]); } +void harr_visit(B x) { + usz ia = a(x)->ia; B* p = harr_ptr(x); + for (usz i = 0; i < ia; i++) mm_visit(p[i]); +} bool harr_canStore(B x) { return true; } void harr_init() { ti[t_harr].get = harr_get; ti[t_hslice].get = hslice_get; + ti[t_harr].getU = harr_getU; ti[t_hslice].getU = hslice_getU; ti[t_harr].slice = harr_slice; ti[t_hslice].slice = hslice_slice; ti[t_harr].free = harr_free; ti[t_hslice].free = slice_free; + ti[t_harr].visit = harr_visit; ti[t_hslice].visit = slice_visit; ti[t_harr].print = arr_print; ti[t_hslice].print = arr_print; + ti[t_harr].isArr = true; ti[t_hslice].isArr = true; ti[t_harr].canStore = harr_canStore; } diff --git a/src/heap.c b/src/heap.c new file mode 100644 index 00000000..0d357f4f --- /dev/null +++ b/src/heap.c @@ -0,0 +1,49 @@ +u32 heapVerify_mode = -1; + + +u64 heapUsed_ctr; +void heapUsedFn(Value* p) { heapUsed_ctr+= mm_size(p); } +u64 mm_heapUsed() { + heapUsed_ctr = 0; + mm_forHeap(heapUsedFn); + return heapUsed_ctr; +} + + +void heap_checkFn(Value* v) { + if (v->refc!=0) { + #ifdef OBJ_COUNTER + printf("delta %d for %s, uid %ld: ", v->refc, format_type(v->type), v->uid); + #else + printf("delta %d for %s: ", (i32)v->refc, format_type(v->type)); + #endif + print(tag(v,OBJ_TAG)); puts(""); + } +} +void heap_callVisit(Value* v) { + ti[v->type].visit(tag(v,OBJ_TAG)); +} +void heapVerify() { + #ifndef HEAP_VERIFY + err("heapVerify() HEAP_VERIFY to be defined"); + #endif + heapVerify_mode=0; mm_forHeap(heap_callVisit); gc_visitRoots(); + mm_forHeap(heap_checkFn); + heapVerify_mode=1; mm_forHeap(heap_callVisit); gc_visitRoots(); + heapVerify_mode=-1; +} + +#ifdef HEAP_VERIFY +bool heapVerify_visit(B x) { + if (heapVerify_mode==-1) return false; + if (isVal(x)) mm_visitP(v(x)); + return true; +} +bool heapVerify_visitP(void* x) { + if(heapVerify_mode==-1) return false; + Value* v = x; + if(heapVerify_mode==0) { v->refc--; if(ti[v->type].isArr && rnk(tag(v,OBJ_TAG))>1)heapVerify_visitP(shObj(tag(v,OBJ_TAG))); } + if(heapVerify_mode==1) { v->refc++; if(ti[v->type].isArr && rnk(tag(v,OBJ_TAG))>1)heapVerify_visitP(shObj(tag(v,OBJ_TAG))); } + return true; +} +#endif \ No newline at end of file diff --git a/src/i32arr.c b/src/i32arr.c index 9e60bce9..784d7992 100644 --- a/src/i32arr.c +++ b/src/i32arr.c @@ -65,8 +65,11 @@ bool i32arr_canStore(B x) { return q_i32(x); } void i32arr_init() { ti[t_i32arr].get = i32arr_get; ti[t_i32slice].get = i32slice_get; + ti[t_i32arr].getU = i32arr_get; ti[t_i32slice].getU = i32slice_get; ti[t_i32arr].slice = i32arr_slice; ti[t_i32slice].slice = i32slice_slice; ti[t_i32arr].free = i32arr_free; ti[t_i32slice].free = slice_free; + ti[t_i32arr].visit = do_nothing; ti[t_i32slice].visit = slice_visit; ti[t_i32arr].print = arr_print; ti[t_i32slice].print = arr_print; + ti[t_i32arr].isArr = true; ti[t_i32slice].isArr = true; ti[t_i32arr].canStore = i32arr_canStore; } diff --git a/src/main.c b/src/main.c index de6838b0..2d9bd371 100644 --- a/src/main.c +++ b/src/main.c @@ -2,14 +2,22 @@ #ifdef DEBUG // #define DEBUG_VM #endif -// #define ALLOC_STAT -// #define ALLOC_SIZES -// #define FORMATTER -// #define TIME -#define FAKE_RUNTIME false + +// #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 +// #define DONT_FREE // don't actually ever free objects, such that they can be printed after being freed for debugging +// #define OBJ_COUNTER // store a unique allocation number with each object for easier analysis +#define FAKE_RUNTIME false // whether to disable the self-hosted runtime + +// #define LOG_GC // log GC stats +// #define FORMATTER // use self-hosted formatter for output +// #define TIME // output runtime of every expression #include "h.h" -#include "mm_2buddy.c" +#include "heap.c" +#include "mm_buddy.c" #include "harr.c" #include "fillarr.c" #include "i32arr.c" @@ -38,23 +46,33 @@ Block* ca3(B b) { return r; } -#include -u64 nsTime() { - struct timespec t; - timespec_get(&t, TIME_UTC); - return t.tv_sec*1000000000ull + t.tv_nsec; +ssize_t getline(char** __lineptr, size_t* n, FILE* stream); + + +void printAllocStats() { + #ifdef ALLOC_STAT + printf("total ever allocated: %lu\n", talloc); + printf("allocated heap size: %ld\n", mm_heapAllocated()); + printf("used heap size: %ld\n", mm_heapUsed()); + printf("ctrA←"); for (i64 i = 0; i < Type_MAX; i++) { if(i)printf("‿"); printf("%lu", ctr_a[i]); } printf("\n"); + printf("ctrF←"); for (i64 i = 0; i < Type_MAX; i++) { if(i)printf("‿"); printf("%lu", ctr_f[i]); } printf("\n"); + u64 leakedCount = 0; + for (i64 i = 0; i < Type_MAX; i++) leakedCount+= ctr_a[i]-ctr_f[i]; + printf("leaked object count: %ld\n", leakedCount); + #ifdef ALLOC_SIZES + for(i64 i = 0; i < actrc; i++) { + u32* c = actrs[i]; + bool any = false; + for (i64 j = 0; j < Type_MAX; j++) if (c[j]) any=true; + if (any) { + printf("%ld", i*4); + for (i64 k = 0; k < Type_MAX; k++) printf("‿%u", c[k]); + printf("\n"); + } + } + #endif + #endif } - -u64 temp_heapUsage; -void heapUsedFn(Value* p) { temp_heapUsage+= mm_size(p); } -u64 heapUsed() { - temp_heapUsage = 0; - mm_forHeap(heapUsedFn); - return temp_heapUsage; -} - -__ssize_t getline (char **__restrict __lineptr, size_t *restrict n, FILE *restrict stream); - int main() { hdr_init(); harr_init(); @@ -80,20 +98,28 @@ int main() { /* ˝`∘○⊸⟜⌾⊘◶⎉ */ bi_N , bi_scan, bi_N , bi_N , bi_N , bi_N , bi_N , bi_val, bi_N, bi_N, /* ⚇⍟ */ bi_N , bi_fill }; + for (i32 i = 0; i < 62; i++) inc(fruntime[i]); B frtObj = m_caB(62, fruntime); + Block* runtime_b = compile( #include "runtime" ); B rtRes = m_funBlock(runtime_b, 0); ptr_dec(runtime_b); B rtObj = TI(rtRes).get(rtRes,0); B rtFinish = TI(rtRes).get(rtRes,1); + dec(rtRes); B* runtime = toHArr(rtObj)->a; runtimeLen = c(Arr,rtObj)->ia; for (usz i = 0; i < runtimeLen; i++) { if (isVal(runtime[i])) v(runtime[i])->flags|= i+1; } - c1(rtFinish, m_v2(inc(bi_decp), inc(bi_primInd))); + dec(c1(rtFinish, m_v2(inc(bi_decp), inc(bi_primInd)))); dec(rtFinish); + + + B compArg = m_v2(FAKE_RUNTIME? frtObj : rtObj, inc(bi_sys)); dec(FAKE_RUNTIME? rtObj : frtObj); + gc_add(compArg); + // uncomment to use src/interp; needed for test.bqn // Block* c = ca3( @@ -107,6 +133,8 @@ int main() { #include "compiler" ); B comp = m_funBlock(comp_b, 0); ptr_dec(comp_b); + gc_add(comp); + #ifdef FORMATTER Block* fmt_b = compile( @@ -114,6 +142,7 @@ int main() { ); B fmtM = m_funBlock(fmt_b, 0); ptr_dec(fmt_b); B fmt = TI(fmtM).m1_d(fmtM, m_caB(4, (B[]){inc(bi_type), inc(bi_decp), inc(bi_fmtF), inc(bi_fmtN)})); + gc_add(fmt); #endif @@ -138,16 +167,12 @@ int main() { // comp = m_funBlock(cbc_b, 0); // free(c_src); // } - - B compArg = m_v2(FAKE_RUNTIME? frtObj : rtObj, bi_sys); - while (true) { // exit by evaluating an empty expression char* ln = NULL; size_t gl = 0; getline(&ln, &gl, stdin); if (ln[0]==10) break; - B obj = fromUTF8(ln, strlen(ln)); - B cbc = c2(comp, inc(compArg), obj); + B cbc = c2(comp, inc(compArg), fromUTF8(ln, strlen(ln))); free(ln); Block* cbc_b = ca3(cbc); @@ -159,6 +184,7 @@ int main() { #else B res = m_funBlock(cbc_b, 0); #endif + ptr_dec(cbc_b); #ifdef FORMATTER B resFmt = c1(fmt, res); @@ -167,34 +193,13 @@ int main() { #else pr("", res); #endif - ptr_dec(cbc_b); + + gc_forceGC(); + #ifdef DEBUG + #endif } - dec(rtRes); - dec(comp); - CTR_FOR(CTR_PRINT) // printf("done\n");fflush(stdout); while(1); - #ifdef ALLOC_STAT - printf("total ever allocated: %lu\n", talloc); - printf("final heap size: %ld\n", mm_totalAllocated()); - printf("leaked heap size: %ld\n", heapUsed()); - printf("ctrA←"); for (i64 i = 0; i < Type_MAX; i++) { if(i)printf("‿"); printf("%lu", ctr_a[i]); } printf("\n"); - printf("ctrF←"); for (i64 i = 0; i < Type_MAX; i++) { if(i)printf("‿"); printf("%lu", ctr_f[i]); } printf("\n"); - u64 leakedCount = 0; - for (i64 i = 0; i < Type_MAX; i++) leakedCount+= ctr_a[i]-ctr_f[i]; - printf("leaked object count: %ld\n", leakedCount); - #ifdef ALLOC_SIZES - for(i64 i = 0; i < actrc; i++) { - u32* c = actrs[i]; - bool any = false; - for (i64 j = 0; j < Type_MAX; j++) if (c[j]) any=true; - if (any) { - printf("%ld", i*4); - for (i64 k = 0; k < Type_MAX; k++) printf("‿%u", c[k]); - printf("\n"); - } - } - #endif - #endif + printAllocStats(); } diff --git a/src/md1.c b/src/md1.c index 03aeea2c..6716bd6f 100644 --- a/src/md1.c +++ b/src/md1.c @@ -100,8 +100,9 @@ B scan_c1(B d, B x) { B f = c(Md1D,d)->f; usz ia = a(x)->ia; if (xr==0) return err("`: argument cannot be a scalar"); if (ia==0) return x; - HArr_p r = (v(x)->type==t_harr && reusable(x))? harr_parts(inc(x)) : m_harrc(x); - BS2B xget = TI(x).get; + bool reuse = v(x)->type==t_harr && reusable(x); + HArr_p r = reuse? harr_parts(inc(x)) : m_harrc(x); + BS2B xget = reuse? TI(x).getU : TI(x).get; if (xr==1) { r.a[0] = xget(x,0); for (usz i = 1; i < ia; i++) r.a[i] = c2(f, inc(r.a[i-1]), xget(x,i)); @@ -115,8 +116,10 @@ B scan_c1(B d, B x) { B f = c(Md1D,d)->f; } B scan_c2(B d, B w, B x) { B f = c(Md1D,d)->f; if (!isArr(x)) return err("`: 𝕩 cannot be a scalar"); - ur xr = rnk(x); usz* xsh = a(x)->sh; BS2B xget = TI(x).get; usz ia = a(x)->ia; - HArr_p r = (v(x)->type==t_harr && reusable(x))? harr_parts(inc(x)) : m_harrc(x); + ur xr = rnk(x); usz* xsh = a(x)->sh; usz ia = a(x)->ia; + bool reuse = v(x)->type==t_harr && reusable(x); + HArr_p r = reuse? harr_parts(inc(x)) : m_harrc(x); + BS2B xget = reuse? TI(x).getU : TI(x).get; if (isArr(w)) { ur wr = rnk(w); usz* wsh = a(w)->sh; BS2B wget = TI(w).get; if (xr==0) return err("`: 𝕩 cannot be a scalar"); @@ -138,9 +141,9 @@ B scan_c2(B d, B w, B x) { B f = c(Md1D,d)->f; } -#define ba(NAME) bi_##NAME = mm_alloc(sizeof(Md1), t_md1_def, ftag(MD1_TAG)); c(Md1,bi_##NAME)->c2 = NAME##_c2; c(Md1,bi_##NAME)->c1 = NAME##_c1 ; c(Md1,bi_##NAME)->extra=pm1_##NAME; -#define bd(NAME) bi_##NAME = mm_alloc(sizeof(Md1), t_md1_def, ftag(MD1_TAG)); c(Md1,bi_##NAME)->c2 = NAME##_c2; c(Md1,bi_##NAME)->c1 = c1_invalid; c(Md1,bi_##NAME)->extra=pm1_##NAME; -#define bm(NAME) bi_##NAME = mm_alloc(sizeof(Md1), t_md1_def, ftag(MD1_TAG)); c(Md1,bi_##NAME)->c2 = c2_invalid;c(Md1,bi_##NAME)->c1 = NAME##_c1 ; c(Md1,bi_##NAME)->extra=pm1_##NAME; +#define ba(NAME) bi_##NAME = mm_alloc(sizeof(Md1), t_md1_def, ftag(MD1_TAG)); c(Md1,bi_##NAME)->c2 = NAME##_c2; c(Md1,bi_##NAME)->c1 = NAME##_c1 ; c(Md1,bi_##NAME)->extra=pm1_##NAME; gc_add(bi_##NAME); +#define bd(NAME) bi_##NAME = mm_alloc(sizeof(Md1), t_md1_def, ftag(MD1_TAG)); c(Md1,bi_##NAME)->c2 = NAME##_c2; c(Md1,bi_##NAME)->c1 = c1_invalid; c(Md1,bi_##NAME)->extra=pm1_##NAME; gc_add(bi_##NAME); +#define bm(NAME) bi_##NAME = mm_alloc(sizeof(Md1), t_md1_def, ftag(MD1_TAG)); c(Md1,bi_##NAME)->c2 = c2_invalid;c(Md1,bi_##NAME)->c1 = NAME##_c1 ; c(Md1,bi_##NAME)->extra=pm1_##NAME; gc_add(bi_##NAME); void print_md1_def(B x) { printf("%s", format_pm1(c(Md1,x)->extra)); } diff --git a/src/md2.c b/src/md2.c index 1fcd3577..7403c590 100644 --- a/src/md2.c +++ b/src/md2.c @@ -8,12 +8,16 @@ B val_c2(B d, B w, B x) { return c2(c(Md2D,d)->g, w,x); } B fillBy_c1(B d, B x) { return c1(c(Md2D,d)->f, x); } B fillBy_c2(B d, B w, B x) { return c2(c(Md2D,d)->f, w,x); } -#define ba(NAME) bi_##NAME = mm_alloc(sizeof(Md2), t_md2_def, ftag(MD2_TAG)); c(Md2,bi_##NAME)->c2 = NAME##_c2; c(Md2,bi_##NAME)->c1 = NAME##_c1; -#define bd(NAME) bi_##NAME = mm_alloc(sizeof(Md2), t_md2_def, ftag(MD2_TAG)); c(Md2,bi_##NAME)->c2 = NAME##_c2; c(Md2,bi_##NAME)->c1 = c1_invalid; -#define bm(NAME) bi_##NAME = mm_alloc(sizeof(Md2), t_md2_def, ftag(MD2_TAG)); c(Md2,bi_##NAME)->c2 = c2_invalid;c(Md2,bi_##NAME)->c1 = NAME##_c1; +#define ba(NAME) bi_##NAME = mm_alloc(sizeof(Md2), t_md2_def, ftag(MD2_TAG)); c(Md2,bi_##NAME)->c2 = NAME##_c2; c(Md2,bi_##NAME)->c1 = NAME##_c1; c(Md2,bi_##NAME)->extra=pm2_##NAME; gc_add(bi_##NAME); +#define bd(NAME) bi_##NAME = mm_alloc(sizeof(Md2), t_md2_def, ftag(MD2_TAG)); c(Md2,bi_##NAME)->c2 = NAME##_c2; c(Md2,bi_##NAME)->c1 = c1_invalid; c(Md1,bi_##NAME)->extra=pm2_##NAME; gc_add(bi_##NAME); +#define bm(NAME) bi_##NAME = mm_alloc(sizeof(Md2), t_md2_def, ftag(MD2_TAG)); c(Md2,bi_##NAME)->c2 = c2_invalid;c(Md2,bi_##NAME)->c1 = NAME##_c1; c(Md1,bi_##NAME)->extra=pm2_##NAME; gc_add(bi_##NAME); + +void print_md2_def(B x) { printf("%s", format_pm2(c(Md1,x)->extra)); } B bi_val, bi_fillBy; -void md2_init() { ba(val) ba(fillBy) } +void md2_init() { ba(val) ba(fillBy) + ti[t_md2_def].print = print_md2_def; +} #undef ba #undef bd diff --git a/src/mm_2buddy.c b/src/mm_2buddy.c index 5d5849ac..82d4382f 100644 --- a/src/mm_2buddy.c +++ b/src/mm_2buddy.c @@ -1,4 +1,5 @@ #include "h.h" +#include "gc.c" #include #ifndef MAP_NORESERVE @@ -32,13 +33,20 @@ struct EmptyValue { // needs set: mmInfo; type=t_empty; next; everything else ca #undef BN #undef BSZ #undef BSZI - +#ifdef OBJ_COUNTER +u64 currObjCounter; +#endif void* mm_allocN(usz sz, u8 type) { assert(sz>12); onAlloc(sz, type); u8 b1 = 64-__builtin_clzl(sz-1ull); - if (sz <= (3ull<<(b1-2))) return b3_allocL(b1-2, type); - return b1_allocL(b1, type); + Value* r; + if (sz <= (3ull<<(b1-2))) r = b3_allocL(b1-2, type); + else r = b1_allocL(b1, type); + #ifdef OBJ_COUNTER + r->uid = currObjCounter++; + #endif + return r; } void mm_free(Value* x) { if (x->mmInfo&64) b3_free(x); @@ -60,6 +68,6 @@ u64 mm_size(Value* x) { if (m&64) return 3ull<<(x->mmInfo&63); else return 1ull<<(x->mmInfo&63); } -u64 mm_totalAllocated() { - return b1_totalAllocated() + b3_totalAllocated(); +u64 mm_heapAllocated() { + return b1_heapAllocated() + b3_heapAllocated(); } diff --git a/src/mm_buddy.c b/src/mm_buddy.c index b77e5447..0d8c752c 100644 --- a/src/mm_buddy.c +++ b/src/mm_buddy.c @@ -1,4 +1,5 @@ #include "h.h" +#include "gc.c" #include #ifndef MAP_NORESERVE @@ -11,20 +12,24 @@ struct EmptyValue { // needs set: mmInfo; type=t_empty; next; everything else ca EmptyValue* next; }; -#define BSZ(x) (1ull<<(x)) -#define BSZI(x) (64-__builtin_clzl((x)-1ull)) -#define MMI(x) x -#define BN(x) mm_##x +#define BSZ(X) (1ull<<(X)) +#define BSZI(X) (64-__builtin_clzl((X)-1ull)) +#define MMI(X) X +#define BN(X) mm_##X #include "mm_buddyTemplate.c" -void mm_visit(B x) { - -} +#ifdef OBJ_COUNTER +u64 currObjCounter; +#endif void* mm_allocN(usz sz, u8 type) { assert(sz>8); onAlloc(sz, type); - return mm_allocL(BSZI(sz), type); + Value* r = mm_allocL(BSZI(sz), type); + #ifdef OBJ_COUNTER + r->uid = currObjCounter++; + #endif + return r; } u64 mm_round(usz sz) { diff --git a/src/mm_buddyTemplate.c b/src/mm_buddyTemplate.c index a7c18b13..48a90bf3 100644 --- a/src/mm_buddyTemplate.c +++ b/src/mm_buddyTemplate.c @@ -25,6 +25,7 @@ static NOINLINE EmptyValue* BN(makeEmpty)(u8 bucket) { // result->next is garbag } if (cb >= 20) { u64 sz = BSZ(cb); + gc_maybeGC(); c = mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_NORESERVE|MAP_PRIVATE|MAP_ANON, -1, 0); if (alSize+1>=alCap) { alCap = alCap? alCap*2 : 1024; @@ -56,16 +57,30 @@ static NOINLINE EmptyValue* BN(makeEmpty)(u8 bucket) { // result->next is garbag void BN(free)(Value* x) { onFree(x); EmptyValue* c = (EmptyValue*) x; + #ifdef DONT_FREE + if (c->type!=t_freed) c->flags = c->type; + #else + u8 b = c->mmInfo&63; + c->next = buckets[b]; + buckets[b] = c; + #endif c->type = t_empty; - u8 b = c->mmInfo&63; - c->next = buckets[b]; - buckets[b] = c; + #ifdef USE_VALGRIND + VALGRIND_MAKE_MEM_NOACCESS(x, BSZ(c->mmInfo&63)); + VALGRIND_MAKE_MEM_DEFINED(&x->type, 1); + VALGRIND_MAKE_MEM_DEFINED(&x->mmInfo, 1); + #endif } void* BN(allocL)(u8 bucket, u8 type) { EmptyValue* x = buckets[bucket]; if (x==NULL) x = BN(makeEmpty)(bucket); else buckets[bucket] = x->next; + #ifdef USE_VALGRIND + VALGRIND_MAKE_MEM_UNDEFINED(x, BSZ(bucket)); + VALGRIND_MAKE_MEM_DEFINED(&x->mmInfo, 1); + #endif + x->mmInfo = (x->mmInfo&0x7f) | gc_tagCurr; x->flags = x->extra = x->type = 0; x->refc = 1; x->type = type; @@ -82,7 +97,7 @@ void BN(forHeap)(V2v f) { } } } -u64 BN(totalAllocated)() { +u64 BN(heapAllocated)() { u64 res = 0; for (u64 i = 0; i < alSize; i++) res+= al[i].sz; return res; diff --git a/src/mm_malloc.c b/src/mm_malloc.c index 7576e75f..f346c8ed 100644 --- a/src/mm_malloc.c +++ b/src/mm_malloc.c @@ -15,7 +15,17 @@ void* mm_allocN(usz sz, u8 type) { return x; } + +void gc_add(B x) { } +void gc_addFn(vfn f) { } +void gc_disable() { } +void gc_enable() { } +void gc_maybeGC() { } +void gc_forceGC() { } +void gc_visitRoots() { } void mm_visit(B x) { } +void mm_visitP(void* x) { } + u64 mm_round(usz x) { return x; } u64 mm_size(Value* x) { return -1; } u64 mm_totalAllocated() { return -1; } diff --git a/src/sfns.c b/src/sfns.c index 695585d1..fe4e8b65 100644 --- a/src/sfns.c +++ b/src/sfns.c @@ -114,9 +114,9 @@ B feq_c2(B t, B w, B x) { return m_i32(r); } -#define ba(NAME) bi_##NAME = mm_alloc(sizeof(Fun), t_fun_def, ftag(FUN_TAG)); c(Fun,bi_##NAME)->c2 = NAME##_c2; c(Fun,bi_##NAME)->c1 = NAME##_c1 ; c(Fun,bi_##NAME)->extra=pf_##NAME; -#define bd(NAME) bi_##NAME = mm_alloc(sizeof(Fun), t_fun_def, ftag(FUN_TAG)); c(Fun,bi_##NAME)->c2 = NAME##_c2; c(Fun,bi_##NAME)->c1 = c1_invalid; c(Fun,bi_##NAME)->extra=pf_##NAME; -#define bm(NAME) bi_##NAME = mm_alloc(sizeof(Fun), t_fun_def, ftag(FUN_TAG)); c(Fun,bi_##NAME)->c2 = c2_invalid;c(Fun,bi_##NAME)->c1 = NAME##_c1 ; c(Fun,bi_##NAME)->extra=pf_##NAME; +#define ba(NAME) bi_##NAME = mm_alloc(sizeof(Fun), t_fun_def, ftag(FUN_TAG)); c(Fun,bi_##NAME)->c2 = NAME##_c2; c(Fun,bi_##NAME)->c1 = NAME##_c1 ; c(Fun,bi_##NAME)->extra=pf_##NAME; gc_add(bi_##NAME); +#define bd(NAME) bi_##NAME = mm_alloc(sizeof(Fun), t_fun_def, ftag(FUN_TAG)); c(Fun,bi_##NAME)->c2 = NAME##_c2; c(Fun,bi_##NAME)->c1 = c1_invalid; c(Fun,bi_##NAME)->extra=pf_##NAME; gc_add(bi_##NAME); +#define bm(NAME) bi_##NAME = mm_alloc(sizeof(Fun), t_fun_def, ftag(FUN_TAG)); c(Fun,bi_##NAME)->c2 = c2_invalid;c(Fun,bi_##NAME)->c1 = NAME##_c1 ; c(Fun,bi_##NAME)->extra=pf_##NAME; gc_add(bi_##NAME); void print_fun_def(B x) { printf("%s", format_pf(c(Fun,x)->extra)); } diff --git a/src/sysfn.c b/src/sysfn.c index d49ea638..9519bc77 100644 --- a/src/sysfn.c +++ b/src/sysfn.c @@ -131,9 +131,9 @@ B internal_c2(B t, B w, B x) { B sys_c1(B t, B x); -#define ba(NAME) bi_##NAME = mm_alloc(sizeof(Fun), t_fun_def, ftag(FUN_TAG)); c(Fun,bi_##NAME)->c2 = NAME##_c2; c(Fun,bi_##NAME)->c1 = NAME##_c1 ; c(Fun,bi_##NAME)->extra=pf_##NAME; -#define bd(NAME) bi_##NAME = mm_alloc(sizeof(Fun), t_fun_def, ftag(FUN_TAG)); c(Fun,bi_##NAME)->c2 = NAME##_c2; c(Fun,bi_##NAME)->c1 = c1_invalid; c(Fun,bi_##NAME)->extra=pf_##NAME; -#define bm(NAME) bi_##NAME = mm_alloc(sizeof(Fun), t_fun_def, ftag(FUN_TAG)); c(Fun,bi_##NAME)->c2 = c2_invalid;c(Fun,bi_##NAME)->c1 = NAME##_c1 ; c(Fun,bi_##NAME)->extra=pf_##NAME; +#define ba(NAME) bi_##NAME = mm_alloc(sizeof(Fun), t_fun_def, ftag(FUN_TAG)); c(Fun,bi_##NAME)->c2 = NAME##_c2; c(Fun,bi_##NAME)->c1 = NAME##_c1 ; c(Fun,bi_##NAME)->extra=pf_##NAME; gc_add(bi_##NAME); +#define bd(NAME) bi_##NAME = mm_alloc(sizeof(Fun), t_fun_def, ftag(FUN_TAG)); c(Fun,bi_##NAME)->c2 = NAME##_c2; c(Fun,bi_##NAME)->c1 = c1_invalid; c(Fun,bi_##NAME)->extra=pf_##NAME; gc_add(bi_##NAME); +#define bm(NAME) bi_##NAME = mm_alloc(sizeof(Fun), t_fun_def, ftag(FUN_TAG)); c(Fun,bi_##NAME)->c2 = c2_invalid;c(Fun,bi_##NAME)->c1 = NAME##_c1 ; c(Fun,bi_##NAME)->extra=pf_##NAME; gc_add(bi_##NAME); B bi_type, bi_decp, bi_primInd, bi_glyph, bi_fill, bi_grLen, bi_grOrd, bi_asrt, bi_sys, bi_internal; void sysfn_init() { bm(type) bm(decp) bm(primInd) bm(glyph) ba(fill) ba(grLen) bd(grOrd) ba(asrt) bm(sys) bd(internal) } diff --git a/src/vm.c b/src/vm.c index 0f45c3fc..50b676d5 100644 --- a/src/vm.c +++ b/src/vm.c @@ -105,6 +105,7 @@ typedef struct Comp { struct Value; B bc; HArr* objs; + u32 blockAm; Block* blocks[]; } Comp; @@ -127,11 +128,11 @@ typedef struct Body { typedef struct Scope { struct Value; + Scope* psc; + u16 varAm; #ifdef DEBUG u64 bcInd; // DEBUG: place of this in bytecode array #endif - u16 varAm; - Scope* psc; B vars[]; } Scope; @@ -140,8 +141,9 @@ typedef struct Md1Block { struct Md1; Scope* sc; Block* bl; } Md1Block; typedef struct Md2Block { struct Md2; Scope* sc; Block* bl; } Md2Block; -Block* compile(B bcq, B objs, B blocks) { // consumes all - usz bam = a(blocks)->ia; +Block* compile(B bcq, B objs, B blocksq) { // consumes all + HArr* h = toHArr(blocksq); + usz bam = h->ia; // B* objPtr = harr_ptr(objs); usz objIA = a(objs)->ia; // for (usz i = 0; i < objIA; i++) objPtr[i] = c2(bi_fill, c1(bi_pick, inc(objPtr[i])), objPtr[i]); @@ -152,7 +154,8 @@ Block* compile(B bcq, B objs, B blocks) { // consumes all Comp* comp = mm_allocN(fsizeof(Comp,blocks,Block*,bam), t_comp); comp->bc = tag(bca, ARR_TAG); comp->objs = toHArr(objs); - B* blockDefs = toHArr(blocks)->a; + comp->blockAm = bam; + B* blockDefs = h->a; for (usz i = 0; i < bam; i++) { B cbld = blockDefs[i]; @@ -166,13 +169,11 @@ Block* compile(B bcq, B objs, B blocks) { // consumes all i32* scan = cbc; i32 ssz = 0, mssz=0; - bool needsV0 = false; while (*scan!=RETN & *scan!=RETD) { ssz+= stackDiff(scan); if (ssz>mssz) mssz = ssz; - if (*scan==LOCO|*scan==LOCM) { i32 d=scan[1]; i32 p=scan[2]; - if (d>U16_MAX) return c(Block,err("LOC_ too deep")); - if (d==0 & p==0) needsV0 = true; + if (*scan==LOCO | *scan==LOCM) { + if (scan[1]>U16_MAX) return c(Block,err("LOC_ too deep")); } scan = nextBC(scan); if (scan-bc >= bcl) return c(Block,err("no RETN/RETD found at end of bytecode")); @@ -183,6 +184,7 @@ Block* compile(B bcq, B objs, B blocks) { // consumes all body->bc = cbc; body->maxStack = mssz; body->varAm = vam; + ptr_inc(comp); Block* bl = mm_allocN(sizeof(Block), t_block); bl->body = body; @@ -194,8 +196,8 @@ Block* compile(B bcq, B objs, B blocks) { // consumes all Block* ret = c(Block,inc(tag(comp->blocks[0], OBJ_TAG))); // TODO store blocks in each body, then decrement each of comp->blocks; also then move temp block list out of Comp as it's useless then // for (usz i = 0; i < bam; i++) ptr_dec(comp->blocks[i]); - - dec(blocks); + ptr_dec(comp); + ptr_dec(h); return ret; } @@ -204,20 +206,20 @@ Scope* scd(Scope* sc, u16 d) { return sc; } -B v_set(Scope* sc, B s, B x, bool upd) { // frees s; returns previous value +void v_set(Scope* sc, B s, B x, bool upd) { // frees s, doesn't consume x if (isVar(s)) { sc = scd(sc, (u16)(s.u>>32)); B prev = sc->vars[(u32)s.u]; if (upd) { - if (prev.u==bi_noVar.u) return err("updating undefined variable"); + if (prev.u==bi_noVar.u) err("updating undefined variable"); dec(prev); } else { - if (prev.u!=bi_noVar.u) return err("redefining variable"); + if (prev.u!=bi_noVar.u) err("redefining variable"); } sc->vars[(u32)s.u] = inc(x); } else { VT(s, t_harr); - if (!shEq(s, x)) return err("spread assignment: mismatched shape"); + if (!shEq(s, x)) err("spread assignment: mismatched shape"); usz ia = a(x)->ia; B* sp = harr_ptr(s); BS2B xget = TI(x).get; @@ -228,7 +230,6 @@ B v_set(Scope* sc, B s, B x, bool upd) { // frees s; returns previous value } dec(s); } - return m_f64(0); } B v_get(Scope* sc, B s) { // get value representing s, replacing with bi_optOut; doesn't consume if (isVar(s)) { @@ -246,7 +247,7 @@ B v_get(Scope* sc, B s) { // get value representing s, replacing with bi_optOut; } } -// none consume anything consume +// all don't consume anything B m_funBlock(Block* bl, Scope* psc); // may return evaluated result, whatever B m_md1Block(Block* bl, Scope* psc); B m_md2Block(Block* bl, Scope* psc); @@ -271,7 +272,7 @@ void allocStack(u64 am) { } } -B evalBC(Body* b, Scope* sc) { +B evalBC(Body* b, Scope* sc) { // doesn't consume #ifdef DEBUG_VM bcDepth+= 2; if (!vmStack) vmStack = malloc(400); @@ -396,10 +397,10 @@ B evalBC(Body* b, Scope* sc) { #undef POP } -B actualExec(Block* bl, Scope* psc, u32 ga, B* svar) { +B actualExec(Block* bl, Scope* psc, u32 ga, B* svar) { // consumes svar contents Body* bdy = bl->body; Scope* sc = mm_allocN(fsizeof(Scope, vars, B, bdy->varAm), t_scope); - sc->psc = psc; if(psc)ptr_inc(psc); + sc->psc = psc; if(psc) ptr_inc(psc); u16 varAm = sc->varAm = bdy->varAm; assert(varAm>=ga); #ifdef DEBUG @@ -408,22 +409,18 @@ B actualExec(Block* bl, Scope* psc, u32 ga, B* svar) { i32 i = 0; while (ivars[i] = svar[i]; i++; } while (ivars[i++] = bi_noVar; - // if (ga & !(bdy->flags&1)) { - // B v0 = sc->vars[0]; - // dec(v0); sc->vars[0] = bi_optOut; // prevent reference cycle; TODO more properly do this (or just remove, it doesn't seem to be doing much) - // } B r = evalBC(bdy, sc); ptr_dec(sc); return r; } -B funBl_c1(B t, B x) { FunBlock* b=c(FunBlock, t ); return actualExec(b->bl, b->sc, 3, (B[]){inc(t), x, bi_nothing }); } -B funBl_c2(B t, B w, B x) { FunBlock* b=c(FunBlock, t ); return actualExec(b->bl, b->sc, 3, (B[]){inc(t), x, w }); } -B md1Bl_c1(B D, B x) { Md1D* d=c(Md1D,D); Md1Block* b=c(Md1Block, d->m1); return actualExec(b->bl, b->sc, 5, (B[]){inc(D), x, bi_nothing, inc(d->m1), inc(d->f) }); } -B md1Bl_c2(B D, B w, B x) { Md1D* d=c(Md1D,D); Md1Block* b=c(Md1Block, d->m1); return actualExec(b->bl, b->sc, 5, (B[]){inc(D), x, w , inc(d->m1), inc(d->f) }); } +B funBl_c1(B t, B x) { FunBlock* b=c(FunBlock, t ); return actualExec(b->bl, b->sc, 3, (B[]){inc(t), x, bi_nothing }); } +B funBl_c2(B t, B w, B x) { FunBlock* b=c(FunBlock, t ); return actualExec(b->bl, b->sc, 3, (B[]){inc(t), x, w }); } +B md1Bl_c1(B D, B x) { Md1D* d=c(Md1D,D); Md1Block* b=c(Md1Block, d->m1); return actualExec(b->bl, b->sc, 5, (B[]){inc(D), x, bi_nothing, inc(d->m1), inc(d->f) }); } +B md1Bl_c2(B D, B w, B x) { Md1D* d=c(Md1D,D); Md1Block* b=c(Md1Block, d->m1); return actualExec(b->bl, b->sc, 5, (B[]){inc(D), x, w , inc(d->m1), inc(d->f) }); } B md2Bl_c1(B D, B x) { Md2D* d=c(Md2D,D); Md2Block* b=c(Md2Block, d->m2); return actualExec(b->bl, b->sc, 6, (B[]){inc(D), x, bi_nothing, inc(d->m2), inc(d->f), inc(d->g)}); } B md2Bl_c2(B D, B w, B x) { Md2D* d=c(Md2D,D); Md2Block* b=c(Md2Block, d->m2); return actualExec(b->bl, b->sc, 6, (B[]){inc(D), x, w , inc(d->m2), inc(d->f), inc(d->g)}); } -B m_funBlock(Block* bl, Scope* psc) { +B m_funBlock(Block* bl, Scope* psc) { // doesn't consume anything if (bl->imm) return actualExec(bl, psc, 0, NULL); B r = mm_alloc(sizeof(FunBlock), t_fun_block, ftag(FUN_TAG)); c(FunBlock, r)->bl = bl; ptr_inc(bl); @@ -449,19 +446,41 @@ B m_md2Block(Block* bl, Scope* psc) { return r; } -void comp_free(B x) { Comp* c = c(Comp ,x); ptr_decR(c->objs); decR(c->bc); } -void body_free(B x) { Body* c = c(Body ,x); ptr_decR(c->comp); } -void block_free(B x) { Block* c = c(Block,x); ptr_decR(c->body); } +void comp_free(B x) { + Comp* c = c(Comp ,x); + ptr_decR(c->objs); + decR(c->bc); + u32 am = c->blockAm; for(u32 i = 0; i < am; i++) ptr_dec(c->blocks[i]); +} void scope_free(B x) { Scope* c = c(Scope,x); if (c->psc) ptr_decR(c->psc); u16 am = c->varAm; for (u32 i = 0; i < am; i++) dec(c->vars[i]); } +void body_free(B x) { Body* c = c(Body ,x); ptr_decR(c->comp); } +void block_free(B x) { Block* c = c(Block,x); ptr_decR(c->body); } void funBl_free(B x) { FunBlock* c = c(FunBlock,x); ptr_decR(c->sc); ptr_decR(c->bl); } void md1Bl_free(B x) { Md1Block* c = c(Md1Block,x); ptr_decR(c->sc); ptr_decR(c->bl); } void md2Bl_free(B x) { Md2Block* c = c(Md2Block,x); ptr_decR(c->sc); ptr_decR(c->bl); } +void comp_visit(B x) { + Comp* c = c(Comp,x); + mm_visitP(c->objs); mm_visit(c->bc); + u32 am = c->blockAm; for(u32 i = 0; i < am; i++) mm_visitP(c->blocks[i]); +} +void scope_visit(B x) { + Scope* c = c(Scope,x); + if (c->psc) mm_visitP(c->psc); + u16 am = c->varAm; + for (u32 i = 0; i < am; i++) mm_visit(c->vars[i]); +} +void body_visit(B x) { Body* c = c(Body ,x); mm_visitP(c->comp); } +void block_visit(B x) { Block* c = c(Block,x); mm_visitP(c->body); } +void funBl_visit(B x) { FunBlock* c = c(FunBlock,x); mm_visitP(c->sc); mm_visitP(c->bl); } +void md1Bl_visit(B x) { Md1Block* c = c(Md1Block,x); mm_visitP(c->sc); mm_visitP(c->bl); } +void md2Bl_visit(B x) { Md2Block* c = c(Md2Block,x); mm_visitP(c->sc); mm_visitP(c->bl); } + void comp_print (B x) { printf("(%p: comp)",v(x)); } void body_print (B x) { printf("(%p: body varam=%d)",v(x),c(Body,x)->varAm); } void block_print(B x) { printf("(%p: block for %p)",v(x),c(Block,x)->body); } @@ -470,12 +489,12 @@ void scope_print(B x) { printf("(%p: scope; vars:",v(x));Scope*sc=c(Scope,x);for // void funBl_print(B x) { printf("(%p: function"" block bl=%p sc=%p)",v(x),c(FunBlock,x)->bl,c(FunBlock,x)->sc); } // void md1Bl_print(B x) { printf("(%p: 1-modifier block bl=%p sc=%p)",v(x),c(Md1Block,x)->bl,c(Md1Block,x)->sc); } // void md2Bl_print(B x) { printf("(%p: 2-modifier block bl=%p sc=%p)",v(x),c(Md2Block,x)->bl,c(Md2Block,x)->sc); } -// void funBl_print(B x) { printf("(%p: function"" block @%ld)",v(x),c(FunBlock,x)->bl->body->bc-c(I32Arr,c(FunBlock,x)->bl->body->comp->bc)->a); } -// void md1Bl_print(B x) { printf("(%p: 1-modifier block @%ld)",v(x),c(Md1Block,x)->bl->body->bc-c(I32Arr,c(Md1Block,x)->bl->body->comp->bc)->a); } -// void md2Bl_print(B x) { printf("(%p: 2-modifier block @%ld)",v(x),c(Md2Block,x)->bl->body->bc-c(I32Arr,c(Md2Block,x)->bl->body->comp->bc)->a); } -void funBl_print(B x) { printf("{function""}"); } -void md1Bl_print(B x) { printf("{1-modifier}"); } -void md2Bl_print(B x) { printf("{2-modifier}"); } +void funBl_print(B x) { printf("(function"" block @%ld)",c(FunBlock,x)->bl->body->bc-c(I32Arr,c(FunBlock,x)->bl->body->comp->bc)->a); } +void md1Bl_print(B x) { printf("(1-modifier block @%ld)",c(Md1Block,x)->bl->body->bc-c(I32Arr,c(Md1Block,x)->bl->body->comp->bc)->a); } +void md2Bl_print(B x) { printf("(2-modifier block @%ld)",c(Md2Block,x)->bl->body->bc-c(I32Arr,c(Md2Block,x)->bl->body->comp->bc)->a); } +// void funBl_print(B x) { printf("{function""}"); } +// void md1Bl_print(B x) { printf("{1-modifier}"); } +// void md2Bl_print(B x) { printf("{2-modifier}"); } B block_decompose(B x) { return m_v2(m_i32(1), x); } @@ -483,13 +502,13 @@ B bl_m1d(B m, B f ) { Md1Block* c = c(Md1Block,m); return c->bl->imm? actual B bl_m2d(B m, B f, B g) { Md2Block* c = c(Md2Block,m); return c->bl->imm? actualExec(c(Md2Block, m)->bl, c(Md2Block, m)->sc, 3, (B[]){m, f, g}) : m_md2D(m,f,g); } void comp_init() { - ti[t_comp ].free = comp_free; ti[t_comp ].print = comp_print; - ti[t_body ].free = body_free; ti[t_body ].print = body_print; - ti[t_block ].free = block_free; ti[t_block ].print = block_print; - ti[t_scope ].free = scope_free; ti[t_scope ].print = scope_print; - ti[t_fun_block].free = funBl_free; ti[t_fun_block].print = funBl_print; ti[t_fun_block].decompose = block_decompose; - ti[t_md1_block].free = md1Bl_free; ti[t_md1_block].print = md1Bl_print; ti[t_md1_block].decompose = block_decompose; ti[t_md1_block].m1_d=bl_m1d; - ti[t_md2_block].free = md2Bl_free; ti[t_md2_block].print = md2Bl_print; ti[t_md2_block].decompose = block_decompose; ti[t_md2_block].m2_d=bl_m2d; + ti[t_comp ].free = comp_free; ti[t_comp ].visit = comp_visit; ti[t_comp ].print = comp_print; + ti[t_body ].free = body_free; ti[t_body ].visit = body_visit; ti[t_body ].print = body_print; + ti[t_block ].free = block_free; ti[t_block ].visit = block_visit; ti[t_block ].print = block_print; + ti[t_scope ].free = scope_free; ti[t_scope ].visit = scope_visit; ti[t_scope ].print = scope_print; + ti[t_fun_block].free = funBl_free; ti[t_fun_block].visit = funBl_visit; ti[t_fun_block].print = funBl_print; ti[t_fun_block].decompose = block_decompose; + ti[t_md1_block].free = md1Bl_free; ti[t_md1_block].visit = md1Bl_visit; ti[t_md1_block].print = md1Bl_print; ti[t_md1_block].decompose = block_decompose; ti[t_md1_block].m1_d=bl_m1d; + ti[t_md2_block].free = md2Bl_free; ti[t_md2_block].visit = md2Bl_visit; ti[t_md2_block].print = md2Bl_print; ti[t_md2_block].decompose = block_decompose; ti[t_md2_block].m2_d=bl_m2d; } void print_vmStack() {