full SETH
This commit is contained in:
parent
b38db2dda0
commit
3991efd3cd
@ -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);
|
||||
}
|
||||
|
||||
2
src/h.h
2
src/h.h
@ -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;
|
||||
|
||||
@ -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);
|
||||
@ -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"); }
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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); }
|
||||
|
||||
82
src/vm.c
82
src/vm.c
@ -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;
|
||||
|
||||
30
src/vm.h
30
src/vm.h
@ -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);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user