#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 "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"
#ifdef PLUTO_ETL_ENABLE
#include <chrono>
#endif
#ifdef PLUTO_VMDUMP
#include <string>
#include <sstream>
#include "lauxlib.h"
#include "lopnames.h"
#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);
return (luaO_str2num(getstr(st), result) == tsslen(st) + 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");
setivalue(s2v(ra + 3), init);
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;
}
setivalue(plimit, l_castU2S(count));
}
}
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(plimit, limit);
setfltvalue(pstep, step);
setfltvalue(s2v(ra), init);
setfltvalue(s2v(ra + 3), init);
}
}
return 0;
}
static int floatforloop (StkId ra) {
lua_Number step = fltvalue(s2v(ra + 2));
lua_Number limit = fltvalue(s2v(ra + 1));
lua_Number idx = fltvalue(s2v(ra));
idx = luai_numadd(L, idx, step);
if (luai_numlt(0, step) ? luai_numle(idx, limit)
: luai_numle(limit, idx)) {
chgfltvalue(s2v(ra), idx);
setfltvalue(s2v(ra + 3), idx);
return 1;
}
else
return 0;
}
void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val,
const TValue *slot) {
int loop;
const TValue *tm;
int isValueString = ttisstring(t) && ttisinteger(key);
for (loop = 0; loop < MAXTAGLOOP; loop++) {
if (slot == NULL) {
lua_assert(!ttistable(t));
if (isValueString) {
lua_Integer index = ivalue(key);
if (index < 0) {
index += tsslen(tsvalue(t)) + 1;
}
if (((lua_Integer)tsslen(tsvalue(t)) < index) || (index < 1)) {
setnilvalue(s2v(val));
return;
}
else {
setsvalue(L, s2v(val), luaS_newlstr(L, &getstr(tsvalue(t))[index - 1], 1));
return;
}
}
else {
tm = luaT_gettmbyobj(L, t, TM_INDEX);
if (l_unlikely(notm(tm)))
luaG_typeerror(L, t, "index");
}
}
else {
lua_assert(isempty(slot));
tm = fasttm(L, hvalue(t)->metatable, TM_INDEX);
if (tm == NULL) {
setnilvalue(s2v(val));
return;
}
}
if (ttisfunction(tm)) {
luaT_callTMres(L, tm, t, key, val);
return;
}
t = tm;
if (luaV_fastget(L, t, key, slot, luaH_get)) {
setobj2s(L, val, slot);
return;
}
}
luaG_runerror(L, "'__index' chain too long; possible loop");
}
void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
TValue *val, const TValue *slot) {
int loop;
for (loop = 0; loop < MAXTAGLOOP; loop++) {
const TValue *tm;
if (slot != NULL) {
Table *h = hvalue(t);
lua_assert(isempty(slot));
tm = fasttm(L, h->metatable, TM_NEWINDEX);
if (tm == NULL) {
#ifndef PLUTO_DISABLE_LENGTH_CACHE
h->length = 0; #endif
#ifndef PLUTO_DISABLE_TABLE_FREEZING
if (l_unlikely(h->isfrozen)) luaG_runerror(L, "attempt to modify frozen table.");
#endif
luaH_finishset(L, h, key, slot, val);
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;
if (luaV_fastget(L, t, key, slot, luaH_get)) {
#ifndef PLUTO_DISABLE_LENGTH_CACHE
hvalue(t)->length = 0; #endif
#ifndef PLUTO_DISABLE_TABLE_FREEZING
if (l_unlikely(hvalue(t)->isfrozen)) luaG_runerror(L, "attempt to modify frozen table.");
#endif
luaV_finishfastset(L, t, slot, val);
return;
}
}
luaG_runerror(L, "'__newindex' chain too long; possible loop");
}
static int l_strcmp (const TString *ts1, const TString *ts2) {
const char *s1 = getstr(ts1);
size_t rl1 = tsslen(ts1);
const char *s2 = getstr(ts2);
size_t rl2 = tsslen(ts2);
for (;;) {
int temp = 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 (ttypetag(t1) != ttypetag(t2)) {
if (ttype(t1) != ttype(t2) || ttype(t1) != LUA_TNUMBER)
return 0;
else {
lua_Integer i1, i2;
return (luaV_tointegerns(t1, &i1, F2Ieq) &&
luaV_tointegerns(t2, &i2, F2Ieq) &&
i1 == i2);
}
}
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 luai_numeq(fltvalue(t1), fltvalue(t2));
case LUA_VLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);
case LUA_VLCF: return fvalue(t1) == fvalue(t2);
case LUA_VSHRSTR: return eqshrstr(tsvalue(t1), tsvalue(t2));
case LUA_VLNGSTR: return luaS_eqlngstr(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;
}
default:
return gcvalue(t1) == gcvalue(t2);
}
if (tm == NULL)
return 0;
else {
luaT_callTMres(L, tm, t1, t2, L->top.p);
return !l_isfalse(s2v(L->top.p));
}
}
#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 = tsslen(st);
memcpy(buff + tl, getstr(st), 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;
#ifndef PLUTO_DISABLE_LENGTH_CACHE
if (!h->length) h->length = luaH_getn(h);
setivalue(s2v(ra), h->length);
#else
setivalue(s2v(ra), luaH_getn(h));
#endif
return;
}
case LUA_VSHRSTR: {
setivalue(s2v(ra), tsvalue(rb)->shrlen);
return;
}
case LUA_VLNGSTR: {
setivalue(s2v(ra), 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);
}
bool luaV_searchelement (lua_State* L, const Table* t, const TValue* element) {
unsigned int i = 0;
unsigned int array_size = luaH_realasize(t);
for (i = 0; i < array_size; i++) {
if (luaV_equalobj(L, element, &t->array[i])) {
return true;
}
}
for (i -= array_size; cast_int(i) < sizenode(t); i++) {
if (luaV_equalobj(L, element, gval(gnode(t, i)))) {
return true;
}
}
return false;
}
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 cast_int(sizeof(lua_Integer) * CHAR_BIT)
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]);
}
}
static void inopr (lua_State *L, StkId ra, TValue *a, TValue *b) {
if (ttisstring(a) && ttisstring(b)) {
if (strstr(getstr(tsvalue(b)), getstr(tsvalue(a))) != nullptr) {
setbtvalue(s2v(ra));
} else {
setbfvalue(s2v(ra));
}
} else {
if (l_unlikely(!ttistable(b))) {
if (ttisstring(a))
luaG_runerror(L, "expected second 'in' operand to be table or string, got %s", ttypename(ttype(b)));
else
luaG_runerror(L, "expected second 'in' operand to be table, got %s", ttypename(ttype(b)));
} else {
if (luaV_searchelement(L, hvalue(b), a)) {
setbtvalue(s2v(ra));
} else {
setbfvalue(s2v(ra));
}
}
}
}
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--;
#if defined(LUA_COMPAT_LT_LE)
if (ci->callstatus & CIST_LEQ) {
ci->callstatus ^= CIST_LEQ;
res = !res;
}
#endif
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) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \
int imm = GETARG_sC(i); \
if (ttisinteger(v1)) { \
lua_Integer iv1 = ivalue(v1); \
pc++; setivalue(s2v(ra), iop(L, iv1, imm)); \
} \
else if (ttisfloat(v1)) { \
lua_Number nb = fltvalue(v1); \
lua_Number fimm = cast_num(imm); \
pc++; setfltvalue(s2v(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)) { \
pc++; setfltvalue(s2v(ra), fop(L, n1, n2)); \
}}
#define op_arithf(L,fop) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = vRC(i); \
op_arithf_aux(L, v1, v2, fop); }
#define op_arithfK(L,fop) { \
StkId ra = RA(i); \
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) { \
StkId ra = RA(i); \
if (ttisinteger(v1) && ttisinteger(v2)) { \
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) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = KC(i); \
lua_Integer i1; \
lua_Integer i2 = ivalue(v2); \
if (tointegerns(v1, &i1)) { \
pc++; setivalue(s2v(ra), op(i1, i2)); \
}}
#define op_bitwise(L,op) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = vRC(i); \
lua_Integer i1; lua_Integer i2; \
if (tointegerns(v1, &i1) && tointegerns(v2, &i2)) { \
pc++; setivalue(s2v(ra), op(i1, i2)); \
}}
#define op_order(L,opi,opn,other) { \
StkId ra = RA(i); \
int cond; \
TValue *rb = vRB(i); \
if (ttisinteger(s2v(ra)) && ttisinteger(rb)) { \
lua_Integer ia = ivalue(s2v(ra)); \
lua_Integer ib = ivalue(rb); \
cond = opi(ia, ib); \
} \
else if (ttisnumber(s2v(ra)) && ttisnumber(rb)) \
cond = opn(s2v(ra), rb); \
else \
Protect(cond = other(L, s2v(ra), rb)); \
docondjump(); }
#define op_orderI(L,opi,opf,inv,tm) { \
StkId ra = RA(i); \
int cond; \
int im = GETARG_sB(i); \
if (ttisinteger(s2v(ra))) \
cond = opi(ivalue(s2v(ra)), im); \
else if (ttisfloat(s2v(ra))) { \
lua_Number fa = fltvalue(s2v(ra)); \
lua_Number fim = cast_num(im); \
cond = opf(fa, fim); \
} \
else { \
int isf = GETARG_C(i); \
Protect(cond = luaT_callorderiTM(L, s2v(ra), im, inv, isf, tm)); \
} \
docondjump(); }
#define RA(i) (base+GETARG_A(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(L) (ci->u.l.savedpc = pc)
#define savestate(L,ci) (savepc(L), L->top.p = ci->top.p)
#define Protect(exp) (savestate(L,ci), (exp), updatetrap(ci))
#define ProtectNT(exp) (savepc(L), (exp), updatetrap(ci))
#define halfProtect(exp) (savestate(L,ci), (exp))
#define checkGC(L,c) \
{ luaC_condGC(L, (savepc(L), 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
LUAI_FUNC int luaB_next (lua_State *L);
LUAI_FUNC int luaB_ipairsaux (lua_State *L);
#ifdef PLUTO_VMDUMP
#include <vector>
[[nodiscard]] static std::string stringify_ttype(const TValue* t) noexcept
{
std::ostringstream str { };
str << ttypename(ttype(t));
str << "-";
switch (ttypetag(t)) {
case LUA_VLCF: str << cast_voidp(cast_sizet(fvalue(t))); break;
case LUA_VUSERDATA: str << cast_voidp(getudatamem(uvalue(t))); break;
case LUA_VLIGHTUSERDATA: str << cast_voidp(pvalue(t)); break;
default: str << gcvalue(t);
}
return str.str();
}
inline void padUntilGoal(std::string& s, const size_t goal) noexcept
{
while (s.length() < goal) s += " ";
}
[[nodiscard]] static std::string stringify_tvalue(const TValue* o) noexcept
{
std::string str { };
switch (ttype(o))
{
case LUA_TSTRING:
str.push_back('"');
str.append(getstr(tsvalue(o)));
str.push_back('"');
break;
case LUA_TNUMBER:
if (ttisinteger(o))
str += std::to_string(ivalue(o));
else
str += std::to_string(nvalue(o));
break;
case LUA_TNIL:
str += "nil";
break;
case LUA_TBOOLEAN:
str += ttistrue(o) ? "true" : "false";
break;
default:
str += stringify_ttype(o);
}
return str;
}
static const std::vector<OpCode> ignoreOps = { vmDumpIgnore };
static const std::vector<OpCode> allowOps = { vmDumpAllow };
#ifdef PLUTO_VMDUMP_WHITELIST
#define vmDumpInit() \
bool ignore = true; \
OpCode opcode = GET_OPCODE(i); \
std::string tmp; \
for (size_t idx = 0; idx < allowOps.size(); idx++) \
if (allowOps.at(idx) == opcode) { tmp = opnames[opcode]; padUntilGoal(tmp, 11); ignore = false; break; }
#else
#define vmDumpInit() \
bool ignore = false; \
OpCode opcode = GET_OPCODE(i); \
std::string tmp; \
for (size_t idx = 0; idx < ignoreOps.size(); idx++) \
if (ignoreOps.at(idx) == opcode) { ignore = true; break; } \
if (!ignore) { tmp = opnames[opcode]; padUntilGoal(tmp, 11); }
#endif
#define vmDumpAddA() if (!ignore) { tmp += std::to_string(GETARG_A(i)); tmp += " "; }
#define vmDumpAddB() if (!ignore) { tmp += std::to_string(GETARG_B(i)); tmp += " "; }
#define vmDumpAddC() if (!ignore) { tmp += std::to_string(GETARG_C(i)); tmp += " "; }
#define vmDumpAdd(o) if (!ignore) { tmp += std::to_string(o); tmp += " "; }
#define vmDumpOut(c) if (!ignore) { padUntilGoal(tmp, 20); std::stringstream cs; cs << c; tmp.append(cs.str()); lua_writestring(tmp.data(), tmp.size()); lua_writeline(); }
#else
#define vmDumpInit()
#define vmDumpAddA()
#define vmDumpAddB()
#define vmDumpAddC()
#define vmDumpAdd(o)
#define vmDumpOut(c)
#endif
#ifdef PLUTO_FORCE_JUMPTABLE
#ifdef PLUTO_VMDUMP
#pragma message("PLUTO_FORCE_JUMPTABLE ignored due to PLUTO_VMDUMP")
#elif defined(PLUTO_ETL_ENABLE)
#pragma message("PLUTO_FORCE_JUMPTABLE ignored due to PLUTO_ETL_ENABLE")
#elif !defined(__GNUC__) && !defined(__clang__)
#include "ljumptab.h"
#endif
#endif
void luaV_execute (lua_State *L, CallInfo *ci) {
LClosure *cl;
TValue *k;
StkId base;
const Instruction *pc;
int trap;
#ifdef PLUTO_ILP_ENABLE
int sequentialJumps = 0;
int sequentialTailCalls = 0;
#endif
#if (defined(__GNUC__) || defined(__clang__)) && !defined(PLUTO_VMDUMP) && !defined(PLUTO_ETL_ENABLE)
#include "ljumptabgcc.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(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));
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpOut ("; move " << stringify_tvalue(vRB(i)) << " into R(A)");
vmbreak;
}
vmcase(OP_LOADI) {
StkId ra = RA(i);
lua_Integer b = GETARG_sBx(i);
setivalue(s2v(ra), b);
vmDumpInit();
vmDumpAddA();
vmDumpAdd (GETARG_sBx(i));
vmDumpOut ("; push " << b);
vmbreak;
}
vmcase(OP_LOADF) {
StkId ra = RA(i);
int b = GETARG_sBx(i);
setfltvalue(s2v(ra), cast_num(b));
vmDumpInit();
vmDumpAddA();
vmDumpAdd (GETARG_sBx(i));
vmDumpOut ("; push " << b << ".0");
vmbreak;
}
vmcase(OP_LOADK) {
StkId ra = RA(i);
TValue *rb = k + GETARG_Bx(i);
setobj2s(L, ra, rb);
vmDumpInit();
vmDumpAddA();
vmDumpAdd (GETARG_Bx(i));
vmDumpOut ("; push " << stringify_tvalue(rb));
vmbreak;
}
vmcase(OP_LOADKX) {
StkId ra = RA(i);
TValue *rb;
rb = k + GETARG_Ax(*pc); pc++;
setobj2s(L, ra, rb);
vmDumpInit();
vmDumpAdd (GETARG_Ax(*pc));
vmDumpOut ("; push " << stringify_tvalue(rb) << " & skip next opcode");
vmbreak;
}
vmcase(OP_LOADFALSE) {
StkId ra = RA(i);
setbfvalue(s2v(ra));
vmDumpInit();
vmDumpAddA();
vmDumpOut ("; push false");
vmbreak;
}
vmcase(OP_LFALSESKIP) {
StkId ra = RA(i);
setbfvalue(s2v(ra));
pc++;
vmDumpInit();
vmDumpAddA();
vmDumpOut ("; push false & skip next opcode");
vmbreak;
}
vmcase(OP_LOADTRUE) {
StkId ra = RA(i);
setbtvalue(s2v(ra));
vmDumpInit();
vmDumpAddA();
vmDumpOut ("; push true");
vmbreak;
}
vmcase(OP_LOADNIL) {
StkId ra = RA(i);
int b = GETARG_B(i);
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpOut ("; push " << (b + 1) << " nil value(s)");
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);
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpOut ("; push " << stringify_tvalue(cl->upvals[b]->v.p));
vmbreak;
}
vmcase(OP_SETUPVAL) {
StkId ra = RA(i);
UpVal *uv = cl->upvals[GETARG_B(i)];
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpOut ("; old=" << stringify_tvalue(uv->v.p) << " new=" << stringify_tvalue(s2v(ra)));
setobj(L, uv->v.p, s2v(ra));
luaC_barrier(L, uv, s2v(ra));
vmbreak;
}
vmcase(OP_GETTABUP) {
StkId ra = RA(i);
const TValue *slot;
TValue *upval = cl->upvals[GETARG_B(i)]->v.p;
TValue *rc = KC(i);
TString *key = tsvalue(rc);
if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) {
setobj2s(L, ra, slot);
}
else
Protect(luaV_finishget(L, upval, rc, ra, slot));
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut("; push T['" << getstr(key) << "'] for " << stringify_tvalue(s2v(ra)) << " (T=" << stringify_tvalue(upval) << ")");
vmbreak;
}
vmcase(OP_GETTABLE) {
StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
TValue *rc = vRC(i);
lua_Unsigned n;
if (ttisinteger(rc)
? (cast_void(n = ivalue(rc)), luaV_fastgeti(L, rb, n, slot))
: luaV_fastget(L, rb, rc, slot, luaH_get)) {
setobj2s(L, ra, slot);
}
else
Protect(luaV_finishget(L, rb, rc, ra, slot));
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut("; push T[" << stringify_tvalue(rc) << "] for " << stringify_tvalue(s2v(ra)) << " (T=" << stringify_tvalue(rb) << ")");
vmbreak;
}
vmcase(OP_GETI) {
StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
int c = GETARG_C(i);
if (luaV_fastgeti(L, rb, c, slot)) {
setobj2s(L, ra, slot);
}
else {
TValue key;
setivalue(&key, c);
Protect(luaV_finishget(L, rb, &key, ra, slot));
}
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut("; push T[" << c << "] for " << stringify_tvalue(s2v(ra)) << " (T=" << stringify_tvalue(rb) << ")");
vmbreak;
}
vmcase(OP_GETFIELD) {
StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
TValue *rc = KC(i);
TString *key = tsvalue(rc);
if (luaV_fastget(L, rb, key, slot, luaH_getshortstr)) {
setobj2s(L, ra, slot);
}
else
Protect(luaV_finishget(L, rb, rc, ra, slot));
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut("; push T['" << getstr(key) << "'] for " << stringify_tvalue(s2v(ra)) << " (T=" << stringify_tvalue(rb) << ")");
vmbreak;
}
vmcase(OP_SETTABUP) {
const TValue *slot;
TValue *upval = cl->upvals[GETARG_A(i)]->v.p;
TValue *rb = KB(i);
TValue *rc = RKC(i);
TString *key = tsvalue(rb);
if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) {
Table *t = hvalue(upval);
#ifndef PLUTO_DISABLE_LENGTH_CACHE
t->length = 0;
#endif
#ifndef PLUTO_DISABLE_TABLE_FREEZING
if (l_unlikely(t->isfrozen))
halfProtect(luaG_runerror(L, "attempt to modify frozen table."));
#endif
luaV_finishfastset(L, upval, slot, rc);
}
else {
Protect(luaV_finishset(L, upval, rb, rc, slot));
}
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; T['" << getstr(key) << "'] = " << stringify_tvalue(rc) << " (T=" << stringify_tvalue(upval) << ")");
vmbreak;
}
vmcase(OP_SETTABLE) {
StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
TValue *rc = RKC(i);
lua_Unsigned n;
if (ttisinteger(rb)
? (cast_void(n = ivalue(rb)), luaV_fastgeti(L, s2v(ra), n, slot))
: luaV_fastget(L, s2v(ra), rb, slot, luaH_get)) {
Table *t = hvalue(s2v(ra));
#ifndef PLUTO_DISABLE_LENGTH_CACHE
t->length = 0; #endif
#ifndef PLUTO_DISABLE_TABLE_FREEZING
if (l_unlikely(t->isfrozen))
halfProtect(luaG_runerror(L, "attempt to modify frozen table."));
#endif
luaV_finishfastset(L, s2v(ra), slot, rc);
}
else
Protect(luaV_finishset(L, s2v(ra), rb, rc, slot));
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; T[" << stringify_tvalue(rb) << "] = " << stringify_tvalue(rc) << " (T=" << stringify_tvalue(s2v(ra)) << ")");
vmbreak;
}
vmcase(OP_SETI) {
StkId ra = RA(i);
const TValue *slot;
int c = GETARG_B(i);
TValue *rc = RKC(i);
if (luaV_fastgeti(L, s2v(ra), c, slot)) {
Table *t = hvalue(s2v(ra));
#ifndef PLUTO_DISABLE_LENGTH_CACHE
t->length = 0; #endif
#ifndef PLUTO_DISABLE_TABLE_FREEZING
if (l_unlikely(t->isfrozen))
halfProtect(luaG_runerror(L, "attempt to modify frozen table."));
#endif
luaV_finishfastset(L, s2v(ra), slot, rc);
}
else {
TValue key;
setivalue(&key, c);
Protect(luaV_finishset(L, s2v(ra), &key, rc, slot));
}
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; T[" << c << "] = " << stringify_tvalue(rc) << " (T=" << stringify_tvalue(s2v(ra)) << ")");
vmbreak;
}
vmcase(OP_SETFIELD) {
StkId ra = RA(i);
const TValue *slot;
TValue *rb = KB(i);
TValue *rc = RKC(i);
TString *key = tsvalue(rb);
if (luaV_fastget(L, s2v(ra), key, slot, luaH_getshortstr)) {
#ifndef PLUTO_DISABLE_TABLE_FREEZING
if (l_unlikely(hvalue(s2v(ra))->isfrozen))
halfProtect(luaG_runerror(L, "attempt to modify frozen table."));
#endif
luaV_finishfastset(L, s2v(ra), slot, rc);
}
else
Protect(luaV_finishset(L, s2v(ra), rb, rc, slot));
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; T['" << getstr(key) << "'] = " << stringify_tvalue(rc) << " (T=" << stringify_tvalue(s2v(ra)) << ")");
vmbreak;
}
vmcase(OP_NEWTABLE) {
StkId ra = RA(i);
int b = GETARG_B(i);
int c = GETARG_C(i);
Table *t;
if (b > 0)
b = 1 << (b - 1);
lua_assert((!TESTARG_k(i)) == (GETARG_Ax(*pc) == 0));
if (TESTARG_k(i))
c += GETARG_Ax(*pc) * (MAXARG_C + 1);
pc++;
L->top.p = ra + 1;
t = luaH_new(L);
#ifndef PLUTO_NO_DEFAULT_TABLE_METATABLE
luaH_initmetatable(L, t);
#endif
sethvalue2s(L, ra, t);
if (b != 0 || c != 0)
luaH_resize(L, t, c, b);
checkGC(L, ra + 1);
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; arraysize=" << c << " hashsize=" << b);
vmbreak;
}
vmcase(OP_SELF) {
StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
TValue *rc = RKC(i);
TString *key = tsvalue(rc);
setobj2s(L, ra + 1, rb);
if (luaV_fastget(L, rb, key, slot, luaH_getstr)) {
setobj2s(L, ra, slot);
}
else
Protect(luaV_finishget(L, rb, rc, ra, slot));
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; push self to call '" << getstr(key) << "'");
vmbreak;
}
vmcase(OP_ADDI) {
vmDumpInit();
vmDumpAddA();
vmDumpAdd (GETARG_sC(i));
vmDumpOut ("; push " << stringify_tvalue(vRB(i)) << " + " << GETARG_sC(i));
op_arithI(L, l_addi, luai_numadd);
vmbreak;
}
vmcase(OP_ADDK) {
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; push " << stringify_tvalue(vRB(i)) << " + " << stringify_tvalue(KC(i)));
op_arithK(L, l_addi, luai_numadd);
vmbreak;
}
vmcase(OP_SUBK) {
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; push " << stringify_tvalue(vRB(i)) << " - " << stringify_tvalue(KC(i)));
op_arithK(L, l_subi, luai_numsub);
vmbreak;
}
vmcase(OP_MULK) {
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; push " << stringify_tvalue(vRB(i)) << " * " << stringify_tvalue(KC(i)));
op_arithK(L, l_muli, luai_nummul);
vmbreak;
}
vmcase(OP_MODK) {
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; push " << stringify_tvalue(vRB(i)) << " % " << stringify_tvalue(KC(i)));
savestate(L, ci);
op_arithK(L, luaV_mod, luaV_modf);
vmbreak;
}
vmcase(OP_POWK) {
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; push " << stringify_tvalue(vRB(i)) << " ^ " << stringify_tvalue(KC(i)));
op_arithfK(L, luai_numpow);
vmbreak;
}
vmcase(OP_DIVK) {
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; push " << stringify_tvalue(vRB(i)) << " / " << stringify_tvalue(KC(i)));
savestate(L, ci);
op_arithfK(L, luai_numdiv);
vmbreak;
}
vmcase(OP_IDIVK) {
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; push " << stringify_tvalue(vRB(i)) << " // " << stringify_tvalue(KC(i)));
savestate(L, ci);
op_arithK(L, luaV_idiv, luai_numidiv);
vmbreak;
}
vmcase(OP_BANDK) {
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; push " << stringify_tvalue(vRB(i)) << " & " << stringify_tvalue(KC(i)));
op_bitwiseK(L, l_band);
vmbreak;
}
vmcase(OP_BORK) {
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; push " << stringify_tvalue(vRB(i)) << " | " << stringify_tvalue(KC(i)));
op_bitwiseK(L, l_bor);
vmbreak;
}
vmcase(OP_BXORK) {
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; push " << stringify_tvalue(vRB(i)) << " ~ " << stringify_tvalue(KC(i)));
op_bitwiseK(L, l_bxor);
vmbreak;
}
vmcase(OP_SHRI) {
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAdd (GETARG_sC(i));
vmDumpOut ("; push " << stringify_tvalue(vRB(i)) << " >> " << GETARG_sC(i));
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_SHLI) {
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; push " << GETARG_sC(i) << " << " << stringify_tvalue(vRB(i)));
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_ADD) {
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; push " << stringify_tvalue(vRB(i)) << " + " << stringify_tvalue(vRC(i)));
op_arith(L, l_addi, luai_numadd);
vmbreak;
}
vmcase(OP_SUB) {
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; push " << stringify_tvalue(vRB(i)) << " - " << stringify_tvalue(vRC(i)));
op_arith(L, l_subi, luai_numsub);
vmbreak;
}
vmcase(OP_MUL) {
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; push " << stringify_tvalue(vRB(i)) << " * " << stringify_tvalue(vRC(i)));
op_arith(L, l_muli, luai_nummul);
vmbreak;
}
vmcase(OP_MOD) {
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; push " << stringify_tvalue(vRB(i)) << " % " << stringify_tvalue(vRC(i)));
savestate(L, ci);
op_arith(L, luaV_mod, luaV_modf);
vmbreak;
}
vmcase(OP_POW) {
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; push " << stringify_tvalue(vRB(i)) << " ^ " << stringify_tvalue(vRC(i)));
op_arithf(L, luai_numpow);
vmbreak;
}
vmcase(OP_DIV) {
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; push " << stringify_tvalue(vRB(i)) << " / " << stringify_tvalue(vRC(i)));
op_arithf(L, luai_numdiv);
vmbreak;
}
vmcase(OP_IDIV) {
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; push " << stringify_tvalue(vRB(i)) << " // " << stringify_tvalue(vRC(i)));
savestate(L, ci);
op_arith(L, luaV_idiv, luai_numidiv);
vmbreak;
}
vmcase(OP_BAND) {
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; push " << stringify_tvalue(vRB(i)) << " & " << stringify_tvalue(vRC(i)));
op_bitwise(L, l_band);
vmbreak;
}
vmcase(OP_BOR) {
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; push " << stringify_tvalue(vRB(i)) << " | " << stringify_tvalue(vRC(i)));
op_bitwise(L, l_bor);
vmbreak;
}
vmcase(OP_BXOR) {
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; push " << stringify_tvalue(vRB(i)) << " ~ " << stringify_tvalue(vRC(i)));
op_bitwise(L, l_bxor);
vmbreak;
}
vmcase(OP_SHR) {
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; push " << stringify_tvalue(vRB(i)) << " >> " << stringify_tvalue(vRC(i)));
op_bitwise(L, luaV_shiftr);
vmbreak;
}
vmcase(OP_SHL) {
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; push " << stringify_tvalue(vRB(i)) << " << " << stringify_tvalue(vRC(i)));
op_bitwise(L, luaV_shiftl);
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));
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; call " << luaT_eventname[tm] << " over " << stringify_tvalue(s2v(ra)) << " & " << stringify_tvalue(rb));
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));
vmDumpInit();
vmDumpAddA();
vmDumpAdd (GETARG_sB(i));
vmDumpAddC();
vmDumpOut ("; call " << luaT_eventname[tm] << " over " << stringify_tvalue(s2v(ra)) << " & " << imm);
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));
vmDumpInit();
vmDumpAddA();
vmDumpAdd (GETARG_sB(i));
vmDumpAddC();
vmDumpOut ("; call " << luaT_eventname[tm] << " over " << stringify_tvalue(s2v(ra)) << " & " << stringify_tvalue(KB(i)) << " (k=" << GETARG_k(i) << ")");
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));
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpOut ("; push -(" << stringify_tvalue(rb) << ")");
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));
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpOut ("; push ~(" << stringify_tvalue(rb) << ")");
vmbreak;
}
vmcase(OP_NOT) {
StkId ra = RA(i);
TValue *rb = vRB(i);
if (l_isfalse(rb))
setbtvalue(s2v(ra));
else
setbfvalue(s2v(ra));
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpOut ("; push " << stringify_tvalue(s2v(ra)) << " (operand=" << stringify_tvalue(rb) << ")");
vmbreak;
}
vmcase(OP_LEN) {
StkId ra = RA(i);
Protect(luaV_objlen(L, ra, vRB(i)));
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpOut ("; push #(" << stringify_tvalue(vRB(i)) << ") (value=" << stringify_tvalue(s2v(ra)) << ")");
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);
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
if (n != 1) {
vmDumpOut("; concat the last " << n << " elements on the stack");
}
else {
vmDumpOut("; Pluto hackily updating the stack pointer");
}
vmbreak;
}
vmcase(OP_CLOSE) {
StkId ra = RA(i);
vmDumpInit();
vmDumpAddA();
vmDumpOut ("; close TBC upvalues");
Protect(luaF_close(L, ra, LUA_OK, 1));
vmbreak;
}
vmcase(OP_TBC) {
StkId ra = RA(i);
halfProtect(luaF_newtbcupval(L, ra));
vmDumpInit();
vmDumpAddA();
vmDumpOut ("; turn R(A) into a TBC upvalue");
vmbreak;
}
vmcase(OP_JMP) {
int offset = GETARG_sJ(i);
#ifdef PLUTO_ILP_ENABLE
if (offset <= 0) {
sequentialJumps++;
}
else sequentialJumps = 0;
if (l_unlikely(sequentialJumps == PLUTO_ILP_MAX_ITERATIONS)) {
savepc(L);
PLUTO_ILP_ERROR;
vmbreak;
}
#endif pc += offset;
updatetrap(ci);
vmDumpInit();
vmDumpAdd (offset);
vmDumpOut ("; offset=" << offset << " newpc=" << pc);
vmbreak;
}
vmcase(OP_EQ) {
StkId ra = RA(i);
int cond;
TValue *rb = vRB(i);
Protect(cond = luaV_equalobj(L, s2v(ra), rb));
docondjump();
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAdd (GETARG_k(i));
vmDumpOut ("; " << stringify_tvalue(s2v(ra)) << " == " << stringify_tvalue(rb));
vmbreak;
}
vmcase(OP_LT) {
op_order(L, l_lti, LTnum, lessthanothers);
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAdd (GETARG_k(i));
vmDumpOut ("; " << stringify_tvalue(s2v(RA(i))) << " < " << stringify_tvalue(vRB(i)));
vmbreak;
}
vmcase(OP_LE) {
op_order(L, l_lei, LEnum, lessequalothers);
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAdd (GETARG_k(i));
vmDumpOut ("; " << stringify_tvalue(s2v(RA(i))) << " <= " << stringify_tvalue(vRB(i)));
vmbreak;
}
vmcase(OP_EQK) {
StkId ra = RA(i);
TValue *rb = KB(i);
int cond = luaV_rawequalobj(s2v(ra), rb);
docondjump();
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAdd (GETARG_k(i));
vmDumpOut ("; " << stringify_tvalue(s2v(ra)) << " == " << stringify_tvalue(rb));
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();
vmDumpInit();
vmDumpAddA();
vmDumpAdd (GETARG_sB(i));
vmDumpAdd (GETARG_k(i));
vmDumpOut ("; " << stringify_tvalue(s2v(ra)) << " == " << im);
vmbreak;
}
vmcase(OP_LTI) {
op_orderI(L, l_lti, luai_numlt, 0, TM_LT);
vmDumpInit();
vmDumpAddA();
vmDumpAdd (GETARG_sB(i));
vmDumpAdd (GETARG_k(i));
vmDumpOut ("; " << stringify_tvalue(s2v(RA(i))) << " < " << GETARG_sB(i));
vmbreak;
}
vmcase(OP_LEI) {
op_orderI(L, l_lei, luai_numle, 0, TM_LE);
vmDumpInit();
vmDumpAddA();
vmDumpAdd (GETARG_sB(i));
vmDumpAdd (GETARG_k(i));
vmDumpOut ("; " << stringify_tvalue(s2v(RA(i))) << " <= " << GETARG_sB(i));
vmbreak;
}
vmcase(OP_GTI) {
op_orderI(L, l_gti, luai_numgt, 1, TM_LT);
vmDumpInit();
vmDumpAddA();
vmDumpAdd (GETARG_sB(i));
vmDumpAdd (GETARG_k(i));
vmDumpOut ("; " << stringify_tvalue(s2v(RA(i))) << " > " << GETARG_sB(i));
vmbreak;
}
vmcase(OP_GEI) {
op_orderI(L, l_gei, luai_numge, 1, TM_LE);
vmDumpInit();
vmDumpAddA();
vmDumpAdd (GETARG_sB(i));
vmDumpAdd (GETARG_k(i));
vmDumpOut ("; " << stringify_tvalue(s2v(RA(i))) << " >= " << GETARG_sB(i));
vmbreak;
}
vmcase(OP_TEST) {
StkId ra = RA(i);
int cond = !l_isfalse(s2v(ra));
#ifdef PLUTO_ILP_ENABLE
int offset = GETARG_sJ(i);
if (offset <= 0) {
sequentialJumps++;
}
else sequentialJumps = 0;
if (l_unlikely(sequentialJumps == PLUTO_ILP_MAX_ITERATIONS)) {
PLUTO_ILP_ERROR;
vmbreak;
}
#endif vmDumpInit();
vmDumpAddA();
vmDumpAdd(GETARG_k(i));
vmDumpAdd(GETARG_sJ(*pc));
if (cond) {
vmDumpOut("; conditional jump: condition is true");
}
else {
vmDumpOut("; conditional jump: condition is false");
}
docondjump();
vmbreak;
}
vmcase(OP_TESTSET) {
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAdd (GETARG_k(i));
StkId ra = RA(i);
TValue *rb = vRB(i);
if (l_isfalse(rb) == GETARG_k(i)) {
pc++;
vmDumpOut("; no assignment");
}
else {
setobj2s(L, ra, rb);
donextjump(ci);
vmDumpOut("; push/assign " << stringify_tvalue(rb));
}
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(L);
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut("; call " << stringify_tvalue(s2v(ra)) << " (nresults=" << nresults << " nparams=" << (b - 1) << ")");
#ifdef PLUTO_ILP_HOOK_FUNCTION
if (fvalue(s2v(ra)) == PLUTO_ILP_HOOK_FUNCTION) {
sequentialJumps = 0;
sequentialTailCalls = 0;
}
#endif
if ((newci = luaD_precall(L, ra, nresults)) == NULL)
{
updatetrap(ci);
}
else
{
ci = newci;
goto startfunc;
}
vmbreak;
}
vmcase(OP_TAILCALL) {
#ifdef PLUTO_ILP_ENABLE
++sequentialTailCalls;
if (l_unlikely(sequentialTailCalls == PLUTO_ILP_MAX_ITERATIONS)) {
PLUTO_ILP_ERROR;
vmbreak;
}
#endif
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);
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut("; tail-call " << stringify_tvalue(s2v(ra)) << " (nparams=" << (b - 1) << ")");
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);
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; return " << n << " value(s)");
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;
L->ci = ci->previous;
L->top.p = base - 1;
for (nres = ci->nresults; l_unlikely(nres > 0); nres--)
setnilvalue(s2v(L->top.p++));
}
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; return nothing");
goto ret;
}
vmcase(OP_RETURN1) {
#ifdef PLUTO_VMDUMP
if (true)
{
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; return " << stringify_tvalue(s2v(RA(i))));
}
#endif
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 = ci->nresults;
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 {
#ifdef PLUTO_ILP_ENABLE
sequentialTailCalls = 0;
#endif
ci = ci->previous;
goto returning;
}
}
vmcase(OP_FORLOOP) {
StkId ra = RA(i);
if (ttisinteger(s2v(ra + 2))) {
lua_Unsigned count = l_castS2U(ivalue(s2v(ra + 1)));
if (count > 0) {
lua_Integer step = ivalue(s2v(ra + 2));
lua_Integer idx = ivalue(s2v(ra));
chgivalue(s2v(ra + 1), count - 1);
idx = intop(+, idx, step);
chgivalue(s2v(ra), idx);
setivalue(s2v(ra + 3), idx);
pc -= GETARG_Bx(i);
}
}
else if (floatforloop(ra))
pc -= GETARG_Bx(i);
updatetrap(ci);
vmDumpInit();
vmDumpAddA();
vmDumpAdd (GETARG_Bx(i));
vmDumpOut ("; update loop: curr=" << stringify_tvalue(s2v(ra + 3)) << " step=" << stringify_tvalue(s2v(ra + 2)));
vmbreak;
}
vmcase(OP_FORPREP) {
vmDumpInit();
vmDumpAddA();
vmDumpAdd (GETARG_Bx(i));
StkId ra = RA(i);
savestate(L, ci);
if (forprep(L, ra))
{
pc += GETARG_Bx(i) + 1;
vmDumpOut("; this loop is skipped");
}
#ifdef PLUTO_VMDUMP
else
{
vmDumpOut("; prepare loop");
}
#endif
vmbreak;
}
vmcase(OP_TFORPREP) {
vmDumpInit();
vmDumpAddA();
vmDumpAdd (GETARG_Bx(i));
vmDumpOut (";");
StkId ra = RA(i);
const Instruction* callpc = pc + GETARG_Bx(i);
i = *callpc;
if ((!ttisfunction(s2v(ra)))
&& ttisnil(luaT_gettmbyobj(L, s2v(ra), TM_CALL))
) {
setobjs2s(L, ra + 1, ra);
setfvalue(s2v(ra), luaB_next);
}
if (ttypetag(s2v(ra)) == LUA_VLCF
&& ttistable(s2v(ra+1))
&& ttisnil(s2v(ra+3))
&& !trap
&& (GETARG_C(i) == 1 || GETARG_C(i) == 2)
) {
if (fvalue(s2v(ra)) == luaB_next && ttisnil(s2v(ra + 2))) {
settt_(s2v(ra + 3), LUA_VITER);
val_(s2v(ra + 3)).it = 0;
} else if (fvalue(s2v(ra)) == luaB_ipairsaux && ttisinteger(s2v(ra + 2))) {
settt_(s2v(ra + 3), LUA_VITERI);
} else {
halfProtect(luaF_newtbcupval(L, ra + 3));
}
} else {
halfProtect(luaF_newtbcupval(L, ra + 3));
}
pc = callpc + 1;
lua_assert(GET_OPCODE(i) == OP_TFORCALL && ra == RA(i));
goto l_tforcall;
}
vmcase(OP_TFORCALL) {
#ifdef PLUTO_VMDUMP
if (true)
{
vmDumpInit();
vmDumpAddA();
vmDumpAddC();
vmDumpOut (";");
}
#endif
l_tforcall: {
StkId ra = RA(i);
if (luai_likely(ttypetag(s2v(ra + 3)) == LUA_VITER)) {
if (luai_likely(!trap)) {
Table *t = hvalue(s2v(ra + 1));
unsigned int idx = val_(s2v(ra + 3)).it;
unsigned int asize = luaH_realasize(t);
i = *(pc++);
lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i));
for (; idx < asize; idx++) {
if (luai_likely(!isempty(&t->array[idx]))) {
setivalue(s2v(ra + 4), idx + 1);
setobj2s(L, ra + 5, &t->array[idx]);
goto l_tforcall_found;
}
}
for (idx -= asize; cast_int(idx) < sizenode(t); idx++) {
Node *n = gnode(t, idx);
if (luai_likely(!isempty(gval(n)))) {
getnodekey(L, s2v(ra + 4), n);
setobj2s(L, ra + 5, gval(n));
idx += asize;
goto l_tforcall_found;
}
}
vmbreak;
l_tforcall_found:
val_(s2v(ra + 3)).it = idx + 1;
setobjs2s(L, ra + 2, ra + 4);
pc -= GETARG_Bx(i);
vmbreak;
}
setnilvalue(s2v(ra + 3));
} else if (luai_likely(ttypetag(s2v(ra + 3)) == LUA_VITERI)) {
if (luai_likely(!trap)) {
Table *t = hvalue(s2v(ra + 1));
lua_Integer n = ivalue(s2v(ra + 2));
const TValue *slot;
n = intop(+, n, 1);
slot = luai_likely(l_castS2U(n) - 1 < t->alimit) ? &t->array[n - 1] : luaH_getint(t, n);
if (luai_likely(!isempty(slot))) {
setobj2s(L, ra + 5, slot);
chgivalue(s2v(ra + 2), n);
i = *(pc++);
lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i));
setobjs2s(L, ra + 4, ra + 2);
pc -= GETARG_Bx(i);
vmbreak;
}
} else {
setnilvalue(s2v(ra + 3));
}
}
memcpy(ra + 4, ra, 3 * sizeof(*ra));
L->top.p = ra + 4 + 3;
ProtectNT(luaD_call(L, ra + 4, GETARG_C(i)));
updatestack(ci);
i = *(pc++);
lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i));
goto l_tforloop;
}}
vmcase(OP_TFORLOOP) {
#ifdef PLUTO_VMDUMP
if (true)
{
vmDumpInit();
vmDumpAddA();
vmDumpAdd (GETARG_Bx(i));
vmDumpOut (";");
}
#endif
l_tforloop: {
StkId ra = RA(i);
if (!ttisnil(s2v(ra + 4))) {
setobjs2s(L, ra + 2, ra + 4);
pc -= GETARG_Bx(i);
}
vmbreak;
}}
vmcase(OP_SETLIST) {
StkId ra = RA(i);
int n = GETARG_B(i);
unsigned int last = GETARG_C(i);
Table *h = hvalue(s2v(ra));
if (n == 0)
n = cast_int(L->top.p - ra) - 1;
else
L->top.p = ci->top.p;
last += n;
if (TESTARG_k(i)) {
last += GETARG_Ax(*pc) * (MAXARG_C + 1);
pc++;
}
if (last > luaH_realasize(h))
luaH_resizearray(L, h, last);
#ifdef PLUTO_VMDUMP
std::string rep;
#endif
for (; n > 0; n--) {
TValue *val = s2v(ra + n);
setobj2t(L, &h->array[last - 1], val);
#ifdef PLUTO_VMDUMP
rep.insert(0, stringify_tvalue(val) + "; ");
#endif
last--;
luaC_barrierback(L, obj2gco(h), val);
}
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; { " << rep << "}");
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);
vmDumpInit();
vmDumpAddA();
vmDumpAdd (GETARG_Bx(i));
vmDumpOut ("; push " << stringify_tvalue(s2v(ra)));
vmbreak;
}
vmcase(OP_VARARG) {
StkId ra = RA(i);
int n = GETARG_C(i) - 1;
Protect(luaT_getvarargs(L, ci, ra, n));
vmDumpInit();
vmDumpAddA();
vmDumpAddC();
vmDumpOut ("; get " << n << " varargs");
vmbreak;
}
vmcase(OP_VARARGPREP) {
ProtectNT(luaT_adjustvarargs(L, GETARG_A(i), ci, cl->p));
if (l_unlikely(trap)) {
luaD_hookcall(L, ci);
L->oldpc = 1;
}
updatebase(ci);
vmDumpInit();
vmDumpAddA();
vmDumpOut ("; prepare for " << GETARG_A(i) << " varargs");
vmbreak;
}
vmcase(OP_EXTRAARG) {
lua_assert(0);
vmDumpInit();
vmDumpAddA();
vmDumpOut (";");
vmbreak;
}
vmcase(OP_IN) {
StkId ra = RA(i);
TValue *a = s2v(ra);
TValue *b = vRB(i);
#ifdef PLUTO_VMDUMP
std::string old = stringify_tvalue(a);
#endif
inopr(L, ra, a, b);
vmDumpInit();
vmDumpAddA();
vmDumpAddB();
vmDumpAddC();
vmDumpOut ("; " << old << " in " << stringify_tvalue(b) << " (" << stringify_tvalue(s2v(ra)) << ")");
vmbreak;
}
vmcase(NUM_OPCODES) {
vmbreak;
}
}
L->checkEtl();
}
}
#ifdef PLUTO_ETL_ENABLE
void lua_State::checkEtl() {
lua_State* const L = this;
if (l_unlikely(L->l_G->deadline < std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now().time_since_epoch()).count())) {
PLUTO_ETL_TIMESUP
}
}
#endif