This commit is contained in:
dzaima 2021-04-14 13:21:06 +03:00
parent b8e786b2cb
commit c820b4b3a5
21 changed files with 529 additions and 217 deletions

2
build
View File

@ -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

View File

@ -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

View File

@ -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) }

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

99
src/gc.c Normal file
View File

@ -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();
}

149
src/h.h
View File

@ -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 <valgrind/valgrind.h>
#include <valgrind/memcheck.h>
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 <time.h>
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;
}

View File

@ -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;
}

49
src/heap.c Normal file
View File

@ -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

View File

@ -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;
}

View File

@ -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 <time.h>
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();
}

View File

@ -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)); }

View File

@ -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

View File

@ -1,4 +1,5 @@
#include "h.h"
#include "gc.c"
#include <sys/mman.h>
#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();
}

View File

@ -1,4 +1,5 @@
#include "h.h"
#include "gc.c"
#include <sys/mman.h>
#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) {

View File

@ -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;

View File

@ -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; }

View File

@ -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)); }

View File

@ -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) }

109
src/vm.c
View File

@ -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 (i<ga) { sc->vars[i] = svar[i]; i++; }
while (i<varAm) sc->vars[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() {