proper bi_optOut handling
This commit is contained in:
parent
592a8312ac
commit
88f8daedbf
12
src/h.h
12
src/h.h
@ -176,7 +176,7 @@ typedef u8 ur;
|
||||
// .FF. .111111111110nnn................................................ sNaN aka tagged aka not f64, if nnn≠0
|
||||
// 7FF. 0111111111110................................................... direct value with no need of refcounting
|
||||
static const u16 C32_TAG = 0b0111111111110001; // 7FF1 0111111111110001................00000000000ccccccccccccccccccccc char
|
||||
static const u16 TAG_TAG = 0b0111111111110010; // 7FF2 0111111111110010................nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn special value (0=nothing, 1=undefined var, 2=bad header; 3=optimized out; 4=error?; 5=no fill)
|
||||
static const u16 TAG_TAG = 0b0111111111110010; // 7FF2 0111111111110010nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn special value (see bi_N ect definitions further below)
|
||||
static const u16 VAR_TAG = 0b0111111111110011; // 7FF3 0111111111110011ddddddddddddddddnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn variable reference
|
||||
static const u16 EXT_TAG = 0b0111111111110100; // 7FF4 0111111111110100ddddddddddddddddnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn extended variable reference
|
||||
static const u16 RAW_TAG = 0b0111111111110101; // 7FF5 0111111111110101nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn raw 48 bits of data
|
||||
@ -346,11 +346,11 @@ u64 mm_heapUsed(void);
|
||||
#endif
|
||||
|
||||
// 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_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);
|
||||
static const B bi_N = b((u64)0x7FF2000000000000ull);
|
||||
static const B bi_noVar = b((u64)0x7FF2C00000000001ull);
|
||||
static const B bi_okHdr = b((u64)0x7FF2000000000002ull);
|
||||
static const B bi_optOut = b((u64)0x7FF2800000000003ull);
|
||||
static const B bi_noFill = b((u64)0x7FF2000000000005ull);
|
||||
extern GLOBAL B bi_emptyHVec, bi_emptyIVec, bi_emptyCVec, bi_emptySVec;
|
||||
#define emptyHVec() incG(bi_emptyHVec)
|
||||
#define emptyIVec() incG(bi_emptyIVec)
|
||||
|
||||
@ -164,12 +164,12 @@ INS B i_MD2C(B f,B m, B g, u32* bc) { POS_UPD; return m2_d (m,f,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_BADREAD(u32* bc, B* cStack, B var) {
|
||||
POS_UPD; GS_UPD; v_tagError(var, 0);
|
||||
}
|
||||
INS B i_EXTO(u32 p, Scope* sc, u32* bc, B* cStack) {
|
||||
B l = sc->ext->vars[p];
|
||||
if(l.u==bi_noVar.u) { POS_UPD; GS_UPD; thrM("Reading variable before its defined"); }
|
||||
if(isTag(l)) { POS_UPD; GS_UPD; v_tagError(l, false); }
|
||||
return inc(l);
|
||||
}
|
||||
INS B i_EXTU(u32 p, Scope* sc) {
|
||||
@ -225,8 +225,8 @@ INS B i_SETMi(B f, B x, Scope* sc, u32 p, u32* bc) { POS_UPD; B r = c2(f,v_getI(
|
||||
INS B i_SETCi(B f, Scope* sc, u32 p, u32* bc) { POS_UPD; B r = c1(f,v_getI(sc, p, true) ); dec(f); v_setI(sc, p, inc(r), true, false); return r; }
|
||||
INS void i_SETNv(B x, Scope* sc, u32 p ) { v_setI(sc, p, x, false, false); }
|
||||
INS void i_SETUv(B x, Scope* sc, u32 p, u32* bc) { POS_UPD; v_setI(sc, p, x, true, false); }
|
||||
INS void i_SETMv(B f, B x, Scope* sc, u32 p, u32* bc) { POS_UPD; B r = c2(f,v_getI(sc, p, false),x); dec(f); v_setI(sc, p, r, true, false); }
|
||||
INS void i_SETCv(B f, Scope* sc, u32 p, u32* bc) { POS_UPD; B r = c1(f,v_getI(sc, p, false) ); dec(f); v_setI(sc, p, r, true, false); }
|
||||
INS void i_SETMv(B f, B x, Scope* sc, u32 p, u32* bc) { POS_UPD; B r = c2(f,v_getI(sc, p, true),x); dec(f); v_setI(sc, p, r, true, false); }
|
||||
INS void i_SETCv(B f, Scope* sc, u32 p, u32* bc) { POS_UPD; B r = c1(f,v_getI(sc, p, true) ); dec(f); v_setI(sc, p, r, true, false); }
|
||||
INS B i_FLDG(B ns, u32 p, Scope* sc) {
|
||||
if (!isNsp(ns)) thrM("Trying to read a field from non-namespace");
|
||||
B r = inc(ns_getU(ns, p));
|
||||
@ -647,7 +647,7 @@ Nvm_res m_nvm(Body* body) {
|
||||
#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);{J1(cA,lI);MOVi1l(U,0x30);BZHI(U,R,U);INCV(U);LBL1(lI);}
|
||||
#define INCB(R,T,U) IMM(T,0xfffffffffffffull);ADD(T,R);IMM(U,0x7fffffffffffeull);CMP(T,U);{J1(cA,lI);MOVi1l(U,48);BZHI(U,R,U);INCV(U);LBL1(lI);}
|
||||
#else
|
||||
#define INCB(R,T,U) IMM(T,0xfffffffffffffull);ADD(T,R);IMM(U,0x7fffffffffffeull);CMP(T,U);{J1(cA,lI);IMM(U,0xffffffffffffull);AND(U,R);INCV(U);LBL1(lI);}
|
||||
#endif
|
||||
@ -698,8 +698,8 @@ Nvm_res m_nvm(Body* body) {
|
||||
case EXTM: TOPs; { u64 d=*bc++; u64 p=*bc++; IMM(R_RES, tagu64((u64)d<<32 | (u32)p, EXT_TAG).u); } break;
|
||||
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
|
||||
MOV(R_A2,R_RES); SHR8i(R_A2, 47); CMP4i(R_A2, v_bad17_read); { J1(cNE,lN); IMM(R_A0,off); MOV(R_A2,R_RES); INV(1,1,i_BADREAD); LBL1(lN); } // check for error
|
||||
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); J1(cNE,lN); IMM(R_A0,off); INV(1,1,i_NOVAR); LBL1(lN); } // check for error
|
||||
} break;
|
||||
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
|
||||
|
||||
@ -197,7 +197,10 @@ ASMI(XOR, Reg o, Reg i) { ASMS; REX8(o,i); ASM1(0x31); MRMr(o,i); ASME; }
|
||||
ASMI(AND, Reg o, Reg i) { ASMS; REX8(o,i); ASM1(0x21); MRMr(o,i); ASME; }
|
||||
|
||||
ASMI(XOR4, Reg o, Reg i) { ASMS; REX4(o,i); ASM1(0x31); MRMr(o,i); ASME; }
|
||||
ASMI(CMP, Reg o, Reg i) { ASMS; REX8(o,i); ASM1(0x39); MRMr(o,i); ASME; }
|
||||
|
||||
ASMI(CMP, Reg o, Reg i) { ASMS; REX8(o,i); ASM1(0x39); MRMr(o,i); ASME; }
|
||||
ASMI(CMP2i,Reg o, i16 imm) { ASMS; REX2(o,0); ASM1(0x81); MRM1(o,0xF8); ASM2(imm); ASME; }
|
||||
ASMI(CMP4i,Reg o, i32 imm) { ASMS; REX4(o,0); ASM1(0x81); MRM1(o,0xF8); ASM4(imm); ASME; }
|
||||
|
||||
ASMI(ADDi, Reg o, i32 imm) { if(!imm) return; ASMS; REX8(o,0); if(imm==(i8)imm) { ASM1(0x83); MRM1(o,0xc0); ASM1(imm); } else { ASM1(0x81); MRM1(o,0xc0); ASM4(imm); } ASME; }
|
||||
ASMI(SUBi, Reg o, i32 imm) { if(!imm) return; ASMS; REX8(o,0); if(imm==(i8)imm) { ASM1(0x83); MRM1(o,0xe8); ASM1(imm); } else { ASM1(0x81); MRM1(o,0xe8); ASM4(imm); } ASME; }
|
||||
|
||||
11
src/load.c
11
src/load.c
@ -824,7 +824,16 @@ void base_init() { // very first init function
|
||||
TIi(t_customObj,visit) = customObj_visit;
|
||||
TIi(t_arbObj,visit) = noop_visit;
|
||||
|
||||
assert((MD1_TAG>>1) == (MD2_TAG>>1)); // just to be sure it isn't changed incorrectly, `isMd` depends on this
|
||||
// making sure that expected properties of constants hold
|
||||
assert((MD1_TAG>>1) == (MD2_TAG>>1)); // dependencies: isMd
|
||||
|
||||
// dependencies: v_tagCheck & the JIT equivalent
|
||||
assert(v_bad17_read == (bi_noVar.u >>47));
|
||||
assert(v_bad17_read == (bi_optOut.u>>47));
|
||||
assert(v_bad17_read != (bi_N.u >>47));
|
||||
assert(v_bad18_write == (bi_noVar.u >>46));
|
||||
assert(v_bad18_write != (bi_optOut.u>>46));
|
||||
assert(v_bad18_write != (bi_N.u >>46));
|
||||
|
||||
#define FA(N,X) bi_##N = m_bfn(N##_c1, N##_c2, pf_##N);
|
||||
#define FM(N,X) bi_##N = m_bfn(N##_c1, c2_bad, pf_##N);
|
||||
|
||||
14
src/vm.c
14
src/vm.c
@ -537,6 +537,12 @@ FORCE_INLINE bool v_merge(Scope* pscs[], B s, B x, bool upd, bool hdr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
NOINLINE NORETURN void v_tagError(B x, bool write) {
|
||||
char* act = write? "Assignment: Attempting to modify" : "Attempting to read";
|
||||
if (x.u == bi_noVar.u) thrF("%S variable which is not yet defined", act);
|
||||
if (x.u == bi_optOut.u) thrF("%S variable which isn't available due to incomplete or aborted F↩", act);
|
||||
fatal("Unexpected v_tagError argument");
|
||||
}
|
||||
NOINLINE void v_setF(Scope* pscs[], B s, B x, bool upd) {
|
||||
if (isArr(s)) { VTY(s, t_harr);
|
||||
B* sp = harr_ptr(s);
|
||||
@ -571,7 +577,7 @@ NOINLINE void v_setF(Scope* pscs[], B s, B x, bool upd) {
|
||||
Scope* sc = pscs[V_DEPTH(s)];
|
||||
B prev = sc->ext->vars[V_POS(s)];
|
||||
if (upd) {
|
||||
if (prev.u==bi_noVar.u) thrM("↩: Updating undefined variable");
|
||||
if (v_checkBadWrite(prev)) v_tagError(prev, true);
|
||||
dec(prev);
|
||||
} else dec(prev);
|
||||
sc->ext->vars[V_POS(s)] = inc(x);
|
||||
@ -621,7 +627,7 @@ NOINLINE B v_getF(Scope* pscs[], B s) {
|
||||
} else if (isExt(s)) {
|
||||
Scope* sc = pscs[V_DEPTH(s)];
|
||||
B r = sc->ext->vars[V_POS(s)];
|
||||
if (r.u==bi_noVar.u) thrM("↩: Reading variable that hasn't been set");
|
||||
if (v_checkBadRead(r)) v_tagError(r, false);
|
||||
sc->ext->vars[V_POS(s)] = bi_optOut;
|
||||
return r;
|
||||
} else {
|
||||
@ -823,7 +829,7 @@ B evalBC(Body* b, Scope* sc, Block* bl) { // doesn't consume
|
||||
}
|
||||
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"); }
|
||||
if(v_checkBadRead(l)) { POS_UPD; v_tagError(l, false); }
|
||||
ADD(inc(l));
|
||||
break;
|
||||
}
|
||||
@ -840,7 +846,7 @@ B evalBC(Body* b, Scope* sc, Block* bl) { // doesn't consume
|
||||
}
|
||||
case EXTO: { u32 d = *bc++; u32 p = *bc++;
|
||||
B l = pscs[d]->ext->vars[p];
|
||||
if(l.u==bi_noVar.u) { POS_UPD; thrM("Reading variable before its defined"); }
|
||||
if(v_checkBadRead(l)) { POS_UPD; v_tagError(l, false); }
|
||||
ADD(inc(l));
|
||||
break;
|
||||
}
|
||||
|
||||
10
src/vm.h
10
src/vm.h
@ -279,10 +279,16 @@ typedef struct WrappedObj {
|
||||
#define V_POS(X) ((u32)((X).u))
|
||||
#define V_DEPTH(X) ((u16)((X).u>>32))
|
||||
|
||||
static u32 v_bad17_read = (TAG_TAG<<1) | 1;
|
||||
static u32 v_bad18_write = (TAG_TAG<<2) | 3;
|
||||
SHOULD_INLINE bool v_checkBadRead(B x) { return (x.u >> 47) == v_bad17_read; }
|
||||
SHOULD_INLINE bool v_checkBadWrite(B x) { return (x.u >> 46) == v_bad18_write; }
|
||||
NOINLINE NORETURN void v_tagError(B x, bool write);
|
||||
|
||||
NOINLINE B v_getF(Scope* pscs[], B s); // doesn't consume
|
||||
FORCE_INLINE B v_getI(Scope* sc, u32 p, bool chk) {
|
||||
B r = sc->vars[p];
|
||||
if (chk && r.u==bi_noVar.u) thrM("↩: Reading variable that hasn't been set");
|
||||
if (chk && v_checkBadRead(r)) v_tagError(r, false);
|
||||
sc->vars[p] = bi_optOut;
|
||||
return r;
|
||||
}
|
||||
@ -296,7 +302,7 @@ NOINLINE bool v_sethF(Scope* pscs[], B s, B x); // doesn't consume
|
||||
FORCE_INLINE void v_setI(Scope* sc, u32 p, B x, bool upd, bool chk) { // consumes x
|
||||
if (upd) {
|
||||
B prev = sc->vars[p];
|
||||
if (chk && prev.u==bi_noVar.u) thrM("↩: Updating variable that hasn't been set");
|
||||
if (chk && v_checkBadWrite(prev)) v_tagError(prev, true);
|
||||
sc->vars[p] = x;
|
||||
dec(prev);
|
||||
} else {
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
%DEF jiteq _jiteq ← {r ← ⍷ (1⋈𝔽)⎊{𝕊: 0⋈•CurrentError@}¨ 4⥊<𝕩 ⋄ "TEST FAIL: all results weren't equal" ! 1=≠r ⋄ {0‿e: !e; 1‿e: e}⊑r}
|
||||
|
||||
# body usage
|
||||
a←"zero"‿"one" ⋄ !a≡a⊸{𝕩?1⊑𝕨;0⊑𝕨}¨0‿1
|
||||
!"No header matched argument" % { 𝕊a‿b: a+b ; d𝕊a‿b‿c: a+b+c} ↕⥊3
|
||||
@ -29,13 +31,13 @@ a←"zero"‿"one" ⋄ !a≡a⊸{𝕩?1⊑𝕨;0⊑𝕨}¨0‿1
|
||||
!"No dyadic F˜⁼ undo header found for this 2-modifier block" % 1 +{𝔽𝔾𝕩}+˜⁼ 1
|
||||
|
||||
# assignment
|
||||
!"Reading variable before its defined" % {a} ⋄ a←1
|
||||
!"↩: Reading variable that hasn't been set" % {a⊢↩↕10} ⋄ a←2
|
||||
!"↩: Updating variable that hasn't been set" % {a↩↕10} ⋄ a←2
|
||||
!"↩: Reading variable that hasn't been set" % {a (↕10)˙↩} ⋄ a←2
|
||||
!"↩: Reading variable that hasn't been set" % a←1 ⋄ {a‿b⊢↩↕2} ⋄ b←2
|
||||
!"↩: Updating variable that hasn't been set" % a←1 ⋄ {a‿b↩↕2} ⋄ b←2
|
||||
!"↩: Reading variable that hasn't been set" % a←1 ⋄ {a‿b (↕10)˙↩} ⋄ b←2
|
||||
!"Attempting to read variable which is not yet defined" % {a} ⋄ a←1
|
||||
!"Attempting to read variable which is not yet defined" % {a⊢↩↕10} ⋄ a←2
|
||||
!"Assignment: Attempting to modify variable which is not yet defined" % {a↩↕10} ⋄ a←2
|
||||
!"Attempting to read variable which is not yet defined" % {a (↕10)˙↩} ⋄ a←2
|
||||
!"Attempting to read variable which is not yet defined" % a←1 ⋄ {a‿b⊢↩↕2} ⋄ b←2
|
||||
!"Assignment: Attempting to modify variable which is not yet defined" % a←1 ⋄ {a‿b↩↕2} ⋄ b←2
|
||||
!"Attempting to read variable which is not yet defined" % a←1 ⋄ {a‿b (↕10)˙↩} ⋄ b←2
|
||||
!"Assignment: Mismatched shape for spread assignment" % a‿b←1
|
||||
!"Assignment: Mismatched shape for spread assignment" % a‿b←1‿2‿3
|
||||
!"Assignment: Mismatched shape for spread assignment" % ⟨a⟩←<1
|
||||
@ -43,9 +45,17 @@ a←"zero"‿"one" ⋄ !a≡a⊸{𝕩?1⊑𝕨;0⊑𝕨}¨0‿1
|
||||
!"Assignment: Mismatched shape for spread assignment" % ⟨⟩←⟨1⟩
|
||||
⟨⟩←⟨⟩ %% ⟨⟩
|
||||
|
||||
# mid-update assignment; precise behavior here isn't particularly important, but it should at least be consistent
|
||||
a←↕2 ⋄ a {𝕊: a←"foo" ⋄ {𝕊:a!↩0}⎊•CurrentError @}↩ ⋄ %% "foo"
|
||||
!"Reading variable that was optimized out by F↩ after error" % a←"foo" ⋄ ! "foo"≡{𝕊:a!↩@}⎊•CurrentError @ ⋄ •Type a
|
||||
# mid-update variable behavior
|
||||
%USE jiteq ⋄ {𝕊: a←"foo" ⋄ {𝕊:a!↩@}⎊•CurrentError @ ⋄ 1} _jiteq @ %% 1
|
||||
!"Attempting to read variable which isn't available due to incomplete or aborted F↩" % %USE jiteq ⋄ {𝕊: a←"foo" ⋄ ! "foo" ≡ {𝕊:a!↩@}⎊•CurrentError @ ⋄ a ⋄ 1} _jiteq @
|
||||
!"Attempting to read variable which isn't available due to incomplete or aborted F↩" % %USE jiteq ⋄ {𝕊: a←"foo" ⋄ a {𝕊: ≠a}↩ ⋄ 1} _jiteq @
|
||||
!"Attempting to read variable which isn't available due to incomplete or aborted F↩" % %USE jiteq ⋄ {𝕊: a←1 ⋄ a {𝕊: a ⊢↩}↩ ⋄ 1} _jiteq @
|
||||
|
||||
# not-yet-defined variable usage
|
||||
!"Attempting to read variable which is not yet defined" % %USE jiteq ⋄ {𝕊: {a ⊢↩ } ⋄ a←1} _jiteq @
|
||||
!"Attempting to read variable which is not yet defined" % %USE jiteq ⋄ {𝕊: {a ⊢↩ ⋄ 1} ⋄ a←1} _jiteq @
|
||||
!"Attempting to read variable which is not yet defined" % %USE jiteq ⋄ {𝕊: {a ⋄ 1} ⋄ a←1} _jiteq @
|
||||
!"Assignment: Attempting to modify variable which is not yet defined" % %USE jiteq ⋄ {𝕊: {a‿a↩1‿2 ⋄ 1} ⋄ a←1} _jiteq @
|
||||
|
||||
# namespaces
|
||||
⟨a,b⟩←•BQN"{x⇐1‿2⋄a⇐3‿4⋄y←5‿6⋄b⇐7‿8}" ⋄ a‿b %% ⟨3‿4 ⋄ 7‿8⟩
|
||||
|
||||
Loading…
Reference in New Issue
Block a user