From 18b89ee8e1059a21f8d5e3a52c2e256b7dea79cb Mon Sep 17 00:00:00 2001 From: Benoit Giannangeli Date: Sat, 4 Feb 2017 09:01:25 +0100 Subject: CLOSURE, CALL --- luac.out | Bin 190 -> 334 bytes src/lfunc.js | 17 +++++++- src/lobject.js | 23 +++++++---- src/lstate.js | 11 +++-- src/lvm.js | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- tests/lvm.js | 22 ++++++++++ 6 files changed, 178 insertions(+), 23 deletions(-) diff --git a/luac.out b/luac.out index 0b992bf..f693654 100644 Binary files a/luac.out and b/luac.out differ diff --git a/src/lfunc.js b/src/lfunc.js index faa0887..929dae8 100644 --- a/src/lfunc.js +++ b/src/lfunc.js @@ -21,7 +21,22 @@ class Proto { } +class UpVal { + + constructor() { + this.v = null; + this.u = { + open: { + next: null, + touched: false + }, + value: null + }; + } + +} module.exports = { - Proto: Proto + Proto: Proto, + UpVal: UpVal }; \ No newline at end of file diff --git a/src/lobject.js b/src/lobject.js index 876a16f..4cc8c4e 100644 --- a/src/lobject.js +++ b/src/lobject.js @@ -3,15 +3,6 @@ const CT = require('./lua.js').constant_types; -class LClosure { - - constructor(n) { - this.p = null; - this.nupvalues = n; - } - -} - class TValue { @@ -24,6 +15,20 @@ class TValue { } +class LClosure extends TValue { + + constructor(n) { + super(CT.LUA_TLCL, null); + + this.p = null; + this.nupvalues = n; + this.upvals = []; + + this.value = this; + } + +} + class TString extends TValue { constructor(string) { diff --git a/src/lstate.js b/src/lstate.js index 15dedcb..f9dbf8e 100644 --- a/src/lstate.js +++ b/src/lstate.js @@ -10,8 +10,13 @@ class CallInfo { this.base = base; this.previous = previous; this.next = next; - this.savedpc = []; this.pcOff = 0; + this.u = { + l: { + base: null, + savedpc: [] + } + }; } } @@ -21,9 +26,9 @@ class lua_State { constructor(cl) { this.top = 1; this.ci = [ - new CallInfo(0, 1, 1, null, null) + new CallInfo(cl, 1, 1, null, null) ]; - this.ci[0].savedpc = cl.p.code; + this.ci[0].u.l.savedpc = cl.p.code; this.ciOff = 0; this.stack = [ cl diff --git a/src/lvm.js b/src/lvm.js index 9518721..963d545 100644 --- a/src/lvm.js +++ b/src/lvm.js @@ -1,11 +1,16 @@ -/*jshint esversion: 6 */ + /*jshint esversion: 6 */ "use strict"; const BytecodeParser = require("./lundump.js"); const OC = require('./lopcodes.js'); const CT = require('./lua.js').constant_types; -const TValue = require('./lobject.js').TValue; -const Table = require('./lobject.js').Table; +const lobject = require('./lobject.js'); +const TValue = lobject.TValue; +const Table = lobject.Table; +const LClosure = lobject.LClosure; +const lfunc = require('./lfunc.js'); +const UpVal = lfunc.UpVal; +const CallInfo = require('./lstate.js').CallInfo; class LuaVM { @@ -52,11 +57,11 @@ class LuaVM { newframe: for (;;) { - var cl = L.stack[ci.func]; + var cl = ci.func; let k = cl.p.k; let base = ci.base; - let i = ci.savedpc[ci.pcOff++]; + let i = ci.u.l.savedpc[ci.pcOff++]; let ra = this.RA(base, i); switch (OC.OpCodes[i.opcode]) { @@ -69,8 +74,8 @@ class LuaVM { break; } case "OP_LOADKX": { - assert(OC.OpCodes[ci.savedpc[ci.pcOff].opcode] === "OP_EXTRAARG"); - L.stack[ra] = k[ci.savedpc[ci.pcOff++].Ax]; + assert(OC.OpCodes[ci.u.l.savedpc[ci.pcOff].opcode] === "OP_EXTRAARG"); + L.stack[ra] = k[ci.u.l.savedpc[ci.pcOff++].Ax]; break; } case "OP_LOADBOOL": { @@ -92,15 +97,15 @@ class LuaVM { case "OP_GETTABUP": { break; } - case "OP_GETTABLE": { - break; - } case "OP_SETTABUP": { break; } case "OP_SETUPVAL": { break; } + case "OP_GETTABLE": { + break; + } case "OP_SETTABLE": { break; } @@ -345,6 +350,16 @@ class LuaVM { break; } case "OP_CALL": { + let b = i.B; + let nresults = i.C - 1; + + if (b !== 0) + L.top = ra+b; + + this.precall(ra, L.stack[ra], nresults); + ci = L.ci; + continue newframe; + break; } case "OP_TAILCALL": { @@ -383,6 +398,20 @@ class LuaVM { break; } case "OP_CLOSURE": { + let p = cl.p.p[i.Bx]; + let nup = p.upvalues.length; + let uv = p.upvalues; + let ncl = new LClosure(nup); + ncl.p = p; + + L.stack[ra] = ncl; + + for (let i = 0; i < nup; i++) { // TODO test + if (uv[i].instack) + ncl.upvals[i] = this.findupval(base + uv[i].idx); + else + ncl.upvals[i] = cl.upvals[uv[i].idx]; + } break; } case "OP_VARARG": { @@ -395,6 +424,85 @@ class LuaVM { } } + precall(off, func, nresults) { + let L = this.L; + let ci; + + switch(func.type) { + case CT.LUA_TCCL: // JS function ? + throw new Error("LUA_TCCL not implemeted yet") + break; + case CT.LUA_TLCF: // still JS function ? + throw new Error("LUA_TLCF not implemeted yet") + break; + case CT.LUA_TLCL: { + let p = func.p; + let n = L.top - off - 1; + let fsize = p.maxstacksize; + let base; + + if (p.is_vararg) { + // base = adjust_varargs(L, p, n); + } else { + for (; n < p.numparams; n++) + L.stack[L.top++] = new TValue(CT.LUA_TNIL, null); + base = off + 1; + } + + // next_ci + if (L.ci.next) { + L.ci = L.ci.next; + } else { + ci = new CallInfo(); + L.ci.next = ci; + ci.previous = L.ci; + ci.next = null; + + L.ci = ci; + } + ci.nresults = nresults; + ci.func = func; + ci.u.l.base = base; + ci.top = base + fsize; + L.top = ci.top; + ci.u.l.savedpc = p.code; + break; + } + default: + // __call + } + } + + postcall(ci, firstResult, nres) { + + } + + findupval(level) { // TODO test + let pp = L.openupval; + + while(pp !== null && pp.v >= level) { + let p = pp; + + if (p.v === level) + return p; + + pp = p.u.open.next; + } + + let uv = new UpVal(); + uv.refcount = 0; + uv.u.open.next = pp; + uv.u.open.touched = true; + + pp = uv; + + uv.v = level; + + // Thread with upvalue list business ? lfunc.c:75 + + return uv; + } + } module.exports = { diff --git a/tests/lvm.js b/tests/lvm.js index 1dbff2e..1b4d8c3 100644 --- a/tests/lvm.js +++ b/tests/lvm.js @@ -157,4 +157,26 @@ test('NEWTABLE', function (t) { vm.L.stack[0] instanceof Table, "Program output is correct" ); +}); + + +test('CALL', function (t) { + let luaCode = ` + local f = function (a, b) + return a + b + end + + local c = f(1, 2) + + return c + `, vm; + + t.plan(0); + + t.comment("Running following code: \n" + luaCode); + + // t.doesNotThrow(function () { + vm = getVM(luaCode); + vm.execute(); + // }, "Program executed without errors"); }); \ No newline at end of file -- cgit v1.2.3-70-g09d2