GC
This commit is contained in:
parent
b8e786b2cb
commit
c820b4b3a5
2
build
2
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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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) }
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
16
src/derv.c
16
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;
|
||||
}
|
||||
|
||||
@ -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
99
src/gc.c
Normal 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
149
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 <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;
|
||||
}
|
||||
16
src/harr.c
16
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;
|
||||
}
|
||||
|
||||
49
src/heap.c
Normal file
49
src/heap.c
Normal 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
|
||||
@ -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;
|
||||
}
|
||||
|
||||
113
src/main.c
113
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 <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();
|
||||
}
|
||||
|
||||
17
src/md1.c
17
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)); }
|
||||
|
||||
|
||||
12
src/md2.c
12
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
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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; }
|
||||
|
||||
@ -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)); }
|
||||
|
||||
|
||||
@ -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
109
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 (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() {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user