From 563e4a87803e9edaae540066737380aaeae7f73e Mon Sep 17 00:00:00 2001 From: dzaima Date: Fri, 3 Sep 2021 00:46:34 +0300 Subject: [PATCH] new bytecode numbering --- src/jit/nvm_x86_64.c | 38 +++++++++++------------ src/vm.c | 52 +++++++++++++++---------------- src/vm.h | 74 ++++++++++++++++++++++++-------------------- 3 files changed, 85 insertions(+), 79 deletions(-) diff --git a/src/jit/nvm_x86_64.c b/src/jit/nvm_x86_64.c index aaaa86cd..210172e5 100644 --- a/src/jit/nvm_x86_64.c +++ b/src/jit/nvm_x86_64.c @@ -90,16 +90,16 @@ INS B i_ARR_p(B el0, i64 sz, B* cStack) { assert(sz>0); INS B i_DFND_0(u32* bc, Scope* sc, Block* bl) { POS_UPD; return m_funBlock(bl, sc); } INS B i_DFND_1(u32* bc, Scope* sc, Block* bl) { POS_UPD; return m_md1Block(bl, sc); } INS B i_DFND_2(u32* bc, Scope* sc, Block* bl) { POS_UPD; return m_md2Block(bl, sc); } -INS B i_OP1D(B f,B m, u32* bc) { POS_UPD; return m1_d (m,f ); } -INS B i_OP2D(B f,B m, B g, u32* bc) { POS_UPD; return m2_d (m,f,g); } -INS B i_OP2H(B m, B g ) { return m2_h (m, g); } +INS B i_MD1C(B f,B m, u32* bc) { POS_UPD; return m1_d (m,f ); } +INS B i_MD2C(B f,B m, B g, u32* bc) { POS_UPD; return m2_d (m,f,g); } +INS B i_MD2R(B m, B g ) { return m2_h (m, g); } INS B i_TR2D(B g, B h ) { return m_atop( g,h); } INS B i_TR3D(B f,B g, B h ) { return m_fork(f,g,h); } INS B i_TR3O(B f,B g, B h ) { return q_N(f)? m_atop(g,h) : m_fork(f,g,h); } INS B i_NOVAR(u32* bc, B* cStack) { POS_UPD; GS_UPD; thrM("Reading variable before its defined"); } -// INS B i_LOCU(u32 p, Scope* sc) { +// INS B i_VARU(u32 p, Scope* sc) { // B* vars = sc->vars; // B r = vars[p]; // vars[p] = bi_optOut; @@ -149,12 +149,12 @@ INS B i_FLDO(B ns, u32 p, Scope* sc) { dec(ns); return r; } -INS B i_VFYM(B o) { // TODO this and NSPM allocate and thus can error on OOM +INS B i_VFYM(B o) { // TODO this and ALIM allocate and thus can error on OOM VfyObj* a = mm_alloc(sizeof(VfyObj), t_vfyObj); a->obj = o; return tag(a,OBJ_TAG); } -INS B i_NSPM(B o, u32 l) { +INS B i_ALIM(B o, u32 l) { FldAlias* a = mm_alloc(sizeof(FldAlias), t_fldAlias); a->obj = o; a->p = l; @@ -234,7 +234,7 @@ static OptRes opt(u32* bc0) { TSSIZE(stk)--; break; } - case LOCM: { u32 d = *bc++; u32 p = *bc++; + case VARM: { u32 d = *bc++; u32 p = *bc++; TSADD(stk,SREF(tag((u64)d<<32 | (u32)p, VAR_TAG), pos)); break; } @@ -257,7 +257,7 @@ static OptRes opt(u32* bc0) { TSADD(data, (u64) c(Fun, f.v)->c2); goto defIns; } - case OP1D: { S(f,0) S(m,1) + case MD1C: { S(f,0) S(m,1) if (f.p==-1 | m.p==-1) goto defIns; B d = m1_d(inc(m.v), inc(f.v)); cact = 5; RM(f.p); RM(m.p); @@ -266,7 +266,7 @@ static OptRes opt(u32* bc0) { stk[TSSIZE(stk)-1] = SREF(d, pos); break; } - case OP2D: { S(f,0) S(m,1) S(g,2) + case MD2C: { S(f,0) S(m,1) S(g,2) if (f.p==-1 | m.p==-1 | g.p==-1) goto defIns; B d = m2_d(inc(m.v), inc(f.v), inc(g.v)); cact = 5; RM(f.p); RM(m.p); RM(g.p); @@ -441,7 +441,7 @@ static u32 readBytes4(u8* d) { file_wChars(m_str32(U"asm_off"), o); dec(o); B s = emptyCVec(); #define F(X) AFMT("s/%p$/%p # i_" #X "/;", i_##X, i_##X); - F(POPS) F(INC) F(FN1C) F(FN1O) F(FN2C) F(FN2O) F(FN1Oi) F(FN2Oi) F(ARR_0) F(ARR_p) F(DFND_0) F(DFND_1) F(DFND_2) F(OP1D) F(OP2D) F(OP2H) F(TR2D) F(TR3D) F(TR3O) F(EXTO) F(EXTU) F(SETN) F(SETU) F(SETM) F(FLDO) F(NSPM) F(RETD) F(SETNi) F(SETUi) F(SETMi) + F(POPS) F(INC) F(FN1C) F(FN1O) F(FN2C) F(FN2O) F(FN1Oi) F(FN2Oi) F(ARR_0) F(ARR_p) F(DFND_0) F(DFND_1) F(DFND_2) F(MD1C) F(MD2C) F(MD2R) F(TR2D) F(TR3D) F(TR3O) F(EXTO) F(EXTU) F(SETN) F(SETU) F(SETM) F(FLDO) F(ALIM) F(RETD) F(SETNi) F(SETUi) F(SETMi) #undef F file_wChars(m_str32(U"asm_sed"), s); dec(s); } @@ -525,7 +525,7 @@ Nvm_res m_nvm(Body* body) { #define INV(N,D,F) SPOS(R_A##N, D, 1); CCALL(F) #define TOPp MOV(R_A0,R_RES) #define TOPs if (depth) { u8 t = SPOS(R_A3, 0, 0); MOV8mr(t, R_RES); } - #define LSC(R,D) { if(D) MOV8rmo(R,R_SP,VAR8(pscs,D)); else MOV(R,r_SC); } + #define LSC(R,D) { if(D) MOV8rmo(R,R_SP,VAR8(pscs,D)); else MOV(R,r_SC); } // TODO return r_SC directly without a pointless mov #define INCV(R) INC4mo(R, offsetof(Value,refc)); // ADD4mi(R_A3, 1); CCALL(i_INC); #ifdef __BMI2__ // TODO move to runtime detection maybe #define INCB(R,T,U) IMM(T,0xfffffffffffffull);ADD(T,R);IMM(U,0x7fffffffffffeull);CMP(T,U);{JA(lI);MOVi1l(U,0x30);BZHI(U,R,U);INCV(U);LBL1(lI);} @@ -565,24 +565,24 @@ Nvm_res m_nvm(Body* body) { GET(R_A3,-1,2); IMM(R_A0,off); MOV(R_A1,r_SC); IMM(R_A2,bl); CCALL(fn); break; - case OP1D: TOPp; GET(R_A1,1,1); IMM(R_A2,off); CCALL(i_OP1D); break; // (B f,B m, u32* bc) - case OP2D: TOPp; GET(R_A1,1,0); GET(R_A2,2,1); IMM(R_A3,off); CCALL(i_OP2D); break; // (B f,B m, B g, u32* bc) - case OP2H: TOPp; GET(R_A1,1,0); CCALL(i_OP2H); break; // (B m, B g) // TODO these can actually error on OOM so should do something with bc/gStack + case MD1C: TOPp; GET(R_A1,1,1); IMM(R_A2,off); CCALL(i_MD1C); break; // (B f,B m, u32* bc) + case MD2C: TOPp; GET(R_A1,1,0); GET(R_A2,2,1); IMM(R_A3,off); CCALL(i_MD2C); break; // (B f,B m, B g, u32* bc) + case MD2R: TOPp; GET(R_A1,1,0); CCALL(i_MD2R); break; // (B m, B g) // TODO these can actually error on OOM so should do something with bc/gStack case TR2D: TOPp; GET(R_A1,1,0); CCALL(i_TR2D); break; // (B g, B h) case TR3D: TOPp; GET(R_A1,1,0); GET(R_A2,2,0); CCALL(i_TR3D); break; // (B f,B g, B h) case TR3O: TOPp; GET(R_A1,1,0); GET(R_A2,2,0); CCALL(i_TR3O); break; // (B f,B g, B h) - case LOCM: TOPs; { u64 d=*bc++; u64 p=*bc++; IMM(R_RES, tag((u64)d<<32 | (u32)p, VAR_TAG).u); } break; + case VARM: TOPs; { u64 d=*bc++; u64 p=*bc++; IMM(R_RES, tag((u64)d<<32 | (u32)p, VAR_TAG).u); } break; case EXTM: TOPs; { u64 d=*bc++; u64 p=*bc++; IMM(R_RES, tag((u64)d<<32 | (u32)p, EXT_TAG).u); } break; - case LOCO: TOPs; { u64 d=*bc++; u64 p=*bc++; LSC(R_A1,d); + case VARO: TOPs; { u64 d=*bc++; u64 p=*bc++; LSC(R_A1,d); MOV8rmo(R_RES,R_A1,p*8+offsetof(Scope,vars)); // read variable INCB(R_RES,R_A2,R_A3); // increment refcount if one's needed if (d) { IMM(R_A2, bi_noVar.u); CMP(R_A2,R_RES); JNE(lN); IMM(R_A0,off); INV(1,1,i_NOVAR); LBL1(lN); } // check for error } break; - case LOCU: TOPs; { u64 d=*bc++; u64 p=*bc++; + case VARU: TOPs; { u64 d=*bc++; u64 p=*bc++; LSC(R_A1,d); MOV8rmo(R_RES,R_A1,p*8+offsetof(Scope,vars)); // read variable IMM(R_A2, bi_optOut.u); MOV8mro(R_A1, R_A2,p*8+offsetof(Scope,vars)); // set to bi_optOut } break; - // case LOCU: TOPs; { u64 d=*bc++; IMM(R_A0,*bc++); LSC(R_A1,d); CCALL(i_LOCU); } break; // (u32 p, Scope* sc) + // case VARU: TOPs; { u64 d=*bc++; IMM(R_A0,*bc++); LSC(R_A1,d); CCALL(i_VARU); } break; // (u32 p, Scope* sc) case EXTO: TOPs; { u64 d=*bc++; IMM(R_A0,*bc++); LSC(R_A1,d); IMM(R_A2,off); INV(3,1,i_EXTO); } break; // (u32 p, Scope* sc, u32* bc, S) case EXTU: TOPs; { u64 d=*bc++; IMM(R_A0,*bc++); LSC(R_A1,d); CCALL(i_EXTU); } break; // (u32 p, Scope* sc) case SETHi:TOPp; { u64 v1=L64; u64 v2=L64; // (B s, B x, Scope** pscs, u32* bc, Body* v1, Body* v2) @@ -599,7 +599,7 @@ Nvm_res m_nvm(Body* body) { case SETUv:TOPp; { u64 d=*bc++; u64 p=*bc++; GET(R_A1,0,2); LSC(R_A1,d); IMM(R_A2,p); IMM(R_A3,off); CCALL(i_SETUv); NORES(1); break; } // ( B x, Scope* sc, u32 p, u32* bc) case SETMv:TOPp; { u64 d=*bc++; u64 p=*bc++; GET(R_A1,1,1); LSC(R_A2,d); IMM(R_A3,p); IMM(R_A4,off); CCALL(i_SETMv); NORES(2); break; } // (B f, B x, Scope* sc, u32 p, u32* bc) case FLDO: TOPp; GET(R_A1,0,2); IMM(R_A1,*bc++); MOV(R_A2,r_SC); CCALL(i_FLDO); break; // (B, u32 p, Scope* sc) - case NSPM: TOPp; IMM(R_A1,*bc++); CCALL(i_NSPM); break; // (B, u32 l) + case ALIM: TOPp; IMM(R_A1,*bc++); CCALL(i_ALIM); break; // (B, u32 l) case VFYM: TOPp; CCALL(i_VFYM); break; // (B) case CHKV: TOPp; IMM(R_A1,off); INV(2,0,i_CHKV); break; // (B, u32* bc, S) case RETD: if (lGPos!=0) GS_SET(r_CS); MOV(R_A0,r_SC); CCALL(i_RETD); ret=true; break; // (Scope* sc) diff --git a/src/vm.c b/src/vm.c index 458c11ee..e06394db 100644 --- a/src/vm.c +++ b/src/vm.c @@ -10,9 +10,9 @@ #define UNWIND_COMPILER 1 #endif -#define FOR_BC(F) F(PUSH) F(VARO) F(VARM) F(ARRO) F(ARRM) F(FN1C) F(FN2C) F(OP1D) F(OP2D) F(TR2D) \ +#define FOR_BC(F) F(PUSH) F(DYNO) F(DYNM) F(ARRO) F(ARRM) F(FN1C) F(FN2C) F(MD1C) F(MD2C) 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(MD2R) F(VARO) F(VARM) F(VFYM) F(SETH) F(RETN) F(FLDO) F(FLDM) F(ALIM) F(RETD) F(SYSV) F(VARU) \ F(EXTO) F(EXTM) F(EXTU) F(ADDI) F(ADDU) F(FN1Ci)F(FN1Oi)F(FN2Ci)F(FN2Oi) \ F(SETNi)F(SETUi)F(SETMi)F(SETNv)F(SETUv)F(SETMv)F(FAIL) @@ -20,17 +20,17 @@ u32* nextBC(u32* p) { i32 off; switch(*p) { case FN1C: case FN2C: case FN1O: case FN2O: - case OP1D: case OP2D: case OP2H: + case MD1C: case MD2C: case MD2R: case TR2D: case TR3D: case TR3O: case SETN: case SETU: case SETM: case SETH: case POPS: case CHKV: case VFYM: case RETN: case RETD: case FAIL: off = 1; break; case PUSH: case DFND: case ARRO: case ARRM: - case VARO: case VARM: case FLDO: case FLDM: - case SYSV: case NSPM: + case DYNO: case DYNM: case FLDO: case FLDM: + case SYSV: case ALIM: off = 2; break; - case LOCO: case LOCM: case LOCU: + case VARO: case VARM: case VARU: case EXTO: case EXTM: case EXTU: case ADDI: case ADDU: case FN1Ci: case FN1Oi: case FN2Ci: case DFND0: case DFND1: case DFND2: @@ -45,11 +45,11 @@ u32* nextBC(u32* p) { i32 stackDiff(u32* 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 DFND0:case DFND1:case DFND2: - case LOCU: case EXTO: case EXTM: case EXTU: case SYSV: case ADDI: case ADDU: return 1; - 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 POPS: case OP2H: case RETN: return -1; - case OP2D: case TR3D: case FN2C: case FN2O: case TR3O: case SETH: case SETHi:return -2; + case PUSH: case DYNO: case DYNM: case DFND: case VARO: case VARM: case DFND0:case DFND1:case DFND2: + case VARU: case EXTO: case EXTM: case EXTU: case SYSV: case ADDI: case ADDU: return 1; + case FN1Ci:case FN1Oi:case CHKV: case VFYM: case FLDO: case FLDM: case RETD: case ALIM: return 0; + case FN2Ci:case FN2Oi:case FN1C: case FN1O: case MD1C: case TR2D: case POPS: case MD2R: case RETN: return -1; + case MD2C: case TR3D: case FN2C: case FN2O: case TR3O: case SETH: case SETHi:return -2; case SETN: return -1; case SETNi:return 0; case SETNv:return -1; case SETU: return -1; case SETUi:return 0; case SETUv:return -1; @@ -60,12 +60,12 @@ i32 stackDiff(u32* p) { 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 PUSH: case DYNO: case DYNM: case DFND: case VARO: case VARM: case VARU: case EXTO: case EXTM: case EXTU: case SYSV: case ADDI: case ADDU: case DFND0:case DFND1:case DFND2:return 0; case CHKV: case RETD: return 0; - case FN1Ci:case FN1Oi:case FLDO: case FLDM: case NSPM: case RETN: case POPS: case VFYM: return 1; - case FN2Ci:case FN2Oi:case FN1C: case FN1O: case OP1D: case TR2D: case OP2H: case SETH: case SETHi:return 2; - case OP2D: case TR3D: case FN2C: case FN2O: case TR3O: return 3; + case FN1Ci:case FN1Oi:case FLDO: case FLDM: case ALIM: case RETN: case POPS: case VFYM: return 1; + case FN2Ci:case FN2Oi:case FN1C: case FN1O: case MD1C: case TR2D: case MD2R: case SETH: case SETHi:return 2; + case MD2C: case TR3D: case FN2C: case FN2O: case TR3O: return 3; case SETN: return 2; case SETNi: case SETNv: return 1; case SETU: return 2; case SETUi: case SETUv: return 1; @@ -287,17 +287,17 @@ Block* compileBlock(B block, Comp* comp, bool* bDone, u32* bc, usz bcIA, B allBl TSADD(usedBlocks, bl); break; } - case LOCO: case LOCM: case LOCU: { + case VARO: case VARM: case VARU: { i32 ins = c[0]; i32 cdepth = c[1]; i32 cpos = c[2]; if (cdepth+1 > mpsc) mpsc = cdepth+1; if (sc && cdepth>=depth) { Scope* csc = sc; - for (i32 i = depth; i < cdepth; i++) if (!(csc = csc->psc)) thrM("VM compiler: LOC_ has an out-of-bounds depth"); + for (i32 i = depth; i < cdepth; i++) if (!(csc = csc->psc)) thrM("VM compiler: VAR_ has an out-of-bounds depth"); if (cpos >= csc->varAm) { cpos-= csc->varAm; - ins = ins==LOCO? EXTO : ins==LOCM? EXTM : EXTO; + ins = ins==VARO? EXTO : ins==VARM? EXTM : EXTO; } } TSADD(newBC, ins); @@ -642,9 +642,9 @@ B evalBC(Block* bl, Body* b, Scope* sc) { // doesn't consume // } // break; // } - case OP1D: { P(f)P(m) GS_UPD;POS_UPD; ADD(m1_d (m,f )); break; } - case OP2D: { P(f)P(m)P(g) GS_UPD;POS_UPD; ADD(m2_d (m,f,g)); break; } - case OP2H: { P(m)P(g) ADD(m2_h (m, g)); break; } + case MD1C: { P(f)P(m) GS_UPD;POS_UPD; ADD(m1_d (m,f )); break; } + case MD2C: { P(f)P(m)P(g) GS_UPD;POS_UPD; ADD(m2_d (m,f,g)); break; } + case MD2R: { P(m)P(g) ADD(m2_h (m, g)); break; } case TR2D: { P(g)P(h) ADD(m_atop( g,h)); break; } case TR3D: { P(f)P(g)P(h) ADD(m_fork(f,g,h)); break; } case TR3O: { P(f)P(g)P(h) @@ -652,17 +652,17 @@ B evalBC(Block* bl, Body* b, Scope* sc) { // doesn't consume else ADD(m_fork(f,g,h)); break; } - case LOCM: { u32 d = *bc++; u32 p = *bc++; + case VARM: { u32 d = *bc++; u32 p = *bc++; ADD(tag((u64)d<<32 | (u32)p, VAR_TAG)); break; } - case LOCO: { u32 d = *bc++; u32 p = *bc++; + case VARO: { u32 d = *bc++; u32 p = *bc++; B l = pscs[d]->vars[p]; if(l.u==bi_noVar.u) { POS_UPD; thrM("Reading variable before its defined"); } ADD(inc(l)); break; } - case LOCU: { u32 d = *bc++; u32 p = *bc++; + case VARU: { u32 d = *bc++; u32 p = *bc++; B* vars = pscs[d]->vars; ADD(vars[p]); vars[p] = bi_optOut; @@ -723,7 +723,7 @@ B evalBC(Block* bl, Body* b, Scope* sc) { // doesn't consume ADD(m_ns(sc, b->nsDesc)); goto end; } - case NSPM: { P(o) u32 l = *bc++; + case ALIM: { P(o) u32 l = *bc++; FldAlias* a = mm_alloc(sizeof(FldAlias), t_fldAlias); a->obj = o; a->p = l; @@ -742,7 +742,7 @@ B evalBC(Block* bl, Body* b, Scope* sc) { // doesn't consume break; } case FAIL: thrM(q_N(sc->vars[2])? "This block cannot be called monadically" : "This block cannot be called dyadically"); - // not implemented: VARO VARM FLDM SYSV + // not implemented: DYNO DYNM FLDM SYSV default: #ifdef DEBUG printf("todo %d\n", bc[-1]); bc++; break; diff --git a/src/vm.h b/src/vm.h index b8611626..e4fbfd6a 100644 --- a/src/vm.h +++ b/src/vm.h @@ -11,42 +11,48 @@ #endif enum { - PUSH = 0, // N; push object from objs[N] - VARO = 1, // N; push variable with name strs[N] - VARM = 2, // N; push mutable variable with name strs[N] - ARRO = 3, // N; create a vector of top N items - ARRM = 4, // N; create a mutable vector of top N items - FN1C = 5, // monadic function call ⟨…,x,f ⟩ → F x - FN2C = 6, // dyadic function call ⟨…,x,f,w⟩ → w F x - OP1D = 7, // derive 1-modifier to function; ⟨…, _m,f⟩ → (f _m) - OP2D = 8, // derive 2-modifier to function; ⟨…,g,_m,f⟩ → (f _m_ g) - TR2D = 9, // derive 2-train aka atop; ⟨…, g,f⟩ → (f g) - TR3D = 10, // derive 3-train aka fork; ⟨…,h,g,f⟩ → (f g h) - SETN = 11, // set new; _ ←_; ⟨…,x, mut⟩ → mut←x - SETU = 12, // set upd; _ ↩_; ⟨…,x, mut⟩ → mut↩x - SETM = 13, // set mod; _ F↩_; ⟨…,x,F,mut⟩ → mut F↩x - POPS = 14, // pop object from stack - DFND = 15, // N; push dfns[N], derived to current scope - FN1O = 16, // optional monadic call (FN1C but checks for · at 𝕩) - FN2O = 17, // optional dyadic call (FN2C but checks for · at 𝕩 & 𝕨) - CHKV = 18, // throw error if top of stack is · - TR3O = 19, // TR3D but creates an atop if F is · - OP2H = 20, // derive 2-modifier to 1-modifier ⟨…,g,_m_⟩ → (_m_ g) - LOCO = 21, // N0,N1; push variable at depth N0 and position N1 - LOCM = 22, // N0,N1; push mutable variable at depth N0 and position N1 - VFYM = 23, // push a mutable version of ToS that fails if set to a non-equal value (for header assignment) - SETH = 24, // set header; acts like SETN, but it doesn't push to stack, and, instead of erroring in cases it would, it skips to the next body - RETN = 25, // returns top of stack - FLDO = 26, // N; get field nameList[N] from ToS - FLDM = 27, // N; get mutable field nameList[N] from ToS - NSPM = 28, // N; replace ToS with one with a namespace field alias N - RETD = 29, // return a namespace of exported items - 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 + PUSH = 0x00, // N; push object from objs[N] + DFND = 0x01, // N; push dfns[N], derived to current scope + SYSV = 0x02, // N; get system function N + + POPS = 0x06, // pop object from stack + RETN = 0x07, // returns top of stack + RETD = 0x08, // return a namespace of exported items + ARRO = 0x0B, // N; create a vector of top N items + ARRM = 0x0C, // N; create a mutable vector of top N items + + FN1C = 0x10, // monadic function call ⟨…,x,f ⟩ → F x + FN2C = 0x11, // dyadic function call ⟨…,x,f,w⟩ → w F x + FN1O = 0x12, // optional monadic call (FN1C but checks for · at 𝕩) + FN2O = 0x13, // optional dyadic call (FN2C but checks for · at 𝕩 & 𝕨) + TR2D = 0x14, // derive 2-train aka atop; ⟨…, g,f⟩ → (f g) + TR3D = 0x15, // derive 3-train aka fork; ⟨…,h,g,f⟩ → (f g h) + CHKV = 0x16, // throw error if top of stack is · + TR3O = 0x17, // TR3D but creates an atop if F is · + + MD1C = 0x1A, // call/derive 1-modifier; ⟨…, _m,f⟩ → (f _m) + MD2C = 0x1B, // call/derive 2-modifier; ⟨…,g,_m,f⟩ → (f _m_ g) + MD2L = 0x1C, // derive 2-modifier to 1-modifier with 𝔽 ⟨…,_m_,f⟩ → (f _m_) + MD2R = 0x1D, // derive 2-modifier to 1-modifier with 𝔾 ⟨…,g,_m_⟩ → (_m_ g) + + VARO = 0x20, // N0,N1; push variable at depth N0 and position N1 + VARM = 0x21, // N0,N1; push mutable variable at depth N0 and position N1 + VARU = 0x22, // N0,N1; like VARO but overrides the slot with bi_optOut + DYNO = 0x26, // N; push variable with name objs[N] + DYNM = 0x27, // N; push mutable variable with name objs[N] + + VFYM = 0x2B, // push a mutable version of ToS that fails if set to a non-equal value (for header assignment) + SETH = 0x2F, // set header; acts like SETN, but it doesn't push to stack, and, instead of erroring in cases it would, it skips to the next body + SETN = 0x30, // set new; _ ←_; ⟨…,x, mut⟩ → mut←x + SETU = 0x31, // set upd; _ ↩_; ⟨…,x, mut⟩ → mut↩x + SETM = 0x32, // set mod; _ F↩_; ⟨…,x,F,mut⟩ → mut F↩x + FLDO = 0x40, // N; get field nameList[N] from ToS + FLDM = 0x41, // N; get mutable field nameList[N] from ToS + ALIM = 0x42, // N; replace ToS with one with a namespace field alias N + EXTO, EXTM, EXTU, // alternate versions of VAR_ for extended variables 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 - SETNi, SETUi, SETMi, // SET_ alternatives that expect the set variable as a depth-position pair like LOC_ + SETNi, SETUi, SETMi, // SET_ alternatives that expect the set variable as a depth-position pair like VAR_ SETNv, SETUv, SETMv, // SET_i alternatives that also don't return the result SETHi, // internal version of SETH, with 2×u64 arguments specifying bodies to jump to on fail (or NULL if is last) DFND0, DFND1, DFND2, // internal versions of DFND with a specific type, and a u64 argument representing the block pointer