#define lvm_c
#define LUA_CORE
#include "lprefix.h"
#include <float.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lua.h"
#include "lapi.h"
#include "ldebug.h"
#include "ldo.h"
#include "lfunc.h"
#include "lgc.h"
#include "lobject.h"
#include "lopcodes.h"
#include "lstate.h"
#include "lstring.h"
#include "ltable.h"
#include "ltm.h"
#include "lvm.h"
#if !defined(LUA_USE_JUMPTABLE)
#if defined(__GNUC__)
#define LUA_USE_JUMPTABLE 1
#else
#define LUA_USE_JUMPTABLE 0
#endif
#endif
#define MAXTAGLOOP 2000
#define NBM (l_floatatt(MANT_DIG))
#if ((((LUA_MAXINTEGER >> (NBM / 4)) >> (NBM / 4)) >> (NBM / 4)) \
>> (NBM - (3 * (NBM / 4)))) > 0
#define MAXINTFITSF ((lua_Unsigned)1 << NBM)
#define l_intfitsf(i) ((MAXINTFITSF + l_castS2U(i)) <= (2 * MAXINTFITSF))
#else
#define l_intfitsf(i) 1
#endif
static int l_strton (const TValue *obj, TValue *result) {
lua_assert(obj != result);
if (!cvt2num(obj))
return 0;
else {
TString *st = tsvalue(obj);
size_t stlen;
const char *s = getlstr(st, stlen);
return (luaO_str2num(s, result) == stlen + 1);
}
}
int luaV_tonumber_ (const TValue *obj, lua_Number *n) {
TValue v;
if (ttisinteger(obj)) {
*n = cast_num(ivalue(obj));
return 1;
}
else if (l_strton(obj, &v)) {
*n = nvalue(&v);
return 1;
}
else
return 0;
}
int luaV_flttointeger (lua_Number n, lua_Integer *p, F2Imod mode) {
lua_Number f = l_floor(n);
if (n != f) {
if (mode == F2Ieq) return 0;
else if (mode == F2Iceil)
f += 1;
}
return lua_numbertointeger(f, p);
}
int luaV_tointegerns (const TValue *obj, lua_Integer *p, F2Imod mode) {
if (ttisfloat(obj))
return luaV_flttointeger(fltvalue(obj), p, mode);
else if (ttisinteger(obj)) {
*p = ivalue(obj);
return 1;
}
else
return 0;
}
int luaV_tointeger (const TValue *obj, lua_Integer *p, F2Imod mode) {
TValue v;
if (l_strton(obj, &v))
obj = &v;
return luaV_tointegerns(obj, p, mode);
}
static int forlimit (lua_State *L, lua_Integer init, const TValue *lim,
lua_Integer *p, lua_Integer step) {
if (!luaV_tointeger(lim, p, (step < 0 ? F2Iceil : F2Ifloor))) {
lua_Number flim;
if (!tonumber(lim, &flim))
luaG_forerror(L, lim, "limit");
if (luai_numlt(0, flim)) {
if (step < 0) return 1;
*p = LUA_MAXINTEGER;
}
else {
if (step > 0) return 1;
*p = LUA_MININTEGER;
}
}
return (step > 0 ? init > *p : init < *p);
}
static int forprep (lua_State *L, StkId ra) {
TValue *pinit = s2v(ra);
TValue *plimit = s2v(ra + 1);
TValue *pstep = s2v(ra + 2);
if (ttisinteger(pinit) && ttisinteger(pstep)) {
lua_Integer init = ivalue(pinit);
lua_Integer step = ivalue(pstep);
lua_Integer limit;
if (step == 0)
luaG_runerror(L, "'for' step is zero");
if (forlimit(L, init, plimit, &limit, step))
return 1;
else {
lua_Unsigned count;
if (step > 0) {
count = l_castS2U(limit) - l_castS2U(init);
if (step != 1)
count /= l_castS2U(step);
}
else {
count = l_castS2U(init) - l_castS2U(limit);
count /= l_castS2U(-(step + 1)) + 1u;
}
chgivalue(s2v(ra), l_castU2S(count));
setivalue(s2v(ra + 1), step);
chgivalue(s2v(ra + 2), init);
}
}
else {
lua_Number init; lua_Number limit; lua_Number step;
if (l_unlikely(!tonumber(plimit, &limit)))
luaG_forerror(L, plimit, "limit");
if (l_unlikely(!tonumber(pstep, &step)))
luaG_forerror(L, pstep, "step");
if (l_unlikely(!tonumber(pinit, &init)))
luaG_forerror(L, pinit, "initial value");
if (step == 0)
luaG_runerror(L, "'for' step is zero");
if (luai_numlt(0, step) ? luai_numlt(limit, init)
: luai_numlt(init, limit))
return 1;
else {
setfltvalue(s2v(ra), limit);
setfltvalue(s2v(ra + 1), step);
setfltvalue(s2v(ra + 2), init);
}
}
return 0;
}
static int floatforloop (StkId ra) {
lua_Number step = fltvalue(s2v(ra + 1));
lua_Number limit = fltvalue(s2v(ra));
lua_Number idx = fltvalue(s2v(ra + 2));
idx = luai_numadd(L, idx, step);
if (luai_numlt(0, step) ? luai_numle(idx, limit)
: luai_numle(limit, idx)) {
chgfltvalue(s2v(ra + 2), idx);
return 1;
}
else
return 0;
}
lu_byte luaV_finishget (lua_State *L, const TValue *t, TValue *key,
StkId val, lu_byte tag) {
int loop;
const TValue *tm;
for (loop = 0; loop < MAXTAGLOOP; loop++) {
if (tag == LUA_VNOTABLE) {
lua_assert(!ttistable(t));
tm = luaT_gettmbyobj(L, t, TM_INDEX);
if (l_unlikely(notm(tm)))
luaG_typeerror(L, t, "index");
}
else {
tm = fasttm(L, hvalue(t)->metatable, TM_INDEX);
if (tm == NULL) {
setnilvalue(s2v(val));
return LUA_VNIL;
}
}
if (ttisfunction(tm)) {
tag = luaT_callTMres(L, tm, t, key, val);
return tag;
}
t = tm;
luaV_fastget(t, key, s2v(val), luaH_get, tag);
if (!tagisempty(tag))
return tag;
}
luaG_runerror(L, "'__index' chain too long; possible loop");
return 0;
}
void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
TValue *val, int hres) {
int loop;
for (loop = 0; loop < MAXTAGLOOP; loop++) {
const TValue *tm;
if (hres != HNOTATABLE) {
Table *h = hvalue(t);
tm = fasttm(L, h->metatable, TM_NEWINDEX);
if (tm == NULL) {
sethvalue2s(L, L->top.p, h);
L->top.p++;
luaH_finishset(L, h, key, val, hres);
L->top.p--;
invalidateTMcache(h);
luaC_barrierback(L, obj2gco(h), val);
return;
}
}
else {
tm = luaT_gettmbyobj(L, t, TM_NEWINDEX);
if (l_unlikely(notm(tm)))
luaG_typeerror(L, t, "index");
}
if (ttisfunction(tm)) {
luaT_callTM(L, tm, t, key, val);
return;
}
t = tm;
luaV_fastset(t, key, val, hres, luaH_pset);
if (hres == HOK) {
luaV_finishfastset(L, t, val);
return;
}
}
luaG_runerror(L, "'__newindex' chain too long; possible loop");
}
#if !defined(l_strcoll)
#define l_strcoll strcoll
#endif
static int l_strcmp (const TString *ts1, const TString *ts2) {
size_t rl1;
const char *s1 = getlstr(ts1, rl1);
size_t rl2;
const char *s2 = getlstr(ts2, rl2);
for (;;) {
int temp = l_strcoll(s1, s2);
if (temp != 0)
return temp;
else {
size_t zl1 = strlen(s1);
size_t zl2 = strlen(s2);
if (zl2 == rl2)
return (zl1 == rl1) ? 0 : 1;
else if (zl1 == rl1)
return -1;
zl1++; zl2++;
s1 += zl1; rl1 -= zl1; s2 += zl2; rl2 -= zl2;
}
}
}
l_sinline int LTintfloat (lua_Integer i, lua_Number f) {
if (l_intfitsf(i))
return luai_numlt(cast_num(i), f);
else {
lua_Integer fi;
if (luaV_flttointeger(f, &fi, F2Iceil))
return i < fi;
else
return f > 0;
}
}
l_sinline int LEintfloat (lua_Integer i, lua_Number f) {
if (l_intfitsf(i))
return luai_numle(cast_num(i), f);
else {
lua_Integer fi;
if (luaV_flttointeger(f, &fi, F2Ifloor))
return i <= fi;
else
return f > 0;
}
}
l_sinline int LTfloatint (lua_Number f, lua_Integer i) {
if (l_intfitsf(i))
return luai_numlt(f, cast_num(i));
else {
lua_Integer fi;
if (luaV_flttointeger(f, &fi, F2Ifloor))
return fi < i;
else
return f < 0;
}
}
l_sinline int LEfloatint (lua_Number f, lua_Integer i) {
if (l_intfitsf(i))
return luai_numle(f, cast_num(i));
else {
lua_Integer fi;
if (luaV_flttointeger(f, &fi, F2Iceil))
return fi <= i;
else
return f < 0;
}
}
l_sinline int LTnum (const TValue *l, const TValue *r) {
lua_assert(ttisnumber(l) && ttisnumber(r));
if (ttisinteger(l)) {
lua_Integer li = ivalue(l);
if (ttisinteger(r))
return li < ivalue(r);
else
return LTintfloat(li, fltvalue(r));
}
else {
lua_Number lf = fltvalue(l);
if (ttisfloat(r))
return luai_numlt(lf, fltvalue(r));
else
return LTfloatint(lf, ivalue(r));
}
}
l_sinline int LEnum (const TValue *l, const TValue *r) {
lua_assert(ttisnumber(l) && ttisnumber(r));
if (ttisinteger(l)) {
lua_Integer li = ivalue(l);
if (ttisinteger(r))
return li <= ivalue(r);
else
return LEintfloat(li, fltvalue(r));
}
else {
lua_Number lf = fltvalue(l);
if (ttisfloat(r))
return luai_numle(lf, fltvalue(r));
else
return LEfloatint(lf, ivalue(r));
}
}
static int lessthanothers (lua_State *L, const TValue *l, const TValue *r) {
lua_assert(!ttisnumber(l) || !ttisnumber(r));
if (ttisstring(l) && ttisstring(r))
return l_strcmp(tsvalue(l), tsvalue(r)) < 0;
else
return luaT_callorderTM(L, l, r, TM_LT);
}
int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
if (ttisnumber(l) && ttisnumber(r))
return LTnum(l, r);
else return lessthanothers(L, l, r);
}
static int lessequalothers (lua_State *L, const TValue *l, const TValue *r) {
lua_assert(!ttisnumber(l) || !ttisnumber(r));
if (ttisstring(l) && ttisstring(r))
return l_strcmp(tsvalue(l), tsvalue(r)) <= 0;
else
return luaT_callorderTM(L, l, r, TM_LE);
}
int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) {
if (ttisnumber(l) && ttisnumber(r))
return LEnum(l, r);
else return lessequalothers(L, l, r);
}
int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
const TValue *tm;
if (ttype(t1) != ttype(t2))
return 0;
else if (ttypetag(t1) != ttypetag(t2)) {
switch (ttypetag(t1)) {
case LUA_VNUMINT: {
lua_Integer i2;
return (luaV_flttointeger(fltvalue(t2), &i2, F2Ieq) &&
ivalue(t1) == i2);
}
case LUA_VNUMFLT: {
lua_Integer i1;
return (luaV_flttointeger(fltvalue(t1), &i1, F2Ieq) &&
i1 == ivalue(t2));
}
case LUA_VSHRSTR: case LUA_VLNGSTR: {
return luaS_eqstr(tsvalue(t1), tsvalue(t2));
}
default:
return 0;
}
}
else {
switch (ttypetag(t1)) {
case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE:
return 1;
case LUA_VNUMINT:
return (ivalue(t1) == ivalue(t2));
case LUA_VNUMFLT:
return (fltvalue(t1) == fltvalue(t2));
case LUA_VLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);
case LUA_VSHRSTR:
return eqshrstr(tsvalue(t1), tsvalue(t2));
case LUA_VLNGSTR:
return luaS_eqstr(tsvalue(t1), tsvalue(t2));
case LUA_VUSERDATA: {
if (uvalue(t1) == uvalue(t2)) return 1;
else if (L == NULL) return 0;
tm = fasttm(L, uvalue(t1)->metatable, TM_EQ);
if (tm == NULL)
tm = fasttm(L, uvalue(t2)->metatable, TM_EQ);
break;
}
case LUA_VTABLE: {
if (hvalue(t1) == hvalue(t2)) return 1;
else if (L == NULL) return 0;
tm = fasttm(L, hvalue(t1)->metatable, TM_EQ);
if (tm == NULL)
tm = fasttm(L, hvalue(t2)->metatable, TM_EQ);
break;
}
case LUA_VLCF:
return (fvalue(t1) == fvalue(t2));
default:
return (gcvalue(t1) == gcvalue(t2));
}
if (tm == NULL)
return 0;
else {
int tag = luaT_callTMres(L, tm, t1, t2, L->top.p);
return !tagisfalse(tag);
}
}
}
#define tostring(L,o) \
(ttisstring(o) || (cvt2str(o) && (luaO_tostring(L, o), 1)))
#define isemptystr(o) (ttisshrstring(o) && tsvalue(o)->shrlen == 0)
static void copy2buff (StkId top, int n, char *buff) {
size_t tl = 0;
do {
TString *st = tsvalue(s2v(top - n));
size_t l;
const char *s = getlstr(st, l);
memcpy(buff + tl, s, l * sizeof(char));
tl += l;
} while (--n > 0);
}
void luaV_concat (lua_State *L, int total) {
if (total == 1)
return;
do {
StkId top = L->top.p;
int n = 2;
if (!(ttisstring(s2v(top - 2)) || cvt2str(s2v(top - 2))) ||
!tostring(L, s2v(top - 1)))
luaT_tryconcatTM(L);
else if (isemptystr(s2v(top - 1)))
cast_void(tostring(L, s2v(top - 2)));
else if (isemptystr(s2v(top - 2))) {
setobjs2s(L, top - 2, top - 1);
}
else {
size_t tl = tsslen(tsvalue(s2v(top - 1)));
TString *ts;
for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) {
size_t l = tsslen(tsvalue(s2v(top - n - 1)));
if (l_unlikely(l >= MAX_SIZE - sizeof(TString) - tl)) {
L->top.p = top - total;
luaG_runerror(L, "string length overflow");
}
tl += l;
}
if (tl <= LUAI_MAXSHORTLEN) {
char buff[LUAI_MAXSHORTLEN];
copy2buff(top, n, buff);
ts = luaS_newlstr(L, buff, tl);
}
else {
ts = luaS_createlngstrobj(L, tl);
copy2buff(top, n, getlngstr(ts));
}
setsvalue2s(L, top - n, ts);
}
total -= n - 1;
L->top.p -= n - 1;
} while (total > 1);
}
void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
const TValue *tm;
switch (ttypetag(rb)) {
case LUA_VTABLE: {
Table *h = hvalue(rb);
tm = fasttm(L, h->metatable, TM_LEN);
if (tm) break;
setivalue(s2v(ra), l_castU2S(luaH_getn(L, h)));
return;
}
case LUA_VSHRSTR: {
setivalue(s2v(ra), tsvalue(rb)->shrlen);
return;
}
case LUA_VLNGSTR: {
setivalue(s2v(ra), cast_st2S(tsvalue(rb)->u.lnglen));
return;
}
default: {
tm = luaT_gettmbyobj(L, rb, TM_LEN);
if (l_unlikely(notm(tm)))
luaG_typeerror(L, rb, "get length of");
break;
}
}
luaT_callTMres(L, tm, rb, rb, ra);
}
lua_Integer luaV_idiv (lua_State *L, lua_Integer m, lua_Integer n) {
if (l_unlikely(l_castS2U(n) + 1u <= 1u)) {
if (n == 0)
luaG_runerror(L, "attempt to divide by zero");
return intop(-, 0, m);
}
else {
lua_Integer q = m / n;
if ((m ^ n) < 0 && m % n != 0)
q -= 1;
return q;
}
}
lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) {
if (l_unlikely(l_castS2U(n) + 1u <= 1u)) {
if (n == 0)
luaG_runerror(L, "attempt to perform 'n%%0'");
return 0;
}
else {
lua_Integer r = m % n;
if (r != 0 && (r ^ n) < 0)
r += n;
return r;
}
}
lua_Number luaV_modf (lua_State *L, lua_Number m, lua_Number n) {
lua_Number r;
luai_nummod(L, m, n, r);
return r;
}
#define NBITS l_numbits(lua_Integer)
lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) {
if (y < 0) {
if (y <= -NBITS) return 0;
else return intop(>>, x, -y);
}
else {
if (y >= NBITS) return 0;
else return intop(<<, x, y);
}
}
static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
StkId ra) {
int nup = p->sizeupvalues;
Upvaldesc *uv = p->upvalues;
int i;
LClosure *ncl = luaF_newLclosure(L, nup);
ncl->p = p;
setclLvalue2s(L, ra, ncl);
for (i = 0; i < nup; i++) {
if (uv[i].instack)
ncl->upvals[i] = luaF_findupval(L, base + uv[i].idx);
else
ncl->upvals[i] = encup[uv[i].idx];
luaC_objbarrier(L, ncl, ncl->upvals[i]);
}
}
void luaV_finishOp (lua_State *L) {
CallInfo *ci = L->ci;
StkId base = ci->func.p + 1;
Instruction inst = *(ci->u.l.savedpc - 1);
OpCode op = GET_OPCODE(inst);
switch (op) {
case OP_MMBIN: case OP_MMBINI: case OP_MMBINK: {
setobjs2s(L, base + GETARG_A(*(ci->u.l.savedpc - 2)), --L->top.p);
break;
}
case OP_UNM: case OP_BNOT: case OP_LEN:
case OP_GETTABUP: case OP_GETTABLE: case OP_GETI:
case OP_GETFIELD: case OP_SELF: {
setobjs2s(L, base + GETARG_A(inst), --L->top.p);
break;
}
case OP_LT: case OP_LE:
case OP_LTI: case OP_LEI:
case OP_GTI: case OP_GEI:
case OP_EQ: {
int res = !l_isfalse(s2v(L->top.p - 1));
L->top.p--;
lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP);
if (res != GETARG_k(inst))
ci->u.l.savedpc++;
break;
}
case OP_CONCAT: {
StkId top = L->top.p - 1;
int a = GETARG_A(inst);
int total = cast_int(top - 1 - (base + a));
setobjs2s(L, top - 2, top);
L->top.p = top - 1;
luaV_concat(L, total);
break;
}
case OP_CLOSE: {
ci->u.l.savedpc--;
break;
}
case OP_RETURN: {
StkId ra = base + GETARG_A(inst);
L->top.p = ra + ci->u2.nres;
ci->u.l.savedpc--;
break;
}
default: {
lua_assert(op == OP_TFORCALL || op == OP_CALL ||
op == OP_TAILCALL || op == OP_SETTABUP || op == OP_SETTABLE ||
op == OP_SETI || op == OP_SETFIELD);
break;
}
}
}
#define l_addi(L,a,b) intop(+, a, b)
#define l_subi(L,a,b) intop(-, a, b)
#define l_muli(L,a,b) intop(*, a, b)
#define l_band(a,b) intop(&, a, b)
#define l_bor(a,b) intop(|, a, b)
#define l_bxor(a,b) intop(^, a, b)
#define l_lti(a,b) (a < b)
#define l_lei(a,b) (a <= b)
#define l_gti(a,b) (a > b)
#define l_gei(a,b) (a >= b)
#define op_arithI(L,iop,fop) { \
TValue *ra = vRA(i); \
TValue *v1 = vRB(i); \
int imm = GETARG_sC(i); \
if (ttisinteger(v1)) { \
lua_Integer iv1 = ivalue(v1); \
pc++; setivalue(ra, iop(L, iv1, imm)); \
} \
else if (ttisfloat(v1)) { \
lua_Number nb = fltvalue(v1); \
lua_Number fimm = cast_num(imm); \
pc++; setfltvalue(ra, fop(L, nb, fimm)); \
}}
#define op_arithf_aux(L,v1,v2,fop) { \
lua_Number n1; lua_Number n2; \
if (tonumberns(v1, n1) && tonumberns(v2, n2)) { \
StkId ra = RA(i); \
pc++; setfltvalue(s2v(ra), fop(L, n1, n2)); \
}}
#define op_arithf(L,fop) { \
TValue *v1 = vRB(i); \
TValue *v2 = vRC(i); \
op_arithf_aux(L, v1, v2, fop); }
#define op_arithfK(L,fop) { \
TValue *v1 = vRB(i); \
TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \
op_arithf_aux(L, v1, v2, fop); }
#define op_arith_aux(L,v1,v2,iop,fop) { \
if (ttisinteger(v1) && ttisinteger(v2)) { \
StkId ra = RA(i); \
lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2); \
pc++; setivalue(s2v(ra), iop(L, i1, i2)); \
} \
else op_arithf_aux(L, v1, v2, fop); }
#define op_arith(L,iop,fop) { \
TValue *v1 = vRB(i); \
TValue *v2 = vRC(i); \
op_arith_aux(L, v1, v2, iop, fop); }
#define op_arithK(L,iop,fop) { \
TValue *v1 = vRB(i); \
TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \
op_arith_aux(L, v1, v2, iop, fop); }
#define op_bitwiseK(L,op) { \
TValue *v1 = vRB(i); \
TValue *v2 = KC(i); \
lua_Integer i1; \
lua_Integer i2 = ivalue(v2); \
if (tointegerns(v1, &i1)) { \
StkId ra = RA(i); \
pc++; setivalue(s2v(ra), op(i1, i2)); \
}}
#define op_bitwise(L,op) { \
TValue *v1 = vRB(i); \
TValue *v2 = vRC(i); \
lua_Integer i1; lua_Integer i2; \
if (tointegerns(v1, &i1) && tointegerns(v2, &i2)) { \
StkId ra = RA(i); \
pc++; setivalue(s2v(ra), op(i1, i2)); \
}}
#define op_order(L,opi,opn,other) { \
TValue *ra = vRA(i); \
int cond; \
TValue *rb = vRB(i); \
if (ttisinteger(ra) && ttisinteger(rb)) { \
lua_Integer ia = ivalue(ra); \
lua_Integer ib = ivalue(rb); \
cond = opi(ia, ib); \
} \
else if (ttisnumber(ra) && ttisnumber(rb)) \
cond = opn(ra, rb); \
else \
Protect(cond = other(L, ra, rb)); \
docondjump(); }
#define op_orderI(L,opi,opf,inv,tm) { \
TValue *ra = vRA(i); \
int cond; \
int im = GETARG_sB(i); \
if (ttisinteger(ra)) \
cond = opi(ivalue(ra), im); \
else if (ttisfloat(ra)) { \
lua_Number fa = fltvalue(ra); \
lua_Number fim = cast_num(im); \
cond = opf(fa, fim); \
} \
else { \
int isf = GETARG_C(i); \
Protect(cond = luaT_callorderiTM(L, ra, im, inv, isf, tm)); \
} \
docondjump(); }
#define RA(i) (base+GETARG_A(i))
#define vRA(i) s2v(RA(i))
#define RB(i) (base+GETARG_B(i))
#define vRB(i) s2v(RB(i))
#define KB(i) (k+GETARG_B(i))
#define RC(i) (base+GETARG_C(i))
#define vRC(i) s2v(RC(i))
#define KC(i) (k+GETARG_C(i))
#define RKC(i) ((TESTARG_k(i)) ? k + GETARG_C(i) : s2v(base + GETARG_C(i)))
#define updatetrap(ci) (trap = ci->u.l.trap)
#define updatebase(ci) (base = ci->func.p + 1)
#define updatestack(ci) \
{ if (l_unlikely(trap)) { updatebase(ci); ra = RA(i); } }
#define dojump(ci,i,e) { pc += GETARG_sJ(i) + e; updatetrap(ci); }
#define donextjump(ci) { Instruction ni = *pc; dojump(ci, ni, 1); }
#define docondjump() if (cond != GETARG_k(i)) pc++; else donextjump(ci);
#define savepc(ci) (ci->u.l.savedpc = pc)
#define savestate(L,ci) (savepc(ci), L->top.p = ci->top.p)
#define Protect(exp) (savestate(L,ci), (exp), updatetrap(ci))
#define ProtectNT(exp) (savepc(ci), (exp), updatetrap(ci))
#define halfProtect(exp) (savestate(L,ci), (exp))
#if !defined(luai_threadyield)
#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);}
#endif
#define checkGC(L,c) \
{ luaC_condGC(L, (savepc(ci), L->top.p = (c)), \
updatetrap(ci)); \
luai_threadyield(L); }
#define vmfetch() { \
if (l_unlikely(trap)) { \
trap = luaG_traceexec(L, pc); \
updatebase(ci); \
} \
i = *(pc++); \
}
#define vmdispatch(o) switch(o)
#define vmcase(l) case l:
#define vmbreak break
void luaV_execute (lua_State *L, CallInfo *ci) {
LClosure *cl;
TValue *k;
StkId base;
const Instruction *pc;
int trap;
#if LUA_USE_JUMPTABLE
#include "ljumptab.h"
#endif
startfunc:
trap = L->hookmask;
returning:
cl = ci_func(ci);
k = cl->p->k;
pc = ci->u.l.savedpc;
if (l_unlikely(trap))
trap = luaG_tracecall(L);
base = ci->func.p + 1;
for (;;) {
Instruction i;
vmfetch();
#if 0 #endif
lua_assert(base == ci->func.p + 1);
lua_assert(base <= L->top.p && L->top.p <= L->stack_last.p);
lua_assert(luaP_isIT(i) || (cast_void(L->top.p = base), 1));
vmdispatch (GET_OPCODE(i)) {
vmcase(OP_MOVE) {
StkId ra = RA(i);
setobjs2s(L, ra, RB(i));
vmbreak;
}
vmcase(OP_LOADI) {
StkId ra = RA(i);
lua_Integer b = GETARG_sBx(i);
setivalue(s2v(ra), b);
vmbreak;
}
vmcase(OP_LOADF) {
StkId ra = RA(i);
int b = GETARG_sBx(i);
setfltvalue(s2v(ra), cast_num(b));
vmbreak;
}
vmcase(OP_LOADK) {
StkId ra = RA(i);
TValue *rb = k + GETARG_Bx(i);
setobj2s(L, ra, rb);
vmbreak;
}
vmcase(OP_LOADKX) {
StkId ra = RA(i);
TValue *rb;
rb = k + GETARG_Ax(*pc); pc++;
setobj2s(L, ra, rb);
vmbreak;
}
vmcase(OP_LOADFALSE) {
StkId ra = RA(i);
setbfvalue(s2v(ra));
vmbreak;
}
vmcase(OP_LFALSESKIP) {
StkId ra = RA(i);
setbfvalue(s2v(ra));
pc++;
vmbreak;
}
vmcase(OP_LOADTRUE) {
StkId ra = RA(i);
setbtvalue(s2v(ra));
vmbreak;
}
vmcase(OP_LOADNIL) {
StkId ra = RA(i);
int b = GETARG_B(i);
do {
setnilvalue(s2v(ra++));
} while (b--);
vmbreak;
}
vmcase(OP_GETUPVAL) {
StkId ra = RA(i);
int b = GETARG_B(i);
setobj2s(L, ra, cl->upvals[b]->v.p);
vmbreak;
}
vmcase(OP_SETUPVAL) {
StkId ra = RA(i);
UpVal *uv = cl->upvals[GETARG_B(i)];
setobj(L, uv->v.p, s2v(ra));
luaC_barrier(L, uv, s2v(ra));
vmbreak;
}
vmcase(OP_GETTABUP) {
StkId ra = RA(i);
TValue *upval = cl->upvals[GETARG_B(i)]->v.p;
TValue *rc = KC(i);
TString *key = tsvalue(rc);
lu_byte tag;
luaV_fastget(upval, key, s2v(ra), luaH_getshortstr, tag);
if (tagisempty(tag))
Protect(luaV_finishget(L, upval, rc, ra, tag));
vmbreak;
}
vmcase(OP_GETTABLE) {
StkId ra = RA(i);
TValue *rb = vRB(i);
TValue *rc = vRC(i);
lu_byte tag;
if (ttisinteger(rc)) {
luaV_fastgeti(rb, ivalue(rc), s2v(ra), tag);
}
else
luaV_fastget(rb, rc, s2v(ra), luaH_get, tag);
if (tagisempty(tag))
Protect(luaV_finishget(L, rb, rc, ra, tag));
vmbreak;
}
vmcase(OP_GETI) {
StkId ra = RA(i);
TValue *rb = vRB(i);
int c = GETARG_C(i);
lu_byte tag;
luaV_fastgeti(rb, c, s2v(ra), tag);
if (tagisempty(tag)) {
TValue key;
setivalue(&key, c);
Protect(luaV_finishget(L, rb, &key, ra, tag));
}
vmbreak;
}
vmcase(OP_GETFIELD) {
StkId ra = RA(i);
TValue *rb = vRB(i);
TValue *rc = KC(i);
TString *key = tsvalue(rc);
lu_byte tag;
luaV_fastget(rb, key, s2v(ra), luaH_getshortstr, tag);
if (tagisempty(tag))
Protect(luaV_finishget(L, rb, rc, ra, tag));
vmbreak;
}
vmcase(OP_SETTABUP) {
int hres;
TValue *upval = cl->upvals[GETARG_A(i)]->v.p;
TValue *rb = KB(i);
TValue *rc = RKC(i);
TString *key = tsvalue(rb);
luaV_fastset(upval, key, rc, hres, luaH_psetshortstr);
if (hres == HOK)
luaV_finishfastset(L, upval, rc);
else
Protect(luaV_finishset(L, upval, rb, rc, hres));
vmbreak;
}
vmcase(OP_SETTABLE) {
StkId ra = RA(i);
int hres;
TValue *rb = vRB(i);
TValue *rc = RKC(i);
if (ttisinteger(rb)) {
luaV_fastseti(s2v(ra), ivalue(rb), rc, hres);
}
else {
luaV_fastset(s2v(ra), rb, rc, hres, luaH_pset);
}
if (hres == HOK)
luaV_finishfastset(L, s2v(ra), rc);
else
Protect(luaV_finishset(L, s2v(ra), rb, rc, hres));
vmbreak;
}
vmcase(OP_SETI) {
StkId ra = RA(i);
int hres;
int b = GETARG_B(i);
TValue *rc = RKC(i);
luaV_fastseti(s2v(ra), b, rc, hres);
if (hres == HOK)
luaV_finishfastset(L, s2v(ra), rc);
else {
TValue key;
setivalue(&key, b);
Protect(luaV_finishset(L, s2v(ra), &key, rc, hres));
}
vmbreak;
}
vmcase(OP_SETFIELD) {
StkId ra = RA(i);
int hres;
TValue *rb = KB(i);
TValue *rc = RKC(i);
TString *key = tsvalue(rb);
luaV_fastset(s2v(ra), key, rc, hres, luaH_psetshortstr);
if (hres == HOK)
luaV_finishfastset(L, s2v(ra), rc);
else
Protect(luaV_finishset(L, s2v(ra), rb, rc, hres));
vmbreak;
}
vmcase(OP_NEWTABLE) {
StkId ra = RA(i);
unsigned b = cast_uint(GETARG_vB(i));
unsigned c = cast_uint(GETARG_vC(i));
Table *t;
if (b > 0)
b = 1u << (b - 1);
if (TESTARG_k(i)) {
lua_assert(GETARG_Ax(*pc) != 0);
c += cast_uint(GETARG_Ax(*pc)) * (MAXARG_vC + 1);
}
pc++;
L->top.p = ra + 1;
t = luaH_new(L);
sethvalue2s(L, ra, t);
if (b != 0 || c != 0)
luaH_resize(L, t, c, b);
checkGC(L, ra + 1);
vmbreak;
}
vmcase(OP_SELF) {
StkId ra = RA(i);
lu_byte tag;
TValue *rb = vRB(i);
TValue *rc = KC(i);
TString *key = tsvalue(rc);
setobj2s(L, ra + 1, rb);
luaV_fastget(rb, key, s2v(ra), luaH_getshortstr, tag);
if (tagisempty(tag))
Protect(luaV_finishget(L, rb, rc, ra, tag));
vmbreak;
}
vmcase(OP_ADDI) {
op_arithI(L, l_addi, luai_numadd);
vmbreak;
}
vmcase(OP_ADDK) {
op_arithK(L, l_addi, luai_numadd);
vmbreak;
}
vmcase(OP_SUBK) {
op_arithK(L, l_subi, luai_numsub);
vmbreak;
}
vmcase(OP_MULK) {
op_arithK(L, l_muli, luai_nummul);
vmbreak;
}
vmcase(OP_MODK) {
savestate(L, ci);
op_arithK(L, luaV_mod, luaV_modf);
vmbreak;
}
vmcase(OP_POWK) {
op_arithfK(L, luai_numpow);
vmbreak;
}
vmcase(OP_DIVK) {
op_arithfK(L, luai_numdiv);
vmbreak;
}
vmcase(OP_IDIVK) {
savestate(L, ci);
op_arithK(L, luaV_idiv, luai_numidiv);
vmbreak;
}
vmcase(OP_BANDK) {
op_bitwiseK(L, l_band);
vmbreak;
}
vmcase(OP_BORK) {
op_bitwiseK(L, l_bor);
vmbreak;
}
vmcase(OP_BXORK) {
op_bitwiseK(L, l_bxor);
vmbreak;
}
vmcase(OP_SHLI) {
StkId ra = RA(i);
TValue *rb = vRB(i);
int ic = GETARG_sC(i);
lua_Integer ib;
if (tointegerns(rb, &ib)) {
pc++; setivalue(s2v(ra), luaV_shiftl(ic, ib));
}
vmbreak;
}
vmcase(OP_SHRI) {
StkId ra = RA(i);
TValue *rb = vRB(i);
int ic = GETARG_sC(i);
lua_Integer ib;
if (tointegerns(rb, &ib)) {
pc++; setivalue(s2v(ra), luaV_shiftl(ib, -ic));
}
vmbreak;
}
vmcase(OP_ADD) {
op_arith(L, l_addi, luai_numadd);
vmbreak;
}
vmcase(OP_SUB) {
op_arith(L, l_subi, luai_numsub);
vmbreak;
}
vmcase(OP_MUL) {
op_arith(L, l_muli, luai_nummul);
vmbreak;
}
vmcase(OP_MOD) {
savestate(L, ci);
op_arith(L, luaV_mod, luaV_modf);
vmbreak;
}
vmcase(OP_POW) {
op_arithf(L, luai_numpow);
vmbreak;
}
vmcase(OP_DIV) {
op_arithf(L, luai_numdiv);
vmbreak;
}
vmcase(OP_IDIV) {
savestate(L, ci);
op_arith(L, luaV_idiv, luai_numidiv);
vmbreak;
}
vmcase(OP_BAND) {
op_bitwise(L, l_band);
vmbreak;
}
vmcase(OP_BOR) {
op_bitwise(L, l_bor);
vmbreak;
}
vmcase(OP_BXOR) {
op_bitwise(L, l_bxor);
vmbreak;
}
vmcase(OP_SHL) {
op_bitwise(L, luaV_shiftl);
vmbreak;
}
vmcase(OP_SHR) {
op_bitwise(L, luaV_shiftr);
vmbreak;
}
vmcase(OP_MMBIN) {
StkId ra = RA(i);
Instruction pi = *(pc - 2);
TValue *rb = vRB(i);
TMS tm = (TMS)GETARG_C(i);
StkId result = RA(pi);
lua_assert(OP_ADD <= GET_OPCODE(pi) && GET_OPCODE(pi) <= OP_SHR);
Protect(luaT_trybinTM(L, s2v(ra), rb, result, tm));
vmbreak;
}
vmcase(OP_MMBINI) {
StkId ra = RA(i);
Instruction pi = *(pc - 2);
int imm = GETARG_sB(i);
TMS tm = (TMS)GETARG_C(i);
int flip = GETARG_k(i);
StkId result = RA(pi);
Protect(luaT_trybiniTM(L, s2v(ra), imm, flip, result, tm));
vmbreak;
}
vmcase(OP_MMBINK) {
StkId ra = RA(i);
Instruction pi = *(pc - 2);
TValue *imm = KB(i);
TMS tm = (TMS)GETARG_C(i);
int flip = GETARG_k(i);
StkId result = RA(pi);
Protect(luaT_trybinassocTM(L, s2v(ra), imm, flip, result, tm));
vmbreak;
}
vmcase(OP_UNM) {
StkId ra = RA(i);
TValue *rb = vRB(i);
lua_Number nb;
if (ttisinteger(rb)) {
lua_Integer ib = ivalue(rb);
setivalue(s2v(ra), intop(-, 0, ib));
}
else if (tonumberns(rb, nb)) {
setfltvalue(s2v(ra), luai_numunm(L, nb));
}
else
Protect(luaT_trybinTM(L, rb, rb, ra, TM_UNM));
vmbreak;
}
vmcase(OP_BNOT) {
StkId ra = RA(i);
TValue *rb = vRB(i);
lua_Integer ib;
if (tointegerns(rb, &ib)) {
setivalue(s2v(ra), intop(^, ~l_castS2U(0), ib));
}
else
Protect(luaT_trybinTM(L, rb, rb, ra, TM_BNOT));
vmbreak;
}
vmcase(OP_NOT) {
StkId ra = RA(i);
TValue *rb = vRB(i);
if (l_isfalse(rb))
setbtvalue(s2v(ra));
else
setbfvalue(s2v(ra));
vmbreak;
}
vmcase(OP_LEN) {
StkId ra = RA(i);
Protect(luaV_objlen(L, ra, vRB(i)));
vmbreak;
}
vmcase(OP_CONCAT) {
StkId ra = RA(i);
int n = GETARG_B(i);
L->top.p = ra + n;
ProtectNT(luaV_concat(L, n));
checkGC(L, L->top.p);
vmbreak;
}
vmcase(OP_CLOSE) {
StkId ra = RA(i);
lua_assert(!GETARG_B(i));
Protect(luaF_close(L, ra, LUA_OK, 1));
vmbreak;
}
vmcase(OP_TBC) {
StkId ra = RA(i);
halfProtect(luaF_newtbcupval(L, ra));
vmbreak;
}
vmcase(OP_JMP) {
dojump(ci, i, 0);
vmbreak;
}
vmcase(OP_EQ) {
StkId ra = RA(i);
int cond;
TValue *rb = vRB(i);
Protect(cond = luaV_equalobj(L, s2v(ra), rb));
docondjump();
vmbreak;
}
vmcase(OP_LT) {
op_order(L, l_lti, LTnum, lessthanothers);
vmbreak;
}
vmcase(OP_LE) {
op_order(L, l_lei, LEnum, lessequalothers);
vmbreak;
}
vmcase(OP_EQK) {
StkId ra = RA(i);
TValue *rb = KB(i);
int cond = luaV_rawequalobj(s2v(ra), rb);
docondjump();
vmbreak;
}
vmcase(OP_EQI) {
StkId ra = RA(i);
int cond;
int im = GETARG_sB(i);
if (ttisinteger(s2v(ra)))
cond = (ivalue(s2v(ra)) == im);
else if (ttisfloat(s2v(ra)))
cond = luai_numeq(fltvalue(s2v(ra)), cast_num(im));
else
cond = 0;
docondjump();
vmbreak;
}
vmcase(OP_LTI) {
op_orderI(L, l_lti, luai_numlt, 0, TM_LT);
vmbreak;
}
vmcase(OP_LEI) {
op_orderI(L, l_lei, luai_numle, 0, TM_LE);
vmbreak;
}
vmcase(OP_GTI) {
op_orderI(L, l_gti, luai_numgt, 1, TM_LT);
vmbreak;
}
vmcase(OP_GEI) {
op_orderI(L, l_gei, luai_numge, 1, TM_LE);
vmbreak;
}
vmcase(OP_TEST) {
StkId ra = RA(i);
int cond = !l_isfalse(s2v(ra));
docondjump();
vmbreak;
}
vmcase(OP_TESTSET) {
StkId ra = RA(i);
TValue *rb = vRB(i);
if (l_isfalse(rb) == GETARG_k(i))
pc++;
else {
setobj2s(L, ra, rb);
donextjump(ci);
}
vmbreak;
}
vmcase(OP_CALL) {
StkId ra = RA(i);
CallInfo *newci;
int b = GETARG_B(i);
int nresults = GETARG_C(i) - 1;
if (b != 0)
L->top.p = ra + b;
savepc(ci);
if ((newci = luaD_precall(L, ra, nresults)) == NULL)
updatetrap(ci);
else {
ci = newci;
goto startfunc;
}
vmbreak;
}
vmcase(OP_TAILCALL) {
StkId ra = RA(i);
int b = GETARG_B(i);
int n;
int nparams1 = GETARG_C(i);
int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0;
if (b != 0)
L->top.p = ra + b;
else
b = cast_int(L->top.p - ra);
savepc(ci);
if (TESTARG_k(i)) {
luaF_closeupval(L, base);
lua_assert(L->tbclist.p < base);
lua_assert(base == ci->func.p + 1);
}
if ((n = luaD_pretailcall(L, ci, ra, b, delta)) < 0)
goto startfunc;
else {
ci->func.p -= delta;
luaD_poscall(L, ci, n);
updatetrap(ci);
goto ret;
}
}
vmcase(OP_RETURN) {
StkId ra = RA(i);
int n = GETARG_B(i) - 1;
int nparams1 = GETARG_C(i);
if (n < 0)
n = cast_int(L->top.p - ra);
savepc(ci);
if (TESTARG_k(i)) {
ci->u2.nres = n;
if (L->top.p < ci->top.p)
L->top.p = ci->top.p;
luaF_close(L, base, CLOSEKTOP, 1);
updatetrap(ci);
updatestack(ci);
}
if (nparams1)
ci->func.p -= ci->u.l.nextraargs + nparams1;
L->top.p = ra + n;
luaD_poscall(L, ci, n);
updatetrap(ci);
goto ret;
}
vmcase(OP_RETURN0) {
if (l_unlikely(L->hookmask)) {
StkId ra = RA(i);
L->top.p = ra;
savepc(ci);
luaD_poscall(L, ci, 0);
trap = 1;
}
else {
int nres = get_nresults(ci->callstatus);
L->ci = ci->previous;
L->top.p = base - 1;
for (; l_unlikely(nres > 0); nres--)
setnilvalue(s2v(L->top.p++));
}
goto ret;
}
vmcase(OP_RETURN1) {
if (l_unlikely(L->hookmask)) {
StkId ra = RA(i);
L->top.p = ra + 1;
savepc(ci);
luaD_poscall(L, ci, 1);
trap = 1;
}
else {
int nres = get_nresults(ci->callstatus);
L->ci = ci->previous;
if (nres == 0)
L->top.p = base - 1;
else {
StkId ra = RA(i);
setobjs2s(L, base - 1, ra);
L->top.p = base;
for (; l_unlikely(nres > 1); nres--)
setnilvalue(s2v(L->top.p++));
}
}
ret:
if (ci->callstatus & CIST_FRESH)
return;
else {
ci = ci->previous;
goto returning;
}
}
vmcase(OP_FORLOOP) {
StkId ra = RA(i);
if (ttisinteger(s2v(ra + 1))) {
lua_Unsigned count = l_castS2U(ivalue(s2v(ra)));
if (count > 0) {
lua_Integer step = ivalue(s2v(ra + 1));
lua_Integer idx = ivalue(s2v(ra + 2));
chgivalue(s2v(ra), l_castU2S(count - 1));
idx = intop(+, idx, step);
chgivalue(s2v(ra + 2), idx);
pc -= GETARG_Bx(i);
}
}
else if (floatforloop(ra))
pc -= GETARG_Bx(i);
updatetrap(ci);
vmbreak;
}
vmcase(OP_FORPREP) {
StkId ra = RA(i);
savestate(L, ci);
if (forprep(L, ra))
pc += GETARG_Bx(i) + 1;
vmbreak;
}
vmcase(OP_TFORPREP) {
StkId ra = RA(i);
TValue temp;
setobj(L, &temp, s2v(ra + 3));
setobjs2s(L, ra + 3, ra + 2);
setobj2s(L, ra + 2, &temp);
halfProtect(luaF_newtbcupval(L, ra + 2));
pc += GETARG_Bx(i);
i = *(pc++);
lua_assert(GET_OPCODE(i) == OP_TFORCALL && ra == RA(i));
goto l_tforcall;
}
vmcase(OP_TFORCALL) {
l_tforcall: {
StkId ra = RA(i);
setobjs2s(L, ra + 5, ra + 3);
setobjs2s(L, ra + 4, ra + 1);
setobjs2s(L, ra + 3, ra);
L->top.p = ra + 3 + 3;
ProtectNT(luaD_call(L, ra + 3, GETARG_C(i)));
updatestack(ci);
i = *(pc++);
lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i));
goto l_tforloop;
}}
vmcase(OP_TFORLOOP) {
l_tforloop: {
StkId ra = RA(i);
if (!ttisnil(s2v(ra + 3)))
pc -= GETARG_Bx(i);
vmbreak;
}}
vmcase(OP_SETLIST) {
StkId ra = RA(i);
unsigned n = cast_uint(GETARG_vB(i));
unsigned last = cast_uint(GETARG_vC(i));
Table *h = hvalue(s2v(ra));
if (n == 0)
n = cast_uint(L->top.p - ra) - 1;
else
L->top.p = ci->top.p;
last += n;
if (TESTARG_k(i)) {
last += cast_uint(GETARG_Ax(*pc)) * (MAXARG_vC + 1);
pc++;
}
if (last > h->asize) {
lua_assert(GETARG_vB(i) == 0);
luaH_resizearray(L, h, last);
}
for (; n > 0; n--) {
TValue *val = s2v(ra + n);
obj2arr(h, last - 1, val);
last--;
luaC_barrierback(L, obj2gco(h), val);
}
vmbreak;
}
vmcase(OP_CLOSURE) {
StkId ra = RA(i);
Proto *p = cl->p->p[GETARG_Bx(i)];
halfProtect(pushclosure(L, p, cl->upvals, base, ra));
checkGC(L, ra + 1);
vmbreak;
}
vmcase(OP_VARARG) {
StkId ra = RA(i);
int n = GETARG_C(i) - 1;
int vatab = GETARG_k(i) ? GETARG_B(i) : -1;
Protect(luaT_getvarargs(L, ci, ra, n, vatab));
vmbreak;
}
vmcase(OP_GETVARG) {
StkId ra = RA(i);
TValue *rc = vRC(i);
luaT_getvararg(ci, ra, rc);
vmbreak;
}
vmcase(OP_ERRNNIL) {
TValue *ra = vRA(i);
if (!ttisnil(ra))
halfProtect(luaG_errnnil(L, cl, GETARG_Bx(i)));
vmbreak;
}
vmcase(OP_VARARGPREP) {
ProtectNT(luaT_adjustvarargs(L, ci, cl->p));
if (l_unlikely(trap)) {
luaD_hookcall(L, ci);
L->oldpc = 1;
}
updatebase(ci);
vmbreak;
}
vmcase(OP_EXTRAARG) {
lua_assert(0);
vmbreak;
}
}
}
}