lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Am 2017-04-05 14:52, schrieb Daurnimator:
On 5 April 2017 at 22:28,  <gz@tset.de> wrote:
I had a go at making the core vm loop of lua 5.3.4 into a direct threaded
interpreter. The change itself was pretty easy, basically it involved

I'd be interested in seeing your patch. Have you uploaded it anywhere?

I'll attach it to this mail. This patch is against lvm.c from lua 5.3.4

As far as I understand it, this should have been a relatively easy
change to make and maintain; lvm.c has #defines ready for you to make
such a modification (vmdispatch, vmcase, vmbreak).

yes, but I didn't use those as this was basically just a hack to see what
benefits it would bring.

Gunnar
765,769d764
< #define vmdispatch(o)	switch(o)
< #define vmcase(l)	case l:
< #define vmbreak		break
< 
< 
784,785d778
< 
< 
786a780,790
>   void * const jmptbl[] = {
>     &&l_OP_MOVE, &&l_OP_LOADK, &&l_OP_LOADKX, &&l_OP_LOADBOOL, &&l_OP_LOADNIL, &&l_OP_GETUPVAL,
>     &&l_OP_GETTABUP, &&l_OP_GETTABLE, &&l_OP_SETTABUP, &&l_OP_SETUPVAL, &&l_OP_SETTABLE,
>     &&l_OP_NEWTABLE, &&l_OP_SELF, &&l_OP_ADD, &&l_OP_SUB, &&l_OP_MUL, &&l_OP_MOD, &&l_OP_POW,
>     &&l_OP_DIV, &&l_OP_IDIV, &&l_OP_BAND, &&l_OP_BOR, &&l_OP_BXOR, &&l_OP_SHL, &&l_OP_SHR,
>     &&l_OP_UNM, &&l_OP_BNOT, &&l_OP_NOT, &&l_OP_LEN, &&l_OP_CONCAT, &&l_OP_JMP, &&l_OP_EQ,
>     &&l_OP_LT, &&l_OP_LE, &&l_OP_TEST, &&l_OP_TESTSET, &&l_OP_CALL, &&l_OP_TAILCALL,
>     &&l_OP_RETURN, &&l_OP_FORLOOP, &&l_OP_FORPREP, &&l_OP_TFORCALL, &&l_OP_TFORLOOP,
>     &&l_OP_SETLIST, &&l_OP_CLOSURE, &&l_OP_VARARG, &&l_OP_EXTRAARG
>   };
> 
796a801
> 
802,1116c807,1097
<     vmdispatch (GET_OPCODE(i)) {
<       vmcase(OP_MOVE) {
<         setobjs2s(L, ra, RB(i));
<         vmbreak;
<       }
<       vmcase(OP_LOADK) {
<         TValue *rb = k + GETARG_Bx(i);
<         setobj2s(L, ra, rb);
<         vmbreak;
<       }
<       vmcase(OP_LOADKX) {
<         TValue *rb;
<         lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG);
<         rb = k + GETARG_Ax(*ci->u.l.savedpc++);
<         setobj2s(L, ra, rb);
<         vmbreak;
<       }
<       vmcase(OP_LOADBOOL) {
<         setbvalue(ra, GETARG_B(i));
<         if (GETARG_C(i)) ci->u.l.savedpc++;  /* skip next instruction (if C) */
<         vmbreak;
<       }
<       vmcase(OP_LOADNIL) {
<         int b = GETARG_B(i);
<         do {
<           setnilvalue(ra++);
<         } while (b--);
<         vmbreak;
<       }
<       vmcase(OP_GETUPVAL) {
<         int b = GETARG_B(i);
<         setobj2s(L, ra, cl->upvals[b]->v);
<         vmbreak;
<       }
<       vmcase(OP_GETTABUP) {
<         TValue *upval = cl->upvals[GETARG_B(i)]->v;
<         TValue *rc = RKC(i);
<         gettableProtected(L, upval, rc, ra);
<         vmbreak;
<       }
<       vmcase(OP_GETTABLE) {
<         StkId rb = RB(i);
<         TValue *rc = RKC(i);
<         gettableProtected(L, rb, rc, ra);
<         vmbreak;
<       }
<       vmcase(OP_SETTABUP) {
<         TValue *upval = cl->upvals[GETARG_A(i)]->v;
<         TValue *rb = RKB(i);
<         TValue *rc = RKC(i);
<         settableProtected(L, upval, rb, rc);
<         vmbreak;
<       }
<       vmcase(OP_SETUPVAL) {
<         UpVal *uv = cl->upvals[GETARG_B(i)];
<         setobj(L, uv->v, ra);
<         luaC_upvalbarrier(L, uv);
<         vmbreak;
<       }
<       vmcase(OP_SETTABLE) {
<         TValue *rb = RKB(i);
<         TValue *rc = RKC(i);
<         settableProtected(L, ra, rb, rc);
<         vmbreak;
<       }
<       vmcase(OP_NEWTABLE) {
<         int b = GETARG_B(i);
<         int c = GETARG_C(i);
<         Table *t = luaH_new(L);
<         sethvalue(L, ra, t);
<         if (b != 0 || c != 0)
<           luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c));
<         checkGC(L, ra + 1);
<         vmbreak;
<       }
<       vmcase(OP_SELF) {
<         const TValue *aux;
<         StkId rb = RB(i);
<         TValue *rc = RKC(i);
<         TString *key = tsvalue(rc);  /* key must be a string */
<         setobjs2s(L, ra + 1, rb);
<         if (luaV_fastget(L, rb, key, aux, luaH_getstr)) {
<           setobj2s(L, ra, aux);
<         }
<         else Protect(luaV_finishget(L, rb, rc, ra, aux));
<         vmbreak;
<       }
<       vmcase(OP_ADD) {
<         TValue *rb = RKB(i);
<         TValue *rc = RKC(i);
<         lua_Number nb; lua_Number nc;
<         if (ttisinteger(rb) && ttisinteger(rc)) {
<           lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
<           setivalue(ra, intop(+, ib, ic));
<         }
<         else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
<           setfltvalue(ra, luai_numadd(L, nb, nc));
<         }
<         else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_ADD)); }
<         vmbreak;
<       }
<       vmcase(OP_SUB) {
<         TValue *rb = RKB(i);
<         TValue *rc = RKC(i);
<         lua_Number nb; lua_Number nc;
<         if (ttisinteger(rb) && ttisinteger(rc)) {
<           lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
<           setivalue(ra, intop(-, ib, ic));
<         }
<         else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
<           setfltvalue(ra, luai_numsub(L, nb, nc));
<         }
<         else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SUB)); }
<         vmbreak;
<       }
<       vmcase(OP_MUL) {
<         TValue *rb = RKB(i);
<         TValue *rc = RKC(i);
<         lua_Number nb; lua_Number nc;
<         if (ttisinteger(rb) && ttisinteger(rc)) {
<           lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
<           setivalue(ra, intop(*, ib, ic));
<         }
<         else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
<           setfltvalue(ra, luai_nummul(L, nb, nc));
<         }
<         else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MUL)); }
<         vmbreak;
<       }
<       vmcase(OP_DIV) {  /* float division (always with floats) */
<         TValue *rb = RKB(i);
<         TValue *rc = RKC(i);
<         lua_Number nb; lua_Number nc;
<         if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
<           setfltvalue(ra, luai_numdiv(L, nb, nc));
<         }
<         else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_DIV)); }
<         vmbreak;
<       }
<       vmcase(OP_BAND) {
<         TValue *rb = RKB(i);
<         TValue *rc = RKC(i);
<         lua_Integer ib; lua_Integer ic;
<         if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
<           setivalue(ra, intop(&, ib, ic));
<         }
<         else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BAND)); }
<         vmbreak;
<       }
<       vmcase(OP_BOR) {
<         TValue *rb = RKB(i);
<         TValue *rc = RKC(i);
<         lua_Integer ib; lua_Integer ic;
<         if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
<           setivalue(ra, intop(|, ib, ic));
<         }
<         else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BOR)); }
<         vmbreak;
<       }
<       vmcase(OP_BXOR) {
<         TValue *rb = RKB(i);
<         TValue *rc = RKC(i);
<         lua_Integer ib; lua_Integer ic;
<         if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
<           setivalue(ra, intop(^, ib, ic));
<         }
<         else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BXOR)); }
<         vmbreak;
<       }
<       vmcase(OP_SHL) {
<         TValue *rb = RKB(i);
<         TValue *rc = RKC(i);
<         lua_Integer ib; lua_Integer ic;
<         if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
<           setivalue(ra, luaV_shiftl(ib, ic));
<         }
<         else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHL)); }
<         vmbreak;
<       }
<       vmcase(OP_SHR) {
<         TValue *rb = RKB(i);
<         TValue *rc = RKC(i);
<         lua_Integer ib; lua_Integer ic;
<         if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
<           setivalue(ra, luaV_shiftl(ib, -ic));
<         }
<         else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHR)); }
<         vmbreak;
<       }
<       vmcase(OP_MOD) {
<         TValue *rb = RKB(i);
<         TValue *rc = RKC(i);
<         lua_Number nb; lua_Number nc;
<         if (ttisinteger(rb) && ttisinteger(rc)) {
<           lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
<           setivalue(ra, luaV_mod(L, ib, ic));
<         }
<         else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
<           lua_Number m;
<           luai_nummod(L, nb, nc, m);
<           setfltvalue(ra, m);
<         }
<         else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MOD)); }
<         vmbreak;
<       }
<       vmcase(OP_IDIV) {  /* floor division */
<         TValue *rb = RKB(i);
<         TValue *rc = RKC(i);
<         lua_Number nb; lua_Number nc;
<         if (ttisinteger(rb) && ttisinteger(rc)) {
<           lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
<           setivalue(ra, luaV_div(L, ib, ic));
<         }
<         else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
<           setfltvalue(ra, luai_numidiv(L, nb, nc));
<         }
<         else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_IDIV)); }
<         vmbreak;
<       }
<       vmcase(OP_POW) {
<         TValue *rb = RKB(i);
<         TValue *rc = RKC(i);
<         lua_Number nb; lua_Number nc;
<         if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
<           setfltvalue(ra, luai_numpow(L, nb, nc));
<         }
<         else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_POW)); }
<         vmbreak;
<       }
<       vmcase(OP_UNM) {
<         TValue *rb = RB(i);
<         lua_Number nb;
<         if (ttisinteger(rb)) {
<           lua_Integer ib = ivalue(rb);
<           setivalue(ra, intop(-, 0, ib));
<         }
<         else if (tonumber(rb, &nb)) {
<           setfltvalue(ra, luai_numunm(L, nb));
<         }
<         else {
<           Protect(luaT_trybinTM(L, rb, rb, ra, TM_UNM));
<         }
<         vmbreak;
<       }
<       vmcase(OP_BNOT) {
<         TValue *rb = RB(i);
<         lua_Integer ib;
<         if (tointeger(rb, &ib)) {
<           setivalue(ra, intop(^, ~l_castS2U(0), ib));
<         }
<         else {
<           Protect(luaT_trybinTM(L, rb, rb, ra, TM_BNOT));
<         }
<         vmbreak;
<       }
<       vmcase(OP_NOT) {
<         TValue *rb = RB(i);
<         int res = l_isfalse(rb);  /* next assignment may change this value */
<         setbvalue(ra, res);
<         vmbreak;
<       }
<       vmcase(OP_LEN) {
<         Protect(luaV_objlen(L, ra, RB(i)));
<         vmbreak;
<       }
<       vmcase(OP_CONCAT) {
<         int b = GETARG_B(i);
<         int c = GETARG_C(i);
<         StkId rb;
<         L->top = base + c + 1;  /* mark the end of concat operands */
<         Protect(luaV_concat(L, c - b + 1));
<         ra = RA(i);  /* 'luaV_concat' may invoke TMs and move the stack */
<         rb = base + b;
<         setobjs2s(L, ra, rb);
<         checkGC(L, (ra >= rb ? ra + 1 : rb));
<         L->top = ci->top;  /* restore top */
<         vmbreak;
<       }
<       vmcase(OP_JMP) {
<         dojump(ci, i, 0);
<         vmbreak;
<       }
<       vmcase(OP_EQ) {
<         TValue *rb = RKB(i);
<         TValue *rc = RKC(i);
<         Protect(
<           if (luaV_equalobj(L, rb, rc) != GETARG_A(i))
<             ci->u.l.savedpc++;
<           else
<             donextjump(ci);
<         )
<         vmbreak;
<       }
<       vmcase(OP_LT) {
<         Protect(
<           if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i))
<             ci->u.l.savedpc++;
<           else
<             donextjump(ci);
<         )
<         vmbreak;
<       }
<       vmcase(OP_LE) {
<         Protect(
<           if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i))
<             ci->u.l.savedpc++;
<           else
<             donextjump(ci);
<         )
<         vmbreak;
<       }
<       vmcase(OP_TEST) {
<         if (GETARG_C(i) ? l_isfalse(ra) : !l_isfalse(ra))
<             ci->u.l.savedpc++;
<           else
---
>     goto *jmptbl[GET_OPCODE(i)];
>     //continue;
> 
>     l_OP_MOVE: {
>       setobjs2s(L, ra, RB(i));
>       continue;
>     }
>     l_OP_LOADK: {
>       TValue *rb = k + GETARG_Bx(i);
>       setobj2s(L, ra, rb);
>       continue;
>     }
>     l_OP_LOADKX: {
>       TValue *rb;
>       lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG);
>       rb = k + GETARG_Ax(*ci->u.l.savedpc++);
>       setobj2s(L, ra, rb);
>       continue;
>     }
>     l_OP_LOADBOOL: {
>       setbvalue(ra, GETARG_B(i));
>       if (GETARG_C(i)) ci->u.l.savedpc++;  /* skip next instruction (if C) */
>       continue;
>     }
>     l_OP_LOADNIL: {
>       int b = GETARG_B(i);
>       do {
>         setnilvalue(ra++);
>       } while (b--);
>       continue;
>     }
>     l_OP_GETUPVAL: {
>       int b = GETARG_B(i);
>       setobj2s(L, ra, cl->upvals[b]->v);
>       continue;
>     }
>     l_OP_GETTABUP: {
>       TValue *upval = cl->upvals[GETARG_B(i)]->v;
>       TValue *rc = RKC(i);
>       gettableProtected(L, upval, rc, ra);
>       continue;
>     }
>     l_OP_GETTABLE: {
>       StkId rb = RB(i);
>       TValue *rc = RKC(i);
>       gettableProtected(L, rb, rc, ra);
>       continue;
>     }
>     l_OP_SETTABUP: {
>       TValue *upval = cl->upvals[GETARG_A(i)]->v;
>       TValue *rb = RKB(i);
>       TValue *rc = RKC(i);
>       settableProtected(L, upval, rb, rc);
>       continue;
>     }
>     l_OP_SETUPVAL: {
>       UpVal *uv = cl->upvals[GETARG_B(i)];
>       setobj(L, uv->v, ra);
>       luaC_upvalbarrier(L, uv);
>       continue;
>     }
>     l_OP_SETTABLE: {
>       TValue *rb = RKB(i);
>       TValue *rc = RKC(i);
>       settableProtected(L, ra, rb, rc);
>       continue;
>     }
>     l_OP_NEWTABLE: {
>       int b = GETARG_B(i);
>       int c = GETARG_C(i);
>       Table *t = luaH_new(L);
>       sethvalue(L, ra, t);
>       if (b != 0 || c != 0)
>         luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c));
>       checkGC(L, ra + 1);
>       continue;
>     }
>     l_OP_SELF: {
>       const TValue *aux;
>       StkId rb = RB(i);
>       TValue *rc = RKC(i);
>       TString *key = tsvalue(rc);  /* key must be a string */
>       setobjs2s(L, ra + 1, rb);
>       if (luaV_fastget(L, rb, key, aux, luaH_getstr)) {
>         setobj2s(L, ra, aux);
>       }
>       else Protect(luaV_finishget(L, rb, rc, ra, aux));
>       continue;
>     }
>     l_OP_ADD: {
>       TValue *rb = RKB(i);
>       TValue *rc = RKC(i);
>       lua_Number nb; lua_Number nc;
>       if (ttisinteger(rb) && ttisinteger(rc)) {
>         lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
>         setivalue(ra, intop(+, ib, ic));
>       }
>       else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
>         setfltvalue(ra, luai_numadd(L, nb, nc));
>       }
>       else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_ADD)); }
>       continue;
>     }
>     l_OP_SUB: {
>       TValue *rb = RKB(i);
>       TValue *rc = RKC(i);
>       lua_Number nb; lua_Number nc;
>       if (ttisinteger(rb) && ttisinteger(rc)) {
>         lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
>         setivalue(ra, intop(-, ib, ic));
>       }
>       else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
>         setfltvalue(ra, luai_numsub(L, nb, nc));
>       }
>       else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SUB)); }
>       continue;
>     }
>     l_OP_MUL: {
>       TValue *rb = RKB(i);
>       TValue *rc = RKC(i);
>       lua_Number nb; lua_Number nc;
>       if (ttisinteger(rb) && ttisinteger(rc)) {
>         lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
>         setivalue(ra, intop(*, ib, ic));
>       }
>       else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
>         setfltvalue(ra, luai_nummul(L, nb, nc));
>       }
>       else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MUL)); }
>       continue;
>     }
>     l_OP_DIV: {  /* float division (always with floats) */
>       TValue *rb = RKB(i);
>       TValue *rc = RKC(i);
>       lua_Number nb; lua_Number nc;
>       if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
>         setfltvalue(ra, luai_numdiv(L, nb, nc));
>       }
>       else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_DIV)); }
>       continue;
>     }
>     l_OP_BAND: {
>       TValue *rb = RKB(i);
>       TValue *rc = RKC(i);
>       lua_Integer ib; lua_Integer ic;
>       if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
>         setivalue(ra, intop(&, ib, ic));
>       }
>       else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BAND)); }
>       continue;
>     }
>     l_OP_BOR: {
>       TValue *rb = RKB(i);
>       TValue *rc = RKC(i);
>       lua_Integer ib; lua_Integer ic;
>       if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
>         setivalue(ra, intop(|, ib, ic));
>       }
>       else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BOR)); }
>       continue;
>     }
>     l_OP_BXOR: {
>       TValue *rb = RKB(i);
>       TValue *rc = RKC(i);
>       lua_Integer ib; lua_Integer ic;
>       if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
>         setivalue(ra, intop(^, ib, ic));
>       }
>       else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BXOR)); }
>       continue;
>     }
>     l_OP_SHL: {
>       TValue *rb = RKB(i);
>       TValue *rc = RKC(i);
>       lua_Integer ib; lua_Integer ic;
>       if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
>         setivalue(ra, luaV_shiftl(ib, ic));
>       }
>       else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHL)); }
>       continue;
>     }
>     l_OP_SHR: {
>       TValue *rb = RKB(i);
>       TValue *rc = RKC(i);
>       lua_Integer ib; lua_Integer ic;
>       if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
>         setivalue(ra, luaV_shiftl(ib, -ic));
>       }
>       else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHR)); }
>       continue;
>     }
>     l_OP_MOD: {
>       TValue *rb = RKB(i);
>       TValue *rc = RKC(i);
>       lua_Number nb; lua_Number nc;
>       if (ttisinteger(rb) && ttisinteger(rc)) {
>         lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
>         setivalue(ra, luaV_mod(L, ib, ic));
>       }
>       else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
>         lua_Number m;
>         luai_nummod(L, nb, nc, m);
>         setfltvalue(ra, m);
>       }
>       else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MOD)); }
>       continue;
>     }
>     l_OP_IDIV: {  /* floor division */
>       TValue *rb = RKB(i);
>       TValue *rc = RKC(i);
>       lua_Number nb; lua_Number nc;
>       if (ttisinteger(rb) && ttisinteger(rc)) {
>         lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
>         setivalue(ra, luaV_div(L, ib, ic));
>       }
>       else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
>         setfltvalue(ra, luai_numidiv(L, nb, nc));
>       }
>       else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_IDIV)); }
>       continue;
>     }
>     l_OP_POW: {
>       TValue *rb = RKB(i);
>       TValue *rc = RKC(i);
>       lua_Number nb; lua_Number nc;
>       if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
>         setfltvalue(ra, luai_numpow(L, nb, nc));
>       }
>       else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_POW)); }
>       continue;
>     }
>     l_OP_UNM: {
>       TValue *rb = RB(i);
>       lua_Number nb;
>       if (ttisinteger(rb)) {
>         lua_Integer ib = ivalue(rb);
>         setivalue(ra, intop(-, 0, ib));
>       }
>       else if (tonumber(rb, &nb)) {
>         setfltvalue(ra, luai_numunm(L, nb));
>       }
>       else {
>         Protect(luaT_trybinTM(L, rb, rb, ra, TM_UNM));
>       }
>       continue;
>     }
>     l_OP_BNOT: {
>       TValue *rb = RB(i);
>       lua_Integer ib;
>       if (tointeger(rb, &ib)) {
>         setivalue(ra, intop(^, ~l_castS2U(0), ib));
>       }
>       else {
>         Protect(luaT_trybinTM(L, rb, rb, ra, TM_BNOT));
>       }
>       continue;
>     }
>     l_OP_NOT: {
>       TValue *rb = RB(i);
>       int res = l_isfalse(rb);  /* next assignment may change this value */
>       setbvalue(ra, res);
>       continue;
>     }
>     l_OP_LEN: {
>       Protect(luaV_objlen(L, ra, RB(i)));
>       continue;
>     }
>     l_OP_CONCAT: {
>       int b = GETARG_B(i);
>       int c = GETARG_C(i);
>       StkId rb;
>       L->top = base + c + 1;  /* mark the end of concat operands */
>       Protect(luaV_concat(L, c - b + 1));
>       ra = RA(i);  /* 'luaV_concat' may invoke TMs and move the stack */
>       rb = base + b;
>       setobjs2s(L, ra, rb);
>       checkGC(L, (ra >= rb ? ra + 1 : rb));
>       L->top = ci->top;  /* restore top */
>       continue;
>     }
>     l_OP_JMP: {
>       dojump(ci, i, 0);
>       continue;
>     }
>     l_OP_EQ: {
>       TValue *rb = RKB(i);
>       TValue *rc = RKC(i);
>       Protect(
>         if (luaV_equalobj(L, rb, rc) != GETARG_A(i))
>           ci->u.l.savedpc++;
>         else
1118,1122c1099,1104
<         vmbreak;
<       }
<       vmcase(OP_TESTSET) {
<         TValue *rb = RB(i);
<         if (GETARG_C(i) ? l_isfalse(rb) : !l_isfalse(rb))
---
>       )
>       continue;
>     }
>     l_OP_LT: {
>       Protect(
>         if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i))
1124,1125c1106
<         else {
<           setobjs2s(L, ra, rb);
---
>         else
1127,1289c1108,1114
<         }
<         vmbreak;
<       }
<       vmcase(OP_CALL) {
<         int b = GETARG_B(i);
<         int nresults = GETARG_C(i) - 1;
<         if (b != 0) L->top = ra+b;  /* else previous instruction set top */
<         if (luaD_precall(L, ra, nresults)) {  /* C function? */
<           if (nresults >= 0)
<             L->top = ci->top;  /* adjust results */
<           Protect((void)0);  /* update 'base' */
<         }
<         else {  /* Lua function */
<           ci = L->ci;
<           goto newframe;  /* restart luaV_execute over new Lua function */
<         }
<         vmbreak;
<       }
<       vmcase(OP_TAILCALL) {
<         int b = GETARG_B(i);
<         if (b != 0) L->top = ra+b;  /* else previous instruction set top */
<         lua_assert(GETARG_C(i) - 1 == LUA_MULTRET);
<         if (luaD_precall(L, ra, LUA_MULTRET)) {  /* C function? */
<           Protect((void)0);  /* update 'base' */
<         }
<         else {
<           /* tail call: put called frame (n) in place of caller one (o) */
<           CallInfo *nci = L->ci;  /* called frame */
<           CallInfo *oci = nci->previous;  /* caller frame */
<           StkId nfunc = nci->func;  /* called function */
<           StkId ofunc = oci->func;  /* caller function */
<           /* last stack slot filled by 'precall' */
<           StkId lim = nci->u.l.base + getproto(nfunc)->numparams;
<           int aux;
<           /* close all upvalues from previous call */
<           if (cl->p->sizep > 0) luaF_close(L, oci->u.l.base);
<           /* move new frame into old one */
<           for (aux = 0; nfunc + aux < lim; aux++)
<             setobjs2s(L, ofunc + aux, nfunc + aux);
<           oci->u.l.base = ofunc + (nci->u.l.base - nfunc);  /* correct base */
<           oci->top = L->top = ofunc + (L->top - nfunc);  /* correct top */
<           oci->u.l.savedpc = nci->u.l.savedpc;
<           oci->callstatus |= CIST_TAIL;  /* function was tail called */
<           ci = L->ci = oci;  /* remove new frame */
<           lua_assert(L->top == oci->u.l.base + getproto(ofunc)->maxstacksize);
<           goto newframe;  /* restart luaV_execute over new Lua function */
<         }
<         vmbreak;
<       }
<       vmcase(OP_RETURN) {
<         int b = GETARG_B(i);
<         if (cl->p->sizep > 0) luaF_close(L, base);
<         b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra)));
<         if (ci->callstatus & CIST_FRESH)  /* local 'ci' still from callee */
<           return;  /* external invocation: return */
<         else {  /* invocation via reentry: continue execution */
<           ci = L->ci;
<           if (b) L->top = ci->top;
<           lua_assert(isLua(ci));
<           lua_assert(GET_OPCODE(*((ci)->u.l.savedpc - 1)) == OP_CALL);
<           goto newframe;  /* restart luaV_execute over new Lua function */
<         }
<       }
<       vmcase(OP_FORLOOP) {
<         if (ttisinteger(ra)) {  /* integer loop? */
<           lua_Integer step = ivalue(ra + 2);
<           lua_Integer idx = intop(+, ivalue(ra), step); /* increment index */
<           lua_Integer limit = ivalue(ra + 1);
<           if ((0 < step) ? (idx <= limit) : (limit <= idx)) {
<             ci->u.l.savedpc += GETARG_sBx(i);  /* jump back */
<             chgivalue(ra, idx);  /* update internal index... */
<             setivalue(ra + 3, idx);  /* ...and external index */
<           }
<         }
<         else {  /* floating loop */
<           lua_Number step = fltvalue(ra + 2);
<           lua_Number idx = luai_numadd(L, fltvalue(ra), step); /* inc. index */
<           lua_Number limit = fltvalue(ra + 1);
<           if (luai_numlt(0, step) ? luai_numle(idx, limit)
<                                   : luai_numle(limit, idx)) {
<             ci->u.l.savedpc += GETARG_sBx(i);  /* jump back */
<             chgfltvalue(ra, idx);  /* update internal index... */
<             setfltvalue(ra + 3, idx);  /* ...and external index */
<           }
<         }
<         vmbreak;
<       }
<       vmcase(OP_FORPREP) {
<         TValue *init = ra;
<         TValue *plimit = ra + 1;
<         TValue *pstep = ra + 2;
<         lua_Integer ilimit;
<         int stopnow;
<         if (ttisinteger(init) && ttisinteger(pstep) &&
<             forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) {
<           /* all values are integer */
<           lua_Integer initv = (stopnow ? 0 : ivalue(init));
<           setivalue(plimit, ilimit);
<           setivalue(init, intop(-, initv, ivalue(pstep)));
<         }
<         else {  /* try making all values floats */
<           lua_Number ninit; lua_Number nlimit; lua_Number nstep;
<           if (!tonumber(plimit, &nlimit))
<             luaG_runerror(L, "'for' limit must be a number");
<           setfltvalue(plimit, nlimit);
<           if (!tonumber(pstep, &nstep))
<             luaG_runerror(L, "'for' step must be a number");
<           setfltvalue(pstep, nstep);
<           if (!tonumber(init, &ninit))
<             luaG_runerror(L, "'for' initial value must be a number");
<           setfltvalue(init, luai_numsub(L, ninit, nstep));
<         }
<         ci->u.l.savedpc += GETARG_sBx(i);
<         vmbreak;
<       }
<       vmcase(OP_TFORCALL) {
<         StkId cb = ra + 3;  /* call base */
<         setobjs2s(L, cb+2, ra+2);
<         setobjs2s(L, cb+1, ra+1);
<         setobjs2s(L, cb, ra);
<         L->top = cb + 3;  /* func. + 2 args (state and index) */
<         Protect(luaD_call(L, cb, GETARG_C(i)));
<         L->top = ci->top;
<         i = *(ci->u.l.savedpc++);  /* go to next instruction */
<         ra = RA(i);
<         lua_assert(GET_OPCODE(i) == OP_TFORLOOP);
<         goto l_tforloop;
<       }
<       vmcase(OP_TFORLOOP) {
<         l_tforloop:
<         if (!ttisnil(ra + 1)) {  /* continue loop? */
<           setobjs2s(L, ra, ra + 1);  /* save control variable */
<            ci->u.l.savedpc += GETARG_sBx(i);  /* jump back */
<         }
<         vmbreak;
<       }
<       vmcase(OP_SETLIST) {
<         int n = GETARG_B(i);
<         int c = GETARG_C(i);
<         unsigned int last;
<         Table *h;
<         if (n == 0) n = cast_int(L->top - ra) - 1;
<         if (c == 0) {
<           lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG);
<           c = GETARG_Ax(*ci->u.l.savedpc++);
<         }
<         h = hvalue(ra);
<         last = ((c-1)*LFIELDS_PER_FLUSH) + n;
<         if (last > h->sizearray)  /* needs more space? */
<           luaH_resizearray(L, h, last);  /* preallocate it at once */
<         for (; n > 0; n--) {
<           TValue *val = ra+n;
<           luaH_setint(L, h, last--, val);
<           luaC_barrierback(L, h, val);
<         }
<         L->top = ci->top;  /* correct top (in case of previous open call) */
<         vmbreak;
<       }
<       vmcase(OP_CLOSURE) {
<         Proto *p = cl->p->p[GETARG_Bx(i)];
<         LClosure *ncl = getcached(p, cl->upvals, base);  /* cached closure */
<         if (ncl == NULL)  /* no match? */
<           pushclosure(L, p, cl->upvals, base, ra);  /* create a new one */
---
>       )
>       continue;
>     }
>     l_OP_LE: {
>       Protect(
>         if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i))
>           ci->u.l.savedpc++;
1291,1315c1116,1278
<           setclLvalue(L, ra, ncl);  /* push cashed closure */
<         checkGC(L, ra + 1);
<         vmbreak;
<       }
<       vmcase(OP_VARARG) {
<         int b = GETARG_B(i) - 1;  /* required results */
<         int j;
<         int n = cast_int(base - ci->func) - cl->p->numparams - 1;
<         if (n < 0)  /* less arguments than parameters? */
<           n = 0;  /* no vararg arguments */
<         if (b < 0) {  /* B == 0? */
<           b = n;  /* get all var. arguments */
<           Protect(luaD_checkstack(L, n));
<           ra = RA(i);  /* previous call may change the stack */
<           L->top = ra + n;
<         }
<         for (j = 0; j < b && j < n; j++)
<           setobjs2s(L, ra + j, base - n + j);
<         for (; j < b; j++)  /* complete required results with nil */
<           setnilvalue(ra + j);
<         vmbreak;
<       }
<       vmcase(OP_EXTRAARG) {
<         lua_assert(0);
<         vmbreak;
---
>           donextjump(ci);
>       )
>       continue;
>     }
>     l_OP_TEST: {
>       if (GETARG_C(i) ? l_isfalse(ra) : !l_isfalse(ra))
>           ci->u.l.savedpc++;
>         else
>         donextjump(ci);
>       continue;
>     }
>     l_OP_TESTSET: {
>       TValue *rb = RB(i);
>       if (GETARG_C(i) ? l_isfalse(rb) : !l_isfalse(rb))
>         ci->u.l.savedpc++;
>       else {
>         setobjs2s(L, ra, rb);
>         donextjump(ci);
>       }
>       continue;
>     }
>     l_OP_CALL: {
>       int b = GETARG_B(i);
>       int nresults = GETARG_C(i) - 1;
>       if (b != 0) L->top = ra+b;  /* else previous instruction set top */
>       if (luaD_precall(L, ra, nresults)) {  /* C function? */
>         if (nresults >= 0)
>           L->top = ci->top;  /* adjust results */
>         Protect((void)0);  /* update 'base' */
>       }
>       else {  /* Lua function */
>         ci = L->ci;
>         goto newframe;  /* restart luaV_execute over new Lua function */
>       }
>       continue;
>     }
>     l_OP_TAILCALL: {
>       int b = GETARG_B(i);
>       if (b != 0) L->top = ra+b;  /* else previous instruction set top */
>       lua_assert(GETARG_C(i) - 1 == LUA_MULTRET);
>       if (luaD_precall(L, ra, LUA_MULTRET)) {  /* C function? */
>         Protect((void)0);  /* update 'base' */
>       }
>       else {
>         /* tail call: put called frame (n) in place of caller one (o) */
>         CallInfo *nci = L->ci;  /* called frame */
>         CallInfo *oci = nci->previous;  /* caller frame */
>         StkId nfunc = nci->func;  /* called function */
>         StkId ofunc = oci->func;  /* caller function */
>         /* last stack slot filled by 'precall' */
>         StkId lim = nci->u.l.base + getproto(nfunc)->numparams;
>         int aux;
>         /* close all upvalues from previous call */
>         if (cl->p->sizep > 0) luaF_close(L, oci->u.l.base);
>         /* move new frame into old one */
>         for (aux = 0; nfunc + aux < lim; aux++)
>           setobjs2s(L, ofunc + aux, nfunc + aux);
>         oci->u.l.base = ofunc + (nci->u.l.base - nfunc);  /* correct base */
>         oci->top = L->top = ofunc + (L->top - nfunc);  /* correct top */
>         oci->u.l.savedpc = nci->u.l.savedpc;
>         oci->callstatus |= CIST_TAIL;  /* function was tail called */
>         ci = L->ci = oci;  /* remove new frame */
>         lua_assert(L->top == oci->u.l.base + getproto(ofunc)->maxstacksize);
>         goto newframe;  /* restart luaV_execute over new Lua function */
>       }
>       continue;
>     }
>     l_OP_RETURN: {
>       int b = GETARG_B(i);
>       if (cl->p->sizep > 0) luaF_close(L, base);
>       b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra)));
>       if (ci->callstatus & CIST_FRESH)  /* local 'ci' still from callee */
>         return;  /* external invocation: return */
>       else {  /* invocation via reentry: continue execution */
>         ci = L->ci;
>         if (b) L->top = ci->top;
>         lua_assert(isLua(ci));
>         lua_assert(GET_OPCODE(*((ci)->u.l.savedpc - 1)) == OP_CALL);
>         goto newframe;  /* restart luaV_execute over new Lua function */
>       }
>     }
>     l_OP_FORLOOP: {
>       if (ttisinteger(ra)) {  /* integer loop? */
>         lua_Integer step = ivalue(ra + 2);
>         lua_Integer idx = intop(+, ivalue(ra), step); /* increment index */
>         lua_Integer limit = ivalue(ra + 1);
>         if ((0 < step) ? (idx <= limit) : (limit <= idx)) {
>           ci->u.l.savedpc += GETARG_sBx(i);  /* jump back */
>           chgivalue(ra, idx);  /* update internal index... */
>           setivalue(ra + 3, idx);  /* ...and external index */
>         }
>       }
>       else {  /* floating loop */
>         lua_Number step = fltvalue(ra + 2);
>         lua_Number idx = luai_numadd(L, fltvalue(ra), step); /* inc. index */
>         lua_Number limit = fltvalue(ra + 1);
>         if (luai_numlt(0, step) ? luai_numle(idx, limit)
>                                 : luai_numle(limit, idx)) {
>           ci->u.l.savedpc += GETARG_sBx(i);  /* jump back */
>           chgfltvalue(ra, idx);  /* update internal index... */
>           setfltvalue(ra + 3, idx);  /* ...and external index */
>         }
>       }
>       continue;
>     }
>     l_OP_FORPREP: {
>       TValue *init = ra;
>       TValue *plimit = ra + 1;
>       TValue *pstep = ra + 2;
>       lua_Integer ilimit;
>       int stopnow;
>       if (ttisinteger(init) && ttisinteger(pstep) &&
>           forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) {
>         /* all values are integer */
>         lua_Integer initv = (stopnow ? 0 : ivalue(init));
>         setivalue(plimit, ilimit);
>         setivalue(init, intop(-, initv, ivalue(pstep)));
>       }
>       else {  /* try making all values floats */
>         lua_Number ninit; lua_Number nlimit; lua_Number nstep;
>         if (!tonumber(plimit, &nlimit))
>           luaG_runerror(L, "'for' limit must be a number");
>         setfltvalue(plimit, nlimit);
>         if (!tonumber(pstep, &nstep))
>           luaG_runerror(L, "'for' step must be a number");
>         setfltvalue(pstep, nstep);
>         if (!tonumber(init, &ninit))
>           luaG_runerror(L, "'for' initial value must be a number");
>         setfltvalue(init, luai_numsub(L, ninit, nstep));
>       }
>       ci->u.l.savedpc += GETARG_sBx(i);
>       continue;
>     }
>     l_OP_TFORCALL: {
>       StkId cb = ra + 3;  /* call base */
>       setobjs2s(L, cb+2, ra+2);
>       setobjs2s(L, cb+1, ra+1);
>       setobjs2s(L, cb, ra);
>       L->top = cb + 3;  /* func. + 2 args (state and index) */
>       Protect(luaD_call(L, cb, GETARG_C(i)));
>       L->top = ci->top;
>       i = *(ci->u.l.savedpc++);  /* go to next instruction */
>       ra = RA(i);
>       lua_assert(GET_OPCODE(i) == OP_TFORLOOP);
>       goto l_tforloop;
>     }
>     l_OP_TFORLOOP: {
>       l_tforloop:
>       if (!ttisnil(ra + 1)) {  /* continue loop? */
>         setobjs2s(L, ra, ra + 1);  /* save control variable */
>          ci->u.l.savedpc += GETARG_sBx(i);  /* jump back */
>       }
>       continue;
>     }
>     l_OP_SETLIST: {
>       int n = GETARG_B(i);
>       int c = GETARG_C(i);
>       unsigned int last;
>       Table *h;
>       if (n == 0) n = cast_int(L->top - ra) - 1;
>       if (c == 0) {
>         lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG);
>         c = GETARG_Ax(*ci->u.l.savedpc++);
1316a1280,1322
>       h = hvalue(ra);
>       last = ((c-1)*LFIELDS_PER_FLUSH) + n;
>       if (last > h->sizearray)  /* needs more space? */
>         luaH_resizearray(L, h, last);  /* preallocate it at once */
>       for (; n > 0; n--) {
>         TValue *val = ra+n;
>         luaH_setint(L, h, last--, val);
>         luaC_barrierback(L, h, val);
>       }
>       L->top = ci->top;  /* correct top (in case of previous open call) */
>       continue;
>     }
>     l_OP_CLOSURE: {
>       Proto *p = cl->p->p[GETARG_Bx(i)];
>       LClosure *ncl = getcached(p, cl->upvals, base);  /* cached closure */
>       if (ncl == NULL)  /* no match? */
>         pushclosure(L, p, cl->upvals, base, ra);  /* create a new one */
>       else
>         setclLvalue(L, ra, ncl);  /* push cashed closure */
>       checkGC(L, ra + 1);
>       continue;
>     }
>     l_OP_VARARG: {
>       int b = GETARG_B(i) - 1;  /* required results */
>       int j;
>       int n = cast_int(base - ci->func) - cl->p->numparams - 1;
>       if (n < 0)  /* less arguments than parameters? */
>         n = 0;  /* no vararg arguments */
>       if (b < 0) {  /* B == 0? */
>         b = n;  /* get all var. arguments */
>         Protect(luaD_checkstack(L, n));
>         ra = RA(i);  /* previous call may change the stack */
>         L->top = ra + n;
>       }
>       for (j = 0; j < b && j < n; j++)
>         setobjs2s(L, ra + j, base - n + j);
>       for (; j < b; j++)  /* complete required results with nil */
>         setnilvalue(ra + j);
>       continue;
>     }
>     l_OP_EXTRAARG: {
>       lua_assert(0);
>       continue;