diff options
-rw-r--r-- | src/lapi.js | 201 | ||||
-rw-r--r-- | src/lauxlib.js | 41 | ||||
-rw-r--r-- | src/ldebug.js | 28 | ||||
-rw-r--r-- | src/ldo.js | 102 | ||||
-rw-r--r-- | src/lobject.js | 78 | ||||
-rw-r--r-- | src/lparser.js | 6 | ||||
-rw-r--r-- | src/lstate.js | 5 | ||||
-rw-r--r-- | src/ltable.js | 4 | ||||
-rw-r--r-- | src/ltm.js | 24 | ||||
-rw-r--r-- | src/lundump.js | 2 | ||||
-rw-r--r-- | src/lvm.js | 326 |
11 files changed, 506 insertions, 311 deletions
diff --git a/src/lapi.js b/src/lapi.js index 9b40b36..1dfd112 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] = from.stack[from.top + 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,22 +137,24 @@ const lua_gettop = function(L) { }; const lua_pushvalue = function(L, idx) { - L.stack[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]; } @@ -162,9 +166,10 @@ const lua_pop = function(L, n) { const reverse = function(L, from, to) { for (; from < to; from++, to--) { - let temp = L.stack[from]; - L.stack[from] = L.stack[to]; - L.stack[to] = temp; + let fromtv = L.stack[from]; + let temp = new TValue(fromtv.type, fromtv.value); + lobject.setobjs2s(L, from, to); + lobject.setobj2s(L, to, temp); } }; @@ -189,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) { @@ -211,34 +216,36 @@ const lua_replace = function(L, idx) { */ const lua_pushnil = function(L) { - L.stack[L.top++] = new TValue(CT.LUA_TNIL, null); - + L.stack[L.top] = new TValue(CT.LUA_TNIL, null); + L.top++; assert(L.top <= L.ci.top, "stack overflow"); }; const lua_pushnumber = function(L, n) { assert(typeof n === "number"); - L.stack[L.top++] = new TValue(CT.LUA_TNUMFLT, n); - + L.stack[L.top] = new TValue(CT.LUA_TNUMFLT, n); + L.top++; assert(L.top <= L.ci.top, "stack overflow"); }; const lua_pushinteger = function(L, n) { assert(typeof n === "number" && (n|0) === n); - - L.stack[L.top++] = new TValue(CT.LUA_TNUMINT, n); - + L.stack[L.top] = new TValue(CT.LUA_TNUMINT, n); + L.top++; assert(L.top <= L.ci.top, "stack overflow"); }; const lua_pushlstring = function(L, s, len) { - assert(Array.isArray(s), "lua_pushlstring expects array of byte"); assert(typeof len === "number"); - - let ts = new TValue(CT.LUA_TLNGSTR, lstring.luaS_bless(L, s.slice(0, len))); - L.stack[L.top++] = ts; - + let ts; + if (len === 0) { + ts = lstring.luaS_bless(L, []); + } else { + assert(Array.isArray(s), "lua_pushlstring expects array of byte"); + ts = lstring.luaS_bless(L, s.slice(0, len)); + } + lobject.pushsvalue2s(L, ts); assert(L.top <= L.ci.top, "stack overflow"); return ts.value; @@ -247,13 +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 { - L.stack[L.top] = new TValue(CT.LUA_TLNGSTR, lstring.luaS_new(L, s)); + 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.pushsvalue2s(L, ts); + s = ts.getstr(); /* internal copy */ } - - L.top++; assert(L.top <= L.ci.top, "stack overflow"); return s; @@ -269,17 +277,18 @@ const lua_pushfstring = function (L, fmt, ...argp) { return lobject.luaO_pushvfstring(L, fmt, argp); }; +/* Similar to lua_pushstring, but takes a JS string */ 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 { - let ts = new TValue(CT.LUA_TLNGSTR, lstring.luaS_newliteral(L, s)); - L.stack[L.top] = ts; + L.top++; + } else { + let ts = lstring.luaS_newliteral(L, s); + lobject.pushsvalue2s(L, ts); + s = ts.getstr(); /* internal copy */ } - - L.top++; assert(L.top <= L.ci.top, "stack overflow"); return s; @@ -296,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"); }; @@ -319,21 +326,21 @@ const lua_pushcfunction = function(L, fn) { const lua_pushjsfunction = lua_pushcfunction; const lua_pushboolean = function(L, b) { - L.stack[L.top++] = new TValue(CT.LUA_TBOOLEAN, b ? true : false); - + L.stack[L.top] = new TValue(CT.LUA_TBOOLEAN, b ? true : false); + L.top++; assert(L.top <= L.ci.top, "stack overflow"); }; const lua_pushlightuserdata = function(L, p) { - L.stack[L.top++] = new TValue(CT.LUA_TLIGHTUSERDATA, p); - + L.stack[L.top] = new TValue(CT.LUA_TLIGHTUSERDATA, p); + L.top++; assert(L.top <= L.ci.top, "stack overflow"); }; const lua_pushthread = function(L) { - L.stack[L.top++] = new TValue(CT.LUA_TTHREAD, L); + L.stack[L.top] = new TValue(CT.LUA_TTHREAD, L); + L.top++; assert(L.top <= L.ci.top, "stack overflow"); - return L.l_G.mainthread === L; }; @@ -351,11 +358,10 @@ const lua_pushglobaltable = function(L) { const auxsetstr = function(L, t, k) { assert(Array.isArray(k), "key must be an array of bytes"); - let str = new TValue(CT.LUA_TLNGSTR, lstring.luaS_new(L, k)); - + let str = lstring.luaS_new(L, k); assert(1 < L.top - L.ci.funcOff, "not enough elements in the stack"); - - L.stack[L.top++] = str; + 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 */ delete L.stack[--L.top]; @@ -409,7 +415,8 @@ const lua_seti = function(L, idx, n) { assert(typeof n === "number" && (n|0) === n); assert(1 < L.top - L.ci.funcOff, "not enough elements in the stack"); let t = index2addr(L, idx); - L.stack[L.top++] = new TValue(CT.LUA_TNUMINT, n); + L.stack[L.top] = new TValue(CT.LUA_TNUMINT, n); + L.top++; 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 */ @@ -430,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) { @@ -453,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]; }; /* @@ -462,24 +470,18 @@ 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 = new TValue(CT.LUA_TLNGSTR, lstring.luaS_new(L, k)); - - L.stack[L.top++] = str; + let str = lstring.luaS_new(L, k); + 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(); }; const lua_rawgeti = function(L, idx, n) { let t = index2addr(L, idx); - assert(t.ttistable(), "table expected"); - - L.stack[L.top++] = ltable.luaH_getint(t.value, n); + lobject.pushobj2s(L, ltable.luaH_getint(t.value, n)); assert(L.top <= L.ci.top, "stack overflow"); - return L.stack[L.top - 1].ttnov(); }; @@ -487,26 +489,23 @@ 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); - L.stack[L.top++] = ltable.luaH_get(L, t.value, k); + 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(); }; const lua_rawget = function(L, idx) { let t = index2addr(L, idx); - assert(t.ttistable(t), "table expected"); - - L.stack[L.top - 1] = ltable.luaH_get(L, t.value, L.stack[L.top - 1]); - + lobject.setobj2s(L, L.top - 1, ltable.luaH_get(L, t.value, L.stack[L.top - 1])); return L.stack[L.top - 1].ttnov(); }; // narray and nrec are mostly useless for this implementation const lua_createtable = function(L, narray, nrec) { let t = new lobject.TValue(CT.LUA_TTABLE, ltable.luaH_new(L)); - L.stack[L.top++] = t; - + L.stack[L.top] = t; + L.top++; assert(L.top <= L.ci.top, "stack overflow"); }; @@ -516,10 +515,9 @@ const luaS_newudata = function(L, size) { const lua_newuserdata = function(L, size) { let u = luaS_newudata(L, size); - L.stack[L.top++] = new lobject.TValue(CT.LUA_TUSERDATA, u); - + L.stack[L.top] = new lobject.TValue(CT.LUA_TUSERDATA, u); + L.top++; assert(L.top <= L.ci.top, "stack overflow"); - return u.data; }; @@ -552,9 +550,8 @@ const lua_getupvalue = function(L, funcindex, n) { if (up) { let name = up.name; let val = up.val; - - L.stack[L.top++] = new TValue(val.type, val.value); - + lobject.pushobj2s(L, val); + assert(L.top <= L.ci.top, "stack overflow"); return name; } return null; @@ -567,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; @@ -598,7 +595,8 @@ const lua_getmetatable = function(L, objindex) { } if (mt !== null && mt !== undefined) { - L.stack[L.top++] = new TValue(CT.LUA_TTABLE, mt); + L.stack[L.top] = new TValue(CT.LUA_TTABLE, mt); + L.top++; assert(L.top <= L.ci.top, "stack overflow"); res = true; } @@ -610,7 +608,8 @@ const lua_getuservalue = function(L, idx) { let o = index2addr(L, idx); assert(L, o.ttisfulluserdata(), "full userdata expected"); let uv = o.value.uservalue; - L.stack[L.top++] = new TValue(uv.type, uv.value); + L.stack[L.top] = new TValue(uv.type, uv.value); + L.top++; assert(L.top <= L.ci.top, "stack overflow"); return L.stack[L.top - 1].ttnov(); }; @@ -628,7 +627,8 @@ const lua_getfield = function(L, idx, k) { const lua_geti = function(L, idx, n) { assert(typeof n === "number" && (n|0) === n); let t = index2addr(L, idx); - L.stack[L.top++] = new TValue(CT.LUA_TNUMINT, n); + L.stack[L.top] = new TValue(CT.LUA_TNUMINT, n); + L.top++; 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(); @@ -654,7 +654,8 @@ const lua_tolstring = function(L, idx) { if (!lvm.cvt2str(o)) { /* not convertible? */ return null; } - o = lobject.luaO_tostring(L, o); + /* TODO: this should modify number on the stack */ + return lobject.luaO_tostring(L, o).getstr(); } return o.svalue(); }; @@ -668,7 +669,8 @@ const lua_toljsstring = function(L, idx) { if (!lvm.cvt2str(o)) { /* not convertible? */ return null; } - o = lobject.luaO_tostring(L, o); + /* TODO: this should modify number on the stack */ + return defs.to_jsstring(lobject.luaO_tostring(L, o).getstr()); } return o.jsstring(); }; @@ -768,7 +770,9 @@ const lua_isproxy = function(p, L) { const create_proxy = function(G, type, value) { let proxy = function(L) { assert(L instanceof lstate.lua_State && G === L.l_G, "must be from same global state"); - L.stack[L.top++] = new TValue(type, value); + L.stack[L.top] = new TValue(type, value); + L.top++; + assert(L.top <= L.ci.top, "stack overflow"); }; seen.set(proxy, G); return proxy; @@ -802,7 +806,8 @@ const lua_compare = function(L, index1, index2, op) { const lua_stringtonumber = function(L, s) { let tv = lobject.luaO_str2num(s); if (tv) { - L.stack[L.top++] = tv; + L.stack[L.top] = tv; + L.top++; assert(L.top <= L.ci.top, "stack overflow"); return s.length+1; } @@ -893,11 +898,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"); - L.stack[L.top++] = L.stack[L.top - 1]; + 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.top - 2); - L.top--; /* remove second operand */ + lobject.luaO_arith(L, op, L.stack[L.top - 2], L.stack[L.top - 1], L.stack[L.top - 2]); + delete L.stack[--L.top]; /* remove second operand */ }; /* @@ -1030,13 +1036,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; } }; @@ -1046,14 +1054,17 @@ const lua_concat = function(L, n) { if (n >= 2) lvm.luaV_concat(L, n); else if (n === 0) { - L.stack[L.top++] = new TValue(CT.LUA_TLNGSTR, lstring.luaS_newliteral(L, "")); + 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); + let tv = new TValue(); + lvm.luaV_objlen(L, tv, t); + L.stack[L.top] = tv; + L.top++; assert(L.top <= L.ci.top, "stack overflow"); }; diff --git a/src/lauxlib.js b/src/lauxlib.js index b14379c..0672c14 100644 --- a/src/lauxlib.js +++ b/src/lauxlib.js @@ -654,6 +654,7 @@ if (!WEB) { this.f = null; /* file being read */ this.buff = new Buffer(1024); /* area for reading file */ this.pos = 0; /* current position in file */ + this.err = void 0; } } @@ -665,7 +666,12 @@ if (!WEB) { lf.n = 0; /* no more pre-read characters */ } else { /* read a block from file */ lf.buff.fill(0); - bytes = fs.readSync(lf.f, lf.buff, 0, lf.buff.length, lf.pos); /* read block */ + try { + bytes = fs.readSync(lf.f, lf.buff, 0, lf.buff.length, lf.pos); /* read block */ + } catch(e) { + lf.err = e; + bytes = 0; + } lf.pos += bytes; } if (bytes > 0) @@ -743,25 +749,24 @@ if (!WEB) { return errfile(L, "open", fnameindex, e); } } - - try { - let com = skipcomment(lf); - /* check for signature first, as we don't want to add line number corrections in binary case */ - if (com.c === lua.LUA_SIGNATURE.charCodeAt(0) && filename) { /* binary file? */ - /* no need to re-open in node.js */ - } else if (com.skipped) { /* read initial portion */ - lf.buff[lf.n++] = '\n'.charCodeAt(0); /* add line to correct line numbers */ - } - if (com.c !== null) - lf.buff[lf.n++] = com.c; /* 'c' is the first character of the stream */ - let status = lua.lua_load(L, getF, lf, lua.lua_tostring(L, -1), mode); - if (filename) fs.closeSync(lf.f); /* close file (even in case of errors) */ - lua.lua_remove(L, fnameindex); - return status; - } catch (err) { + let com = skipcomment(lf); + /* check for signature first, as we don't want to add line number corrections in binary case */ + if (com.c === lua.LUA_SIGNATURE.charCodeAt(0) && filename) { /* binary file? */ + /* no need to re-open in node.js */ + } else if (com.skipped) { /* read initial portion */ + lf.buff[lf.n++] = '\n'.charCodeAt(0); /* add line to correct line numbers */ + } + if (com.c !== null) + lf.buff[lf.n++] = com.c; /* 'c' is the first character of the stream */ + let status = lua.lua_load(L, getF, lf, lua.lua_tostring(L, -1), mode); + let readstatus = lf.err; + if (filename) try { fs.closeSync(lf.f); } catch(e) {} /* close file (even in case of errors) */ + if (readstatus) { lua.lua_settop(L, fnameindex); /* ignore results from 'lua_load' */ - return errfile(L, "read", fnameindex, err); + return errfile(L, "read", fnameindex, readstatus); } + lua.lua_remove(L, fnameindex); + return status; }; const luaL_loadfile = function(L, filename) { diff --git a/src/ldebug.js b/src/ldebug.js index 0f387af..3636a06 100644 --- a/src/ldebug.js +++ b/src/ldebug.js @@ -140,7 +140,8 @@ const lua_getlocal = function(L, ar, n) { let local = findlocal(L, ar.i_ci, n); if (local) { name = local.name; - L.stack[L.top++] = L.stack[local.pos]; + lobject.pushobj2s(L, L.stack[local.pos]); + assert(L.top <= L.ci.top, "stack overflow"); } else { name = null; } @@ -155,7 +156,7 @@ const lua_setlocal = function(L, ar, n) { let name = local.name; let pos = local.pos; if (name) { - L.stack[pos] = L.stack[L.top - 1]; + lobject.setobjs2s(L, pos, L.top - 1); delete L.stack[--L.top]; /* pop value */ } swapextra(L); @@ -181,12 +182,14 @@ const funcinfo = function(ar, cl) { const collectvalidlines = function(L, f) { if (f === null || f instanceof lobject.CClosure) { - L.stack[L.top++] = new lobject.TValue(CT.LUA_TNIL, null); + L.stack[L.top] = new lobject.TValue(CT.LUA_TNIL, null); + L.top++; assert(L.top <= L.ci.top, "stack overflow"); } else { let lineinfo = f.l.p.lineinfo; let t = ltable.luaH_new(L); - L.stack[L.top++] = new lobject.TValue(CT.LUA_TTABLE, t); + L.stack[L.top] = new lobject.TValue(CT.LUA_TTABLE, t); + L.top++; assert(L.top <= L.ci.top, "stack overflow"); let v = new lobject.TValue(CT.LUA_TBOOLEAN, true); for (let i = 0; i < f.l.p.length; i++) @@ -261,26 +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) { - L.stack[L.top++] = func; + lobject.pushobj2s(L, func); assert(L.top <= L.ci.top, "stack overflow"); } @@ -590,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; - L.stack[L.top] = L.stack[L.top - 1]; - L.stack[L.top - 1] = L.stack[errfunc]; - 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); } @@ -638,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); } }; @@ -22,21 +22,28 @@ const CT = defs.constant_types; const TS = defs.thread_status; const seterrorobj = function(L, errcode, oldtop) { + let current_top = L.top; + + /* extend stack so that L.stack[oldtop] is sure to exist */ + while (L.top < oldtop + 1) + L.stack[L.top++] = new lobject.TValue(CT.LUA_TNIL, null); + switch (errcode) { case TS.LUA_ERRMEM: { - L.stack[oldtop] = new lobject.TValue(CT.LUA_TLNGSTR, lstring.luaS_newliteral(L, "not enough memory")); + lobject.setsvalue2s(L, oldtop, lstring.luaS_newliteral(L, "not enough memory")); break; } case TS.LUA_ERRERR: { - L.stack[oldtop] = new lobject.TValue(CT.LUA_TLNGSTR, lstring.luaS_newliteral(L, "error in error handling")); + lobject.setsvalue2s(L, oldtop, lstring.luaS_newliteral(L, "error in error handling")); break; } default: { - L.stack[oldtop] = L.stack[L.top - 1]; + lobject.setobjs2s(L, oldtop, current_top - 1); } } - L.top = oldtop + 1; + while (L.top > oldtop + 1) + delete L.stack[--L.top]; }; const ERRORSTACKSIZE = luaconf.LUAI_MAXSTACK + 200; @@ -94,8 +101,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 +158,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 +173,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 +200,42 @@ const moveresults = function(L, firstResult, res, nres, wanted) { break; case 1: { if (nres === 0) - L.stack[firstResult] = lobject.luaO_nilobject; - L.stack[res] = L.stack[firstResult]; + 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++) - L.stack[res + i] = L.stack[firstResult + 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++) { - L.stack[res + i] = L.stack[firstResult + i]; - } + for (i = 0; i < wanted; i++) + lobject.setobjs2s(L, res + i, firstResult + i); } else { for (i = 0; i < nres; i++) - L.stack[res + i] = L.stack[firstResult + i]; - for (; i < wanted; i++) - L.stack[res + i] = new lobject.TValue(CT.LUA_TNIL, null); + lobject.setobjs2s(L, res + i, firstResult + i); + 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 +263,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 +282,8 @@ const adjust_varargs = function(L, p, actual) { let i; for (i = 0; i < nfixargs && i < actual; i++) { - L.stack[L.top++] = L.stack[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,10 +297,10 @@ 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--) - L.stack[p] = L.stack[p-1]; - L.top++; /* slot ensured by caller */ - L.stack[off] = new lobject.TValue(tm.type, tm.value); /* tag method is the new function to be called */ + 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 */ }; /* @@ -351,8 +381,8 @@ const luaD_rawrunprotected = function(L, f, ud) { /* copy of luaG_errormsg without the throw */ if (L.errfunc !== 0) { /* is there an error handling function? */ let errfunc = L.errfunc; - L.stack[L.top] = L.stack[L.top - 1]; - L.stack[L.top - 1] = L.stack[errfunc]; + lobject.setobjs2s(L, L.top, L.top - 1); /* move argument */ + lobject.setobjs2s(L, L.top - 1, errfunc); /* push function */ L.top++; luaD_callnoyield(L, L.top - 2, 1); } @@ -464,9 +494,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 */ - L.stack[L.top++] = new lobject.TValue(CT.LUA_TLNGSTR, lstring.luaS_newliteral(L, msg)); /* push error message */ - 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; }; @@ -657,8 +694,6 @@ const luaD_protectedparser = function(L, z, name, mode) { return status; }; -module.exports.SParser = SParser; -module.exports.adjust_varargs = adjust_varargs; module.exports.luaD_call = luaD_call; module.exports.luaD_callnoyield = luaD_callnoyield; module.exports.luaD_checkstack = luaD_checkstack; @@ -676,6 +711,3 @@ module.exports.lua_isyieldable = lua_isyieldable; module.exports.lua_resume = lua_resume; module.exports.lua_yield = lua_yield; module.exports.lua_yieldk = lua_yieldk; -module.exports.moveresults = moveresults; -module.exports.stackerror = stackerror; -module.exports.tryfuncTM = tryfuncTM; diff --git a/src/lobject.js b/src/lobject.js index d08849c..7f81438 100644 --- a/src/lobject.js +++ b/src/lobject.js @@ -126,11 +126,21 @@ class TValue { this.value = x; } + chgfltvalue(x) { + assert(this.type == CT.LUA_TNUMFLT); + this.value = x; + } + setivalue(x) { this.type = CT.LUA_TNUMINT; this.value = x; } + chgivalue(x) { + assert(this.type == CT.LUA_TNUMINT); + this.value = x; + } + setnilvalue() { this.type = CT.LUA_TNIL; this.value = void 0; @@ -151,6 +161,31 @@ class TValue { this.value = x; } + setsvalue(x) { + this.type = CT.LUA_TLNGSTR; /* LUA_TSHRSTR? */ + this.value = x; + } + + setuvalue(x) { + this.type = CT.LUA_TUSERDATA; + this.value = x; + } + + setthvalue(x) { + this.type = CT.LUA_TTHREAD; + this.value = x; + } + + setclLvalue(x) { + this.type = CT.LUA_TLCL; + this.value = x; + } + + setclCvalue(x) { + this.type = CT.LUA_TCCL; + this.value = x; + } + sethvalue(x) { this.type = CT.LUA_TTABLE; this.value = x; @@ -185,6 +220,24 @@ 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].setfrom(L.stack[oldidx]); +}; +/* to stack (not from same stack) */ +const setobj2s = function(L, newidx, oldtv) { + L.stack[newidx].setfrom(oldtv); +}; +const setsvalue2s = function(L, newidx, ts) { + L.stack[newidx].setsvalue(ts); +}; + const luaO_nilobject = new TValue(CT.LUA_TNIL, null); Object.freeze(luaO_nilobject); module.exports.luaO_nilobject = luaO_nilobject; @@ -477,12 +530,12 @@ const luaO_tostring = function(L, obj) { buff.push(char['0']); /* adds '.0' to result */ } } - return new TValue(CT.LUA_TLNGSTR, lstring.luaS_bless(L, buff)); + return lstring.luaS_bless(L, buff); }; const pushstr = function(L, str) { ldo.luaD_inctop(L); - L.stack[L.top-1] = new TValue(CT.LUA_TLNGSTR, lstring.luaS_new(L, str)); + setsvalue2s(L, L.top-1, lstring.luaS_new(L, str)); }; const luaO_pushvfstring = function(L, fmt, argp) { @@ -510,11 +563,11 @@ const luaO_pushvfstring = function(L, fmt, argp) { case char['d']: case char['I']: ldo.luaD_inctop(L); - L.stack[L.top-1] = luaO_tostring(L, new TValue(CT.LUA_TNUMINT, argp[a++])); + setsvalue2s(L, L.top-1, luaO_tostring(L, new TValue(CT.LUA_TNUMINT, argp[a++]))); break; case char['f']: ldo.luaD_inctop(L); - L.stack[L.top-1] = luaO_tostring(L, new TValue(CT.LUA_TNUMFLT, argp[a++])); + setsvalue2s(L, L.top-1, luaO_tostring(L, new TValue(CT.LUA_TNUMFLT, argp[a++]))); break; case char['p']: let v = argp[a++]; @@ -614,8 +667,7 @@ const luaO_arith = function(L, op, p1, p2, p3) { 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 */ @@ -623,8 +675,7 @@ const luaO_arith = function(L, op, p1, p2, p3) { 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 */ @@ -632,13 +683,11 @@ const luaO_arith = function(L, op, p1, p2, p3) { 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 */ @@ -669,3 +718,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 13f75c9..0079141 100644 --- a/src/lparser.js +++ b/src/lparser.js @@ -1565,10 +1565,10 @@ const luaY_parser = function(L, z, buff, dyd, name, firstchar) { let funcstate = new FuncState(); let cl = lfunc.luaF_newLclosure(L, 1); /* create main closure */ ldo.luaD_inctop(L); - L.stack[L.top-1] = new TValue(defs.CT.LUA_TLCL, cl); + 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 2413574..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; @@ -147,7 +147,8 @@ const f_luaopen = function(L) { const lua_newthread = function(L) { let g = L.l_G; let L1 = new lua_State(g); - L.stack[L.top++] = new lobject.TValue(CT.LUA_TTHREAD, L1); + L.stack[L.top] = new lobject.TValue(CT.LUA_TTHREAD, L1); + L.top++; assert(L.top <= L.ci.top, "stack overflow"); L1.hookmask = L.hookmask; L1.basehookcount = L.basehookcount; diff --git a/src/ltable.js b/src/ltable.js index 5a31b48..53a5d79 100644 --- a/src/ltable.js +++ b/src/ltable.js @@ -261,8 +261,8 @@ const luaH_next = function(L, table, keyI) { } while (entry.key.ttisdeadkey()); } } - L.stack[keyI] = new lobject.TValue(entry.key.type, entry.key.value); - L.stack[keyI+1] = new lobject.TValue(entry.value.type, entry.value.value); + lobject.setobj2s(L, keyI, entry.key); + lobject.setobj2s(L, keyI+1, entry.value); return true; }; @@ -108,25 +108,24 @@ const luaT_objtypename = function(L, o) { }; const luaT_callTM = function(L, f, p1, p2, p3, hasres) { - let result = p3; let func = L.top; - L.stack[L.top] = new lobject.TValue(f.type, f.value); /* push function (assume EXTRA_STACK) */ - L.stack[L.top + 1] = new lobject.TValue(p1.type, p1.value); /* 1st argument */ - L.stack[L.top + 2] = new lobject.TValue(p2.type, p2.value); /* 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 */ - L.stack[L.top++] = new lobject.TValue(p3.type, p3.value); /* 3rd argument */ + lobject.pushobj2s(L, p3); /* 3rd argument */ if (L.ci.callstatus & lstate.CIST_LUA) ldo.luaD_call(L, func, hasres); else ldo.luaD_callnoyield(L, func, hasres); - if (hasres) { - assert(typeof result === "number"); - L.stack[result] = L.stack[--L.top]; + if (hasres) { /* if has result, move it to its place */ + let tv = L.stack[L.top-1]; + delete L.stack[--L.top]; + p3.setfrom(tv); } }; @@ -160,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)) - return -1; + let res = new lobject.TValue(); + if (!luaT_callbinTM(L, p1, p2, res, event)) + return null; else - return !L.stack[L.top].l_isfalse() ? 1 : 0; + return !res.l_isfalse(); }; const fasttm = function(l, et, e) { diff --git a/src/lundump.js b/src/lundump.js index 4931fe8..3f61cb6 100644 --- a/src/lundump.js +++ b/src/lundump.js @@ -266,7 +266,7 @@ const luaU_undump = function(L, Z, name) { S.checkHeader(); let cl = lfunc.luaF_newLclosure(L, S.readByte()); ldo.luaD_inctop(L); - L.stack[L.top-1] = new lobject.TValue(defs.CT.LUA_TLCL, cl); + 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: { - L.stack[base + inst.A] = L.stack[--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 */ @@ -54,25 +55,46 @@ const luaV_finishOp = function(L) { let top = L.top - 1; /* top when 'luaT_trybinTM' was called */ let b = inst.B; /* first element to concatenate */ let total = top - 1 - (base + b); /* yet to concatenate */ - L.stack[top - 2] = L.stack[top]; /* put TM result in proper position */ + lobject.setobjs2s(L, top - 2, top); /* put TM result in proper position */ if (total > 1) { /* are there elements to concat? */ L.top = top - 1; /* top is one after last element (at top-2) */ luaV_concat(L, total); /* concat them (may yield again) */ } - /* move final result to final position */ - L.stack[ci.l_base + inst.A] = L.stack[L.top - 1]; - L.top = ci.top; /* restore top */ + lobject.setobjs2s(L, ci.l_base + inst.A, L.top - 1); + /* 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; } } @@ -121,22 +143,22 @@ const luaV_execute = function(L) { switch (opcode) { case OCi.OP_MOVE: { - L.stack[ra] = L.stack[RB(L, base, i)]; + lobject.setobjs2s(L, ra, RB(L, base, i)); break; } case OCi.OP_LOADK: { let konst = k[i.Bx]; - L.stack[ra] = new lobject.TValue(konst.type, konst.value); + lobject.setobj2s(L, ra, konst); break; } case OCi.OP_LOADKX: { assert(ci.l_code[ci.l_savedpc].opcode === OCi.OP_EXTRAARG); let konst = k[ci.l_code[ci.l_savedpc++].Ax]; - L.stack[ra] = new lobject.TValue(konst.type, konst.value); + lobject.setobj2s(L, ra, konst); 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) */ @@ -145,18 +167,18 @@ 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: { let o = cl.upvals[i.B].val(); - L.stack[ra] = new lobject.TValue(o.type, o.value); + lobject.setobj2s(L, ra, o); break; } 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]); } @@ -193,16 +215,15 @@ 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: { - let table = L.stack[RB(L, base, i)]; - let key = RKC(L, base, k, i); - - L.stack[ra + 1] = table; + let rb = RB(L, base, i); + let rc = RKC(L, base, k, i); + lobject.setobjs2s(L, ra + 1, rb); - gettable(L, table, key, ra); + gettable(L, L.stack[rb], rc, ra); break; } case OCi.OP_ADD: { @@ -212,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; } @@ -227,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; } @@ -242,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; } @@ -257,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; } @@ -272,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; } @@ -285,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; } @@ -298,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; } @@ -313,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; } @@ -326,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; } @@ -339,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; } @@ -352,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; } @@ -365,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; } @@ -376,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; } @@ -388,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: { @@ -409,8 +430,15 @@ const luaV_execute = function(L) { L.top = base + c + 1; /* mark the end of concat operands */ luaV_concat(L, c - b + 1); let rb = base + b; - L.stack[ra] = L.stack[rb]; - L.top = ci.top; /* restore top */ + lobject.setobjs2s(L, ra, rb); + /* 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: { @@ -446,11 +474,12 @@ const luaV_execute = function(L) { break; } case OCi.OP_TESTSET: { - let rb = L.stack[RB(L, base, i)]; + let rbIdx = RB(L, base, i); + let rb = L.stack[rbIdx]; if (i.C ? rb.l_isfalse() : !rb.l_isfalse()) ci.l_savedpc++; else { - L.stack[ra] = rb; + lobject.setobjs2s(L, ra, rbIdx); donextjump(L, ci); } break; @@ -459,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; @@ -473,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,10 +537,16 @@ const luaV_execute = function(L) { let lim = nci.l_base + nfunc.value.p.numparams; if (cl.p.p.length > 0) lfunc.luaF_close(L, oci.l_base); for (let aux = 0; nfuncOff + aux < lim; aux++) - L.stack[ofuncOff + aux] = L.stack[nfuncOff + aux]; - oci.func = nci.func; + lobject.setobjs2s(L, ofuncOff + aux, nfuncOff + aux); 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; @@ -507,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,8 +588,8 @@ const luaV_execute = function(L) { if (0 < step ? idx <= limit : limit <= idx) { ci.l_savedpc += i.sBx; - L.stack[ra].value = idx; - L.stack[ra + 3] = new lobject.TValue(CT.LUA_TNUMINT, idx); + L.stack[ra].chgivalue(idx); /* update internal index... */ + L.stack[ra + 3].setivalue(idx); } } else { /* floating loop */ let step = L.stack[ra + 2].value; @@ -531,8 +598,8 @@ const luaV_execute = function(L) { if (0 < step ? idx <= limit : limit <= idx) { ci.l_savedpc += i.sBx; - L.stack[ra].value = idx; - L.stack[ra + 3] = new lobject.TValue(CT.LUA_TNUMFLT, idx); + L.stack[ra].chgfltvalue(idx); /* update internal index... */ + L.stack[ra + 3].setfltvalue(idx); } } break; @@ -551,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; @@ -565,21 +632,34 @@ const luaV_execute = function(L) { } case OCi.OP_TFORCALL: { let cb = ra + 3; /* call base */ - L.stack[cb + 2] = L.stack[ra + 2]; - L.stack[cb + 1] = L.stack[ra + 1]; - L.stack[cb] = L.stack[ra]; - L.top = cb + 3; /* func. + 2 args (state and index) */ + lobject.setobjs2s(L, cb+2, ra+2); + lobject.setobjs2s(L, cb+1, ra+1); + lobject.setobjs2s(L, cb, ra); + /* 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? */ - L.stack[ra] = L.stack[ra + 1]; /* save control variable */ + lobject.setobjs2s(L, ra, ra + 1); /* save control variable */ ci.l_savedpc += i.sBx; /* jump back */ } break; @@ -602,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: { @@ -621,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++) - L.stack[ra + j] = L.stack[base - 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: { @@ -656,31 +752,29 @@ const luaV_lessthan = function(L, l, r) { return l_strcmp(l.tsvalue(), r.tsvalue()) < 0 ? 1 : 0; else { let res = ltm.luaT_callorderTM(L, l, r, ltm.TMS.TM_LT); - if (res < 0) + if (res === null) ldebug.luaG_ordererror(L, l, r); return res ? 1 : 0; } }; const luaV_lessequal = function(L, l, r) { - let res; - if (l.ttisnumber() && r.ttisnumber()) return LEnum(l, r) ? 1 : 0; else if (l.ttisstring() && r.ttisstring()) return l_strcmp(l.tsvalue(), r.tsvalue()) <= 0 ? 1 : 0; else { - res = ltm.luaT_callorderTM(L, l, r, ltm.TMS.TM_LE); - if (res >= 0) + let res = ltm.luaT_callorderTM(L, l, r, ltm.TMS.TM_LE); + if (res !== null) return res ? 1 : 0; } /* try 'lt': */ L.ci.callstatus |= lstate.CIST_LEQ; /* mark it is doing 'lt' for 'le' */ - res = ltm.luaT_callorderTM(L, r, l, ltm.TMS.TM_LT); + let res = ltm.luaT_callorderTM(L, r, l, ltm.TMS.TM_LT); L.ci.callstatus ^= lstate.CIST_LEQ; /* clear mark */ - if (res < 0) + if (res === null) ldebug.luaG_ordererror(L, l, r); - return res !== 1 ? 1 : 0; /* result is negated */ + return res ? 0 : 1; /* result is negated */ }; const luaV_equalobj = function(L, t1, t2) { @@ -726,8 +820,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) { @@ -891,12 +986,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); @@ -944,7 +1039,7 @@ const pushclosure = function(L, p, encup, base, ra) { let uv = p.upvalues; let ncl = new lobject.LClosure(L, nup); ncl.p = p; - L.stack[ra] = new lobject.TValue(CT.LUA_TLCL, ncl); + L.stack[ra].setclLvalue(ncl); for (let i = 0; i < nup; i++) { if (uv[i].instack) ncl.upvals[i] = lfunc.luaF_findupval(L, base + uv[i].idx); @@ -968,7 +1063,7 @@ const tostring = function(L, i) { if (o.ttisstring()) return true; if (cvt2str(o)) { - L.stack[i] = lobject.luaO_tostring(L, o); + lobject.setsvalue2s(L, i, lobject.luaO_tostring(L, o)); return true; } @@ -990,32 +1085,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])) { - L.stack[top - 2] = L.stack[top - 1]; - delete L.stack[top - 1]; + lobject.setobjs2s(L, top - 2, 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)); - L.stack[top - n] = new lobject.TValue(CT.LUA_TLNGSTR, ts); + 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 */ }; @@ -1033,19 +1125,19 @@ const gettable = function(L, t, key, ra) { } else { let slot = ltable.luaH_get(L, t.value, key); if (!slot.ttisnil()) { - L.stack[ra] = new lobject.TValue(slot.type, slot.value); + lobject.setobj2s(L, ra, slot); return; } 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]' */ |