summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordaurnimator <quae@daurnimator.com>2017-05-02 16:37:50 +1000
committerdaurnimator <quae@daurnimator.com>2017-05-03 12:20:43 +1000
commitcb0295e52870f22c5dd1a1726342b8d4b147b1c5 (patch)
tree3655d4d6f4873ed246c00c0eb6680a06124f3046 /src
parent50820e54d065bffbb504e6b20b6c27802e102c25 (diff)
downloadfengari-cb0295e52870f22c5dd1a1726342b8d4b147b1c5.tar.gz
fengari-cb0295e52870f22c5dd1a1726342b8d4b147b1c5.tar.bz2
fengari-cb0295e52870f22c5dd1a1726342b8d4b147b1c5.zip
Refactor table implementation
Diffstat (limited to 'src')
-rw-r--r--src/lapi.js91
-rw-r--r--src/lcode.js5
-rw-r--r--src/ldebug.js6
-rw-r--r--src/lobject.js39
-rw-r--r--src/lstate.js8
-rw-r--r--src/ltable.js191
-rw-r--r--src/ltablib.js56
-rw-r--r--src/ltm.js9
-rw-r--r--src/lvm.js16
9 files changed, 235 insertions, 186 deletions
diff --git a/src/lapi.js b/src/lapi.js
index a336220..4de27c2 100644
--- a/src/lapi.js
+++ b/src/lapi.js
@@ -329,18 +329,14 @@ const auxsetstr = function(L, t, k) {
assert(1 < L.top - L.ci.funcOff, "not enough elements in the stack");
- if (t.ttistable() && !lobject.table_index(t, k).ttisnil()) {
- lobject.table_newindex(t, k, L.stack[L.top - 1]);
- L.top--; /* pop value */
- } else {
- L.stack[L.top++] = str;
- lvm.settable(L, t, L.stack[L.top - 1], L.stack[L.top - 2]);
- L.top -= 2; /* pop value and key */
- }
+ L.stack[L.top++] = str;
+ lvm.settable(L, t, L.stack[L.top - 1], L.stack[L.top - 2]);
+ /* pop value and key */
+ L.top -= 2;
};
const lua_setglobal = function(L, name) {
- auxsetstr(L, L.l_G.l_registry.value.get(defs.LUA_RIDX_GLOBALS), name);
+ auxsetstr(L, ltable.luaH_getint(L.l_G.l_registry.value, defs.LUA_RIDX_GLOBALS), name);
};
const lua_setmetatable = function(L, objindex) {
@@ -351,13 +347,13 @@ const lua_setmetatable = function(L, objindex) {
mt = null;
else {
assert(L.stack[L.top - 1].ttistable(), "table expected");
- mt = L.stack[L.top - 1];
+ mt = L.stack[L.top - 1].value;
}
switch (obj.ttnov()) {
case CT.LUA_TUSERDATA:
case CT.LUA_TTABLE: {
- obj.metatable = mt;
+ obj.value.metatable = mt;
break;
}
default: {
@@ -366,7 +362,7 @@ const lua_setmetatable = function(L, objindex) {
}
}
- L.top--;
+ L.stack[--L.top] = void 0;
return true;
};
@@ -383,17 +379,23 @@ const lua_setfield = function(L, idx, k) {
};
const lua_seti = function(L, idx, n) {
+ assert(typeof n === "number");
assert(1 < L.top - L.ci.funcOff, "not enough elements in the stack");
let t = index2addr(L, idx);
- lvm.settable(L, t, n, L.stack[L.top - 1]);
- L.top--; /* pop value */
+ L.stack[L.top++] = new TValue(CT.LUA_TNUMINT, n);
+ 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 */
+ L.stack[--L.top] = void 0;
+ L.stack[--L.top] = void 0;
};
const lua_rawset = function(L, idx) {
assert(2 < L.top - L.ci.funcOff, "not enough elements in the stack");
let o = index2addr(L, idx);
assert(o.ttistable(), "table expected");
- lobject.table_newindex(o, L.stack[L.top - 2], L.stack[L.top - 1]);
+ let slot = ltable.luaH_set(o.value, L.stack[L.top - 2]);
+ slot.setfrom(L.stack[L.top - 1]);
L.top -= 2;
};
@@ -401,8 +403,9 @@ const lua_rawsetp = function(L, idx, p) {
assert(1 < L.top - L.ci.funcOff, "not enough elements in the stack");
let o = index2addr(L, idx);
assert(L, o.ttistable(), "table expected");
- let k = p;
- lobject.table_newindex(o, k, L.stack[L.top - 1]);
+ let k = new TValue(CT.LUA_TLIGHTUSERDATA, p);
+ let slot = ltable.luaH_set(o.value, k);
+ slot.setfrom(L.stack[L.top - 1]);
L.top--;
};
@@ -414,15 +417,10 @@ const auxgetstr = function(L, t, k) {
assert(Array.isArray(k), "key must be an array of bytes");
let str = L.l_G.intern(k);
- let slot = lobject.table_index(t, k);
- if (t.ttistable() && !slot.ttisnil()) {
- L.stack[L.top++] = slot;
- assert(L.top <= L.ci.top, "stack overflow");
- } else {
- L.stack[L.top++] = str;
- assert(L.top <= L.ci.top, "stack overflow");
- lvm.gettable(L, t, L.stack[L.top - 1], L.top - 1);
- }
+
+ L.stack[L.top++] = 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();
};
@@ -432,8 +430,7 @@ const lua_rawgeti = function(L, idx, n) {
assert(t.ttistable(), "table expected");
- L.stack[L.top++] = lobject.table_index(t, n);
-
+ L.stack[L.top++] = ltable.luaH_getint(t.value, n);
assert(L.top <= L.ci.top, "stack overflow");
return L.stack[L.top - 1].ttnov();
@@ -442,8 +439,8 @@ const lua_rawgeti = function(L, idx, n) {
const lua_rawgetp = function(L, idx, p) {
let t = index2addr(L, idx);
assert(t.ttistable(), "table expected");
- let k = p;
- L.stack[L.top++] = lobject.table_index(t, k);
+ let k = new TValue(CT.LUA_TLIGHTUSERDATA, p);
+ L.stack[L.top++] = ltable.luaH_get(t.value, k);
assert(L.top <= L.ci.top, "stack overflow");
return L.stack[L.top - 1].ttnov();
};
@@ -453,7 +450,7 @@ const lua_rawget = function(L, idx) {
assert(t.ttistable(t), "table expected");
- L.stack[L.top - 1] = lobject.table_index(t, L.stack[L.top - 1]);
+ L.stack[L.top - 1] = ltable.luaH_get(t.value, L.stack[L.top - 1]);
return L.stack[L.top - 1].ttnov();
};
@@ -550,7 +547,7 @@ const lua_getmetatable = function(L, objindex) {
switch (obj.ttnov()) {
case CT.LUA_TTABLE:
case CT.LUA_TUSERDATA:
- mt = obj.metatable;
+ mt = obj.value.metatable;
break;
default:
mt = L.l_G.mt[obj.ttnov];
@@ -558,7 +555,7 @@ const lua_getmetatable = function(L, objindex) {
}
if (mt !== null && mt !== undefined) {
- L.stack[L.top++] = mt;
+ L.stack[L.top++] = new TValue(CT.LUA_TTABLE, mt);
assert(L.top <= L.ci.top, "stack overflow");
res = true;
}
@@ -587,20 +584,14 @@ const lua_getfield = function(L, idx, k) {
const lua_geti = function(L, idx, n) {
let t = index2addr(L, idx);
- let slot = lobject.table_index(t, n);
- if (!slot.ttisnil()) {
- L.stack[L.top++] = slot;
- assert(L.top <= L.ci.top, "stack overflow");
- } else {
- L.stack[L.top++] = new TValue(CT.LUA_TNUMINT, n);
- assert(L.top <= L.ci.top, "stack overflow");
- lvm.gettable(L, t, L.stack[L.top - 1], L.top - 1);
- }
+ L.stack[L.top++] = new TValue(CT.LUA_TNUMINT, n);
+ 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_getglobal = function(L, name) {
- return auxgetstr(L, L.l_G.l_registry.value.get(defs.LUA_RIDX_GLOBALS), name);
+ return auxgetstr(L, ltable.luaH_getint(L.l_G.l_registry.value, defs.LUA_RIDX_GLOBALS), name);
};
/*
@@ -656,7 +647,7 @@ const lua_rawlen = function(L, idx) {
case CT.LUA_TUSERDATA:
return o.len;
case CT.LUA_TTABLE:
- return ltable.luaH_getn(o);
+ return ltable.luaH_getn(o.value);
default:
return 0;
}
@@ -819,8 +810,7 @@ const lua_load = function(L, reader, data, chunckname, mode) {
let f = L.stack[L.top - 1].value; /* get newly created function */
if (f.nupvalues >= 1) { /* does it have an upvalue? */
/* get global table from registry */
- let reg = L.l_G.l_registry;
- let gt = reg.value.get(defs.LUA_RIDX_GLOBALS);
+ let gt = ltable.luaH_getint(L.l_G.l_registry.value, defs.LUA_RIDX_GLOBALS);
/* set global table as 1st upvalue of 'f' (may be LUA_ENV) */
f.upvals[0].u.value = new TValue(gt.type, gt.value);
}
@@ -936,14 +926,15 @@ const lua_error = function(L) {
const lua_next = function(L, idx) {
let t = index2addr(L, idx);
assert(t.ttistable(), "table expected");
- let more = ltable.luaH_next(L, t, L.top - 1);
+ let more = ltable.luaH_next(L, t.value, L.top - 1);
if (more) {
L.top++;
assert(L.top <= L.ci.top, "stack overflow");
- } else
+ return 1;
+ } else {
L.top--;
-
- return more;
+ return 0;
+ }
};
const lua_concat = function(L, n) {
diff --git a/src/lcode.js b/src/lcode.js
index 9fb7b06..690d07c 100644
--- a/src/lcode.js
+++ b/src/lcode.js
@@ -7,6 +7,7 @@ const llex = require('./llex.js');
const lobject = require('./lobject.js');
const lopcode = require('./lopcodes.js');
const lparser = require('./lparser.js');
+const ltable = require('./ltable.js');
require('./lstate.js'); /* XXX: if this isn't here then things break on require("ltm") */
const ltm = require('./ltm.js');
const lvm = require('./lvm.js');
@@ -482,7 +483,7 @@ const freeexps = function(fs, e1, e2) {
*/
const addk = function(fs, key, v) {
let f = fs.f;
- let idx = lobject.table_index(fs.ls.h, key); /* index scanner table */
+ let idx = ltable.luaH_set(fs.ls.h.value, key); /* index scanner table */
if (idx && !idx.ttisnil()) { /* is there an index there? */
/* correct value? (warning: must distinguish floats from integers!) */
if (idx.value < fs.nk && f.k[idx.value].ttype() === v.ttype() && f.k[idx.value].value === v.value)
@@ -490,7 +491,7 @@ const addk = function(fs, key, v) {
}
/* constant not found; create a new entry */
let k = fs.nk;
- lobject.table_newindex(fs.ls.h, key, new TValue(CT.LUA_TNUMINT, k));
+ idx.setivalue(k);
f.k[k] = v;
fs.nk++;
return k;
diff --git a/src/ldebug.js b/src/ldebug.js
index d429457..d565829 100644
--- a/src/ldebug.js
+++ b/src/ldebug.js
@@ -180,12 +180,12 @@ const collectvalidlines = function(L, f) {
assert(L.top <= L.ci.top, "stack overflow");
} else {
let lineinfo = f.l.p.lineinfo;
- let t = new TValue(CT.LUA_TTABLE, ltable.luaH_new(L));
- L.stack[L.top++] = t;
+ let t = ltable.luaH_new(L);
+ L.stack[L.top++] = new TValue(CT.LUA_TTABLE, t);
assert(L.top <= L.ci.top, "stack overflow");
let v = new TValue(CT.LUA_TBOOLEAN, true);
for (let i = 0; i < f.l.p.length; i++)
- lobject.table_newindex(t, lineinfo[i], v);
+ ltable.luaH_setint(t, lineinfo[i], v);
}
};
diff --git a/src/lobject.js b/src/lobject.js
index 784720b..d38e276 100644
--- a/src/lobject.js
+++ b/src/lobject.js
@@ -18,7 +18,6 @@ class TValue {
this.id = tvalueCount++;
this.type = type;
this.value = value;
- this.metatable = null;
}
/* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */
@@ -164,41 +163,6 @@ class TValue {
const luaO_nilobject = new TValue(CT.LUA_TNIL, null);
module.exports.luaO_nilobject = luaO_nilobject;
-const table_keyValue = function(key) {
- // Those lua values are used by value, others by reference
- if (key instanceof TValue) {
- if ([CT.LUA_TNIL,
- CT.LUA_TBOOLEAN,
- CT.LUA_TSTRING,
- CT.LUA_TTHREAD,
- CT.LUA_TNUMINT].indexOf(key.type) > -1) {
- key = key.value;
- } else if ([CT.LUA_TSHRSTR, CT.LUA_TLNGSTR].indexOf(key.type) > -1) {
- key = key.value.map(e => `${e}|`).join('');
- }
- } else if (typeof key === "string") { // To avoid
- key = defs.to_luastring(key).map(e => `${e}|`).join('');
- } else if (Array.isArray(key)) {
- key = key.map(e => `${e}|`).join('');
- }
-
- return key;
-};
-
-const table_newindex = function(table, key, value) {
- key = table_keyValue(key);
-
- table.value.set(key, value);
-};
-
-const table_index = function(table, key) {
- key = table_keyValue(key);
-
- let v = table.value.get(key);
-
- return v ? v : luaO_nilobject;
-};
-
class LClosure {
constructor(L, n) {
@@ -512,6 +476,3 @@ module.exports.luaO_str2num = luaO_str2num;
module.exports.luaO_utf8desc = luaO_utf8desc;
module.exports.luaO_utf8esc = luaO_utf8esc;
module.exports.numarith = numarith;
-module.exports.table_index = table_index;
-module.exports.table_keyValue = table_keyValue;
-module.exports.table_newindex = table_newindex;
diff --git a/src/lstate.js b/src/lstate.js
index 4b4aaa5..1b077d2 100644
--- a/src/lstate.js
+++ b/src/lstate.js
@@ -104,10 +104,10 @@ const stack_init = function(L1, L) {
** Create registry table and its predefined values
*/
const init_registry = function(L, g) {
- let registry = new lobject.TValue(CT.LUA_TTABLE, ltable.luaH_new(L));
- g.l_registry = registry;
- registry.value.set(defs.LUA_RIDX_MAINTHREAD, L);
- registry.value.set(defs.LUA_RIDX_GLOBALS, new lobject.TValue(CT.LUA_TTABLE, ltable.luaH_new(L)));
+ let registry = ltable.luaH_new(L);
+ g.l_registry.sethvalue(registry);
+ ltable.luaH_setint(registry, defs.LUA_RIDX_MAINTHREAD, new lobject.TValue(CT.LUA_TTHREAD, L));
+ ltable.luaH_setint(registry, defs.LUA_RIDX_GLOBALS, new lobject.TValue(CT.LUA_TTABLE, ltable.luaH_new(L)));
};
/*
diff --git a/src/ltable.js b/src/ltable.js
index 432a91d..0d711b4 100644
--- a/src/ltable.js
+++ b/src/ltable.js
@@ -1,84 +1,167 @@
/*jshint esversion: 6 */
"use strict";
+const assert = require('assert');
+
const defs = require('./defs.js');
+const ldebug = require('./ldebug.js');
const lobject = require('./lobject.js');
const CT = defs.constant_types;
-
-const ordered_intindexes = function(table) {
- return [...table.value.keys()]
- .filter(e => typeof e === 'number' && e % 1 === 0 && e > 0) // Only integer indexes
- .sort(function (a, b) {
- return a > b ? 1 : -1;
- });
+/* converts strings (arrays) to a consistent map key */
+const hashstr = function(str) {
+ return str.map(e => `${e}|`).join('');
};
-const ordered_indexes = function(table) {
- return [...table.value.keys()]
- .sort(function(a, b) {
- if (typeof a !== "number" || a <= 0) return 1;
- if (typeof b !== "number" || b <= 0) return -1;
- return a > b ? 1 : -1;
- });
+const table_hash = function(key) {
+ switch(key.type) {
+ case CT.LUA_TBOOLEAN:
+ case CT.LUA_TLIGHTUSERDATA: /* XXX: if user pushes conflicting lightuserdata then the table will do odd things */
+ case CT.LUA_TNUMFLT:
+ case CT.LUA_TNUMINT:
+ case CT.LUA_TTABLE:
+ case CT.LUA_TLCL:
+ case CT.LUA_TLCF:
+ case CT.LUA_TCCL:
+ case CT.LUA_TUSERDATA:
+ case CT.LUA_TTHREAD:
+ return key.value;
+ case CT.LUA_TSHRSTR:
+ case CT.LUA_TLNGSTR:
+ return hashstr(key.value);
+ default:
+ throw new Error("unknown key type: " + key.type);
+ }
};
const luaH_new = function(L) {
- let t = new Map();
+ let t = {
+ strong: new Map(),
+ metatable: null
+ };
return t;
};
-/*
-** Try to find a boundary in table 't'. A 'boundary' is an integer index
-** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).
-*/
-const luaH_getn = function(table) {
- let indexes = ordered_intindexes(table);
- let len = indexes.length;
+const getgeneric = function(t, hash) {
+ let v = t.strong.get(hash);
+ return v ? v.value : lobject.luaO_nilobject;
+};
- // If first index != 1, length is 0
- if (indexes[0] !== 1) return 0;
+const luaH_getint = function(t, key) {
+ assert(typeof key == "number");
+ return getgeneric(t, key);
+};
- for (let i = 0; i < len; i++) {
- let key = indexes[i];
+const luaH_getstr = function(t, key) {
+ assert(Array.isArray(key));
+ return getgeneric(t, hashstr(key));
+};
- if (!lobject.table_index(table, key).ttisnil() // t[key] is non-nil
- && (indexes[i + 1] - key > 1 || lobject.table_index(table, indexes[i + 1]).ttisnil())) { // gap with next key or next value is nil
- return indexes[i];
- }
- }
+const luaH_get = function(t, key) {
+ assert(key instanceof lobject.TValue);
+ if (key.ttisnil())
+ return lobject.luaO_nilobject;
+ return getgeneric(t, table_hash(key));
+};
- return 0;
+const setgeneric = function(t, hash, key) {
+ let v = t.strong.get(hash);
+ if (v)
+ return v.value;
+
+ let tv = new lobject.TValue(CT.LUA_TNIL, null);
+ t.strong.set(hash, {
+ key: key,
+ value: tv
+ });
+ return tv;
};
-const luaH_next = function(L, table, keyI) {
- let keyO = L.stack[keyI];
- let key = lobject.table_keyValue(keyO);
- let indexes = ordered_indexes(table);
+const luaH_setint = function(t, key, value) {
+ assert(typeof key == "number" && value instanceof lobject.TValue && key|0 === key);
+ let hash = key; /* table_hash known result */
+ let v = t.strong.get(hash);
+ if (v) {
+ let tv = v.value;
+ tv.setfrom(value);
+ } else {
+ t.strong.set(hash, {
+ key: new lobject.TValue(CT.LUA_TNUMINT, key),
+ value: new lobject.TValue(value.type, value.value)
+ });
+ }
+};
- if (indexes.length === 0) return 0;
+const luaH_set = function(t, key) {
+ assert(key instanceof lobject.TValue);
+ let hash = table_hash(key);
+ return setgeneric(t, hash, new lobject.TValue(key.type, key.value));
+};
- let i = indexes.indexOf(key);
+const luaH_delete = function(t, key) {
+ assert(key instanceof lobject.TValue);
+ let hash = table_hash(key);
+ t.strong.delete(hash);
+};
- if ((i >= 0 || key === null) && i < indexes.length - 1) {
- if (key === null) i = -1;
- let nidx = indexes[i+1];
- let tnidx = typeof nidx;
+/*
+** Try to find a boundary in table 't'. A 'boundary' is an integer index
+** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).
+*/
+const luaH_getn = function(t) {
+ let i = 0;
+ let j = t.strong.size + 1; /* use known size of Map to bound search */
+ /* now do a binary search between them */
+ while (j - i > 1) {
+ let m = Math.floor((i+j)/2);
+ if (luaH_getint(t, m).ttisnil()) j = m;
+ else i = m;
+ }
+ return i;
+};
- if (tnidx === 'number' && nidx % 1 === 0)
- L.stack[keyI] = new lobject.TValue(CT.LUA_TNUMINT, indexes[i + 1]);
- else if (tnidx === 'string')
- L.stack[keyI] = new lobject.TValue(CT.LUA_TLNGSTR, indexes[i + 1].split('|').map(e => Number.parseInt(e)).slice(0, -1));
- else
- L.stack[keyI] = indexes[i + 1];
+/*
+** Javascript tables don't have any next-like primitive.
+** For each call of `next` this does a full iteration up to the item
+*/
+const luaH_next = function(L, table, keyI) {
+ let keyO = L.stack[keyI];
- L.stack[keyI + 1] = table.value.get(indexes[i + 1]);
- return 1;
+ let iterresult;
+ if (keyO.type === CT.LUA_TNIL) {
+ iterresult = table.strong.keys().next();
+ } else {
+ let hash = table_hash(keyO);
+
+ if (!table.strong.has(hash))
+ /* item not in table */
+ return ldebug.luaG_runerror(L, "invalid key to 'next'");
+
+ let indexes = table.strong.keys();
+ while (1) {
+ let e = indexes.next();
+ if (e.done)
+ throw "unreachable";
+ else if (e.value == hash)
+ break;
+ }
+ iterresult = indexes.next();
}
+ if (iterresult.done)
+ return false;
- return 0;
+ let entry = table.strong.get(iterresult.value);
+ 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);
+ return true;
};
-module.exports.luaH_new = luaH_new;
-module.exports.luaH_next = luaH_next;
-module.exports.luaH_getn = luaH_getn;
+module.exports.luaH_delete = luaH_delete;
+module.exports.luaH_get = luaH_get;
+module.exports.luaH_getint = luaH_getint;
+module.exports.luaH_getn = luaH_getn;
+module.exports.luaH_getstr = luaH_getstr;
+module.exports.luaH_set = luaH_set;
+module.exports.luaH_setint = luaH_setint;
+module.exports.luaH_new = luaH_new;
+module.exports.luaH_next = luaH_next;
diff --git a/src/ltablib.js b/src/ltablib.js
index 78c71e4..929cf4b 100644
--- a/src/ltablib.js
+++ b/src/ltablib.js
@@ -4,6 +4,7 @@ const lua = require('./lua.js');
const lapi = require('./lapi.js');
const lauxlib = require('./lauxlib.js');
const llimit = require('./llimit.js');
+const ltable = require('./ltable.js');
/*
@@ -175,32 +176,43 @@ const unpack = function(L) {
// TODO: Maybe do the quicksort after all
const auxsort = function(L) {
- let t = lapi.index2addr(L, 1);
+ let a = [];
+ for (let i=1; ;i++) {
+ if(lua.lua_geti(L, 1, i) === lua.LUA_TNIL) {
+ lua.lua_pop(L, 1);
+ break;
+ }
+ let t = lapi.index2addr(L, -1);
+ a.push({
+ oldkey: i,
+ value: t
+ });
+ lua.lua_pop(L, 1);
+ }
+ let sort_function;
if (lua.lua_type(L, 2) !== lua.LUA_TFUNCTION) { /* no function? */
- [...t.value.entries()]
- .sort(function (a, b) {
- if (typeof a[0] !== 'number') return 1;
- else if (typeof b[0] !== 'number') return -1;
- return lapi.lua_compare_(L, a[1], b[1], lua.LUA_OPLT) === 1 ? -1 : 1; /* a < b */
- })
- .forEach((e, i) => typeof e[0] === 'number' ? t.value.set(i + 1, e[1]) : true);
+ sort_function = function (a, b) {
+ return lapi.lua_compare_(L, a.value, b.value, lua.LUA_OPLT) === 1 ? -1 : 1; /* a < b */
+ };
} else {
- [...t.value.entries()]
- .sort(function (a, b) {
- if (typeof a[0] !== 'number') return 1;
- else if (typeof b[0] !== 'number') return -1;
-
- lua.lua_pushvalue(L, 2); /* push function */
- lua.lua_pushtvalue(L, a[1]); /* since we use Map.sort, a and b are not on the stack */
- lua.lua_pushtvalue(L, b[1]);
- lua.lua_call(L, 2, 1); /* call function */
- let res = lua.lua_toboolean(L, -1); /* get result */
- lua.lua_pop(L, 1); /* pop result */
- return res ? -1 : 1;
- })
- .forEach((e, i) => typeof e[0] === 'number' ? t.value.set(i + 1, e[1]) : true);
+ sort_function = function (a, b) {
+ lua.lua_pushvalue(L, 2); /* push function */
+ lua.lua_pushtvalue(L, a.value); /* since we use Map.sort, a and b are not on the stack */
+ lua.lua_pushtvalue(L, b.value);
+ lua.lua_call(L, 2, 1); /* call function */
+ let res = lua.lua_toboolean(L, -1); /* get result */
+ lua.lua_pop(L, 1); /* pop result */
+ return res ? -1 : 1;
+ };
}
+ a.sort(sort_function)
+ .forEach(function(e, i) {
+ if (e.oldkey != i+1) {
+ lua.lua_pushtvalue(L, e.value);
+ lua.lua_seti(L, 1, i+1);
+ }
+ });
};
const sort = function(L) {
diff --git a/src/ltm.js b/src/ltm.js
index c94d8f1..76e7b0c 100644
--- a/src/ltm.js
+++ b/src/ltm.js
@@ -7,6 +7,7 @@ const defs = require('./defs.js');
const lobject = require('./lobject.js');
const ldo = require('./ldo.js');
const lstate = require('./lstate.js');
+const ltable = require('./ltable.js');
const ldebug = require('./ldebug.js');
const lvm = require('./lvm.js');
const CT = defs.constant_types;
@@ -69,9 +70,9 @@ const luaT_init = function(L) {
*/
const luaT_objtypename = function(L, o) {
let mt;
- if ((o.ttistable() && (mt = o.metatable) !== null) ||
+ if ((o.ttistable() && (mt = o.value.metatable) !== null) ||
(o.ttisfulluserdata() && (mt = o.value.metatable) !== null)) {
- let name = lobject.table_index(mt, defs.to_luastring('__name', true));
+ let name = ltable.luaH_getstr(mt, defs.to_luastring('__name', true));
if (name.ttisstring())
return name.value;
}
@@ -142,13 +143,13 @@ const luaT_gettmbyobj = function(L, o, event) {
switch(o.ttnov()) {
case CT.LUA_TTABLE:
case CT.LUA_TUSERDATA:
- mt = o.metatable;
+ mt = o.value.metatable;
break;
default:
mt = L.l_G.mt[o.ttnov()];
}
- return mt ? lobject.table_index(mt, event) : lobject.luaO_nilobject;
+ return mt ? ltable.luaH_getstr(mt, event) : lobject.luaO_nilobject;
};
module.exports.TMS = TMS;
diff --git a/src/lvm.js b/src/lvm.js
index 24822b6..3e70275 100644
--- a/src/lvm.js
+++ b/src/lvm.js
@@ -651,11 +651,11 @@ const luaV_execute = function(L) {
c = ci.u.l.savedpc[ci.pcOff++].Ax;
}
- let table = L.stack[ra];
+ let h = L.stack[ra].value;
let last = ((c - 1) * OC.LFIELDS_PER_FLUSH) + n;
for (; n > 0; n--) {
- lobject.table_newindex(table, last--, L.stack[ra + n]);
+ ltable.luaH_setint(h, last--, L.stack[ra + n]);
}
L.top = ci.top; /* correct top (in case of previous open call) */
@@ -973,7 +973,7 @@ const luaV_objlen = function(L, ra, rb) {
case CT.LUA_TTABLE: {
tm = ltm.luaT_gettmbyobj(L, rb, ltm.TMS.TM_LEN);
if (!tm.ttisnil()) break;
- L.stack[ra] = new TValue(CT.LUA_TNUMINT, ltable.luaH_getn(rb));
+ L.stack[ra] = new TValue(CT.LUA_TNUMINT, ltable.luaH_getn(rb.value));
return;
}
case CT.LUA_TSHRSTR:
@@ -1051,10 +1051,10 @@ const gettable = function(L, table, key, ra, recur) {
ldebug.luaG_runerror(L, defs.to_luastring("'__index' chain too long; possible loop", true));
if (table.ttistable()) {
- let element = lobject.table_index(table, key);
+ let element = ltable.luaH_get(table.value, key);
if (!element.ttisnil()) {
- L.stack[ra] = element;
+ L.stack[ra] = new TValue(element.type, element.value);
} else {
luaV_finishget(L, table, key, ra, element, recur);
}
@@ -1094,10 +1094,10 @@ const settable = function(L, table, key, v, recur) {
ldebug.luaG_runerror(L, defs.to_luastring("'__newindex' chain too long; possible loop", true));
if (table.ttistable()) {
- let element = lobject.table_index(table, key);
+ let element = ltable.luaH_set(table.value, key);
if (!element.ttisnil()) {
- lobject.table_newindex(table, key, v);
+ element.setfrom(v);
} else {
luaV_finishset(L, table, key, v, element, recur);
}
@@ -1112,7 +1112,7 @@ const luaV_finishset = function(L, t, key, val, slot, recur) {
assert(slot.ttisnil());
tm = ltm.luaT_gettmbyobj(L, t, ltm.TMS.TM_NEWINDEX); // TODO: fasttm
if (tm.ttisnil()) {
- lobject.table_newindex(t, key, val);
+ slot.setfrom(val);
return;
}
} else { /* not a table; check metamethod */