full SETH

This commit is contained in:
dzaima 2021-08-21 03:32:11 +03:00
parent b38db2dda0
commit 3991efd3cd
8 changed files with 140 additions and 56 deletions

View File

@ -132,7 +132,7 @@ NOINLINE void print(B x) {
else if (x.u==bi_N.u) printf("·");
else if (x.u==bi_optOut.u) printf("(value optimized out)");
else if (x.u==bi_noVar.u) printf("(unset variable placeholder)");
else if (x.u==bi_badHdr.u) printf("(bad header note)");
else if (x.u==bi_okHdr.u) printf("(accepted SETH placeholder)");
else if (x.u==bi_noFill.u) printf("(no fill placeholder)");
else printf("(todo tag "N64x")", x.u>>48);
}

View File

@ -231,7 +231,7 @@ void gc_visitRoots(void);
// some primitive actions
static const B bi_N = b((u64)0x7FF2000000000000ull); // tag(0, TAG_TAG); // make gcc happy
static const B bi_noVar = b((u64)0x7FF2000000000001ull); // tag(1, TAG_TAG);
static const B bi_badHdr = b((u64)0x7FF2000000000002ull); // tag(2, TAG_TAG);
static const B bi_okHdr = b((u64)0x7FF2000000000002ull); // tag(2, TAG_TAG);
static const B bi_optOut = b((u64)0x7FF2000000000003ull); // tag(3, TAG_TAG);
static const B bi_noFill = b((u64)0x7FF2000000000005ull); // tag(5, TAG_TAG);
extern B bi_emptyHVec, bi_emptyIVec, bi_emptyCVec, bi_emptySVec;

View File

@ -1,7 +0,0 @@
#pragma once
#include "../vm.h"
B evalJIT(Body* b, Scope* sc, u8* ptr);
typedef struct Nvm_res { u8* p; B refs; } Nvm_res;
Nvm_res m_nvm(Body* b);
void nvm_free(u8* ptr);

View File

@ -1,5 +1,5 @@
#include "../core.h"
#include "nvm.h"
#include "../vm.h"
B evalJIT(Body* b, Scope* sc, u8* ptr) { thrM("JIT: Not supported"); }
Nvm_res m_nvm(Body* b) { thrM("JIT: Not supported"); }
void nvm_free(u8* ptr) { thrM("JIT: Not supported"); }

View File

