From 7b844c5caf81ac843a210477ef47fd16e8af2f2c Mon Sep 17 00:00:00 2001 From: Benoit Giannangeli Date: Thu, 2 Feb 2017 22:38:35 +0100 Subject: Lua VM --- luac.out | Bin 192 -> 0 bytes sandbox/hello.bc.txt | 17 ++++++++ sandbox/hello.js | 3 +- src/lobject.js | 2 +- src/lopcodes.js | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/lstate.js | 28 ------------- src/lundump.js | 63 +++++++++++++++++++---------- src/lvm.js | 24 ++++++++++++ 8 files changed, 194 insertions(+), 52 deletions(-) delete mode 100644 luac.out create mode 100644 sandbox/hello.bc.txt create mode 100644 src/lopcodes.js delete mode 100644 src/lstate.js create mode 100644 src/lvm.js diff --git a/luac.out b/luac.out deleted file mode 100644 index 25258bb..0000000 Binary files a/luac.out and /dev/null differ diff --git a/sandbox/hello.bc.txt b/sandbox/hello.bc.txt new file mode 100644 index 0000000..b41f555 --- /dev/null +++ b/sandbox/hello.bc.txt @@ -0,0 +1,17 @@ +main (9 instructions at 0x7ff931403170) +0+ params, 5 slots, 1 upvalue, 2 locals, 4 constants, 1 function + 1 [1] LOADK 0 -1 ; 1 + 2 [2] LOADK 1 -2 ; 2 + 3 [3] GETTABUP 2 0 -3 ; _ENV "print" + 4 [3] MOVE 3 0 + 5 [3] MOVE 4 1 + 6 [3] CALL 2 3 1 + 7 [7] CLOSURE 2 0 ; 0x7ff9314032e0 + 8 [5] SETTABUP 0 -4 2 ; _ENV "c" + 9 [7] RETURN 0 1 + +function (3 instructions at 0x7ff9314032e0) +2 params, 3 slots, 0 upvalues, 2 locals, 0 constants, 0 functions + 1 [6] ADD 2 0 1 + 2 [6] RETURN 2 2 + 3 [7] RETURN 0 1 \ No newline at end of file diff --git a/sandbox/hello.js b/sandbox/hello.js index f8f6e15..df32dd8 100644 --- a/sandbox/hello.js +++ b/sandbox/hello.js @@ -2,7 +2,6 @@ const DataView = require('buffer-dataview'); const fs = require('fs'); const BytecodeParser = require("../src/lundump.js"); -const lua_State = require('../src/lstate.js').lua_State; -let p = new BytecodeParser(new lua_State(), new DataView(fs.readFileSync("./sandbox/hello.bc"))) +let p = new BytecodeParser(new DataView(fs.readFileSync("./sandbox/hello.bc"))) p.luaU_undump(); \ No newline at end of file diff --git a/src/lobject.js b/src/lobject.js index 1858fd3..262b38d 100644 --- a/src/lobject.js +++ b/src/lobject.js @@ -3,7 +3,7 @@ class LClosure { - constructor(L, n) { + constructor(n) { this.p = null; this.nupvalues = n; } diff --git a/src/lopcodes.js b/src/lopcodes.js new file mode 100644 index 0000000..b7dfb0f --- /dev/null +++ b/src/lopcodes.js @@ -0,0 +1,109 @@ +/*jshint esversion: 6 */ +"use strict"; + +const OpCodes = [ + "OP_MOVE", /* A B R(A) := R(B) */ + "OP_LOADK", /* A Bx R(A) := Kst(Bx) */ + "OP_LOADKX", /* A R(A) := Kst(extra arg) */ + "OP_LOADBOOL", /* A B C R(A) := (Bool)B; if (C) pc++ */ + "OP_LOADNIL", /* A B R(A), R(A+1), ..., R(A+B) := nil */ + "OP_GETUPVAL", /* A B R(A) := UpValue[B] */ + + "OP_GETTABUP", /* A B C R(A) := UpValue[B][RK(C)] */ + "OP_GETTABLE", /* A B C R(A) := R(B)[RK(C)] */ + + "OP_SETTABUP", /* A B C UpValue[A][RK(B)] := RK(C) */ + "OP_SETUPVAL", /* A B UpValue[B] := R(A) */ + "OP_SETTABLE", /* A B C R(A)[RK(B)] := RK(C) */ + + "OP_NEWTABLE", /* A B C R(A) := {} (size = B,C) */ + + "OP_SELF", /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */ + + "OP_ADD", /* A B C R(A) := RK(B) + RK(C) */ + "OP_SUB", /* A B C R(A) := RK(B) - RK(C) */ + "OP_MUL", /* A B C R(A) := RK(B) * RK(C) */ + "OP_MOD", /* A B C R(A) := RK(B) % RK(C) */ + "OP_POW", /* A B C R(A) := RK(B) ^ RK(C) */ + "OP_DIV", /* A B C R(A) := RK(B) / RK(C) */ + "OP_IDIV", /* A B C R(A) := RK(B) // RK(C) */ + "OP_BAND", /* A B C R(A) := RK(B) & RK(C) */ + "OP_BOR", /* A B C R(A) := RK(B) | RK(C) */ + "OP_BXOR", /* A B C R(A) := RK(B) ~ RK(C) */ + "OP_SHL", /* A B C R(A) := RK(B) << RK(C) */ + "OP_SHR", /* A B C R(A) := RK(B) >> RK(C) */ + "OP_UNM", /* A B R(A) := -R(B) */ + "OP_BNOT", /* A B R(A) := ~R(B) */ + "OP_NOT", /* A B R(A) := not R(B) */ + "OP_LEN", /* A B R(A) := length of R(B) */ + + "OP_CONCAT", /* A B C R(A) := R(B).. ... ..R(C) */ + + "OP_JMP", /* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */ + "OP_EQ", /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ + "OP_LT", /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ + "OP_LE", /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ + + "OP_TEST", /* A C if not (R(A) <=> C) then pc++ */ + "OP_TESTSET", /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ + + "OP_CALL", /* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ + "OP_TAILCALL", /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ + "OP_RETURN", /* A B return R(A), ... ,R(A+B-2) (see note) */ + + "OP_FORLOOP", /* A sBx R(A)+=R(A+2); + if R(A) > 1); /* 'sBx' is signed */ +const MAXARG_Ax = ((1<> o.POS_OP) & p.MASK1(o.SIZE_OP, 0), + A: (ins >> o.POS_A) & p.MASK1(o.SIZE_A, 0), + B: (ins >> o.POS_B) & p.MASK1(o.SIZE_B, 0), + C: (ins >> o.POS_C) & p.MASK1(o.SIZE_C, 0), + Bx: (ins >> o.POS_Bx) & p.MASK1(o.SIZE_Bx, 0), + Ax: (ins >> o.POS_Ax) & p.MASK1(o.SIZE_Ax, 0), + sBx: (ins >> o.POS_Bx) & p.MASK1(o.SIZE_Bx, 0) - o.MAXARG_sBx + }; + + console.log(` [${i}] Op: ${o.OpCodes[f.code[i].opcode]} A: ${f.code[i].A} B: ${f.code[i].B} C: ${f.code[i].C} Ax: ${f.code[i].Ax} Bx: ${f.code[i].Bx} sBx: ${f.code[i].sBx}`); + } } readUpvalues(f) { @@ -144,28 +166,28 @@ class BytecodeParser { type: constant_types.LUA_TNIL, value: null }); - console.log(`LUA_TNIL = ${f.k[f.k.length - 1].value}`); + console.log(` LUA_TNIL = ${f.k[f.k.length - 1].value}`); break; case constant_types.LUA_TBOOLEAN: f.k.push({ type: constant_types.LUA_TBOOLEAN, value: this.readByte() }); - console.log(`LUA_TBOOLEAN = ${f.k[f.k.length - 1].value}`); + console.log(` LUA_TBOOLEAN = ${f.k[f.k.length - 1].value}`); break; case constant_types.LUA_TNUMFLT: f.k.push({ type: constant_types.LUA_TNUMFLT, value: this.readNumber() }); - console.log(`LUA_TNUMFLT = ${f.k[f.k.length - 1].value}`); + console.log(` LUA_TNUMFLT = ${f.k[f.k.length - 1].value}`); break; case constant_types.LUA_TNUMINT: f.k.push({ type: constant_types.LUA_TNUMINT, value: this.readInteger() }); - console.log(`LUA_TNUMINT = ${f.k[f.k.length - 1].value}`); + console.log(` LUA_TNUMINT = ${f.k[f.k.length - 1].value}`); break; case constant_types.LUA_TSHRSTR: case constant_types.LUA_TLNGSTR: @@ -173,7 +195,7 @@ class BytecodeParser { type: constant_types.LUA_TLNGSTR, value: this.readString() }); - console.log(`LUA_TLNGSTR = ${f.k[f.k.length - 1].value}`); + console.log(` LUA_TLNGSTR = ${f.k[f.k.length - 1].value}`); break; default: throw new Error(`unrecognized constant '${t}'`); @@ -284,9 +306,8 @@ class BytecodeParser { luaU_undump() { this.checkHeader(); - let cl = new LClosure(this.L, this.readByte()); - this.L.top++; - cl.p = new Proto(this.L); + let cl = new LClosure(this.readByte()); + cl.p = new Proto(); this.readFunction(cl.p); diff --git a/src/lvm.js b/src/lvm.js new file mode 100644 index 0000000..0ea3342 --- /dev/null +++ b/src/lvm.js @@ -0,0 +1,24 @@ +/*jshint esversion: 6 */ +"use strict"; + +const BytecodeParser = require("./lundump.js"); + +class LuaVM { + + constructor(cl) { + this.cl = cl + } + + execute() { + newframe: + for (;;) { + + } + } + +} + +module.exports = { + LuaVM: LuaVM, + OpCodes: OpCodes +}; \ No newline at end of file -- cgit v1.2.3-70-g09d2