I’m less sure if this helps, because on top of the other one, I can’t tell if it does. I’ll have to test without the other optimization.
I know if I do this sort of lookup dispatch in my C forths/lisps, they don’t help. Usually the switch-case is best - probably due to inlining rather than function pointer tables. I’ve never sat down to look, just empirical testing. But, maybe it helps in JS.
turns the switch-case into a lookup table:
diff --git a/js/lil.js b/js/lil.js
index 31b10f4..a88963c 100644
--- a/js/lil.js
+++ b/js/lil.js
@@ -714,50 +714,52 @@ docall=(f,a,tail)=>{
issue(f.a.length==1&&f.a[0][0]=='.'?env_bind(f.c,[f.a[0].slice(3)],monad.list(a)): env_bind(f.c,f.a,a),f.b)
calldepth=max(calldepth,state.e.length)
}
+ops={
+ [op.DROP ]:(o,imm,b)=>{arg()},
+ [op.DUP ]:(o,imm,b)=>{const a=arg();ret(a),ret(a);},
+ [op.SWAP ]:(o,imm,b)=>{const a=arg();b=arg();ret(a),ret(b);},
+ [op.OVER ]:(o,imm,b)=>{const a=arg();b=arg();ret(b),ret(a),ret(b);},
+ [op.JUMP ]:(o,imm,b)=>{setpc(imm)},
+ [op.JUMPF]:(o,imm,b)=>{if(!lb(arg()))setpc(imm)},
+ [op.JUMPT]:(o,imm,b)=>{if( lb(arg()))setpc(imm)},
+ [op.LIT ]:(o,imm,b)=>{ret(blk_getimm(b,imm))},
+ [op.GET ]:(o,imm,b)=>{ret(env_get(getev(),blk_getimm(b,imm)));},
+ [op.SET ]:(o,imm,b)=>{const v=arg();env_set(getev(),blk_getimm(b,imm),v),ret(v);},
+ [op.LOC ]:(o,imm,b)=>{const v=arg();env_local(getev(),blk_getimm(b,imm),v),ret(v);},
+ [op.LOCS ]:(o,imm,b)=>{env_locals(getev(),blk_getimm(b,imm));},
+ [op.BUND ]:(o,imm,b)=>{const r=[];for(let z=0;z<imm;z++)r.push(arg());r.reverse(),ret(lml(r));},
+ [op.OP1 ]:(o,imm,b)=>{ ret(monadi[imm](arg()));},
+ [op.OP2 ]:(o,imm,b)=>{const y=arg();ret(dyadi [imm](arg(),y));},
+ [op.OP3 ]:(o,imm,b)=>{const z=arg(),y=arg();ret(triadi[imm](arg(),y,z));},
+ [op.IPRE ]:(o,imm,b)=>{const s=arg(),i=arg();ret(i),docall(s,i.v[imm]);if(lion(s)||lii(s)||linat(s)){for(let z=0;z<=imm;z++)i.v[z]=null}},
+ [op.IPOST]:(o,imm,b)=>{const s=arg(),i=arg(),r=arg();ret(i.v[imm]?r:s),ret(i),ret(s);},
+ [op.AMEND]:(o,imm,b)=>{
+ let v=arg(),r=arg(),i=ll(arg()),ro=arg(),n=blk_getimm(b,imm),t={v:1}
+ if(i.length&&!i[0]){i=i.filter(x=>x),t.v=0}r=amendv(ro,i,v,0,t);if(t.v&&!lin(n))env_set(getev(),n,r);ret(r);
+ },
+ [op.CALL ]:(o,imm,b)=>{const a=arg(),f=arg();docall(f,a,o==op.TAIL);}, // same as tail
+ [op.TAIL ]:(o,imm,b)=>{const a=arg(),f=arg();docall(f,a,o==op.TAIL);},
+ [op.BIND ]:(o,imm,b)=>{const f=arg(),r=lmon(f.n,f.a,f.b);r.c=getev(),env_local(getev(),lms(f.n),r),ret(r);},
+ [op.ITER ]:(o,imm,b)=>{const x=arg();ret(lil(x)?x:ld(x));ret(lid(x)?lmd():lml([]));},
+ [op.FIDX ]:(o,imm,b)=>{const x=arg(),f=arg();if((lid(f)||lil(f)||lis(f))&&lil(x)){ret(lml(x.v.map(x=>l_at(f,x))));setpc(imm)}else{ret(x)};},
+ [op.FMAP ]:(o,imm,b)=>{const x=arg(),f=monadi[imm];ret(lid(x)?lmd(x.k,x.v.map(f)):lml(ll(x).map(f)));},
+ [op.EACH ]:(o,imm,b)=>{
+ const n=arg(),r=arg(),s=arg();if(count(r)==count(s)){setpc(imm),ret(r);}
+ else{const z=count(r), v=lml([s.v[z],lid(s)?s.k[z]:lmn(z),lmn(z)]);
+ state.e.push(env_bind(getev(),n,v)),ret(s),ret(r);}
+ },
+ [op.NEXT ]:(o,imm,b)=>{const v=arg(),r=arg(),s=arg();state.e.pop();if(lid(r))r.k.push(s.k[r.v.length]);r.v.push(v),ret(s),ret(r),setpc(imm);},
+ [op.COL ]:(o,imm,b)=>{
+ const ex=arg(),t=arg(),n=tab_cols(t),v=ll(monad.cols(t));ret(t)
+ n.push('column'),v.push(t),issue(env_bind(getev(),n,lml(v)),ex);
+ },
+}
runop=_=>{
op_count+=1
const b=getblock();if(!liblk(b))ret(state.t.pop())
const pc=getpc(),o=blk_getb(b,pc),imm=(oplens[o]==3?blk_gets(b,1+pc):0); setpc(pc+oplens[o])
- switch(o){
- case op.DROP :arg();break
- case op.DUP :{const a=arg();ret(a),ret(a);break}
- case op.SWAP :{const a=arg(),b=arg();ret(a),ret(b);break}
- case op.OVER :{const a=arg(),b=arg();ret(b),ret(a),ret(b);break}
- case op.JUMP :setpc(imm);break
- case op.JUMPF:if(!lb(arg()))setpc(imm);break
- case op.JUMPT:if( lb(arg()))setpc(imm);break
- case op.LIT :ret(blk_getimm(b,imm));break
- case op.GET :{ret(env_get(getev(),blk_getimm(b,imm)));break}
- case op.SET :{const v=arg();env_set(getev(),blk_getimm(b,imm),v),ret(v);break}
- case op.LOC :{const v=arg();env_local(getev(),blk_getimm(b,imm),v),ret(v);break}
- case op.LOCS :{env_locals(getev(),blk_getimm(b,imm));break}
- case op.BUND :{const r=[];for(let z=0;z<imm;z++)r.push(arg());r.reverse(),ret(lml(r));break}
- case op.OP1 :{ ret(monadi[imm](arg() ));break}
- case op.OP2 :{const y=arg();ret(dyadi [imm](arg(),y ));break}
- case op.OP3 :{const z=arg(),y=arg();ret(triadi[imm](arg(),y,z));break}
- case op.IPRE :{const s=arg(),i=arg();ret(i),docall(s,i.v[imm]);if(lion(s)||lii(s)||linat(s)){for(let z=0;z<=imm;z++)i.v[z]=null}break}
- case op.IPOST:{const s=arg(),i=arg(),r=arg();ret(i.v[imm]?r:s),ret(i),ret(s);break}
- case op.AMEND:{
- let v=arg(),r=arg(),i=ll(arg()),ro=arg(),n=blk_getimm(b,imm),t={v:1}
- if(i.length&&!i[0]){i=i.filter(x=>x),t.v=0}r=amendv(ro,i,v,0,t);if(t.v&&!lin(n))env_set(getev(),n,r);ret(r);break
- }
- case op.CALL : // fall through:
- case op.TAIL :{const a=arg(),f=arg();docall(f,a,o==op.TAIL);break}
- case op.BIND :{const f=arg(),r=lmon(f.n,f.a,f.b);r.c=getev(),env_local(getev(),lms(f.n),r),ret(r);break}
- case op.ITER :{const x=arg();ret(lil(x)?x:ld(x));ret(lid(x)?lmd():lml([]));break}
- case op.FIDX :{const x=arg(),f=arg();if((lid(f)||lil(f)||lis(f))&&lil(x)){ret(lml(x.v.map(x=>l_at(f,x))));setpc(imm)}else{ret(x)};break}
- case op.FMAP :{const x=arg(),f=monadi[imm];ret(lid(x)?lmd(x.k,x.v.map(f)):lml(ll(x).map(f)));break}
- case op.EACH :{
- const n=arg(),r=arg(),s=arg();if(count(r)==count(s)){setpc(imm),ret(r);break}
- const z=count(r), v=lml([s.v[z],lid(s)?s.k[z]:lmn(z),lmn(z)]);
- state.e.push(env_bind(getev(),n,v)),ret(s),ret(r);break
- }
- case op.NEXT :{const v=arg(),r=arg(),s=arg();state.e.pop();if(lid(r))r.k.push(s.k[r.v.length]);r.v.push(v),ret(s),ret(r),setpc(imm);break}
- case op.COL :{
- const ex=arg(),t=arg(),n=tab_cols(t),v=ll(monad.cols(t));ret(t)
- n.push('column'),v.push(t),issue(env_bind(getev(),n,lml(v)),ex);break
- }
- }while(running()&&getpc()>=blk_here(getblock()))descope()
+ ops[o](o,imm,b)
+ while(running()&&getpc()>=blk_here(getblock()))descope()
}
fchar=x=>x=='I'?'i': x=='B'?'b': x=='L'?'s': x=='t'?'J': x=='T'?'J': x