@ -4,7 +4,7 @@
#include "../utils/file.h"
#include "../utils/talloc.h"
#include "../utils/mut.h"
#include "nvm.h"
#include "../vm.h"
#ifndef USE_PERF
#define USE_PERF 0 // enable writing symbols to /tmp/perf-<pid>.map
@ -124,9 +124,18 @@ INS B i_SETM(B s, B f, B x, Scope** pscs, u32* bc) { POS_UPD;
v_set(pscs, s, r, true); dec(s);
return r;
}
INS void i_SETH(B s, B x, Scope** pscs, u32* bc) { POS_UPD;
INS B i_SETH(B s, B x, Scope** pscs, u32* bc, Body* v1, Body* v2) { POS_UPD;
bool ok = v_seth(pscs, s, x); dec(x); dec(s);
if (!ok) thrM("VM: Header fallback NYI");
if (ok) return bi_okHdr;
Scope* sc = pscs[0];
Body* body = q_N(sc->vars[2])? v1 : v2;
if (body==NULL) thrF("No header matched argument%S", q_N(sc->vars[2])?"":"s");
Block* bl = body->bl;
// because of nvm returning semantics, we cannot quick-skip to the next body. TODO maybe we can by moving tail of evalJIT into i_RETN etc and some magic™ here?
u64 ga = blockGivenVars(bl);
for (u64 i = 0; i < ga; i++) inc(sc->vars[i]);
Scope* nsc = m_scope(body, sc->psc, body->varAm, ga, sc->vars);
return execBodyInlineI(bl, body, nsc);
}
INS B i_SETNi( B x, Scope* sc, u32 p, u32* bc) { POS_UPD; v_setI(sc, p, inc(x), false); return x; }
INS B i_SETUi( B x, Scope* sc, u32 p, u32* bc) { POS_UPD; v_setI(sc, p, inc(x), true ); return x; }
@ -155,8 +164,8 @@ INS B i_CHKV(B x, u32* bc, B* cStack) {
if(q_N(x)) { POS_UPD; GS_UPD; thrM("Unexpected Nothing (·)"); }
return x;
}
INS B i_FAIL(u32* bc, B* cStack) {
POS_UPD; GS_UPD; thrM("No body matched");
INS B i_FAIL(u32* bc, Scope* sc, B* cStack) {
POS_UPD; GS_UPD; thrM(q_N(sc->vars[2])? "This block cannot be called monadically" : "This block cannot be called dyadically");
}
INS B i_RETD(Scope* sc) {
Body* b = sc->body;
@ -502,6 +511,7 @@ Nvm_res m_nvm(Body* body) {
u32* bc = optRes.bc;
i32 lGPos = 0; // last updated gStack offset
TSALLOC(u64, retLbls, 1);
while (true) {
u32* s = bc;
u32* n = nextBC(bc);
@ -576,10 +586,12 @@ Nvm_res m_nvm(Body* body) {
// case LOCU: TOPs; { u64 d=*bc++; IMM(R_A0,*bc++); LSC(R_A1,d); CCALL(i_LOCU); } 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 SETN: TOPp; GET(R_A1,1,1); LEAi(R_A2,R_SP,VAR(pscs,0)); IMM(R_A3,off); CCALL(i_SETN); break; // (B s, B x, Scope** pscs, u32* bc)
case SETU: TOPp; GET(R_A1,1,1); LEAi(R_A2,R_SP,VAR(pscs,0)); IMM(R_A3,off); CCALL(i_SETU); break; // (B s, B x, Scope** pscs, u32* bc)
case SETM: TOPp; GET(R_A1,1,1) GET(R_A2,2,1); LEAi(R_A3,R_SP,VAR(pscs,0)); IMM(R_A4,off); CCALL(i_SETM); break; // (B s, B f, B x, Scope** pscs, u32* bc)
case SETH: TOPp; GET(R_A1,1,1); LEAi(R_A2,R_SP,VAR(pscs,0)); IMM(R_A3,off); CCALL(i_SETH); break; // (B s, B x, Scope** pscs, u32* bc)
case SETHi:TOPp; { u64 v1=L64; u64 v2=L64; // (B s, B x, Scope** pscs, u32* bc, Body* v1, Body* v2)
if (lGPos!=0) GS_SET(r_CS); lGPos=0; IMM(R_A4,v1); IMM(R_A5,v2);
/**/ GET(R_A1,1,1); LEAi(R_A2,R_SP,VAR(pscs,0)); IMM(R_A3,off); CCALL(i_SETH); IMM(R_A0, bi_okHdr.u); CMP(R_A0,R_RES); JNE4(l); TSADD(retLbls, l); break; }
case SETN: TOPp; GET(R_A1,1,1); LEAi(R_A2,R_SP,VAR(pscs,0)); IMM(R_A3,off); CCALL(i_SETN); break; // (B s, B x, Scope** pscs, u32* bc)
case SETU: TOPp; GET(R_A1,1,1); LEAi(R_A2,R_SP,VAR(pscs,0)); IMM(R_A3,off); CCALL(i_SETU); break; // (B s, B x, Scope** pscs, u32* bc)
case SETM: TOPp; GET(R_A1,1,1); GET(R_A2,2,1); LEAi(R_A3,R_SP,VAR(pscs,0)); IMM(R_A4,off); CCALL(i_SETM); break; // (B s, B f, B x, Scope** pscs, u32* bc)
// TODO SETNi doesn't really need to update gStack
case SETNi: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_SETNi); break; } // ( B x, Scope* sc, u32 p, u32* bc)
case SETUi: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_SETUi); break; } // ( B x, Scope* sc, u32 p, u32* bc)
@ -591,9 +603,9 @@ Nvm_res m_nvm(Body* body) {
case NSPM: TOPp; IMM(R_A1,*bc++); CCALL(i_NSPM); 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) GS_SET(r_CS); MOV(R_A0,r_SC); CCALL(i_RETD); ret=true; break; // (Scope* sc)
case RETN: if (lGPos) GS_SET(r_CS); ret=true; break;
case FAIL: TOPs; IMM(R_A0,off); INV(1,0,i_FAIL); ret=true; break;
case RETD: if (lGPos!=0) GS_SET(r_CS); MOV(R_A0,r_SC); CCALL(i_RETD); ret=true; break; // (Scope* sc)
case RETN: if (lGPos!=0) GS_SET(r_CS); ret=true; break;
case FAIL: TOPs; IMM(R_A0,off); MOV(R_A1,r_SC); INV(2,0,i_FAIL); ret=true; break;
default: thrF("JIT: Unsupported bytecode %i/%S", *s, nameBC(s));
}
#undef GET
@ -612,6 +624,11 @@ Nvm_res m_nvm(Body* body) {
if (ret) break;
}
freeOpt(optRes);
u64 retLblAm = TSSIZE(retLbls);
for (u64 i = 0; i < retLblAm; i++) {
u64 l = retLbls[i]; LBL4(l);
}
TSFREE(retLbls);
ADDi(R_SP, lsz);
POP(r_SC);
POP(r_CS);

View File

@ -92,6 +92,7 @@ static inline TStack* asm_r(TStack* o) {
return o;
}
static inline void asm_1(TStack* o, i8 v) {
o->data[o->size++] = v;
}
@ -101,6 +102,14 @@ static inline void asm_4(TStack* o, i32 v) { int size = o->size;
memcpy(o->data+size, (i32[]){v}, 4); // slightly less UB than an unaligned move
o->size = size+4;
}
static inline void asm_w4(u8* data, i32 v) {
memcpy(data, (i32[]){v}, 4);
}
static inline i32 asm_r4(u8* data) {
i32 v;
memcpy(&v, data, 4);
return v;
}
static inline void asm_8(TStack* o, i64 v) { int size = o->size;
// o->data[size+0] = (u8)(v ); o->data[size+1] = (u8)(v>> 8); o->data[size+2] = (u8)(v>>16); o->data[size+3] = (u8)(v>>24);
// o->data[size+4] = (u8)(v>>32); o->data[size+5] = (u8)(v>>40); o->data[size+6] = (u8)(v>>48); o->data[size+7] = (u8)(v>>56);
@ -414,7 +423,7 @@ static inline void asm_a(TStack* o, u64 len, u8 v[]) {
#define CALLi(POS) {AC1(CALLi,(u64)(POS)); TSADD(b_r, ASM_SIZE-4);} // POS must be 32-bit
#define RET() {b_o=asm_r(b_o); ASM1(0xC3);}
#define JO(L) u64 L=ASM_SIZE; {b_o=asm_r(b_o); ASM1(0x70);ASM1(-2);}
#define JO(L) u64 L=ASM_SIZE; {b_o=asm_r(b_o); ASM1(0x70);ASM1(-2);} // -2 comes from the instruction being 2 bytes long and L being defined at the start
#define JNO(L) u64 L=ASM_SIZE; {b_o=asm_r(b_o); ASM1(0x71);ASM1(-2);}
#define JB(L) u64 L=ASM_SIZE; {b_o=asm_r(b_o); ASM1(0x72);ASM1(-2);}
#define JAE(L) u64 L=ASM_SIZE; {b_o=asm_r(b_o); ASM1(0x73);ASM1(-2);}
@ -430,7 +439,24 @@ static inline void asm_a(TStack* o, u64 len, u8 v[]) {
#define JGE(L) u64 L=ASM_SIZE; {b_o=asm_r(b_o); ASM1(0x7D);ASM1(-2);}
#define JLE(L) u64 L=ASM_SIZE; {b_o=asm_r(b_o); ASM1(0x7E);ASM1(-2);}
#define JG(L) u64 L=ASM_SIZE; {b_o=asm_r(b_o); ASM1(0x7F);ASM1(-2);}
#define LBL1(L) { i64 t=(i8)b_o->data[L+1] + ASM_SIZE-(i64)L; if(t!=(i8)t)err("x86-64 codegen: jump too long!"); b_o->data[L+1] = t; }
#define LBL1(L) { i64 t=(i8)b_o->data[L+1] + ASM_SIZE-(i64)L; if(t!=(i8)t) err("x86-64 codegen: jump too long!"); b_o->data[L+1] = t; }
#define JO4(L) u64 L=ASM_SIZE; {b_o=asm_r(b_o); ASM1(0x0f);ASM1(0x80);ASM4(-6);}
#define JNO4(L) u64 L=ASM_SIZE; {b_o=asm_r(b_o); ASM1(0x0f);ASM1(0x81);ASM4(-6);}
#define JB4(L) u64 L=ASM_SIZE; {b_o=asm_r(b_o); ASM1(0x0f);ASM1(0x82);ASM4(-6);}
#define JAE4(L) u64 L=ASM_SIZE; {b_o=asm_r(b_o); ASM1(0x0f);ASM1(0x83);ASM4(-6);}
#define JE4(L) u64 L=ASM_SIZE; {b_o=asm_r(b_o); ASM1(0x0f);ASM1(0x84);ASM4(-6);}
#define JNE4(L) u64 L=ASM_SIZE; {b_o=asm_r(b_o); ASM1(0x0f);ASM1(0x85);ASM4(-6);}
#define JBE4(L) u64 L=ASM_SIZE; {b_o=asm_r(b_o); ASM1(0x0f);ASM1(0x86);ASM4(-6);}
#define JA4(L) u64 L=ASM_SIZE; {b_o=asm_r(b_o); ASM1(0x0f);ASM1(0x87);ASM4(-6);}
#define JS4(L) u64 L=ASM_SIZE; {b_o=asm_r(b_o); ASM1(0x0f);ASM1(0x88);ASM4(-6);}
#define JNS4(L) u64 L=ASM_SIZE; {b_o=asm_r(b_o); ASM1(0x0f);ASM1(0x89);ASM4(-6);}
#define JP4(L) u64 L=ASM_SIZE; {b_o=asm_r(b_o); ASM1(0x0f);ASM1(0x8A);ASM4(-6);}
#define JNP4(L) u64 L=ASM_SIZE; {b_o=asm_r(b_o); ASM1(0x0f);ASM1(0x8B);ASM4(-6);}
#define JL4(L) u64 L=ASM_SIZE; {b_o=asm_r(b_o); ASM1(0x0f);ASM1(0x8C);ASM4(-6);}
#define JGE4(L) u64 L=ASM_SIZE; {b_o=asm_r(b_o); ASM1(0x0f);ASM1(0x8D);ASM4(-6);}
#define JLE4(L) u64 L=ASM_SIZE; {b_o=asm_r(b_o); ASM1(0x0f);ASM1(0x8E);ASM4(-6);}
#define JG4(L) u64 L=ASM_SIZE; {b_o=asm_r(b_o); ASM1(0x0f);ASM1(0x8F);ASM4(-6);}
#define LBL4(L) { i64 t=asm_r4(b_o->data+(L+2)) + ASM_SIZE-(i64)L; if(t!=(i32)t) err("x86-64 codegen: jump too long!"); asm_w4(b_o->data+(L+2), t); }
ASMI(ADD, Reg o, Reg i) { nREX8(o,i); ASM1(0x01); nA_REG(o,i); }
ASMI(SUB, Reg o, Reg i) { nREX8(o,i); ASM1(0x29); nA_REG(o,i); }

View File

@ -1,7 +1,6 @@
#include <unistd.h>
#include "core.h"
#include "vm.h"
#include "jit/nvm.h"
#include "ns.h"
#include "utils/utf.h"
#include "utils/talloc.h"
@ -36,7 +35,7 @@ u32* nextBC(u32* p) {
case ADDI: case ADDU:
case FN1Ci: case FN1Oi: case FN2Ci: case SETNi: case SETUi: case SETMi: case SETNv: case SETUv: case SETMv:
off = 3; break;
case FN2Oi:
case FN2Oi: case SETHi:
off = 5; break;
default: UD;
}
@ -48,7 +47,7 @@ i32 stackDiff(u32* p) {
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 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: return -2;
case OP2D: 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;
@ -62,7 +61,7 @@ i32 stackConsumed(u32* p) {
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 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: return 2;
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 SETN: return 2; case SETNi: case SETNv: return 1;
@ -144,7 +143,11 @@ static Body* m_body(i32 vam, i32 pos, u16 maxStack, u16 maxPSC) { // leaves varI
body->varAm = (u16)vam;
return body;
}
typedef struct SETHRequest {
u32 off; // offset into bytecode where the two integers must be inserted
u32 pos1; // offset into bodyI/bodyMap of what's wanted for monadic
u32 pos2; // ↑ for dyadic
} SETHRequest;
Block* compileBlock(B block, Comp* comp, bool* bDone, u32* bc, usz bcIA, B allBlocks, B allBodies, B nameList, Scope* sc, i32 depth) {
usz blIA = a(block)->ia;
if (blIA!=3) thrM("VM compiler: Bad block info size");
@ -179,12 +182,14 @@ Block* compileBlock(B block, Comp* comp, bool* bDone, u32* bc, usz bcIA, B allBl
bodyAm2 = 1;
}
// for (int i = 0; i < bodyILen+2; i++) printf("%d ", bodyI[i]); putchar('\n'); printf("things: %d %d\n", bodyAm1, bodyAm2);
TSALLOC(Block*, usedBlocks, 2); // list of blocks to be referenced by DFND, stored in result->blocks
TSALLOC(Body*, bodies, 2); // list of bodies of this block
TSALLOC(i32, newBC, 20); // transformed bytecode
TSALLOC(i32, mapBC, 20); // map of original bytecode to transformed
TSALLOC(Block*, usedBlocks, 2); // list of blocks to be referenced by DFND, stored in result->blocks
TSALLOC(Body*, bodies, 2); // list of bodies of this block
TALLOC(Body*, bodyMap, bodyILen+2); // map from index in bodyI to the corresponding body
TSALLOC(SETHRequest, sethReqs, 10); // list of SETHi's to fill out when bodyMap is complete
i32 pos1 = 0;
i32 pos1 = 0; // pos1 and pos2 always stay valid indexes in bodyI because bodyI is padded with -1s
i32 pos2 = bodyAm1+1;
i32 index1 = -1;
i32 index2 = -1;
@ -200,6 +205,7 @@ Block* compileBlock(B block, Comp* comp, bool* bDone, u32* bc, usz bcIA, B allBl
body->nsDesc = NULL;
TSADD(bodies, body);
}
bodyMap[bodyAm1] = bodyMap[bodyILen+1] = NULL;
while (true) {
i32 curr1 = bodyI[pos1];
@ -207,8 +213,9 @@ Block* compileBlock(B block, Comp* comp, bool* bDone, u32* bc, usz bcIA, B allBl
i32 currBody = curr1<curr2? curr1 : curr2;
if (currBody==I32_MAX) break;
// printf("step %d %d: %d %d %d\n", pos1, pos2, curr1, curr2, currBody);
if (curr1==currBody) { if (index1==-1) index1=TSSIZE(bodies); pos1++; }
if (curr2==currBody) { if (index2==-1) index2=TSSIZE(bodies); pos2++; }
u64 bodyIdx = TSSIZE(bodies);
bool is1 = curr1==currBody; if (is1) { if (index1==-1) index1=bodyIdx; pos1++; }
bool is2 = curr2==currBody; if (is2) { if (index2==-1) index2=bodyIdx; pos2++; }
// printf("idxs: %d %d\n", index1, index2);
@ -294,6 +301,11 @@ Block* compileBlock(B block, Comp* comp, bool* bDone, u32* bc, usz bcIA, B allBl
TSADD(newBC, cpos);
break;
}
case SETH:
TSADD(newBC, SETHi);
TSADD(sethReqs, ((SETHRequest){.off = TSSIZE(newBC), .pos1 = pos1, .pos2 = pos2}));
A64(0); A64(0); // to be filled in by later sethReqs handling
break;
default: {
u32* ccpy = c;
while (ccpy!=n) TSADD(newBC, *ccpy++);
@ -321,7 +333,17 @@ Block* compileBlock(B block, Comp* comp, bool* bDone, u32* bc, usz bcIA, B allBl
}
TSADD(bodies, body);
if (is1) bodyMap[pos1-1] = body;
if (is2) bodyMap[pos2-1] = body;
}
u64 sethReqAm = TSSIZE(sethReqs);
for (u64 i = 0; i < sethReqAm; i++) {
SETHRequest r = sethReqs[i];
u64 v1 = (u64)bodyMap[r.pos1]; newBC[r.off+0] = (u32)v1; newBC[r.off+1] = v1>>32;
u64 v2 = (u64)bodyMap[r.pos2]; newBC[r.off+2] = (u32)v2; newBC[r.off+3] = v2>>32;
}
TSFREE(sethReqs);
TFREE(bodyMap);
TFREE(bodyI);
usz blC = TSSIZE(usedBlocks);
@ -491,6 +513,7 @@ NOINLINE B v_getR(Scope* pscs[], B s) {
FORCE_INLINE B execBodyInlineI(Block* block, Body* body, Scope* sc);
#ifdef DEBUG_VM
i32 bcDepth=-2;
@ -662,9 +685,22 @@ B evalBC(Block* bl, Body* b, Scope* sc) { // doesn't consume
ADD(r);
break;
}
case SETH: { P(s) P(x) GS_UPD; POS_UPD;
case SETHi:{ P(s) P(x) GS_UPD; POS_UPD; u64 v1 = L64; u64 v2 = L64;
bool ok = v_seth(pscs, s, x); dec(x); dec(s);
if (!ok) thrM("VM: Header fallback NYI");
if (!ok) {
Body* body = (Body*)(q_N(sc->vars[2])? v1 : v2);
if (body==NULL) thrF("No header matched argument%S", q_N(sc->vars[2])?"":"s");
GS_UPD;
popEnv();
i32 ga = blockGivenVars(bl);
for (u64 i = 0; i < ga; i++) inc(sc->vars[i]);
Scope* nsc = m_scope(body, sc->psc, body->varAm, ga, sc->vars);
scope_dec(sc);
return execBodyInlineI(bl, body, nsc);
}
break;
}
case FLDO: { P(ns) GS_UPD; u32 p = *bc++; POS_UPD;
@ -697,7 +733,7 @@ B evalBC(Block* bl, Body* b, Scope* sc) { // doesn't consume
ADD(tag(a,OBJ_TAG));
break;
}
case FAIL: thrM("No body matched");
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
default:
#ifdef DEBUG
@ -729,7 +765,7 @@ B evalBC(Block* bl, Body* b, Scope* sc) { // doesn't consume
#undef GS_UPD
}
Scope* m_scope(Body* body, Scope* psc, u16 varAm, i32 initVarAm, B* initVars) { // doesn't consume
Scope* m_scope(Body* body, Scope* psc, u16 varAm, i32 initVarAm, B* initVars) { // consumes initVarAm items of initVars
Scope* sc = mm_alloc(fsizeof(Scope, vars, B, varAm), t_scope);
sc->body = body; ptr_inc(body);
sc->psc = psc; if(psc) ptr_inc(psc);
@ -741,28 +777,12 @@ Scope* m_scope(Body* body, Scope* psc, u16 varAm, i32 initVarAm, B* initVars) {
return sc;
}
FORCE_INLINE B execBodyInlineI(Block* block, Body* body, Scope* sc) { // consumes sc, unlike execBlockInline
#if JIT_START != -1
if (body->nvm) { toJIT: return evalJIT(body, sc, body->nvm); }
bool jit = true;
#if JIT_START > 0
jit = body->callCount++ >= JIT_START;
#endif
// jit = body->bc[2]==m_f64(123456).u>>32; // enable JIT for blocks starting with `123456⋄`
if (jit) {
Nvm_res r = m_nvm(body);
body->nvm = r.p;
body->nvmRefs = r.refs;
goto toJIT;
}
#endif
return evalBC(block, body, sc);
}
B execBlockInline(Block* block, Scope* sc) { ptr_inc(sc); return execBodyInlineI(block, block->bodies[0], sc); }
FORCE_INLINE B execBlock(Block* block, Body* body, Scope* psc, i32 ga, B* svar) { // consumes svar contents
u16 varAm = body->varAm;
assert(varAm>=ga);
assert(ga == blockGivenVars(block));
Scope* sc = m_scope(body, psc, varAm, ga, svar);
B r = execBodyInlineI(block, body, sc);
return r;

View File

@ -48,7 +48,8 @@ enum {
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_
SETNv, SETUv, SETMv, // SET_i alternatives that also don't return the result
FAIL, // no body matched
SETHi, // internal version of SETH, with 2×u64 arguments specifying bodies to jump to on fail (or NULL if is last)
FAIL, // this body cannot be called monadically/dyadically
BC_SIZE
};
@ -127,7 +128,31 @@ Block* bqn_comp(B str, B path, B args);
Block* bqn_compSc(B str, B path, B args, Scope* sc, bool repl);
Block* compile(B bcq, B objs, B blocks, B bodies, B indices, B tokenInfo, B src, B path, Scope* sc);
Scope* m_scope(Body* body, Scope* psc, u16 varAm, i32 initVarAm, B* initVars);
typedef struct Nvm_res { u8* p; B refs; } Nvm_res;
Nvm_res m_nvm(Body* b);
void nvm_free(u8* ptr);
B evalJIT(Body* b, Scope* sc, u8* ptr);
B evalBC(Block* bl, Body* b, Scope* sc);
B execBlockInline(Block* block, Scope* sc); // doesn't consume; executes bytecode of the monadic body directly in the scope
FORCE_INLINE B execBodyInlineI(Block* block, Body* body, Scope* sc) { // consumes sc, unlike execBlockInline
#if JIT_START != -1
if (body->nvm) { toJIT: return evalJIT(body, sc, body->nvm); }
bool jit = true;
#if JIT_START > 0
jit = body->callCount++ >= JIT_START;
#endif
// jit = body->bc[2]==m_f64(123456).u>>32; // enable JIT for blocks starting with `123456⋄`
if (jit) {
Nvm_res r = m_nvm(body);
body->nvm = r.p;
body->nvmRefs = r.refs;
goto toJIT;
}
#endif
return evalBC(block, body, sc);
}
u32* nextBC(u32* p);
i32 stackDiff(u32* p);
@ -188,6 +213,9 @@ FORCE_INLINE void scope_dec(Scope* sc) { // version of ptr_dec for scopes, that
}
ptr_dec(sc);
}
FORCE_INLINE i32 blockGivenVars(Block* bl) {
return (bl->imm?0:3) + bl->ty + (bl->ty>0);
}
void vm_pst(Env* s, Env* e);
void vm_pstLive(void);
void vm_printPos(Comp* comp, i32 bcPos, i64 pos);