diff options
Diffstat (limited to 'src')
| -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]' */  | 
