diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lapi.js | 98 | ||||
-rw-r--r-- | src/ldebug.js | 21 | ||||
-rw-r--r-- | src/ldo.js | 79 | ||||
-rw-r--r-- | src/lobject.js | 28 | ||||
-rw-r--r-- | src/lparser.js | 4 | ||||
-rw-r--r-- | src/lstate.js | 2 | ||||
-rw-r--r-- | src/ltm.js | 18 | ||||
-rw-r--r-- | src/lundump.js | 2 | ||||
-rw-r--r-- | 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; i<n; i++) + cl.upvalue[i].setfrom(L.stack[L.top - n + i]); + for (let i=1; i<n; i++) + delete L.stack[--L.top]; + if (n>0) + --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); } }; @@ -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<narg; i++) + delete L.stack[--L.top]; + lobject.setsvalue2s(L, L.top-1, ts); /* push error message */ + } return TS.LUA_ERRRUN; }; diff --git a/src/lobject.js b/src/lobject.js index aec7109..f395036 100644 --- a/src/lobject.js +++ b/src/lobject.js @@ -220,16 +220,22 @@ class TValue { } +const pushobj2s = function(L, tv) { + L.stack[L.top++] = new TValue(tv.type, tv.value); +}; +const pushsvalue2s = function(L, ts) { + L.stack[L.top++] = new TValue(CT.LUA_TLNGSTR, ts); +}; /* from stack to (same) stack */ const setobjs2s = function(L, newidx, oldidx) { - L.stack[newidx] = L.stack[oldidx]; + L.stack[newidx].setfrom(L.stack[oldidx]); }; /* to stack (not from same stack) */ const setobj2s = function(L, newidx, oldtv) { - L.stack[newidx] = new TValue(oldtv.type, oldtv.value); + L.stack[newidx].setfrom(oldtv); }; const setsvalue2s = function(L, newidx, ts) { - L.stack[newidx] = new TValue(CT.LUA_TLNGSTR, ts); + L.stack[newidx].setsvalue(ts); }; const luaO_nilobject = new TValue(CT.LUA_TNIL, null); @@ -528,8 +534,8 @@ const luaO_tostring = function(L, obj) { }; const pushstr = function(L, str) { - setsvalue2s(L, L.top, lstring.luaS_new(L, str)); ldo.luaD_inctop(L); + setsvalue2s(L, L.top-1, lstring.luaS_new(L, str)); }; const luaO_pushvfstring = function(L, fmt, argp) { @@ -659,8 +665,7 @@ const luaO_arith = function(L, op, p1, p2, res) { case defs.LUA_OPBNOT: { /* operate only on integers */ let i1, i2; if ((i1 = lvm.tointeger(p1)) !== false && (i2 = lvm.tointeger(p2)) !== false) { - res.type = CT.LUA_TNUMINT; - res.value = intarith(L, op, i1, i2); + res.setivalue(intarith(L, op, i1, i2)); return; } else break; /* go to the end */ @@ -668,8 +673,7 @@ const luaO_arith = function(L, op, p1, p2, res) { case defs.LUA_OPDIV: case defs.LUA_OPPOW: { /* operate only on floats */ let n1, n2; if ((n1 = lvm.tonumber(p1)) !== false && (n2 = lvm.tonumber(p2)) !== false) { - res.type = CT.LUA_TNUMFLT; - res.value = numarith(L, op, n1, n2); + res.setfltvalue(numarith(L, op, n1, n2)); return; } else break; /* go to the end */ @@ -677,13 +681,11 @@ const luaO_arith = function(L, op, p1, p2, res) { default: { /* other operations */ let n1, n2; if (p1.ttisinteger() && p2.ttisinteger()) { - res.type = CT.LUA_TNUMINT; - res.value = intarith(L, op, p1.value, p2.value); + res.setivalue(intarith(L, op, p1.value, p2.value)); return; } else if ((n1 = lvm.tonumber(p1)) !== false && (n2 = lvm.tonumber(p2)) !== false) { - res.type = CT.LUA_TNUMFLT; - res.value = numarith(L, op, n1, n2); + res.setfltvalue(numarith(L, op, n1, n2)); return; } else break; /* go to the end */ @@ -714,6 +716,8 @@ module.exports.luaO_tostring = luaO_tostring; module.exports.luaO_utf8desc = luaO_utf8desc; module.exports.luaO_utf8esc = luaO_utf8esc; module.exports.numarith = numarith; +module.exports.pushobj2s = pushobj2s; +module.exports.pushsvalue2s = pushsvalue2s; module.exports.setobjs2s = setobjs2s; module.exports.setobj2s = setobj2s; module.exports.setsvalue2s = setsvalue2s; diff --git a/src/lparser.js b/src/lparser.js index 96bad67..0079141 100644 --- a/src/lparser.js +++ b/src/lparser.js @@ -1568,7 +1568,7 @@ const luaY_parser = function(L, z, buff, dyd, name, firstchar) { L.stack[L.top-1].setclLvalue(cl); lexstate.h = ltable.luaH_new(L); /* create table for scanner */ ldo.luaD_inctop(L); - L.stack[L.top-1] = new TValue(defs.CT.LUA_TTABLE, lexstate.h); + L.stack[L.top-1].sethvalue(lexstate.h); funcstate.f = cl.p = new Proto(L); funcstate.f.source = lstring.luaS_new(L, name); lexstate.buff = buff; @@ -1579,7 +1579,7 @@ const luaY_parser = function(L, z, buff, dyd, name, firstchar) { assert(!funcstate.prev && funcstate.nups === 1 && !lexstate.fs); /* all scopes should be correctly finished */ assert(dyd.actvar.n === 0 && dyd.gt.n === 0 && dyd.label.n === 0); - L.top--; /* remove scanner's table */ + delete L.stack[--L.top]; /* remove scanner's table */ return cl; /* closure is on the stack, too */ }; diff --git a/src/lstate.js b/src/lstate.js index b7a11bc..9046adf 100644 --- a/src/lstate.js +++ b/src/lstate.js @@ -109,8 +109,8 @@ const stack_init = function(L1, L) { let ci = L1.base_ci; ci.next = ci.previous = null; ci.callstatus = 0; - ci.func = L1.stack[L1.top]; ci.funcOff = L1.top; + ci.func = L1.stack[L1.top]; L1.stack[L1.top++] = new lobject.TValue(CT.LUA_TNIL, null); ci.top = L1.top + defs.LUA_MINSTACK; L1.ci = ci; @@ -110,13 +110,12 @@ const luaT_objtypename = function(L, o) { const luaT_callTM = function(L, f, p1, p2, p3, hasres) { let func = L.top; - lobject.setobj2s(L, L.top, f); /* push function (assume EXTRA_STACK) */ - lobject.setobj2s(L, L.top + 1, p1); /* 1st argument */ - lobject.setobj2s(L, L.top + 2, p2); /* 2nd argument */ - L.top += 3; + lobject.pushobj2s(L, f); /* push function (assume EXTRA_STACK) */ + lobject.pushobj2s(L, p1); /* 1st argument */ + lobject.pushobj2s(L, p2); /* 2nd argument */ if (!hasres) /* no result? 'p3' is third argument */ - lobject.setobj2s(L, L.top++, p3); /* 3rd argument */ + lobject.pushobj2s(L, p3); /* 3rd argument */ if (L.ci.callstatus & lstate.CIST_LUA) ldo.luaD_call(L, func, hasres); @@ -124,7 +123,9 @@ const luaT_callTM = function(L, f, p1, p2, p3, hasres) { ldo.luaD_callnoyield(L, func, hasres); if (hasres) { /* if has result, move it to its place */ - lobject.setobjs2s(L, p3, --L.top); + let tv = L.stack[L.top-1]; + delete L.stack[--L.top]; + p3.setfrom(tv); } }; @@ -158,10 +159,11 @@ const luaT_trybinTM = function(L, p1, p2, res, event) { }; const luaT_callorderTM = function(L, p1, p2, event) { - if (!luaT_callbinTM(L, p1, p2, L.top, event)) + let res = new lobject.TValue(CT.LUA_TNIL, null); + if (!luaT_callbinTM(L, p1, p2, res, event)) return -1; else - return !L.stack[L.top].l_isfalse() ? 1 : 0; + return res.l_isfalse() ? 0 : 1; }; const fasttm = function(l, et, e) { diff --git a/src/lundump.js b/src/lundump.js index 5686430..3f61cb6 100644 --- a/src/lundump.js +++ b/src/lundump.js @@ -265,8 +265,8 @@ const luaU_undump = function(L, Z, name) { let S = new BytecodeParser(L, Z, name); S.checkHeader(); let cl = lfunc.luaF_newLclosure(L, S.readByte()); - L.stack[L.top].setclLvalue(cl); ldo.luaD_inctop(L); + L.stack[L.top-1].setclLvalue(cl); cl.p = new lfunc.Proto(L); S.readFunction(cl.p, null); assert(cl.nupvalues === cl.p.upvalues.length); @@ -34,12 +34,13 @@ const luaV_finishOp = function(L) { case OCi.OP_MOD: case OCi.OP_POW: case OCi.OP_UNM: case OCi.OP_BNOT: case OCi.OP_LEN: case OCi.OP_GETTABUP: case OCi.OP_GETTABLE: case OCi.OP_SELF: { - lobject.setobjs2s(L, base + inst.A, --L.top); + lobject.setobjs2s(L, base + inst.A, L.top-1); + delete L.stack[--L.top]; break; } case OCi.OP_LE: case OCi.OP_LT: case OCi.OP_EQ: { let res = !L.stack[L.top - 1].l_isfalse(); - L.top--; + delete L.stack[--L.top]; if (ci.callstatus & lstate.CIST_LEQ) { /* "<=" using "<" instead? */ assert(op === OCi.OP_LE); ci.callstatus ^= lstate.CIST_LEQ; /* clear mark */ @@ -61,17 +62,39 @@ const luaV_finishOp = function(L) { } /* move final result to final position */ lobject.setobjs2s(L, ci.l_base + inst.A, L.top - 1); - 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_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]' */ |