local bit = require "bit32" local ir = require "luainlua.bytecode.ir" local utils = require "luainlua.common.utils" --[[ /*---------------------------------------------------------------------- name args description ------------------------------------------------------------------------*/ OP_MOVE,/* A B R(A) := R(B) */ OP_LOADK,/* A Bx R(A) := Kst(Bx) */ OP_LOADBOOL,/* A B C R(A) := (Bool)B; if (C) pc++ */ OP_LOADNIL,/* A B R(A) := ... := R(B) := nil */ OP_GETUPVAL,/* A B R(A) := UpValue[B] */ OP_GETGLOBAL,/* A Bx R(A) := Gbl[Kst(Bx)] */ OP_GETTABLE,/* A B C R(A) := R(B)[RK(C)] */ OP_SETGLOBAL,/* A Bx Gbl[Kst(Bx)] := R(A) */ 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_DIV,/* 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_UNM,/* 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,/* sBx pc+=sBx */ 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) C) then pc++ "TESTSET", --if (R(B) <=> C) then R(A) := R(B) else pc++ "CALL", --R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) "TAILCALL", --return R(A)(R(A+1), ... ,R(A+B-1)) "RETURN", --return R(A), ... ,R(A+B-2)(see note) "FORLOOP", --R(A)+=R(A+2); "FORPREP", --R(A)-=R(A+2); pc+=sBx "TFORCALL", --R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); "TFORLOOP", --if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx } "SETLIST", --R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B "CLOSURE", --R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) "VARARG", --R(A), R(A+1), ..., R(A+B-1) = vararg "EXTRAARG", --extra (larger) argument for previous opcode } for v,k in ipairs(OPCODES) do OPCODES[k] = v end local A, B, C, Ax, Bx, sBx = 'A', 'B', 'C', 'Ax', 'Bx', 'sBx' local R, RK, Kst, V = ir.R, ir.RK, ir.Kst, ir.V local ARGS = { {{A, R}, {B, R}}, --R(A) := R(B) {{A, R}, {Bx, Kst}}, --R(A) := Kst(Bx) {{A, R}}, --R(A) := Kst(extra arg) (next instruction is extra args) {{A, R}, {B, V}, {C, V}}, --R(A) := (Bool)B; if (C) pc++ {{A, R}, {B, R}}, --R(A) := ... := R(B) := nil {{A, R}, {B, V}}, --R(A) := UpValue[B] {{A, R}, {B, V}, {C, RK}}, --R(A) := UpValue[B][RK(C)] {{A, R}, {B, R}, {C, RK}}, --R(A) := R(B)[RK(C)] {{A, V}, {B, RK}, {C, RK}}, --UpValue[A][RK(B)] := RK(C) {{A, R}, {B, V}}, --UpValue[B] := R(A) {{A, R}, {B, RK}, {C, RK}}, --R(A)[RK(B)] := RK(C) {{A, R}, {B, V}, {C, V}}, --R(A) := {} (size = B,C) {{A, R}, {B, RK}, {C, RK}}, --R(A) := RK(B) + RK(C) {{A, R}, {B, RK}, {C, RK}}, {{A, R}, {B, RK}, {C, RK}}, {{A, R}, {B, RK}, {C, RK}}, {{A, R}, {B, RK}, {C, RK}}, {{A, R}, {B, RK}, {C, RK}}, {{A, R}, {B, RK}, {C, RK}}, {{A, R}, {B, R}}, --R(A) := -R(B) {{A, R}, {B, R}}, {{A, R}, {B, R}}, --R(A) := length of R(B) {{A, R}, {B, R}, {C, R}}, --R(A) := R(B).. ... ..R(C) {{A, V}, {sBx, V}}, --pc+=sBx; if (A) close all upvalues >= R(A - 1) {{A, V}, {B, RK}, {C, RK}}, --if ((RK(B) == RK(C)) ~= A) then pc++ {{A, V}, {B, RK}, {C, RK}}, {{A, V}, {B, RK}, {C, RK}}, {{A, R}, {C, V}}, --if not (R(A) <=> C) then pc++ {{A, R}, {B, R}, {C, V}}, --if (R(B) <=> C) then R(A) := R(B) else pc++ {{A, R}, {B, V}, {C, V}}, --R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) {{A, R}, {B, R}, {C, function() return V(0) end}}, --return R(A)(R(A+1), ... ,R(A+B-1)) {{A, R}, {B, V}}, --return R(A), ... ,R(A+B-2)(see note) {{A, R}, {sBx, V}}, --R(A)+=R(A+2) {{A, R}, {sBx, V}}, {{A, R}, {C, V}}, --R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); {{A, R}, {sBx, V}}, --if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx } {{A, R}, {B, V}, {C, V}}, {{A, R}, {Bx, V}}, {{A, R}, {B, V}}, {{Ax, V}} } local OPMT = {__tostring = function(self) local r = {"A", "B", "C", "Ax", "Bx", "sBx"} local r2 = {} for _,v in ipairs(r) do if v == "sBx" and self.to then table.insert(r2,string.format("to=%s",self.to)) elseif self[v] then table.insert(r2,string.format("%s=%s",v,tostring(self[v]))) end end return string.format("%s(%s)",self.op, table.concat(r2, ', ')) end} local function instruction(ctx, int, position) -- 6 8 9 9 local op = bit.band(int, 0x3f)+1 local A = bit.rshift(bit.band(int, 0x3fc0), 6) local C = bit.rshift(bit.band(int, 0x7fc000), 6+8) local B = bit.rshift(bit.band(int, 0xff800000), 6+8+9) local Ax = bit.rshift(int, 6) local Bx = bit.lshift(B, 9)+C local sBx = Bx - 131071 local this = {A = A, B = B, C = C, Ax = Ax, Bx = Bx, sBx = sBx } if not OPCODES[op] then error("Opcode " .. op .. " not found!") end local inst = setmetatable({op = OPCODES[op]}, OPMT) for _,v in ipairs(ARGS[op]) do inst[v[1]] = v[2](ctx, this[v[1]], position) end return inst end local function serialize(instruction) -- data, pos, ctx local op = OPCODES[instruction.op] local A = function(int) return bit.lshift(bit.band(int, 0xff), 6) end local C = function(int) return bit.lshift(bit.band(int, 0x1ff), 6+8) end local B = function(int) return bit.lshift(bit.band(int, 0x1ff), 6+8+9) end local Ax = function(int) return bit.lshift(int, 6) end local Bx = function(int) return bit.lshift(int, 14) end local sBx = function(int) return Bx(int + 131071) end local this = {A = A, B = B, C = C, Ax = Ax, Bx = Bx, sBx = sBx } local serialized_instruction = op - 1 for i, parameter in ipairs(ARGS[op]) do local type = unpack(parameter) local arg = instruction[type] serialized_instruction = bit.bor(serialized_instruction, this[type](arg.raw)) end return serialized_instruction end local function make(ctx, pc, name, ...) local op = OPCODES[name] assert(ARGS[op], tostring(name)) local inst = setmetatable({op = OPCODES[op]}, OPMT) local arguments = {...} assert( #ARGS[op] == #arguments, "Wrong number of arguments for " .. name .. ", expecting " .. #ARGS[op] .. " but got " .. #arguments .. " instead.") for i, parameter in ipairs(ARGS[op]) do local type, func = unpack(parameter) inst[type] = func(ctx, arguments[i], pc) end return inst end return {instruction = instruction, serialize = serialize, make = make, OPCODES = OPCODES, ARGS = ARGS, OPMT = OPMT}