diff --git a/src/builtins/fns.c b/src/builtins/fns.c index c5c174bf..5aa8b9fc 100644 --- a/src/builtins/fns.c +++ b/src/builtins/fns.c @@ -1,6 +1,7 @@ #include "../core.h" #include "../utils/hash.h" #include "../utils/mut.h" +#include "../utils/talloc.h" #include "../nfns.h" diff --git a/src/builtins/md2.c b/src/builtins/md2.c index fc6a6cf6..e47e2b07 100644 --- a/src/builtins/md2.c +++ b/src/builtins/md2.c @@ -1,5 +1,6 @@ #include "../core.h" #include "../utils/builtins.h" +#include "../utils/talloc.h" B md2BI_uc1(B t, B o, B f, B g, B x) { return c(BMd2,t)->uc1(t, o, f, g, x); } B md2BI_ucw(B t, B o, B f, B g, B w, B x) { return c(BMd2,t)->ucw(t, o, f, g, w, x); } diff --git a/src/builtins/sfns.c b/src/builtins/sfns.c index e0d44c96..c3e76b75 100644 --- a/src/builtins/sfns.c +++ b/src/builtins/sfns.c @@ -2,6 +2,7 @@ #include "../utils/each.h" #include "../utils/mut.h" #include "../utils/builtins.h" +#include "../utils/talloc.h" B shape_c1(B t, B x) { diff --git a/src/builtins/sort.c b/src/builtins/sort.c index c9d52005..c4874cdb 100644 --- a/src/builtins/sort.c +++ b/src/builtins/sort.c @@ -1,4 +1,5 @@ #include "../core.h" +#include "../utils/talloc.h" diff --git a/src/core/mm.c b/src/core/mm.c index d4db6bf6..d944b21d 100644 --- a/src/core/mm.c +++ b/src/core/mm.c @@ -1,5 +1,7 @@ #include "../core.h" +u64 allocB; // currently allocated number of bytes + #if MM==0 #include "../opt/mm_malloc.c" #elif MM==1 diff --git a/src/core/stuff.c b/src/core/stuff.c index 1709baed..261e573f 100644 --- a/src/core/stuff.c +++ b/src/core/stuff.c @@ -1,17 +1,22 @@ #include "../core.h" #include "../utils/mut.h" #include "../utils/utf.h" +#include "../utils/talloc.h" -u64 allocB; // currently allocated number of bytes B bi_emptyHVec, bi_emptyIVec, bi_emptyCVec, bi_emptySVec; -NOINLINE TStack* tstack_ext(TStack* o, u32 elsz) { - usz ncap = o->cap*2; - TStack* n = (TStack*)mm_allocN(sizeof(TStack) + elsz*ncap, t_temp); - memcpy(n->data, o->data, o->cap*elsz); - n->cap = ncap; - n->size = o->size; - mm_free((Value*)o); +NOINLINE TStack* ts_e(TStack* o, u32 elsz, u64 am) { u64 size = o->size; + u64 alsz = mm_round(fsizeof(TStack, data, u8, (size+am)*elsz)); + TStack* n; + if (alsz==mm_size((Value*)o)) { + n = o; + } else { + n = (TStack*)mm_allocN(alsz, t_temp); + memcpy(n->data, o->data, o->cap*elsz); + mm_free((Value*)o); + n->size = size; + } + n->cap = (mm_size((Value*)n)-offsetof(TStack,data))/elsz; return n; } diff --git a/src/core/stuff.h b/src/core/stuff.h index 7db06184..1072bcf6 100644 --- a/src/core/stuff.h +++ b/src/core/stuff.h @@ -21,39 +21,6 @@ static B mm_alloc(usz sz, u8 type, u64 tag) { #define MAP_NORESERVE 0 // apparently needed for freebsd or something #endif -typedef struct TAlloc { - struct Value; - u8 data[]; -} TAlloc; -#define TOFF offsetof(TAlloc, data) -#define TALLOC(T,N,AM) T* N = (T*) ((TAlloc*)mm_allocN(TOFF + (AM)*sizeof(T) + 8, t_temp))->data; // +8 so mm is happy -#define TOBJ(N) (void*)((u8*)(N) - TOFF) -#define TFREE(N) mm_free((Value*)TOBJ(N)); -#define TREALLOC(N, AM) talloc_realloc(TOBJ(N), AM) -#define TSIZE(N) (mm_size(TOBJ(N))-TOFF) -static inline void* talloc_realloc(TAlloc* t, u64 am) { // TODO maybe shouldn't be inline? - u64 stored = mm_size((Value*)t)-TOFF; - if (stored > am) return t->data; - TALLOC(u8,r,am); - memcpy(r, t->data, stored); - mm_free((Value*)t); - return r; -} - -typedef struct TStack { - struct Value; - usz size; - usz cap; - u8 data[]; -} TStack; -#define TSALLOC(T,N,I) usz N##_dc=(I); u32 N##_e=sizeof(T); TStack* N##_o = (TStack*)mm_allocN(sizeof(TStack)+N##_e*N##_dc, t_temp); N##_o->size=0; N##_o->cap=N##_dc; T* N = (T*)N##_o->data; -#define TSFREE(N) mm_free((Value*)N##_o); -#define TSDBL(N) { N##_o = tstack_ext(N##_o, N##_e); N = (void*)N##_o->data; } -#define TSADD(N,X) { if (N##_o->size==N##_o->cap) TSDBL(N); N[N##_o->size++] = X; } -#define TSADDA(N,P,AM) { u64 n=AM; while(N##_o->size+n>N##_o->cap) TSDBL(N); memcpy(N+N##_o->size,P,n*N##_e); N##_o->size+= AM; } -#define TSSIZE(N) (N##_o->size) -TStack* tstack_ext(TStack* o, u32 elsz); - // shape mess typedef struct ShArr { diff --git a/src/h.h b/src/h.h index 70b46a3f..e81478b2 100644 --- a/src/h.h +++ b/src/h.h @@ -106,7 +106,7 @@ #define AUTO __auto_type #define LIKELY(X) __builtin_expect(X,1) #define RARE(X) __builtin_expect(X,0) -#define RFLD(X,T,F) ((T*)((char*)(X) - offsetof(T,F))) // reverse-read field: `T* x = …; E v = x->f; x == RFLD(v, T, f)` +#define RFLD(X,T,F) ((T*)((char*)(X) - offsetof(T,F))) // value, result type, field name; reverse-read field: `T* x = …; E v = x->f; x == RFLD(v, T, f)` #define N64x "%"SCNx64 #define N64d "%"SCNd64 #define N64u "%"SCNu64 @@ -122,7 +122,7 @@ typedef u8 ur; CTR_FOR(F) #undef F -#define fsizeof(T,F,E,n) (offsetof(T, F) + sizeof(E)*(n)) // type, flexible array member name, flexible array member type, item amount +#define fsizeof(T,F,E,N) (offsetof(T, F) + sizeof(E)*(N)) // type, flexible array member name, flexible array member type, item amount #define ftag(x) ((u64)(x) << 48) #define tag(v, t) b(((u64)(v)) | ftag(t)) // .111111111110000000000000000000000000000000000000000000000000000 infinity diff --git a/src/jit/nvm.c b/src/jit/nvm.c index ac8889d6..1dbaad25 100644 --- a/src/jit/nvm.c +++ b/src/jit/nvm.c @@ -2,6 +2,7 @@ #include "../core/gstack.h" #include "../ns.h" #include "../utils/file.h" +#include "../utils/talloc.h" #ifndef USE_PERF #define USE_PERF 0 // enable writing symbols to /tmp/perf-.map @@ -45,7 +46,7 @@ static void* mmX_allocN(usz sz, u8 type) { assert(sz>=16); return mmX_allocL(BSZ #endif #define P(N) B N=GSP; #if VM_POS - #define POS_UPD (envCurr-1)->bcL = bc-1; + #define POS_UPD (envCurr-1)->bcL = bc; #else #define POS_UPD #endif @@ -61,28 +62,39 @@ INS B i_ADDI(u64 v) { INS B i_ADDU(u64 v) { return b(v); } -INS B i_FN1C(B f, u32* bc GA1) { P(x) // TODO figure out a way to instead pass an offset in bc, so that shorter `mov`s can be used to pass it - GS_UPD;POS_UPD; +INS B i_FN1C(B f, u32* bc GA1) { P(x) GS_UPD;POS_UPD; // TODO figure out a way to instead pass an offset in bc, so that shorter `mov`s can be used to pass it B r = c1(f, x); dec(f); return r; } -INS B i_FN1O(B f, u32* bc GA1) { P(x) - GS_UPD;POS_UPD; +INS B i_FN1O(B f, u32* bc GA1) { P(x) GS_UPD;POS_UPD; B r = isNothing(x)? x : c1(f, x); dec(f); return r; } -INS B i_FN2C(B w, u32* bc GA1) { P(f)P(x) - GS_UPD;POS_UPD; +INS B i_FN2C(B w, u32* bc GA1) { P(f)P(x) GS_UPD;POS_UPD; B r = c2(f, w, x); dec(f); return r; } -INS B i_FN2O(B w, u32* bc GA1) { P(f)P(x) - GS_UPD;POS_UPD; B r; +INS B i_FN2O(B w, u32* bc GA1) { P(f)P(x) GS_UPD;POS_UPD; + B r; if (isNothing(x)) { dec(w); r = x; } else r = isNothing(w)? c1(f, x) : c2(f, w, x); dec(f); return r; } +INS B i_FN1Ci(B x, BB2B fi, u32* bc GA1) { GS_UPD;POS_UPD; + return fi(b((u64)0), x); +} +INS B i_FN2Ci(B w, BBB2B fi, u32* bc GA1) { P(x) GS_UPD;POS_UPD; + return fi(b((u64)0), w, x); +} +INS B i_FN1Oi(B x, BB2B fm, u32* bc GA1) { GS_UPD;POS_UPD; + B r = isNothing(x)? x : fm(b((u64)0), x); + return r; +} +INS B i_FN2Oi(B w, BB2B fm, BBB2B fd, u32* bc GA1) { P(x) GS_UPD;POS_UPD; + if (isNothing(x)) { dec(w); return x; } + else return isNothing(w)? fm(b((u64)0), x) : fd(b((u64)0), w, x); +} INS B i_ARR_0() { // TODO combine with ADDI return inc(bi_emptyHVec); } @@ -151,12 +163,11 @@ INS B i_NSPM(B o, u32 l) { c(FldAlias,a)->p = l; return a; } -INS B i_RETD(Scope** pscs GA1) { +INS B i_RETD(Scope** pscs GA1) { GS_UPD; Scope* sc = pscs[0]; Body* b = sc->body; ptr_inc(sc); ptr_inc(b->nsDesc); - GS_UPD; return m_ns(sc, b->nsDesc); } @@ -171,8 +182,6 @@ INS B i_RETD(Scope** pscs GA1) { - - #include "x86_64.h" #if USE_PERF @@ -204,6 +213,110 @@ static void write_asm(u8* p, u64 sz) { // for debugging; view with objdump -b bi } +typedef struct SRef { B v; i32 p; } SRef; +#define SREF(V,P) ((SRef){.v=V, .p=P}) +typedef struct OptRes { u32* bc; u32* offset; } OptRes; +static OptRes opt(u32* bc0) { + TSALLOC(SRef, stk, 8); + TSALLOC(u8, actions, 64); // 1 per instruction; 0: nothing; 1: indicates return; 2: remove; 3: FN1_/FN2C; 4: FN2O + TSALLOC(u64, data, 64); // variable length; whatever things are needed for the specific action + u32* bc = bc0; usz pos = 0; + while (true) { + u32* sbc = bc; + #define L64 ({ u64 r = bc[0] | ((u64)bc[1])<<32; bc+= 2; r; }) + bool ret = false; + u8 cact = 0; + switch (*bc++) { case FN1Ci: case FN1Oi: case FN2Ci: case FN2Oi: thrM("JIT optimization: didn't already expect immediate FN__"); + case ADDU: case ADDI: cact = 0; TSADD(stk,SREF(b(L64), pos)); break; + case FN1C: case FN1O: { SRef f = stk[TSSIZE(stk)-1]; + if (!isFun(f.v) || v(f.v)->type!=t_funBI) goto defIns; + actions[f.p] = 2; cact = 3; + TSADD(data, (u64) c(Fun, f.v)->c1); + goto defStk; + break; + } + case FN2C: { SRef f = stk[TSSIZE(stk)-2]; + if (!isFun(f.v) || v(f.v)->type!=t_funBI) goto defIns; + actions[f.p] = 2; cact = 3; + TSADD(data, (u64) c(Fun, f.v)->c2); + goto defStk; + break; + } + case FN2O: { SRef f = stk[TSSIZE(stk)-2]; + if (!isFun(f.v) || v(f.v)->type!=t_funBI) goto defIns; + actions[f.p] = 2; cact = 4; + TSADD(data, (u64) c(Fun, f.v)->c1); + TSADD(data, (u64) c(Fun, f.v)->c2); + goto defStk; + break; + } + case RETN: case RETD: + ret = true; + cact = 1; + goto defIns; + default: defIns:; + defStk: + TSSIZE(stk)-= stackConsumed(sbc); + i32 added = stackAdded(sbc); + for (i32 i = 0; i < added; i++) TSADD(stk, SREF(bi_optOut, -1)) + } + TSADD(actions, cact); + #undef L64 + if (ret) break; + bc = nextBC(sbc); + pos++; + } + TSFREE(stk); + + TSALLOC(u32, rbc, TSSIZE(actions)); + TSALLOC(u32, roff, TSSIZE(actions)); + bc = bc0; + u64 tpos = 0, dpos = 0; + while (true) { + u32* sbc = bc; + u32* ebc = nextBC(sbc); + #define L64 ({ u64 r = bc[0] | ((u64)bc[1])<<32; bc+= 2; r; }) + u32 ctype = actions[tpos++]; + bool ret = false; + u32 v = *bc++; + u64 psz = TSSIZE(rbc); + #define A64(X) { u64 a64=(X); TSADD(rbc, (u32)a64); TSADD(rbc, a64>>32); } + switch (ctype) { default: UD; + case 3: assert(v==FN1C|v==FN1O|v==FN2C); + TSADD(rbc, v==FN1C? FN1Ci : v==FN1O? FN1Oi : FN2Ci); + A64(data[dpos++]); + break; + case 4: assert(v==FN2O); + TSADD(rbc, FN2Oi); + A64(data[dpos++]); + A64(data[dpos++]); + break; + + case 2: break; // remove + + case 1: ret = true; goto def2; // return + + case 0: def2:; // do nothing + TSADDA(rbc, sbc, ebc-sbc); + } + u64 added = TSSIZE(rbc)-psz; + for (i32 i = 0; i < added; i++) TSADD(roff, sbc-bc0); + #undef A64 + if (ret) break; + bc = ebc; + } + bc = bc0; pos = 0; + + TSFREE(data); + TSFREE(actions); + return (OptRes){.bc = rbc, .offset = roff}; +} +#undef SREF +void freeOpt(OptRes o) { + TSFREEP(o.bc); + TSFREEP(o.offset); +} + static u32 readBytes4(u8* d) { return d[0] | d[1]<<8 | d[2]<<16 | d[3]<<24; } @@ -224,12 +337,15 @@ u8* m_nvm(Body* body) { if ((u64)i_SETN != (u32)(u64)i_SETN) thrM("JIT: Refusing to run with CBQN code outside of the 32-bit address range"); // #define CCALL(F) { IMM(r_TMP, F); ASM(CALL, r_TMP, -); } #define CCALL(F) { TSADD(rel, ASM_SIZE); ASM(CALLI, (u32)(u64)F, -); } - u32* bc = body->bc; + u32* origBC = body->bc; + OptRes optRes = opt(origBC); Block** blocks = body->blocks->a; i32 depth = 0; + u32* bc = optRes.bc; while (true) { u32* s = bc; u32* n = nextBC(bc); + u32* off = origBC + optRes.offset[s-optRes.bc]; bool ret = false; #define L64 ({ u64 r = bc[0] | ((u64)bc[1])<<32; bc+= 2; r; }) // #define LEA0(O,I,OFF) { ASM(MOV,O,I); ADDI(O,OFF); } @@ -256,10 +372,14 @@ u8* m_nvm(Body* body) { IMM(REG_ARG0, L64); CCALL(i_ADDU); #endif break; - case FN1C: TOPp; IMM(REG_ARG1, s); INV(2,0,i_FN1C); break; // (B, u32* bc, S) - case FN2C: TOPp; IMM(REG_ARG1, s); INV(2,0,i_FN2C); break; // (B, u32* bc, S) - case FN1O: TOPp; IMM(REG_ARG1, s); INV(2,0,i_FN1O); break; // (B, u32* bc, S) - case FN2O: TOPp; IMM(REG_ARG1, s); INV(2,0,i_FN2O); break; // (B, u32* bc, S) + case FN1C: TOPp; IMM(REG_ARG1,off); INV(2,0,i_FN1C); break; // (B, u32* bc, S) + case FN2C: TOPp; IMM(REG_ARG1,off); INV(2,0,i_FN2C); break; // (B, u32* bc, S) + case FN1O: TOPp; IMM(REG_ARG1,off); INV(2,0,i_FN1O); break; // (B, u32* bc, S) + case FN2O: TOPp; IMM(REG_ARG1,off); INV(2,0,i_FN2O); break; // (B, u32* bc, S) + case FN1Ci:TOPp; IMM(REG_ARG1,L64); IMM(REG_ARG2,off); INV(3,0,i_FN1Ci); break; // (B, BB2B fm, u32* bc, S) + case FN2Ci:TOPp; IMM(REG_ARG1,L64); IMM(REG_ARG2,off); INV(3,0,i_FN2Ci); break; // (B, BBB2B fd, u32* bc, S) + case FN1Oi:TOPp; IMM(REG_ARG1,L64); IMM(REG_ARG2,off); INV(3,0,i_FN1Oi); break; // (B, BB2B fm, u32* bc, S) + case FN2Oi:TOPp; IMM(REG_ARG1,L64); IMM(REG_ARG2, L64); IMM(REG_ARG3,off); INV(4,0,i_FN2Oi); break; // (B, BB2B fm, BBB2B fd, u32* bc, S) case ARRM: case ARRO:; u32 sz = *bc++; if (sz) { TOPp; IMM(REG_ARG1, sz); INV(2,0,i_ARR_p); } // (B, i64 sz, S) @@ -269,23 +389,23 @@ u8* m_nvm(Body* body) { Block* bl = blocks[*bc++]; u64 fn = (u64)(bl->ty==0? i_DFND_0 : bl->ty==1? i_DFND_1 : bl->ty==2? i_DFND_2 : NULL); if (fn==0) thrM("JIT: Bad DFND argument"); - IMM(REG_ARG0,s); ASM(MOV,REG_ARG1,r_PSCS); IMM(REG_ARG2,bl); INV(3,1,fn); + IMM(REG_ARG0,off); ASM(MOV,REG_ARG1,r_PSCS); IMM(REG_ARG2,bl); INV(3,1,fn); break; - case OP1D: TOPp; IMM(REG_ARG1,s); INV(2,0,i_OP1D); break; // (B, u32* bc, S) - case OP2D: TOPp; IMM(REG_ARG1,s); INV(2,0,i_OP2D); break; // (B, u32* bc, S) + case OP1D: TOPp; IMM(REG_ARG1,off); INV(2,0,i_OP1D); break; // (B, u32* bc, S) + case OP2D: TOPp; IMM(REG_ARG1,off); INV(2,0,i_OP2D); break; // (B, u32* bc, S) case OP2H: TOPp; INV(1,0,i_OP2H); break; // (B, S) case TR2D: TOPp; INV(1,0,i_TR2D); break; // (B, S) case TR3D: TOPp; INV(1,0,i_TR3D); break; // (B, S) case TR3O: TOPp; INV(1,0,i_TR3O); break; // (B, S) case LOCM: TOPs; { u64 d=*bc++; u64 p=*bc++; IMM(REG_RES, tag((u64)d<<32 | (u32)p, VAR_TAG).u); } break; case EXTM: TOPs; { u64 d=*bc++; u64 p=*bc++; IMM(REG_RES, tag((u64)d<<32 | (u32)p, EXT_TAG).u); } break; - case LOCO: TOPs; IMM(REG_ARG0,*bc++); IMM(REG_ARG1,*bc++); ASM(MOV,REG_ARG2,r_PSCS); IMM(REG_ARG3,s); INV(4,1,i_LOCO); break; // (u32 d, u32 p, Scope** pscs, u32* bc, S) - case EXTO: TOPs; IMM(REG_ARG0,*bc++); IMM(REG_ARG1,*bc++); ASM(MOV,REG_ARG2,r_PSCS); IMM(REG_ARG3,s); INV(4,1,i_EXTO); break; // (u32 d, u32 p, Scope** pscs, u32* bc, S) + case LOCO: TOPs; IMM(REG_ARG0,*bc++); IMM(REG_ARG1,*bc++); ASM(MOV,REG_ARG2,r_PSCS); IMM(REG_ARG3,off); INV(4,1,i_LOCO); break; // (u32 d, u32 p, Scope** pscs, u32* bc, S) + case EXTO: TOPs; IMM(REG_ARG0,*bc++); IMM(REG_ARG1,*bc++); ASM(MOV,REG_ARG2,r_PSCS); IMM(REG_ARG3,off); INV(4,1,i_EXTO); break; // (u32 d, u32 p, Scope** pscs, u32* bc, S) case LOCU: TOPs; IMM(REG_ARG0,*bc++); IMM(REG_ARG1,*bc++); ASM(MOV,REG_ARG2,r_PSCS); CCALL(i_LOCU); break; // (u32 d, u32 p, Scope** pscs, S) case EXTU: TOPs; IMM(REG_ARG0,*bc++); IMM(REG_ARG1,*bc++); ASM(MOV,REG_ARG2,r_PSCS); CCALL(i_EXTU); break; // (u32 d, u32 p, Scope** pscs, S) - case SETN: TOPp; ASM(MOV,REG_ARG1,r_PSCS); IMM(REG_ARG2,s); INV(3,0,i_SETN); break; // (B, Scope** pscs, u32* bc, S) - case SETU: TOPp; ASM(MOV,REG_ARG1,r_PSCS); IMM(REG_ARG2,s); INV(3,0,i_SETU); break; // (B, Scope** pscs, u32* bc, S) - case SETM: TOPp; ASM(MOV,REG_ARG1,r_PSCS); IMM(REG_ARG2,s); INV(3,0,i_SETM); break; // (B, Scope** pscs, u32* bc, S) + case SETN: TOPp; ASM(MOV,REG_ARG1,r_PSCS); IMM(REG_ARG2,off); INV(3,0,i_SETN); break; // (B, Scope** pscs, u32* bc, S) + case SETU: TOPp; ASM(MOV,REG_ARG1,r_PSCS); IMM(REG_ARG2,off); INV(3,0,i_SETU); break; // (B, Scope** pscs, u32* bc, S) + case SETM: TOPp; ASM(MOV,REG_ARG1,r_PSCS); IMM(REG_ARG2,off); INV(3,0,i_SETM); break; // (B, Scope** pscs, u32* bc, S) case FLDO: TOPp; IMM(REG_ARG1,*bc++); ASM(MOV,REG_ARG2,r_PSCS); INV(3,0,i_FLDO); break; // (B, u32 p, Scope** pscs, S) case NSPM: TOPp; IMM(REG_ARG1,*bc++); CCALL(i_NSPM); break; // (B, u32 l, S) case RETD: ASM(MOV,REG_ARG0,r_PSCS); INV(1,1,i_RETD); ret=true; break; // (Scope** pscs, S); stack diff 0 is wrong, but updating it is useless @@ -301,6 +421,7 @@ u8* m_nvm(Body* body) { depth+= stackDiff(s); if (ret) break; } + freeOpt(optRes); ASM(POP, r_CS, -); ASM(POP, r_PSCS, -); ASM(POP, r_TMP, -); diff --git a/src/jit/x86_64.h b/src/jit/x86_64.h index 05bd36d0..b9fa2455 100644 --- a/src/jit/x86_64.h +++ b/src/jit/x86_64.h @@ -17,6 +17,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #pragma once #include "../core.h" +#include "../utils/talloc.h" // 16 integer registers: // 0 1 2 (0: not saved, 1: callee saves, 2: caller saves) diff --git a/src/utils/file.c b/src/utils/file.c index 923f7e61..41fd1af2 100644 --- a/src/utils/file.c +++ b/src/utils/file.c @@ -2,6 +2,7 @@ #include "../core.h" #include "file.h" #include "mut.h" +#include "talloc.h" FILE* file_open(B path, char* desc, char* mode) { // doesn't consume u64 plen = utf8lenB(path); diff --git a/src/utils/hash.h b/src/utils/hash.h index 06b9ff03..d46ba954 100644 --- a/src/utils/hash.h +++ b/src/utils/hash.h @@ -1,5 +1,6 @@ #pragma once #include "wyhash.h" +#include "talloc.h" extern u64 wy_secret[4]; diff --git a/src/utils/talloc.h b/src/utils/talloc.h new file mode 100644 index 00000000..4b7271ea --- /dev/null +++ b/src/utils/talloc.h @@ -0,0 +1,35 @@ +#pragma once + +typedef struct TAlloc { + struct Value; + u8 data[]; +} TAlloc; +#define TOFF offsetof(TAlloc, data) +#define TALLOC(T,N,AM) T* N = (T*) ((TAlloc*)mm_allocN(TOFF + (AM)*sizeof(T) + 8, t_temp))->data; // +8 so mm is happy +#define TOBJ(N) (void*)((u8*)(N) - TOFF) +#define TFREE(N) mm_free((Value*)TOBJ(N)); +#define TREALLOC(N, AM) talloc_realloc(TOBJ(N), AM) +#define TSIZE(N) (mm_size(TOBJ(N))-TOFF) +static inline void* talloc_realloc(TAlloc* t, u64 am) { // TODO maybe shouldn't be inline? + u64 stored = mm_size((Value*)t)-TOFF; + if (stored > am) return t->data; + TALLOC(u8,r,am); + memcpy(r, t->data, stored); + mm_free((Value*)t); + return r; +} + +typedef struct TStack { + struct Value; + usz size; + usz cap; + u8 data[]; +} TStack; +#define TSALLOC(T,N,I) usz N##_dc=(I); u32 N##_e=sizeof(T); TStack* N##_o = (TStack*)mm_allocN(sizeof(TStack)+N##_e*N##_dc, t_temp); N##_o->size=0; N##_o->cap=N##_dc; T* N = (T*)N##_o->data; +#define TSFREE(N) mm_free((Value*)N##_o); +#define TSUPD(N,AM) { N##_o = ts_e(N##_o, N##_e, AM); N = (void*)N##_o->data; } +#define TSADD(N,X) { if (N##_o->size==N##_o->cap) TSUPD(N, 1); N[N##_o->size++] = X; } +#define TSADDA(N,P,AM) { u64 n=AM; if(N##_o->size+n>N##_o->cap) TSUPD(N, n); memcpy(N+N##_o->size,P,n*N##_e); N##_o->size+= n; } +#define TSFREEP(N) mm_free((void*)RFLD(N, TStack, data)); +#define TSSIZE(N) (N##_o->size) +TStack* ts_e(TStack* o, u32 elsz, u64 am); diff --git a/src/vm.c b/src/vm.c index 0e067644..7bf27b49 100644 --- a/src/vm.c +++ b/src/vm.c @@ -4,6 +4,7 @@ #include "jit/nvm.h" #include "ns.h" #include "utils/utf.h" +#include "utils/talloc.h" #ifndef USE_JIT #define USE_JIT 0 // enable the extremely basic x86-64 JIT that mostly just generates MOVs and CALLs @@ -13,7 +14,7 @@ #define FOR_BC(F) F(PUSH) F(VARO) F(VARM) F(ARRO) F(ARRM) F(FN1C) F(FN2C) F(OP1D) F(OP2D) F(TR2D) \ F(TR3D) F(SETN) F(SETU) F(SETM) F(POPS) F(DFND) F(FN1O) F(FN2O) F(CHKV) F(TR3O) \ F(OP2H) F(LOCO) F(LOCM) F(VFYM) F(SETH) F(RETN) F(FLDO) F(FLDM) F(NSPM) F(RETD) F(SYSV) F(LOCU) \ - F(EXTO) F(EXTM) F(EXTU) + F(EXTO) F(EXTM) F(EXTU) F(ADDI) F(ADDU) F(FN1Ci)F(FN1Oi)F(FN2Ci)F(FN2Oi) u32* nextBC(u32* p) { switch(*p) { @@ -29,21 +30,36 @@ u32* nextBC(u32* p) { return p+2; case LOCO: case LOCM: case LOCU: case EXTO: case EXTM: case EXTU: - case ADDI: case ADDU: + case ADDI: case ADDU: case FN1Ci: case FN1Oi: case FN2Ci: return p+3; + case FN2Oi: + return p+5; default: return 0; } } i32 stackDiff(u32* p) { - switch(*p) { + if (*p==ARRO|*p==ARRM) return 1-p[1]; + switch(*p) { default: UD; // case ARRO: case ARRM: return 1-p[1]; case PUSH: case VARO: case VARM: case DFND: case LOCO: case LOCM: case LOCU: case EXTO: case EXTM: case EXTU: case SYSV: case ADDI: case ADDU: return 1; - case CHKV: case VFYM: case FLDO: case FLDM: case RETD: case NSPM: 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: return 1-p[1]; - default: return 9999999; + case FN1Ci:case FN1Oi:case CHKV: case VFYM: case FLDO: case FLDM: case RETD: case NSPM: return 0; + case FN2Ci:case FN2Oi:case FN1C: case FN1O: case OP1D: case TR2D: case SETN: case SETU: case POPS: case OP2H: case SETH: case RETN: return -1; + case OP2D: case TR3D: case FN2C: case FN2O: case SETM: case TR3O: return -2; } } +i32 stackConsumed(u32* p) { + if (*p==ARRO|*p==ARRM) return p[1]; + switch(*p) { default: UD; // case ARRO: case ARRM: return -p[1]; + case PUSH: case VARO: case VARM: case DFND: case LOCO: case LOCM: case LOCU: case EXTO: case EXTM: case EXTU: case SYSV: case ADDI: case ADDU: return 0; + case CHKV: case VFYM: case RETD: return 0; + case FN1Ci:case FN1Oi:case FLDO: case FLDM: case NSPM: case RETN: case POPS: return 1; + case FN2Ci:case FN2Oi:case FN1C: case FN1O: case OP1D: case TR2D: case SETN: case SETU: case OP2H: case SETH: return 2; + case OP2D: case TR3D: case FN2C: case FN2O: case SETM: case TR3O: return 3; + } +} +i32 stackAdded(u32* p) { + if (*p==ARRO|*p==ARRM) return 1; + return stackDiff(p)+stackConsumed(p); +} char* nameBC(u32* p) { switch(*p) { default: return "(unknown)"; #define F(X) case X: return #X; @@ -184,6 +200,7 @@ Block* compileBlock(B block, Comp* comp, bool* bDone, u32* bc, usz bcIA, B block break; } } + #undef A64 usz nlen = TSSIZE(nBCT)-TSSIZE(mapT); for (usz i = 0; i < nlen; i++) TSADD(mapT, c-bc); h+= stackDiff(c); diff --git a/src/vm.h b/src/vm.h index c4a51de5..a090636b 100644 --- a/src/vm.h +++ b/src/vm.h @@ -34,7 +34,8 @@ enum { SYSV = 30, // N; get system function N LOCU = 31, // N0,N1; like LOCO but overrides the slot with bi_optOut EXTO, EXTM, EXTU, // alternate versions of LOC_ for extended variables - ADDI, ADDU, // separate PUSH for refcounting needed/not needed (stores the object inline, instead of reading from `objs`) + ADDI, ADDU, // separate PUSH for refcounting needed/not needed (stores the object inline as 2 u32s, instead of reading from `objs`) + FN1Ci, FN1Oi, FN2Ci, FN2Oi, // FN__ alternatives that don't take the function from the stack, but instead as an 2×u32 immediate in the bytecode BC_SIZE }; @@ -106,6 +107,9 @@ B evalBC(Body* b, Scope* sc); // doesn't consume; executes bytecode of the body u32* nextBC(u32* p); i32 stackDiff(u32* p); +i32 stackConsumed(u32* p); +i32 stackAdded(u32* p); +char* nameBC(u32* p); typedef struct FunBlock { struct Fun; Scope* sc; Block* bl; } FunBlock;