stacktraces
This commit is contained in:
parent
03cebc6aff
commit
2202200a6e
1
src/h.h
1
src/h.h
@ -242,6 +242,7 @@ jmp_buf* prepareCatch();
|
||||
#endif
|
||||
void popCatch();
|
||||
B catchMessage;
|
||||
u64 envPrevHeight; // envStart+prevEnvHeight will give the original envCurr
|
||||
|
||||
|
||||
|
||||
|
||||
11
src/load.c
11
src/load.c
@ -1,16 +1,16 @@
|
||||
#include "h.h"
|
||||
|
||||
Block* load_compObj(B x) { // consumes
|
||||
Block* load_compObj(B x, B src) { // consumes
|
||||
BS2B xget = TI(x).get;
|
||||
usz xia = a(x)->ia;
|
||||
if (xia!=5 & xia!=3) thrM("load_compObj: bad item count");
|
||||
Block* r = xia==5? compile(xget(x,0),xget(x,1),xget(x,2),xget(x,3),xget(x,4))
|
||||
: compile(xget(x,0),xget(x,1),xget(x,2),bi_N,bi_N);
|
||||
Block* r = xia==5? compile(xget(x,0),xget(x,1),xget(x,2),xget(x,3),xget(x,4), src)
|
||||
: compile(xget(x,0),xget(x,1),xget(x,2),bi_N, bi_N, src);
|
||||
dec(x);
|
||||
return r;
|
||||
}
|
||||
Block* load_compImport(B bc, B objs, B blocks) { // consumes all
|
||||
return compile(bc, objs, blocks, bi_N, bi_N);
|
||||
return compile(bc, objs, blocks, bi_N, bi_N, bi_N);
|
||||
}
|
||||
|
||||
B load_comp;
|
||||
@ -25,7 +25,8 @@ B bqn_fmt(B x) { // consumes
|
||||
|
||||
|
||||
Block* bqn_comp(B str) { // consumes
|
||||
return load_compObj(c2(load_comp, inc(load_compArg), str));
|
||||
inc(str);
|
||||
return load_compObj(c2(load_comp, inc(load_compArg), str), str);
|
||||
}
|
||||
B bqn_exec(B str) { // consumes
|
||||
Block* block = bqn_comp(str);
|
||||
|
||||
10
src/main.c
10
src/main.c
@ -13,8 +13,9 @@
|
||||
// #define OBJ_COUNTER // store a unique allocation number with each object for easier analysis
|
||||
// #define ALL_R0 // use all of r0.bqn for runtime_0
|
||||
// #define ALL_R1 // use all of r1.bqn for runtime
|
||||
#define EACH_FILLS false // whether to try to squeeze out fills for ¨ and ⌜
|
||||
#define SFNS_FILLS true // whether to insert fills for structural functions (∾, ≍, etc)
|
||||
#define VM_POS false // whether to store detailed execution position information for stacktraces
|
||||
#define EACH_FILLS false // whether to try to squeeze out fills for ¨ and ⌜
|
||||
#define SFNS_FILLS true // whether to insert fills for structural functions (∾, ≍, etc)
|
||||
#define FAKE_RUNTIME false // whether to disable the self-hosted runtime
|
||||
|
||||
// #define LOG_GC // log GC stats
|
||||
@ -82,9 +83,8 @@ int main() {
|
||||
|
||||
|
||||
while (CATCH) {
|
||||
printf("caught: ");
|
||||
print(catchMessage);
|
||||
puts("");
|
||||
printf("Error: "); print(catchMessage); putchar('\n');
|
||||
vm_pst(envCurr, envStart+envPrevHeight);
|
||||
dec(catchMessage);
|
||||
}
|
||||
while (true) { // exit by evaluating an empty expression
|
||||
|
||||
157
src/vm.c
157
src/vm.c
@ -3,7 +3,10 @@
|
||||
|
||||
// #define GS_REALLOC // whether to dynamically realloc gStack
|
||||
#ifndef GS_SIZE
|
||||
#define GS_SIZE 16384 // if !GS_REALLOC, size in number of B objects of the global object stack
|
||||
#define GS_SIZE 65536 // if !GS_REALLOC, size in number of B objects of the global object stack
|
||||
#endif
|
||||
#ifndef ENV_SIZE
|
||||
#define ENV_SIZE 4096 // max recursion depth; GS_SIZE and C stack size may limit this
|
||||
#endif
|
||||
|
||||
enum {
|
||||
@ -65,16 +68,11 @@ i32* nextBC(i32* p) {
|
||||
}
|
||||
i32 stackDiff(i32* p) {
|
||||
switch(*p) {
|
||||
case PUSH: case VARO: case VARM: case DFND: case LOCO: case LOCM: case LOCU: case SYSV:
|
||||
return 1;
|
||||
case CHKV: case VFYM: case FLDO: case FLDM: case RETD:
|
||||
return 0;
|
||||
case FN1C: case OP1D: case TR2D: case SETN: case SETU: case POPS: case FN1O: case OP2H: case SETH: case RETN:
|
||||
return -1;
|
||||
case FN2C: case OP2D: case TR3D: case SETM: case FN2O: case TR3O:
|
||||
return -2;
|
||||
case ARRO: case ARRM: case NSPM:
|
||||
return 1-p[1];
|
||||
case PUSH: case VARO: case VARM: case DFND: case LOCO: case LOCM: case LOCU: case SYSV: return 1;
|
||||
case CHKV: case VFYM: case FLDO: case FLDM: case RETD: return 0;
|
||||
case FN1C: case OP1D: case TR2D: case SETN: case SETU: case POPS: case FN1O: case OP2H: case SETH: case RETN: return -1;
|
||||
case FN2C: case OP2D: case TR3D: case SETM: case FN2O: case TR3O: return -2;
|
||||
case ARRO: case ARRM: case NSPM: return 1-p[1];
|
||||
default: return 9999999;
|
||||
}
|
||||
}
|
||||
@ -110,6 +108,8 @@ typedef struct Scope Scope;
|
||||
typedef struct Comp {
|
||||
struct Value;
|
||||
B bc;
|
||||
B src;
|
||||
B indices;
|
||||
HArr* objs;
|
||||
u32 blockAm;
|
||||
Block* blocks[];
|
||||
@ -142,9 +142,6 @@ struct Scope {
|
||||
Scope* psc;
|
||||
Body* body;
|
||||
u16 varAm;
|
||||
#ifdef DEBUG
|
||||
u64 bcInd; // DEBUG: place of this in bytecode array
|
||||
#endif
|
||||
B vars[];
|
||||
};
|
||||
|
||||
@ -153,7 +150,7 @@ 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 blocksq, B indices, B tokenInfo) { // consumes all
|
||||
Block* compile(B bcq, B objs, B blocksq, B indices, B tokenInfo, B src) { // consumes all
|
||||
HArr* blocksH = toHArr(blocksq);
|
||||
usz bam = blocksH->ia;
|
||||
|
||||
@ -165,10 +162,11 @@ Block* compile(B bcq, B objs, B blocksq, B indices, B tokenInfo) { // consumes a
|
||||
usz bcl = bca->ia;
|
||||
Comp* comp = mm_allocN(fsizeof(Comp,blocks,Block*,bam), t_comp);
|
||||
comp->bc = tag(bca, ARR_TAG);
|
||||
comp->indices = indices;
|
||||
comp->src = src;
|
||||
comp->objs = toHArr(objs);
|
||||
comp->blockAm = bam;
|
||||
B* blockDefs = blocksH->a;
|
||||
dec(indices);
|
||||
B nameList;
|
||||
if (isNothing(tokenInfo)) {
|
||||
nameList = bi_emptyHVec;
|
||||
@ -176,6 +174,15 @@ Block* compile(B bcq, B objs, B blocksq, B indices, B tokenInfo) { // consumes a
|
||||
B t = TI(tokenInfo).getU(tokenInfo,2);
|
||||
nameList = TI(t).getU(t,0);
|
||||
}
|
||||
if (!isNothing(src) && !isNothing(indices)) {
|
||||
if (isAtm(indices) || rnk(indices)!=1 || a(indices)->ia!=2) thrM("compile: bad indices");
|
||||
for (i32 i = 0; i < 2; i++) {
|
||||
B ind = TI(indices).getU(indices,i);
|
||||
if (isAtm(ind) || rnk(ind)!=1 || a(ind)->ia!=bcl) thrM("compile: bad indices");
|
||||
BS2B indGetU = TI(ind).getU;
|
||||
for (usz j = 0; j < bcl; j++) o2i(indGetU(ind,j));
|
||||
}
|
||||
}
|
||||
|
||||
for (usz i = 0; i < bam; i++) {
|
||||
B cbld = blockDefs[i];
|
||||
@ -290,10 +297,12 @@ i32* vmStack;
|
||||
i32 bcCtr = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
B* gStack; // points to after end
|
||||
B* gStackStart;
|
||||
B* gStackEnd;
|
||||
|
||||
void gsReserve(u64 am) {
|
||||
#ifdef GS_REALLOC
|
||||
if (am>gStackEnd-gStack) {
|
||||
@ -311,7 +320,6 @@ void gsReserve(u64 am) {
|
||||
NOINLINE
|
||||
#endif
|
||||
void gsReserveR(u64 am) { gsReserve(am); }
|
||||
|
||||
void gsAdd(B x) {
|
||||
#ifdef GS_REALLOC
|
||||
if (gStack==gStackEnd) gsReserveR(1);
|
||||
@ -335,6 +343,32 @@ void gsPrint() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef struct Env {
|
||||
Scope* sc;
|
||||
union { i32** bcP; i32* bcL; i32 bcV; };
|
||||
} Env;
|
||||
|
||||
Env* envCurr;
|
||||
Env* envStart;
|
||||
Env* envEnd;
|
||||
|
||||
static inline void pushEnv(Scope* sc, i32** bc) {
|
||||
if (envCurr==envEnd) thrM("stack overflow");
|
||||
envCurr->sc = sc;
|
||||
#if VM_POS
|
||||
envCurr->bcP = bc;
|
||||
#else
|
||||
envCurr->bcL = *bc;
|
||||
#endif
|
||||
envCurr++;
|
||||
}
|
||||
static inline void popEnv() {
|
||||
assert(envCurr>envStart);
|
||||
envCurr--;
|
||||
}
|
||||
|
||||
B evalBC(Body* b, Scope* sc) { // doesn't consume
|
||||
#ifdef DEBUG_VM
|
||||
bcDepth+= 2;
|
||||
@ -346,6 +380,7 @@ B evalBC(Body* b, Scope* sc) { // doesn't consume
|
||||
B* objs = b->comp->objs->a;
|
||||
Block** blocks = b->comp->blocks;
|
||||
i32* bc = b->bc;
|
||||
pushEnv(sc, &bc);
|
||||
gsReserve(b->maxStack);
|
||||
Scope* pscs[b->maxPSC+1];
|
||||
pscs[0] = sc;
|
||||
@ -490,6 +525,7 @@ B evalBC(Body* b, Scope* sc) { // doesn't consume
|
||||
#endif
|
||||
B r = POP;
|
||||
GS_UPD;
|
||||
popEnv();
|
||||
return r;
|
||||
#undef P
|
||||
#undef ADD
|
||||
@ -504,9 +540,6 @@ B actualExec(Block* bl, Scope* psc, i32 ga, B* svar) { // consumes svar contents
|
||||
sc->psc = psc; if(psc) ptr_inc(psc);
|
||||
u16 varAm = sc->varAm = body->varAm;
|
||||
assert(varAm>=ga);
|
||||
#ifdef DEBUG
|
||||
sc->bcInd = body->bc-c(I32Arr,body->comp->bc)->a;
|
||||
#endif
|
||||
i32 i = 0;
|
||||
while (i<ga) { sc->vars[i] = svar[i]; i++; }
|
||||
while (i<varAm) sc->vars[i++] = bi_noVar;
|
||||
@ -549,8 +582,7 @@ B m_md2Block(Block* bl, Scope* psc) {
|
||||
|
||||
void comp_free(B x) {
|
||||
Comp* c = c(Comp, x);
|
||||
ptr_decR(c->objs);
|
||||
decR(c->bc);
|
||||
ptr_decR(c->objs); decR(c->bc); decR(c->src); decR(c->indices);
|
||||
u32 am = c->blockAm; for(u32 i = 0; i < am; i++) ptr_dec(c->blocks[i]);
|
||||
}
|
||||
void scope_free(B x) {
|
||||
@ -568,7 +600,7 @@ void md2Bl_free(B x) { Md2Block* c = c(Md2Block,x); ptr_decR(c->sc); ptr_decR(c-
|
||||
|
||||
void comp_visit(B x) {
|
||||
Comp* c = c(Comp,x);
|
||||
mm_visitP(c->objs); mm_visit(c->bc);
|
||||
mm_visitP(c->objs); mm_visit(c->bc); mm_visit(c->src); mm_visit(c->indices);
|
||||
u32 am = c->blockAm; for(u32 i = 0; i < am; i++) mm_visitP(c->blocks[i]);
|
||||
}
|
||||
void scope_visit(B x) {
|
||||
@ -604,6 +636,15 @@ B block_decompose(B x) { return m_v2(m_i32(1), x); }
|
||||
B bl_m1d(B m, B f ) { Md1Block* c = c(Md1Block,m); return c->bl->imm? actualExec(c(Md1Block, m)->bl, c(Md1Block, m)->sc, 2, (B[]){m, f }) : m_md1D(m,f ); }
|
||||
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 allocStack(void** curr, void** start, void** end, i32 elSize, i32 count) {
|
||||
usz pageSize = sysconf(_SC_PAGESIZE);
|
||||
u64 sz = (elSize*count + pageSize-1)/pageSize * pageSize;
|
||||
assert(sz%elSize == 0);
|
||||
*curr = *start = mmap(NULL, sz+pageSize, PROT_READ|PROT_WRITE, MAP_NORESERVE|MAP_PRIVATE|MAP_ANON, -1, 0);
|
||||
*end = ((char*)*start)+sz;
|
||||
mprotect(*end, pageSize, PROT_NONE); // idk first way i found to force erroring on overflow
|
||||
}
|
||||
|
||||
static inline void comp_init() {
|
||||
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;
|
||||
@ -613,12 +654,9 @@ static inline void comp_init() {
|
||||
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;
|
||||
#ifndef GS_REALLOC
|
||||
usz pageSize = sysconf(_SC_PAGESIZE);
|
||||
u64 sz = (GS_SIZE + pageSize-1)/pageSize * pageSize;
|
||||
gStack = gStackStart = mmap(NULL, sz*sizeof(B)+pageSize, PROT_READ|PROT_WRITE, MAP_NORESERVE|MAP_PRIVATE|MAP_ANON, -1, 0);
|
||||
gStackEnd = gStackStart+sz;
|
||||
mprotect(gStackEnd, pageSize, PROT_NONE); // idk first way i found to force erroring on overflow
|
||||
allocStack((void**)&gStack, (void**)&gStackStart, (void**)&gStackEnd, sizeof(B), GS_SIZE);
|
||||
#endif
|
||||
allocStack((void**)&envCurr, (void**)&envStart, (void**)&envEnd, sizeof(Env), ENV_SIZE);
|
||||
}
|
||||
|
||||
void print_vmStack() {
|
||||
@ -633,7 +671,8 @@ void print_vmStack() {
|
||||
|
||||
typedef struct CatchFrame {
|
||||
jmp_buf jmp;
|
||||
u64 gStackDepth;
|
||||
u64 gsDepth;
|
||||
u64 envDepth;
|
||||
u64 cfDepth;
|
||||
} CatchFrame;
|
||||
CatchFrame* cf; // points to after end
|
||||
@ -650,7 +689,8 @@ jmp_buf* prepareCatch() { // in the case of returning false, must call popCatch(
|
||||
cfEnd = cfStart+n;
|
||||
}
|
||||
cf->cfDepth = cf-cfStart;
|
||||
cf->gStackDepth = gStack-gStackStart;
|
||||
cf->gsDepth = gStack-gStackStart;
|
||||
cf->envDepth = envCurr-envStart;
|
||||
return &(cf++)->jmp;
|
||||
}
|
||||
void popCatch() {
|
||||
@ -665,9 +705,20 @@ NOINLINE void thr(B msg) {
|
||||
catchMessage = msg;
|
||||
cf--;
|
||||
|
||||
B* gStackNew = gStackStart + cf->gStackDepth;
|
||||
if (gStackNew>gStack) err("bad catch gStackDepth");
|
||||
B* gStackNew = gStackStart + cf->gsDepth;
|
||||
assert(gStackNew<=gStack);
|
||||
while (gStack!=gStackNew) dec(*--gStack);
|
||||
envPrevHeight = envCurr-envStart;
|
||||
Env* envNew = envStart + cf->envDepth;
|
||||
assert(envNew<=envCurr);
|
||||
while (envCurr!=envNew) {
|
||||
envCurr--;
|
||||
#if VM_POS
|
||||
envCurr->bcV = *envCurr->bcP - i32arr_ptr(envCurr->sc->body->comp->bc) - 1;
|
||||
#else
|
||||
envCurr->bcV = envCurr->bcL - i32arr_ptr(envCurr->sc->body->comp->bc);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (cfStart+cf->cfDepth > cf) err("bad catch cfDepth");
|
||||
cf = cfStart+cf->cfDepth;
|
||||
@ -687,3 +738,43 @@ NOINLINE void thr(B msg) {
|
||||
NOINLINE void thrM(char* s) {
|
||||
thr(fromUTF8(s, strlen(s)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
NOINLINE void vm_pst(Env* s, Env* e) {
|
||||
assert(s<=e);
|
||||
i64 l = e-s;
|
||||
i64 i = l-1;
|
||||
while (i>=0) {
|
||||
Env* c = s+i;
|
||||
if (l>30 && i==l-10) {
|
||||
printf("(%ld entries omitted)\n", l-20);
|
||||
i = 10;
|
||||
}
|
||||
i32 bcPos = c->bcV;
|
||||
Comp* comp = c->sc->body->comp;
|
||||
B src = comp->src;
|
||||
if (!isNothing(src) && !isNothing(comp->indices)) {
|
||||
B inds = TI(comp->indices).getU(comp->indices, 0); usz cs = o2s(TI(inds).getU(inds,bcPos));
|
||||
B inde = TI(comp->indices).getU(comp->indices, 1); usz ce = o2s(TI(inde).getU(inde,bcPos))+1;
|
||||
int start = printf("%ld: ", i);
|
||||
usz srcL = a(src)->ia;
|
||||
BS2B srcGetU = TI(src).getU;
|
||||
usz srcS = cs;
|
||||
while (srcS>0 && o2cu(srcGetU(src,srcS-1))!='\n') srcS--;
|
||||
usz srcE = srcS;
|
||||
while (srcE<srcL) { u32 chr = o2cu(srcGetU(src, srcE)); if(chr=='\n')break; printUTF8(chr); srcE++; }
|
||||
if (ce>srcE) ce = srcE;
|
||||
cs-= srcS;
|
||||
ce-= srcS;
|
||||
putchar('\n');
|
||||
for (i32 i = 0; i < cs+start; i++) putchar(' ');
|
||||
for (i32 i = cs; i < ce; i++) putchar('^');
|
||||
putchar('\n');
|
||||
// printf(" inds:%d…%d\n", cinds, cinde);
|
||||
} else {
|
||||
printf("%ld: source unknown\n", i);
|
||||
}
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
6
test.bqn
6
test.bqn
@ -12,11 +12,13 @@ tests ← •FLines path∾"/test/cases/"∾case
|
||||
tests/˜↩ (('#'≢⊑)∧0<≠)¨tests
|
||||
{𝕊: tests/˜↩'!'≠⊑¨tests}⍟⊑ 's'∊opt
|
||||
{𝕊: tests/˜↩'!'=⊑¨tests}⍟⊑ 'e'∊opt
|
||||
verify ← ⊑'v'∊opt
|
||||
RMC ← ⊐⟜'#'⊑⊸↑⊢ # doesn't work for token.bqn but whatever
|
||||
Q ← {
|
||||
i←⊑𝕩⊐'%'
|
||||
(('!'≠⊑𝕩)∧⊑'v'∊opt)◶⟨(1+i)⊸↓ ⋄ {∾⟨"(" ⋄ i↑𝕩 ⋄ ") ≡ {" ⋄ (⊐⟜'#'⊑⊸↑⊢) (1+i)↓𝕩 ⋄ " }"⟩}⟩ 𝕩
|
||||
((1+'!'≠⊑𝕩)×verify)◶⟨(1+i)⊸↓ ⋄ {∾ ⟨"""should've errored!""∘•BQN⎊1 """ ⋄ {𝕩/˜1+𝕩='"'}𝕩↓˜1+⊑𝕩⊐'%' ⋄ """"⟩} ⋄ {∾⟨"""incorrect!""‿1⊑˜(" ⋄ i↑𝕩 ⋄ ") ≡ {" ⋄ (1+i)↓𝕩 ⋄ " }"⟩}⟩ RMC 𝕩
|
||||
}
|
||||
Out ← {•Out'%'⊸∊◶⊢‿Q𝕩}
|
||||
Out ← {•Out'%'⊸∊◶(verify◶⊢‿{∾⟨"""incorrect!""‿1⊑˜1≡{" ⋄ RMC 𝕩 ⋄ " }"⟩})‿Q𝕩}
|
||||
|
||||
((⊑'m'∊opt)⊑Out‿{•Show𝕩⋄Out𝕩})¨tests
|
||||
# ('%'⊸∊∨ '#'= ·⊑ ∾⟜"#")◶•Out‿@¨tests
|
||||
|
||||
Loading…
Reference in New Issue
Block a user