From ed0518f417a61b32e531f85c434b8024859202cd Mon Sep 17 00:00:00 2001 From: daurnimator Date: Wed, 24 May 2017 20:44:34 +1000 Subject: Modify stack values up to L.top instead of replacing --- src/lapi.js | 98 +++++++++++----------- src/ldebug.js | 21 ++--- src/ldo.js | 79 +++++++++++++----- src/lobject.js | 28 ++++--- src/lparser.js | 4 +- src/lstate.js | 2 +- src/ltm.js | 18 ++-- src/lundump.js | 2 +- src/lvm.js | 257 +++++++++++++++++++++++++++++++++++++++------------------ 9 files changed, 320 insertions(+), 189 deletions(-) diff --git a/src/lapi.js b/src/lapi.js index 9b10d94..a8e0c82 100644 --- a/src/lapi.js +++ b/src/lapi.js @@ -112,7 +112,9 @@ const lua_xmove = function(from, to, n) { from.top -= n; for (let i = 0; i < n; i++) { + to.stack[to.top] = new lobject.TValue(); lobject.setobj2s(to, to.top, from.stack[from.top + i]); + delete from.stack[from.top + i]; to.top++; } }; @@ -135,21 +137,24 @@ const lua_gettop = function(L) { }; const lua_pushvalue = function(L, idx) { - lobject.setobj2s(L, L.top, index2addr(L, idx)); - L.top++; + lobject.pushobj2s(L, index2addr(L, idx)); assert(L.top <= L.ci.top, "stack overflow"); }; const lua_settop = function(L, idx) { let func = L.ci.funcOff; + let newtop; if (idx >= 0) { assert(idx <= L.stack_last - (func + 1), "new top too large"); - while (L.top < func + 1 + idx) - L.stack[L.top++] = new TValue(CT.LUA_TNIL, null); - L.top = func + 1 + idx; + newtop = func + 1 + idx; } else { assert(-(idx + 1) <= L.top - (func + 1), "invalid new top"); - let newtop = L.top + idx + 1; /* 'subtract' index (index is negative) */ + newtop = L.top + idx + 1; /* 'subtract' index (index is negative) */ + } + if (L.top < newtop) { + while (L.top < newtop) + L.stack[L.top++] = new TValue(CT.LUA_TNIL, null); + } else { while (L.top > newtop) delete L.stack[--L.top]; } @@ -161,7 +166,8 @@ const lua_pop = function(L, n) { const reverse = function(L, from, to) { for (; from < to; from++, to--) { - let temp = L.stack[from]; + let fromtv = L.stack[from]; + let temp = new TValue(fromtv.type, fromtv.value); lobject.setobjs2s(L, from, to); lobject.setobj2s(L, to, temp); } @@ -188,7 +194,7 @@ const lua_rotate = function(L, idx, n) { const lua_copy = function(L, fromidx, toidx) { let from = index2addr(L, fromidx); - L.stack[index2addr_(L, toidx)] = new TValue(from.type, from.value); + L.stack[index2addr_(L, toidx)].setfrom(from); }; const lua_remove = function(L, idx) { @@ -239,8 +245,7 @@ const lua_pushlstring = function(L, s, len) { assert(Array.isArray(s), "lua_pushlstring expects array of byte"); ts = lstring.luaS_bless(L, s.slice(0, len)); } - lobject.setsvalue2s(L, L.top, ts); - L.top++; + lobject.pushsvalue2s(L, ts); assert(L.top <= L.ci.top, "stack overflow"); return ts.value; @@ -249,14 +254,14 @@ const lua_pushlstring = function(L, s, len) { const lua_pushstring = function (L, s) { assert(Array.isArray(s) || s === undefined || s === null, "lua_pushstring expects array of byte"); - if (s === undefined || s === null) - L.stack[L.top] = new TValue(CT.LUA_TNIL, null); - else { + if (s === undefined || s === null) { + L.stack[L.top] = new TValue(CT.LUA_TNIL, null) + L.top++; + } else { let ts = lstring.luaS_new(L, s); - lobject.setsvalue2s(L, L.top, ts); + lobject.pushsvalue2s(L, ts); s = ts.getstr(); /* internal copy */ } - L.top++; assert(L.top <= L.ci.top, "stack overflow"); return s; @@ -276,14 +281,14 @@ const lua_pushfstring = function (L, fmt, ...argp) { const lua_pushliteral = function (L, s) { assert(typeof s === "string" || s === undefined || s === null, "lua_pushliteral expects a JS string"); - if (s === undefined || s === null) + if (s === undefined || s === null) { L.stack[L.top] = new TValue(CT.LUA_TNIL, null); - else { + L.top++; + } else { let ts = lstring.luaS_newliteral(L, s); - lobject.setsvalue2s(L, L.top, ts); + lobject.pushsvalue2s(L, ts); s = ts.getstr(); /* internal copy */ } - L.top++; assert(L.top <= L.ci.top, "stack overflow"); return s; @@ -300,16 +305,14 @@ const lua_pushcclosure = function(L, fn, n) { assert(n <= MAXUPVAL, "upvalue index too large"); let cl = new CClosure(L, fn, n); - - L.top -= n; - while (n--) { - cl.upvalue[n].setfrom(L.stack[L.top + n]) - delete L.stack[L.top + n]; - } - - L.stack[L.top] = new TValue(CT.LUA_TCCL, cl); + for (let i=0; i0) + --L.top; + L.stack[L.top].setclCvalue(cl); } - L.top++; assert(L.top <= L.ci.top, "stack overflow"); }; @@ -357,8 +360,7 @@ const auxsetstr = function(L, t, k) { let str = lstring.luaS_new(L, k); assert(1 < L.top - L.ci.funcOff, "not enough elements in the stack"); - lobject.setsvalue2s(L, L.top, str); /* push 'str' (to make it a TValue) */ - L.top++; + lobject.pushsvalue2s(L, str); /* push 'str' (to make it a TValue) */ assert(L.top <= L.ci.top, "stack overflow"); lvm.settable(L, t, L.stack[L.top - 1], L.stack[L.top - 2]); /* pop value and key */ @@ -435,7 +437,8 @@ const lua_rawset = function(L, idx) { slot.setfrom(v); } ltable.invalidateTMcache(o.value); - L.top -= 2; + delete L.stack[--L.top]; + delete L.stack[--L.top]; }; const lua_rawseti = function(L, idx, n) { @@ -458,7 +461,7 @@ const lua_rawsetp = function(L, idx, p) { let slot = ltable.luaH_set(L, o.value, k); slot.setfrom(v); } - L.top--; + delete L.stack[--L.top]; }; /* @@ -468,8 +471,7 @@ const lua_rawsetp = function(L, idx, p) { const auxgetstr = function(L, t, k) { assert(Array.isArray(k), "key must be an array of bytes"); let str = lstring.luaS_new(L, k); - lobject.setsvalue2s(L, L.top, str); - L.top++; + lobject.pushsvalue2s(L, str); assert(L.top <= L.ci.top, "stack overflow"); lvm.gettable(L, t, L.stack[L.top - 1], L.top - 1); return L.stack[L.top - 1].ttnov(); @@ -478,8 +480,7 @@ const auxgetstr = function(L, t, k) { const lua_rawgeti = function(L, idx, n) { let t = index2addr(L, idx); assert(t.ttistable(), "table expected"); - lobject.setobj2s(L, L.top, ltable.luaH_getint(t.value, n)); - L.top++; + lobject.pushobj2s(L, ltable.luaH_getint(t.value, n)); assert(L.top <= L.ci.top, "stack overflow"); return L.stack[L.top - 1].ttnov(); }; @@ -488,8 +489,7 @@ const lua_rawgetp = function(L, idx, p) { let t = index2addr(L, idx); assert(t.ttistable(), "table expected"); let k = new TValue(CT.LUA_TLIGHTUSERDATA, p); - lobject.setobj2s(L, L.top, ltable.luaH_get(L, t.value, k)); - L.top++; + lobject.pushobj2s(L, ltable.luaH_get(L, t.value, k)); assert(L.top <= L.ci.top, "stack overflow"); return L.stack[L.top - 1].ttnov(); }; @@ -550,8 +550,7 @@ const lua_getupvalue = function(L, funcindex, n) { if (up) { let name = up.name; let val = up.val; - lobject.setobj2s(L, L.top, val); - L.top++; + lobject.pushobj2s(L, val); assert(L.top <= L.ci.top, "stack overflow"); return name; } @@ -565,8 +564,8 @@ const lua_setupvalue = function(L, funcindex, n) { if (aux) { let name = aux.name; let val = aux.val; - L.top--; - val.setfrom(L.stack[L.top]); + val.setfrom(L.stack[L.top-1]); + delete L.stack[--L.top]; return name; } return null; @@ -898,13 +897,12 @@ const lua_arith = function(L, op) { assert(2 < L.top - L.ci.funcOff, "not enough elements in the stack"); /* all other operations expect two operands */ else { /* for unary operations, add fake 2nd operand */ assert(1 < L.top - L.ci.funcOff, "not enough elements in the stack"); - lobject.setobjs2s(L, L.top, L.top - 1); - L.top++; + lobject.pushobj2s(L, L.stack[L.top-1]); assert(L.top <= L.ci.top, "stack overflow"); } /* first operand at top - 2, second at top - 1; result go to top - 2 */ lobject.luaO_arith(L, op, L.stack[L.top - 2], L.stack[L.top - 1], L.stack[L.top - 2]); - L.top--; /* remove second operand */ + delete L.stack[--L.top]; /* remove second operand */ }; /* @@ -1037,13 +1035,15 @@ const lua_error = function(L) { const lua_next = function(L, idx) { let t = index2addr(L, idx); assert(t.ttistable(), "table expected"); + L.stack[L.top] = new TValue(); let more = ltable.luaH_next(L, t.value, L.top - 1); if (more) { L.top++; assert(L.top <= L.ci.top, "stack overflow"); return 1; } else { - L.top--; + delete L.stack[L.top]; + delete L.stack[--L.top]; return 0; } }; @@ -1053,15 +1053,15 @@ const lua_concat = function(L, n) { if (n >= 2) lvm.luaV_concat(L, n); else if (n === 0) { - lobject.setsvalue2s(L, L.top, lstring.luaS_bless(L, [])); - L.top++; + lobject.pushsvalue2s(L, lstring.luaS_bless(L, [])); assert(L.top <= L.ci.top, "stack overflow"); } }; const lua_len = function(L, idx) { let t = index2addr(L, idx); - lvm.luaV_objlen(L, L.top, t); + L.stack[L.top] = new TValue(); + lvm.luaV_objlen(L, L.stack[L.top], t); L.top++; assert(L.top <= L.ci.top, "stack overflow"); }; diff --git a/src/ldebug.js b/src/ldebug.js index 2a9ada6..3636a06 100644 --- a/src/ldebug.js +++ b/src/ldebug.js @@ -140,8 +140,7 @@ const lua_getlocal = function(L, ar, n) { let local = findlocal(L, ar.i_ci, n); if (local) { name = local.name; - lobject.setobj2s(L, L.top, L.stack[local.pos]); - L.top++; + lobject.pushobj2s(L, L.stack[local.pos]); assert(L.top <= L.ci.top, "stack overflow"); } else { name = null; @@ -265,27 +264,24 @@ const auxgetinfo = function(L, what, ar, f, ci) { }; const lua_getinfo = function(L, what, ar) { - let status, cl, ci, func, funcOff; + let status, cl, ci, func; swapextra(L); if (what[0] === '>'.charCodeAt(0)) { ci = null; - funcOff = L.top - 1; - func = L.stack[funcOff]; + func = L.stack[L.top - 1]; assert(L, func.ttisfunction(), "function expected"); what = what.slice(1); /* skip the '>' */ L.top--; /* pop function */ } else { ci = ar.i_ci; func = ci.func; - funcOff = ci.funcOff; assert(ci.func.ttisfunction()); } cl = func.ttisclosure() ? func.value : null; status = auxgetinfo(L, what, ar, cl, ci); if (what.indexOf('f'.charCodeAt(0)) >= 0) { - lobject.setobjs2s(L, L.top, funcOff); - L.top++; + lobject.pushobj2s(L, func); assert(L.top <= L.ci.top, "stack overflow"); } @@ -595,9 +591,8 @@ const luaG_runerror = function(L, fmt, ...argp) { const luaG_errormsg = function(L) { if (L.errfunc !== 0) { /* is there an error handling function? */ let errfunc = L.errfunc; - lobject.setobjs2s(L, L.top, L.top - 1); /* move argument */ - lobject.setobjs2s(L, L.top - 1, errfunc); /* push function */ - L.top++; + lobject.pushobj2s(L, L.stack[L.top - 1]); /* move argument */ + lobject.setobjs2s(L, L.top - 2, errfunc); /* push function */ ldo.luaD_callnoyield(L, L.top - 2, 1); } @@ -643,8 +638,8 @@ const luaG_traceexec = function(L) { L.hookcount = 1; /* undo decrement to zero */ ci.l_savedpc--; /* undo increment (resume will increment it again) */ ci.callstatus |= lstate.CIST_HOOKYIELD; /* mark that it yielded */ - ci.func = L.stack[L.top - 1]; /* protect stack below results */ - ci.funcOff = L.top - 1; + ci.funcOff = L.top - 1; /* protect stack below results */ + ci.func = L.stack[ci.funcOff]; ldo.luaD_throw(L, TS.LUA_YIELD); } }; diff --git a/src/ldo.js b/src/ldo.js index b32e404..464d373 100644 --- a/src/ldo.js +++ b/src/ldo.js @@ -36,7 +36,13 @@ const seterrorobj = function(L, errcode, oldtop) { } } - L.top = oldtop + 1; + if (L.top < oldtop + 1) { + while (L.top < oldtop + 1) + L.stack[L.top++] = new lobject.TValue(CT.LUA_TNIL, null); + } else { + while (L.top > oldtop + 1) + delete L.stack[--L.top]; + } }; const ERRORSTACKSIZE = luaconf.LUAI_MAXSTACK + 200; @@ -94,8 +100,8 @@ const luaD_shrinkstack = function(L) { }; const luaD_inctop = function(L) { - luaD_checkstack(L, 1); - L.top++; + luaD_checkstack(L, 1); + L.stack[L.top++] = new lobject.TValue(CT.LUA_TNIL, null); }; /* @@ -151,7 +157,14 @@ const luaD_precall = function(L, off, nresults) { ci.nresults = nresults; ci.func = func; ci.l_base = base; - L.top = ci.top = base + fsize; + ci.top = base + fsize; + if (L.top < ci.top) { + while (L.top < ci.top) + L.stack[L.top++] = new lobject.TValue(CT.LUA_TNIL, null); + } else { + while (L.top > ci.top) + delete L.stack[--L.top]; + } ci.l_code = p.code; ci.l_savedpc = 0; ci.callstatus = lstate.CIST_LUA; @@ -159,6 +172,7 @@ const luaD_precall = function(L, off, nresults) { return false; } default: + luaD_checkstack(L, 1); tryfuncTM(L, off, func); return luaD_precall(L, off, nresults); } @@ -185,33 +199,42 @@ const moveresults = function(L, firstResult, res, nres, wanted) { break; case 1: { if (nres === 0) - L.stack[firstResult] = lobject.luaO_nilobject; - lobject.setobjs2s(L, res, firstResult); /* move it to proper place */ + L.stack[res].setnilvalue(); + else { + lobject.setobjs2s(L, res, firstResult); /* move it to proper place */ + } break; } case defs.LUA_MULTRET: { for (let i = 0; i < nres; i++) lobject.setobjs2s(L, res + i, firstResult + i); + for (let i=L.top; i>=(res + nres); i--) + delete L.stack[i]; L.top = res + nres; return false; } default: { let i; if (wanted <= nres) { - for (i = 0; i < wanted; i++) { + for (i = 0; i < wanted; i++) lobject.setobjs2s(L, res + i, firstResult + i); - } } else { for (i = 0; i < nres; i++) lobject.setobjs2s(L, res + i, firstResult + i); - for (; i < wanted; i++) - L.stack[res + i] = new lobject.TValue(CT.LUA_TNIL, null); + for (; i < wanted; i++) { + if (res+i >= L.top) + L.stack[res + i] = new lobject.TValue(CT.LUAT_NIL, null); + else + L.stack[res + i].setnilvalue(); + } } break; } } - - L.top = res + wanted; /* top points after the last result */ + let newtop = res + wanted; /* top points after the last result */ + for (let i=L.top; i>=newtop; i--) + delete L.stack[i]; + L.top = newtop; return true; }; @@ -239,7 +262,13 @@ const luaD_hook = function(L, event, line) { assert(!L.allowhook); L.allowhook = 1; ci.top = ci_top; - L.top = top; + if (L.top < top) { + while (L.top < top) + L.stack[L.top++] = new lobject.TValue(CT.LUA_TNIL, null); + } else { + while (L.top > top) + delete L.stack[--L.top]; + } ci.callstatus &= ~lstate.CIST_HOOKED; } }; @@ -252,8 +281,8 @@ const adjust_varargs = function(L, p, actual) { let i; for (i = 0; i < nfixargs && i < actual; i++) { - lobject.setobjs2s(L, L.top++, fixed + i); - L.stack[fixed + i] = new lobject.TValue(CT.LUA_TNIL, null); + lobject.pushobj2s(L, L.stack[fixed + i]); + L.stack[fixed + i].setnilvalue(); } for (; i < nfixargs; i++) @@ -267,9 +296,9 @@ const tryfuncTM = function(L, off, func) { if (!tm.ttisfunction(tm)) ldebug.luaG_typeerror(L, func, defs.to_luastring("call", true)); /* Open a hole inside the stack at 'func' */ - for (let p = L.top; p > off; p--) - lobject.setobjs2s(L, p, p-1); - L.top++; /* slot ensured by caller */ + lobject.pushobj2s(L, L.stack[L.top-1]); /* push top of stack again */ + for (let p = L.top-2; p > off; p--) + lobject.setobjs2s(L, p, p-1); /* move other items up one */ lobject.setobj2s(L, off, tm); /* tag method is the new function to be called */ }; @@ -464,10 +493,16 @@ const recover = function(L, status) { ** coroutine error handler and should not kill the coroutine.) */ const resume_error = function(L, msg, narg) { - L.top -= narg; /* remove args from the stack */ - lobject.setsvalue2s(L, L.top, lstring.luaS_newliteral(L, msg)); /* push error message */ - L.top++; - assert(L.top <= L.ci.top, "stack overflow"); + let ts = lstring.luaS_newliteral(L, msg); + if (narg === 0) { + lobject.pushsvalue2s(L, ts); + assert(L.top <= L.ci.top, "stack overflow"); + } else { + /* remove args from the stack */ + for (let i=1; i ci.top) + delete L.stack[--L.top]; + } break; } case OCi.OP_TFORCALL: { assert(ci.l_code[ci.l_savedpc].opcode === OCi.OP_TFORLOOP); - L.top = ci.top; /* correct top */ + /* correct top */ + if (L.top < ci.top) { + while (L.top < ci.top) + L.stack[L.top++] = new lobject.TValue(CT.LUA_TNIL, null); + } else { + while (L.top > ci.top) + delete L.stack[--L.top]; + } break; } case OCi.OP_CALL: { - if (inst.C - 1 >= 0) /* nresults >= 0? */ - L.top = ci.top; /* adjust results */ + if (inst.C - 1 >= 0) { /* nresults >= 0? */ + /* adjust results */ + if (L.top < ci.top) { + while (L.top < ci.top) + L.stack[L.top++] = new lobject.TValue(CT.LUA_TNIL, null); + } else { + while (L.top > ci.top) + delete L.stack[--L.top]; + } + } break; } } @@ -135,7 +158,7 @@ const luaV_execute = function(L) { break; } case OCi.OP_LOADBOOL: { - L.stack[ra] = new lobject.TValue(CT.LUA_TBOOLEAN, i.B !== 0); + L.stack[ra].setbvalue(i.B !== 0); if (i.C !== 0) ci.l_savedpc++; /* skip next instruction (if C) */ @@ -144,7 +167,7 @@ const luaV_execute = function(L) { } case OCi.OP_LOADNIL: { for (let j = 0; j <= i.B; j++) - L.stack[ra + j] = new lobject.TValue(CT.LUA_TNIL, null); + L.stack[ra + j].setnilvalue(); break; } case OCi.OP_GETUPVAL: { @@ -155,7 +178,7 @@ const luaV_execute = function(L) { case OCi.OP_SETUPVAL: { let uv = cl.upvals[i.B]; if (uv.isopen()) { - uv.L.stack[uv.v] = L.stack[ra]; + uv.L.stack[uv.v].setfrom(L.stack[ra]); } else { uv.value.setfrom(L.stack[ra]); } @@ -192,7 +215,7 @@ const luaV_execute = function(L) { break; } case OCi.OP_NEWTABLE: { - L.stack[ra] = new lobject.TValue(CT.LUA_TTABLE, ltable.luaH_new(L)); + L.stack[ra].sethvalue(ltable.luaH_new(L)); break; } case OCi.OP_SELF: { @@ -210,11 +233,11 @@ const luaV_execute = function(L) { let numberop2 = tonumber(op2); if (op1.ttisinteger() && op2.ttisinteger()) { - L.stack[ra] = new lobject.TValue(CT.LUA_TNUMINT, (op1.value + op2.value)|0); + L.stack[ra].setivalue((op1.value + op2.value)|0); } else if (numberop1 !== false && numberop2 !== false) { - L.stack[ra] = new lobject.TValue(CT.LUA_TNUMFLT, numberop1 + numberop2); + L.stack[ra].setfltvalue(numberop1 + numberop2); } else { - ltm.luaT_trybinTM(L, op1, op2, ra, ltm.TMS.TM_ADD); + ltm.luaT_trybinTM(L, op1, op2, L.stack[ra], ltm.TMS.TM_ADD); } break; } @@ -225,11 +248,11 @@ const luaV_execute = function(L) { let numberop2 = tonumber(op2); if (op1.ttisinteger() && op2.ttisinteger()) { - L.stack[ra] = new lobject.TValue(CT.LUA_TNUMINT, (op1.value - op2.value)|0); + L.stack[ra].setivalue((op1.value - op2.value)|0); } else if (numberop1 !== false && numberop2 !== false) { - L.stack[ra] = new lobject.TValue(CT.LUA_TNUMFLT, numberop1 - numberop2); + L.stack[ra].setfltvalue(numberop1 - numberop2); } else { - ltm.luaT_trybinTM(L, op1, op2, ra, ltm.TMS.TM_SUB); + ltm.luaT_trybinTM(L, op1, op2, L.stack[ra], ltm.TMS.TM_SUB); } break; } @@ -240,11 +263,11 @@ const luaV_execute = function(L) { let numberop2 = tonumber(op2); if (op1.ttisinteger() && op2.ttisinteger()) { - L.stack[ra] = new lobject.TValue(CT.LUA_TNUMINT, Math.imul(op1.value, op2.value)); + L.stack[ra].setivalue(Math.imul(op1.value, op2.value)); } else if (numberop1 !== false && numberop2 !== false) { - L.stack[ra] = new lobject.TValue(CT.LUA_TNUMFLT, numberop1 * numberop2); + L.stack[ra].setfltvalue(numberop1 * numberop2); } else { - ltm.luaT_trybinTM(L, op1, op2, ra, ltm.TMS.TM_MUL); + ltm.luaT_trybinTM(L, op1, op2, L.stack[ra], ltm.TMS.TM_MUL); } break; } @@ -255,11 +278,11 @@ const luaV_execute = function(L) { let numberop2 = tonumber(op2); if (op1.ttisinteger() && op2.ttisinteger()) { - L.stack[ra] = new lobject.TValue(CT.LUA_TNUMINT, luaV_mod(L, op1.value, op2.value)); + L.stack[ra].setivalue(luaV_mod(L, op1.value, op2.value)); } else if (numberop1 !== false && numberop2 !== false) { - L.stack[ra] = new lobject.TValue(CT.LUA_TNUMFLT, llimit.luai_nummod(L, numberop1, numberop2)); + L.stack[ra].setfltvalue(llimit.luai_nummod(L, numberop1, numberop2)); } else { - ltm.luaT_trybinTM(L, op1, op2, ra, ltm.TMS.TM_MOD); + ltm.luaT_trybinTM(L, op1, op2, L.stack[ra], ltm.TMS.TM_MOD); } break; } @@ -270,9 +293,9 @@ const luaV_execute = function(L) { let numberop2 = tonumber(op2); if (numberop1 !== false && numberop2 !== false) { - L.stack[ra] = new lobject.TValue(CT.LUA_TNUMFLT, Math.pow(numberop1, numberop2)); + L.stack[ra].setfltvalue(Math.pow(numberop1, numberop2)); } else { - ltm.luaT_trybinTM(L, op1, op2, ra, ltm.TMS.TM_POW); + ltm.luaT_trybinTM(L, op1, op2, L.stack[ra], ltm.TMS.TM_POW); } break; } @@ -283,9 +306,9 @@ const luaV_execute = function(L) { let numberop2 = tonumber(op2); if (numberop1 !== false && numberop2 !== false) { - L.stack[ra] = new lobject.TValue(CT.LUA_TNUMFLT, numberop1 / numberop2); + L.stack[ra].setfltvalue(numberop1 / numberop2); } else { - ltm.luaT_trybinTM(L, op1, op2, ra, ltm.TMS.TM_DIV); + ltm.luaT_trybinTM(L, op1, op2, L.stack[ra], ltm.TMS.TM_DIV); } break; } @@ -296,11 +319,11 @@ const luaV_execute = function(L) { let numberop2 = tonumber(op2); if (op1.ttisinteger() && op2.ttisinteger()) { - L.stack[ra] = new lobject.TValue(CT.LUA_TNUMINT, luaV_div(L, op1.value, op2.value)); + L.stack[ra].setivalue(luaV_div(L, op1.value, op2.value)); } else if (numberop1 !== false && numberop2 !== false) { - L.stack[ra] = new lobject.TValue(CT.LUA_TNUMFLT, Math.floor(numberop1 / numberop2)); + L.stack[ra].setfltvalue(Math.floor(numberop1 / numberop2)); } else { - ltm.luaT_trybinTM(L, op1, op2, ra, ltm.TMS.TM_IDIV); + ltm.luaT_trybinTM(L, op1, op2, L.stack[ra], ltm.TMS.TM_IDIV); } break; } @@ -311,9 +334,9 @@ const luaV_execute = function(L) { let numberop2 = tointeger(op2); if (numberop1 !== false && numberop2 !== false) { - L.stack[ra] = new lobject.TValue(CT.LUA_TNUMINT, (numberop1 & numberop2)); + L.stack[ra].setivalue(numberop1 & numberop2); } else { - ltm.luaT_trybinTM(L, op1, op2, ra, ltm.TMS.TM_BAND); + ltm.luaT_trybinTM(L, op1, op2, L.stack[ra], ltm.TMS.TM_BAND); } break; } @@ -324,9 +347,9 @@ const luaV_execute = function(L) { let numberop2 = tointeger(op2); if (numberop1 !== false && numberop2 !== false) { - L.stack[ra] = new lobject.TValue(CT.LUA_TNUMINT, (numberop1 | numberop2)); + L.stack[ra].setivalue(numberop1 | numberop2); } else { - ltm.luaT_trybinTM(L, op1, op2, ra, ltm.TMS.TM_BOR); + ltm.luaT_trybinTM(L, op1, op2, L.stack[ra], ltm.TMS.TM_BOR); } break; } @@ -337,9 +360,9 @@ const luaV_execute = function(L) { let numberop2 = tointeger(op2); if (numberop1 !== false && numberop2 !== false) { - L.stack[ra] = new lobject.TValue(CT.LUA_TNUMINT, (numberop1 ^ numberop2)); + L.stack[ra].setivalue(numberop1 ^ numberop2); } else { - ltm.luaT_trybinTM(L, op1, op2, ra, ltm.TMS.TM_BXOR); + ltm.luaT_trybinTM(L, op1, op2, L.stack[ra], ltm.TMS.TM_BXOR); } break; } @@ -350,9 +373,9 @@ const luaV_execute = function(L) { let numberop2 = tointeger(op2); if (numberop1 !== false && numberop2 !== false) { - L.stack[ra] = new lobject.TValue(CT.LUA_TNUMINT, luaV_shiftl(numberop1, numberop2)); + L.stack[ra].setivalue(luaV_shiftl(numberop1, numberop2)); } else { - ltm.luaT_trybinTM(L, op1, op2, ra, ltm.TMS.TM_SHL); + ltm.luaT_trybinTM(L, op1, op2, L.stack[ra], ltm.TMS.TM_SHL); } break; } @@ -363,9 +386,9 @@ const luaV_execute = function(L) { let numberop2 = tointeger(op2); if (numberop1 !== false && numberop2 !== false) { - L.stack[ra] = new lobject.TValue(CT.LUA_TNUMINT, luaV_shiftl(numberop1, -numberop2)); + L.stack[ra].setivalue(luaV_shiftl(numberop1, -numberop2)); } else { - ltm.luaT_trybinTM(L, op1, op2, ra, ltm.TMS.TM_SHR); + ltm.luaT_trybinTM(L, op1, op2, L.stack[ra], ltm.TMS.TM_SHR); } break; } @@ -374,11 +397,11 @@ const luaV_execute = function(L) { let numberop = tonumber(op); if (op.ttisinteger()) { - L.stack[ra] = new lobject.TValue(CT.LUA_TNUMINT, (-op.value)|0); + L.stack[ra].setivalue((-op.value)|0); } else if (numberop !== false) { - L.stack[ra] = new lobject.TValue(CT.LUA_TNUMFLT, -numberop); + L.stack[ra].setfltvalue(-numberop); } else { - ltm.luaT_trybinTM(L, op, op, ra, ltm.TMS.TM_UNM); + ltm.luaT_trybinTM(L, op, op, L.stack[ra], ltm.TMS.TM_UNM); } break; } @@ -386,19 +409,19 @@ const luaV_execute = function(L) { let op = L.stack[RB(L, base, i)]; if (op.ttisinteger()) { - L.stack[ra] = new lobject.TValue(CT.LUA_TNUMINT, ~op.value); + L.stack[ra].setivalue(~op.value); } else { - ltm.luaT_trybinTM(L, op, op, ra, ltm.TMS.TM_BNOT); + ltm.luaT_trybinTM(L, op, op, L.stack[ra], ltm.TMS.TM_BNOT); } break; } case OCi.OP_NOT: { let op = L.stack[RB(L, base, i)]; - L.stack[ra] = new lobject.TValue(CT.LUA_TBOOLEAN, op.l_isfalse()); + L.stack[ra].setbvalue(op.l_isfalse()); break; } case OCi.OP_LEN: { - luaV_objlen(L, ra, L.stack[RB(L, base, i)]); + luaV_objlen(L, L.stack[ra], L.stack[RB(L, base, i)]); break; } case OCi.OP_CONCAT: { @@ -408,7 +431,14 @@ const luaV_execute = function(L) { luaV_concat(L, c - b + 1); let rb = base + b; lobject.setobjs2s(L, ra, rb); - L.top = ci.top; /* restore top */ + /* restore top */ + if (L.top < ci.top) { + while (L.top < ci.top) + L.stack[L.top++] = new lobject.TValue(CT.LUA_TNIL, null); + } else { + while (L.top > ci.top) + delete L.stack[--L.top]; + } break; } case OCi.OP_JMP: { @@ -458,12 +488,26 @@ const luaV_execute = function(L) { let b = i.B; let nresults = i.C - 1; - if (b !== 0) - L.top = ra+b; + if (b !== 0) { + if (L.top < ra+b) { + while (L.top < ra+b) + L.stack[L.top++] = new lobject.TValue(CT.LUA_TNIL, null); + } else { + while (L.top > ra+b) + delete L.stack[--L.top]; + } + } if (ldo.luaD_precall(L, ra, nresults)) { - if (nresults >= 0) - L.top = ci.top; + if (nresults >= 0) { + if (L.top < ci.top) { + while (L.top < ci.top) + L.stack[L.top++] = new lobject.TValue(CT.LUA_TNIL, null); + } else { + while (L.top > ci.top) + delete L.stack[--L.top]; + } + } } else { ci = L.ci; continue newframe; @@ -472,7 +516,16 @@ const luaV_execute = function(L) { break; } case OCi.OP_TAILCALL: { - if (i.B !== 0) L.top = ra + i.B; + let b = i.B; + if (b !== 0) { + if (L.top < ra+b) { + while (L.top < ra+b) + L.stack[L.top++] = new lobject.TValue(CT.LUA_TNIL, null); + } else { + while (L.top > ra+b) + delete L.stack[--L.top]; + } + } /* else previous instruction set top */ if (ldo.luaD_precall(L, ra, LUA_MULTRET)) { // JS function } else { /* tail call: put called frame (n) in place of caller one (o) */ @@ -485,9 +538,15 @@ const luaV_execute = function(L) { if (cl.p.p.length > 0) lfunc.luaF_close(L, oci.l_base); for (let aux = 0; nfuncOff + aux < lim; aux++) lobject.setobjs2s(L, ofuncOff + aux, nfuncOff + aux); - oci.func = nci.func; oci.l_base = ofuncOff + (nci.l_base - nfuncOff); - oci.top = L.top = ofuncOff + (L.top - nfuncOff); + oci.top = ofuncOff + (L.top - nfuncOff); + if (L.top < nci.top) { + while (L.top < oci.top) + L.stack[L.top++] = new lobject.TValue(CT.LUA_TNIL, null); + } else { + while (L.top > oci.top) + delete L.stack[--L.top]; + } oci.l_code = nci.l_code; oci.l_savedpc = nci.l_savedpc; oci.callstatus |= lstate.CIST_TAIL; @@ -506,10 +565,19 @@ const luaV_execute = function(L) { if (ci.callstatus & lstate.CIST_FRESH) return; /* external invocation: return */ - + /* invocation via reentry: continue execution */ ci = L.ci; - if (b) L.top = ci.top; - + if (b) { + if (L.top < ci.top) { + while (L.top < ci.top) + L.stack[L.top++] = new lobject.TValue(CT.LUA_TNIL, null); + } else { + while (L.top > ci.top) + delete L.stack[--L.top]; + } + } + assert(ci.callstatus & lstate.CIST_LUA); + assert(ci.l_code[ci.l_savedpc - 1].opcode === OCi.OP_CALL); continue newframe; } case OCi.OP_FORLOOP: { @@ -521,7 +589,7 @@ const luaV_execute = function(L) { if (0 < step ? idx <= limit : limit <= idx) { ci.l_savedpc += i.sBx; L.stack[ra].chgivalue(idx); /* update internal index... */ - L.stack[ra + 3] = new lobject.TValue(CT.LUA_TNUMINT, idx); + L.stack[ra + 3].setivalue(idx); } } else { /* floating loop */ let step = L.stack[ra + 2].value; @@ -531,7 +599,7 @@ const luaV_execute = function(L) { if (0 < step ? idx <= limit : limit <= idx) { ci.l_savedpc += i.sBx; L.stack[ra].chgfltvalue(idx); /* update internal index... */ - L.stack[ra + 3] = new lobject.TValue(CT.LUA_TNUMFLT, idx); + L.stack[ra + 3].setfltvalue(idx); } } break; @@ -550,13 +618,13 @@ const luaV_execute = function(L) { let nlimit, nstep, ninit; if ((nlimit = tonumber(plimit)) === false) ldebug.luaG_runerror(L, defs.to_luastring("'for' limit must be a number", true)); - L.stack[ra + 1] = new lobject.TValue(CT.LUA_TNUMFLT, nlimit); + L.stack[ra + 1].setfltvalue(nlimit); if ((nstep = tonumber(pstep)) === false) ldebug.luaG_runerror(L, defs.to_luastring("'for' step must be a number", true)); - L.stack[ra + 2] = new lobject.TValue(CT.LUA_TNUMFLT, nstep); + L.stack[ra + 2].setfltvalue(nstep); if ((ninit = tonumber(init)) === false) ldebug.luaG_runerror(L, defs.to_luastring("'for' initial value must be a number", true)); - L.stack[ra] = new lobject.TValue(CT.LUA_TNUMFLT, ninit - nstep); + L.stack[ra].setfltvalue(ninit - nstep); } ci.l_savedpc += i.sBx; @@ -567,15 +635,28 @@ const luaV_execute = function(L) { lobject.setobjs2s(L, cb+2, ra+2); lobject.setobjs2s(L, cb+1, ra+1); lobject.setobjs2s(L, cb, ra); - L.top = cb + 3; /* func. + 2 args (state and index) */ + /* func. + 2 args (state and index) */ + if (L.top < cb + 3) { + while (L.top < cb + 3) + L.stack[L.top++] = new lobject.TValue(CT.LUA_TNIL, null); + } else { + while (L.top > cb + 3) + delete L.stack[--L.top]; + } ldo.luaD_call(L, cb, i.C); + if (L.top < ci.top) { + while (L.top < ci.top) + L.stack[L.top++] = new lobject.TValue(CT.LUA_TNIL, null); + } else { + while (L.top > ci.top) + delete L.stack[--L.top]; + } /* go straight to OP_TFORLOOP */ - L.top = ci.top; i = ci.l_code[ci.l_savedpc++]; ra = RA(L, base, i); assert(i.opcode === OCi.OP_TFORLOOP); - /* fall through */ } + /* fall through */ case OCi.OP_TFORLOOP: { if (!L.stack[ra + 1].ttisnil()) { /* continue loop? */ lobject.setobjs2s(L, ra, ra + 1); /* save control variable */ @@ -601,7 +682,14 @@ const luaV_execute = function(L) { ltable.luaH_setint(h, last--, L.stack[ra + n]); } - L.top = ci.top; /* correct top (in case of previous open call) */ + /* correct top (in case of previous open call) */ + if (L.top < ci.top) { + while (L.top < ci.top) + L.stack[L.top++] = new lobject.TValue(CT.LUA_TNIL, null); + } else { + while (L.top > ci.top) + delete L.stack[--L.top]; + } break; } case OCi.OP_CLOSURE: { @@ -620,14 +708,23 @@ const luaV_execute = function(L) { if (b < 0) { b = n; /* get all var. arguments */ ldo.luaD_checkstack(L, n); - L.top = ra + n; + if (L.top >= ra+n) { + while (L.top > ra+n) + delete L.stack[--L.top]; + } else { + while (L.top < ra+n) { + L.stack[L.top] = new lobject.TValue(); + L.top++; + } + } + assert(L.top == ra + n); } for (j = 0; j < b && j < n; j++) lobject.setobjs2s(L, ra + j, base - n + j); for (; j < b; j++) /* complete required results with nil */ - L.stack[ra + j] = new lobject.TValue(CT.LUA_TNIL, null); + L.stack[ra + j].setnilvalue(); break; } case OCi.OP_EXTRAARG: { @@ -725,8 +822,9 @@ const luaV_equalobj = function(L, t1, t2) { if (tm === null) /* no TM? */ return 0; - ltm.luaT_callTM(L, tm, t1, t2, L.top, 1); - return L.stack[L.top].l_isfalse() ? 0 : 1; + let tv = new lobject.TValue(); /* doesn't use the stack */ + ltm.luaT_callTM(L, tm, t1, t2, tv, 1); + return tv.l_isfalse() ? 0 : 1; }; const luaV_rawequalobj = function(t1, t2) { @@ -890,12 +988,12 @@ const luaV_objlen = function(L, ra, rb) { let h = rb.value; tm = ltm.fasttm(L, h.metatable, ltm.TMS.TM_LEN); if (tm !== null) break; /* metamethod? break switch to call it */ - L.stack[ra] = new lobject.TValue(CT.LUA_TNUMINT, ltable.luaH_getn(h)); /* else primitive len */ + ra.setivalue(ltable.luaH_getn(h)); /* else primitive len */ return; } case CT.LUA_TSHRSTR: case CT.LUA_TLNGSTR: - L.stack[ra] = new lobject.TValue(CT.LUA_TNUMINT, rb.vslen()); + ra.setivalue(rb.vslen()); return; default: { tm = ltm.luaT_gettmbyobj(L, rb, ltm.TMS.TM_LEN); @@ -989,32 +1087,29 @@ const luaV_concat = function(L, total) { let n = 2; /* number of elements handled in this pass (at least 2) */ if (!(L.stack[top-2].ttisstring() || cvt2str(L.stack[top-2])) || !tostring(L, top - 1)) { - ltm.luaT_trybinTM(L, L.stack[top-2], L.stack[top-1], top-2, ltm.TMS.TM_CONCAT); - delete L.stack[top - 1]; + ltm.luaT_trybinTM(L, L.stack[top-2], L.stack[top-1], L.stack[top-2], ltm.TMS.TM_CONCAT); } else if (isemptystr(L.stack[top-1])) { tostring(L, top - 2); - delete L.stack[top - 1]; } else if (isemptystr(L.stack[top-2])) { lobject.setobjs2s(L, top - 2, top - 1); - delete L.stack[top - 1]; } else { /* at least two non-empty string values; get as many as possible */ let toconcat = new Array(total); toconcat[total-1] = L.stack[top-1].svalue(); - delete L.stack[top - 1]; for (n = 1; n < total; n++) { if (!tostring(L, top - n - 1)) { toconcat = toconcat.slice(total-n); break; } toconcat[total-n-1] = L.stack[top - n - 1].svalue(); - delete L.stack[top - n - 1]; } let ts = lstring.luaS_bless(L, Array.prototype.concat.apply([], toconcat)); lobject.setsvalue2s(L, top - n, ts); } total -= n - 1; /* got 'n' strings to create 1 new */ - L.top -= n - 1; /* popped 'n' strings and pushed one */ + /* popped 'n' strings and pushed one */ + for (; L.top > top-(n-1);) + delete L.stack[--L.top]; } while (total > 1); /* repeat until only 1 result left */ }; @@ -1037,14 +1132,14 @@ const gettable = function(L, t, key, ra) { } else { /* 't' is a table */ tm = ltm.fasttm(L, t.value.metatable, ltm.TMS.TM_INDEX); /* table's metamethod */ if (tm === null) { /* no metamethod? */ - L.stack[ra] = new lobject.TValue(CT.LUA_TNIL, null); /* result is nil */ + L.stack[ra].setnilvalue(); /* result is nil */ return; } } /* else will try the metamethod */ } if (tm.ttisfunction()) { /* is metamethod a function? */ - ltm.luaT_callTM(L, tm, t, key, ra, 1); /* call it */ + ltm.luaT_callTM(L, tm, t, key, L.stack[ra], 1); /* call it */ return; } t = tm; /* else try to access 'tm[key]' */ -- cgit v1.2.3-70-g09d2