summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Giannangeli <giann008@gmail.com>2017-02-05 09:12:54 +0100
committerBenoit Giannangeli <giann008@gmail.com>2017-02-05 09:12:54 +0100
commit86a09b63a6a316ee0855ce1d5307ea89f0b6f1ec (patch)
tree9f94608831b94a8a287c3e5edbe1e74d397bb241
parent18b89ee8e1059a21f8d5e3a52c2e256b7dea79cb (diff)
downloadfengari-86a09b63a6a316ee0855ce1d5307ea89f0b6f1ec.tar.gz
fengari-86a09b63a6a316ee0855ce1d5307ea89f0b6f1ec.tar.bz2
fengari-86a09b63a6a316ee0855ce1d5307ea89f0b6f1ec.zip
Fixed bad use of L.top
-rw-r--r--luac.outbin334 -> 334 bytes
-rw-r--r--src/lstate.js9
-rw-r--r--src/lvm.js113
-rw-r--r--tests/lvm.js23
4 files changed, 76 insertions, 69 deletions
diff --git a/luac.out b/luac.out
index f693654..7cb0869 100644
--- a/luac.out
+++ b/luac.out
Binary files differ
diff --git a/src/lstate.js b/src/lstate.js
index f9dbf8e..bf49b42 100644
--- a/src/lstate.js
+++ b/src/lstate.js
@@ -7,13 +7,12 @@ class CallInfo {
constructor(func, top, base, previous, next) {
this.func = func;
this.top = top;
- this.base = base;
this.previous = previous;
this.next = next;
this.pcOff = 0;
this.u = {
l: {
- base: null,
+ base: base,
savedpc: []
}
};
@@ -25,10 +24,8 @@ class lua_State {
constructor(cl) {
this.top = 1;
- this.ci = [
- new CallInfo(cl, 1, 1, null, null)
- ];
- this.ci[0].u.l.savedpc = cl.p.code;
+ this.ci = new CallInfo(cl, 1, 1, null, null);
+ this.ci.u.l.savedpc = cl.p.code;
this.ciOff = 0;
this.stack = [
cl
diff --git a/src/lvm.js b/src/lvm.js
index 963d545..0fa1de5 100644
--- a/src/lvm.js
+++ b/src/lvm.js
@@ -1,4 +1,4 @@
- /*jshint esversion: 6 */
+/*jshint esversion: 6 */
"use strict";
const BytecodeParser = require("./lundump.js");
@@ -31,11 +31,11 @@ class LuaVM {
}
RKB(base, k, i) {
- return OC.ISK(b) ? k[OC.INDEXK(b)] : base + i.B;
+ return OC.ISK(i.B) ? k[OC.INDEXK(i.B)] : this.L.stack[base + i.B];
}
RKC(base, k, i) {
- return OC.ISK(c) ? k[OC.INDEXK(c)] : base + i.C;
+ return OC.ISK(i.C) ? k[OC.INDEXK(i.C)] : this.L.stack[base + i.C];
}
static tonumber(v) {
@@ -53,13 +53,13 @@ class LuaVM {
execute() {
let L = this.L;
- let ci = L.ci[this.L.ciOff];
newframe:
for (;;) {
+ let ci = L.ci;
var cl = ci.func;
let k = cl.p.k;
- let base = ci.base;
+ let base = ci.u.l.base
let i = ci.u.l.savedpc[ci.pcOff++];
let ra = this.RA(base, i);
@@ -117,47 +117,47 @@ class LuaVM {
break;
}
case "OP_ADD": {
- let op1 = k[i.B];
- let op2 = k[i.C];
+ let op1 = this.RKB(base, k, i);
+ let op2 = this.RKC(base, k, i);
let numberop1 = LuaVM.tonumber(op1);
let numberop2 = LuaVM.tonumber(op2);
if (op1.type === CT.LUA_TNUMINT && op2.type === CT.LUA_TNUMINT) {
- L.stack[ra] = new TValue(CT.LUA_TNUMINT, k[i.B].value + k[i.C].value);
+ L.stack[ra] = new TValue(CT.LUA_TNUMINT, op1.value + op2.value);
} else if (numberop1 !== false && numberop2 !== false) {
- L.stack[ra] = new TValue(CT.LUA_TNUMFLT, k[i.B].value + k[i.C].value);
+ L.stack[ra] = new TValue(CT.LUA_TNUMFLT, op1.value + op2.value);
} else {
// Metamethod
- throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
+ throw new Error(`Can't perform binary operation on ${op1.value} and ${op2.value}`);
}
break;
}
case "OP_SUB": {
- let op1 = k[i.B];
- let op2 = k[i.C];
+ let op1 = this.RKB(base, k, i);
+ let op2 = this.RKC(base, k, i);
let numberop1 = LuaVM.tonumber(op1);
let numberop2 = LuaVM.tonumber(op2);
if (op1.type === CT.LUA_TNUMINT && op2.type === CT.LUA_TNUMINT) {
- L.stack[ra] = new TValue(CT.LUA_TNUMINT, k[i.B].value - k[i.C].value);
+ L.stack[ra] = new TValue(CT.LUA_TNUMINT, op1.value - op2.value);
} else if (numberop1 !== false && numberop2 !== false) {
- L.stack[ra] = new TValue(CT.LUA_TNUMFLT, k[i.B].value - k[i.C].value);
+ L.stack[ra] = new TValue(CT.LUA_TNUMFLT, op1.value - op2.value);
} else {
// Metamethod
- throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
+ throw new Error(`Can't perform binary operation on ${op1.value} and ${k[i.C].value}`);
}
break;
}
case "OP_MUL": {
- let op1 = k[i.B];
- let op2 = k[i.C];
+ let op1 = this.RKB(base, k, i);
+ let op2 = this.RKC(base, k, i);
let numberop1 = LuaVM.tonumber(op1);
let numberop2 = LuaVM.tonumber(op2);
if (op1.type === CT.LUA_TNUMINT && op2.type === CT.LUA_TNUMINT) {
- L.stack[ra] = new TValue(CT.LUA_TNUMINT, k[i.B].value * k[i.C].value);
+ L.stack[ra] = new TValue(CT.LUA_TNUMINT, op1.value * op2.value);
} else if (numberop1 !== false && numberop2 !== false) {
- L.stack[ra] = new TValue(CT.LUA_TNUMFLT, k[i.B].value * k[i.C].value);
+ L.stack[ra] = new TValue(CT.LUA_TNUMFLT, k[i.B].value * op2.value);
} else {
// Metamethod
throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
@@ -165,15 +165,15 @@ class LuaVM {
break;
}
case "OP_MOD": {
- let op1 = k[i.B];
- let op2 = k[i.C];
+ let op1 = this.RKB(base, k, i);
+ let op2 = this.RKC(base, k, i);
let numberop1 = LuaVM.tonumber(op1);
let numberop2 = LuaVM.tonumber(op2);
if (op1.type === CT.LUA_TNUMINT && op2.type === CT.LUA_TNUMINT) {
- L.stack[ra] = new TValue(CT.LUA_TNUMINT, k[i.B].value % k[i.C].value);
+ L.stack[ra] = new TValue(CT.LUA_TNUMINT, op1.value % op2.value);
} else if (numberop1 !== false && numberop2 !== false) {
- L.stack[ra] = new TValue(CT.LUA_TNUMFLT, k[i.B].value % k[i.C].value);
+ L.stack[ra] = new TValue(CT.LUA_TNUMFLT, k[i.B].value % op2.value);
} else {
// Metamethod
throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
@@ -181,13 +181,13 @@ class LuaVM {
break;
}
case "OP_POW": {
- let op1 = k[i.B];
- let op2 = k[i.C];
+ let op1 = this.RKB(base, k, i);
+ let op2 = this.RKC(base, k, i);
let numberop1 = LuaVM.tonumber(op1);
let numberop2 = LuaVM.tonumber(op2);
if (numberop1 !== false && numberop2 !== false) {
- L.stack[ra] = new TValue(CT.LUA_TNUMFLT, Math.pow(k[i.B].value, k[i.C].value));
+ L.stack[ra] = new TValue(CT.LUA_TNUMFLT, Math.pow(op1.value, op2.value));
} else {
// Metamethod
throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
@@ -195,13 +195,13 @@ class LuaVM {
break;
}
case "OP_DIV": {
- let op1 = k[i.B];
- let op2 = k[i.C];
+ let op1 = this.RKB(base, k, i);
+ let op2 = this.RKC(base, k, i);
let numberop1 = LuaVM.tonumber(op1);
let numberop2 = LuaVM.tonumber(op2);
if (numberop1 !== false && numberop2 !== false) {
- L.stack[ra] = new TValue(CT.LUA_TNUMFLT, k[i.B].value / k[i.C].value);
+ L.stack[ra] = new TValue(CT.LUA_TNUMFLT, k[i.B].value / op2.value);
} else {
// Metamethod
throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
@@ -209,15 +209,15 @@ class LuaVM {
break;
}
case "OP_IDIV": {
- let op1 = k[i.B];
- let op2 = k[i.C];
+ let op1 = this.RKB(base, k, i);
+ let op2 = this.RKC(base, k, i);
let numberop1 = LuaVM.tonumber(op1);
let numberop2 = LuaVM.tonumber(op2);
if (op1.type === CT.LUA_TNUMINT && op2.type === CT.LUA_TNUMINT) {
- L.stack[ra] = new TValue(CT.LUA_TNUMINT, Math.floor(k[i.B].value / k[i.C].value));
+ L.stack[ra] = new TValue(CT.LUA_TNUMINT, Math.floor(op1.value / op2.value));
} else if (numberop1 !== false && numberop2 !== false) {
- L.stack[ra] = new TValue(CT.LUA_TNUMFLT, Math.floor(k[i.B].value / k[i.C].value));
+ L.stack[ra] = new TValue(CT.LUA_TNUMFLT, Math.floor(op1.value / op2.value));
} else {
// Metamethod
throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
@@ -225,13 +225,13 @@ class LuaVM {
break;
}
case "OP_BAND": {
- let op1 = k[i.B];
- let op2 = k[i.C];
+ let op1 = this.RKB(base, k, i);
+ let op2 = this.RKC(base, k, i);
let numberop1 = LuaVM.tonumber(op1);
let numberop2 = LuaVM.tonumber(op2);
if (op1.type === CT.LUA_TNUMINT && op2.type === CT.LUA_TNUMINT) {
- L.stack[ra] = new TValue(CT.LUA_TNUMINT, k[i.B].value & k[i.C].value);
+ L.stack[ra] = new TValue(CT.LUA_TNUMINT, op1.value & op2.value);
} else {
// Metamethod
throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
@@ -239,13 +239,13 @@ class LuaVM {
break;
}
case "OP_BOR": {
- let op1 = k[i.B];
- let op2 = k[i.C];
+ let op1 = this.RKB(base, k, i);
+ let op2 = this.RKC(base, k, i);
let numberop1 = LuaVM.tonumber(op1);
let numberop2 = LuaVM.tonumber(op2);
if (op1.type === CT.LUA_TNUMINT && op2.type === CT.LUA_TNUMINT) {
- L.stack[ra] = new TValue(CT.LUA_TNUMINT, k[i.B].value | k[i.C].value);
+ L.stack[ra] = new TValue(CT.LUA_TNUMINT, op1.value | op2.value);
} else {
// Metamethod
throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
@@ -253,13 +253,13 @@ class LuaVM {
break;
}
case "OP_BXOR": {
- let op1 = k[i.B];
- let op2 = k[i.C];
+ let op1 = this.RKB(base, k, i);
+ let op2 = this.RKC(base, k, i);
let numberop1 = LuaVM.tonumber(op1);
let numberop2 = LuaVM.tonumber(op2);
if (op1.type === CT.LUA_TNUMINT && op2.type === CT.LUA_TNUMINT) {
- L.stack[ra] = new TValue(CT.LUA_TNUMINT, k[i.B].value ^ k[i.C].value);
+ L.stack[ra] = new TValue(CT.LUA_TNUMINT, op1.value ^ op2.value);
} else {
// Metamethod
throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
@@ -267,13 +267,13 @@ class LuaVM {
break;
}
case "OP_SHL": {
- let op1 = k[i.B];
- let op2 = k[i.C];
+ let op1 = this.RKB(base, k, i);
+ let op2 = this.RKC(base, k, i);
let numberop1 = LuaVM.tonumber(op1);
let numberop2 = LuaVM.tonumber(op2);
if (op1.type === CT.LUA_TNUMINT && op2.type === CT.LUA_TNUMINT) {
- L.stack[ra] = new TValue(CT.LUA_TNUMINT, k[i.B].value << k[i.C].value);
+ L.stack[ra] = new TValue(CT.LUA_TNUMINT, op1.value << op2.value);
} else {
// Metamethod
throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
@@ -281,13 +281,13 @@ class LuaVM {
break;
}
case "OP_SHR": {
- let op1 = k[i.B];
- let op2 = k[i.C];
+ let op1 = this.RKB(base, k, i);
+ let op2 = this.RKC(base, k, i);
let numberop1 = LuaVM.tonumber(op1);
let numberop2 = LuaVM.tonumber(op2);
if (op1.type === CT.LUA_TNUMINT && op2.type === CT.LUA_TNUMINT) {
- L.stack[ra] = new TValue(CT.LUA_TNUMINT, k[i.B].value >> k[i.C].value);
+ L.stack[ra] = new TValue(CT.LUA_TNUMINT, op1.value >> op2.value);
} else {
// Metamethod
throw new Error(`Can't perform binary operation on ${k[i.B].value} and ${k[i.C].value}`);
@@ -299,12 +299,12 @@ class LuaVM {
let numberop = LuaVM.tonumber(op);
if (op.type === CT.LUA_TNUMINT) {
- L.stack[ra] = new TValue(CT.LUA_TNUMINT, -L.stack[this.RB(base, i)].value);
+ L.stack[ra] = new TValue(CT.LUA_TNUMINT, -op.value);
} else if (numberop !== false) {
- L.stack[ra] = new TValue(CT.LUA_TNUMFLT, -L.stack[this.RB(base, i)].value);
+ L.stack[ra] = new TValue(CT.LUA_TNUMFLT, -op.value);
} else {
// Metamethod
- throw new Error(`Can't perform unary operation on ${k[i.B].value} and ${k[i.C].value}`);
+ throw new Error(`Can't perform unary operation on ${op.value}`);
}
break;
}
@@ -313,10 +313,10 @@ class LuaVM {
let numberop = LuaVM.tonumber(op);
if (op.type === CT.LUA_TNUMINT) {
- L.stack[ra] = new TValue(CT.LUA_TNUMINT, ~L.stack[this.RB(base, i)].value);
+ L.stack[ra] = new TValue(CT.LUA_TNUMINT, ~op.value);
} else {
// Metamethod
- throw new Error(`Can't perform unary operation on ${k[i.B].value} and ${k[i.C].value}`);
+ throw new Error(`Can't perform unary operation on ${op.value}`);
}
break;
}
@@ -367,14 +367,16 @@ class LuaVM {
}
case "OP_RETURN": {
if (i.B >= 2) {
+ // TODO moveresults, ldo.c:334
for (let j = 0; j <= i.B-2; j++) {
L.stack[L.ciOff + j] = L.stack[ra + j];
+ L.top++;
}
}
+ L.ciOff--;
L.ci = ci.previous;
// TODO what to return when end of program ?
- console.log(L.stack);
if (L.ci === null) return;
if (i.B !== 0) L.top = ci.top;
@@ -445,7 +447,7 @@ class LuaVM {
// base = adjust_varargs(L, p, n);
} else {
for (; n < p.numparams; n++)
- L.stack[L.top++] = new TValue(CT.LUA_TNIL, null);
+ L.stack[L.top++] = new TValue(CT.LUA_TNIL, null); // complete missing arguments
base = off + 1;
}
@@ -459,6 +461,7 @@ class LuaVM {
ci.next = null;
L.ci = ci;
+ L.ciOff++;
}
ci.nresults = nresults;
ci.func = func;
diff --git a/tests/lvm.js b/tests/lvm.js
index 1b4d8c3..54c40ae 100644
--- a/tests/lvm.js
+++ b/tests/lvm.js
@@ -1,3 +1,4 @@
+/*jshint esversion: 6 */
"use strict";
const test = require('tape');
@@ -60,7 +61,7 @@ test('LOADK, RETURN', function (t) {
}, "Program executed without errors");
t.strictEqual(
- vm.L.stack[0].value,
+ vm.L.stack[vm.L.top - 1].value,
"hello world",
"Program output is correct"
);
@@ -84,7 +85,7 @@ test('MOV', function (t) {
}, "Program executed without errors");
t.strictEqual(
- vm.L.stack[0].value,
+ vm.L.stack[vm.L.top - 1].value,
"hello world",
"Program output is correct"
);
@@ -107,7 +108,7 @@ test('Binary op', function (t) {
}, "Program executed without errors");
t.deepEqual(
- vm.L.stack.slice(0, 12).map(function (e) { return e.value; }),
+ vm.L.stack.slice(vm.L.top - 12 - 1, vm.L.top - 1).map(function (e) { return e.value; }),
[15, -5, 50, 0.5, 5, 9765625.0, 0, 0, 15, 15, 5120, 0],
"Program output is correct"
);
@@ -131,7 +132,7 @@ test('Unary op, LOADBOOL', function (t) {
}, "Program executed without errors");
t.deepEqual(
- vm.L.stack.slice(0, 3).map(function (e) { return e.value; }),
+ vm.L.stack.slice(vm.L.top - 3 - 1, vm.L.top - 1).map(function (e) { return e.value; }),
[-5, true, -6],
"Program output is correct"
);
@@ -154,7 +155,7 @@ test('NEWTABLE', function (t) {
}, "Program executed without errors");
t.ok(
- vm.L.stack[0] instanceof Table,
+ vm.L.stack[vm.L.top - 1] instanceof Table,
"Program output is correct"
);
});
@@ -171,12 +172,18 @@ test('CALL', function (t) {
return c
`, vm;
- t.plan(0);
+ t.plan(2);
t.comment("Running following code: \n" + luaCode);
- // t.doesNotThrow(function () {
+ t.doesNotThrow(function () {
vm = getVM(luaCode);
vm.execute();
- // }, "Program executed without errors");
+ }, "Program executed without errors");
+
+ t.strictEqual(
+ vm.L.stack[vm.L.top - 1].value,
+ 3,
+ "Program output is correct"
+ );
}); \ No newline at end of file