From 2d1df4714e2736dbde7855ddcd76b4c1de822fa5 Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Mon, 23 Jan 2012 21:58:02 +1000 Subject: Added a big bunch of example lua scripts for testing the speed of lua compiling. --- LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/lcode.lua | 1125 +++++++++++++++++++++ 1 file changed, 1125 insertions(+) create mode 100644 LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/lcode.lua (limited to 'LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/lcode.lua') diff --git a/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/lcode.lua b/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/lcode.lua new file mode 100644 index 0000000..4dc8548 --- /dev/null +++ b/LuaSL/testLua/yueliang-0.4.1/orig-5.1.3/lcode.lua @@ -0,0 +1,1125 @@ +--[[-------------------------------------------------------------------- + + lcode.lua + Lua 5 code generator in Lua + This file is part of Yueliang. + + Copyright (c) 2005-2007 Kein-Hong Man + The COPYRIGHT file describes the conditions + under which this software may be distributed. + + See the ChangeLog for more information. + +----------------------------------------------------------------------]] + +--[[-------------------------------------------------------------------- +-- Notes: +-- * one function manipulate a pointer argument with a simple data type +-- (can't be emulated by a table, ambiguous), now returns that value: +-- luaK:concat(fs, l1, l2) +-- * luaM_growvector uses the faux luaY:growvector, for limit checking +-- * some function parameters changed to boolean, additional code +-- translates boolean back to 1/0 for instruction fields +-- +-- Not implemented: +-- * NOTE there is a failed assert in luaK:addk, a porting problem +-- +-- Added: +-- * constant MAXSTACK from llimits.h +-- * luaK:ttisnumber(o) (from lobject.h) +-- * luaK:nvalue(o) (from lobject.h) +-- * luaK:setnilvalue(o) (from lobject.h) +-- * luaK:setnvalue(o, x) (from lobject.h) +-- * luaK:setbvalue(o, x) (from lobject.h) +-- * luaK:sethvalue(o, x) (from lobject.h), parameter L deleted +-- * luaK:setsvalue(o, x) (from lobject.h), parameter L deleted +-- * luaK:numadd, luaK:numsub, luaK:nummul, luaK:numdiv, luaK:nummod, +-- luaK:numpow, luaK:numunm, luaK:numisnan (from luaconf.h) +-- * copyexp(e1, e2) added in luaK:posfix to copy expdesc struct +-- +-- Changed in 5.1.x: +-- * enum BinOpr has a new entry, OPR_MOD +-- * enum UnOpr has a new entry, OPR_LEN +-- * binopistest, unused in 5.0.x, has been deleted +-- * macro setmultret is new +-- * functions isnumeral, luaK_ret, boolK are new +-- * funcion nilK was named nil_constant in 5.0.x +-- * function interface changed: need_value, patchtestreg, concat +-- * TObject now a TValue +-- * functions luaK_setreturns, luaK_setoneret are new +-- * function luaK:setcallreturns deleted, to be replaced by: +-- luaK:setmultret, luaK:ret, luaK:setreturns, luaK:setoneret +-- * functions constfolding, codearith, codecomp are new +-- * luaK:codebinop has been deleted +-- * function luaK_setlist is new +-- * OPR_MULT renamed to OPR_MUL +----------------------------------------------------------------------]] + +-- requires luaP, luaX, luaY +luaK = {} + +------------------------------------------------------------------------ +-- constants used by code generator +------------------------------------------------------------------------ +-- maximum stack for a Lua function +luaK.MAXSTACK = 250 -- (from llimits.h) + +--[[-------------------------------------------------------------------- +-- other functions +----------------------------------------------------------------------]] + +------------------------------------------------------------------------ +-- emulation of TValue macros (these are from lobject.h) +-- * TValue is a table since lcode passes references around +-- * tt member field removed, using Lua's type() instead +-- * for setsvalue, sethvalue, parameter L (deleted here) in lobject.h +-- is used in an assert for testing, see checkliveness(g,obj) +------------------------------------------------------------------------ +function luaK:ttisnumber(o) + if o then return type(o.value) == "number" else return false end +end +function luaK:nvalue(o) return o.value end +function luaK:setnilvalue(o) o.value = nil end +function luaK:setsvalue(o, x) o.value = x end +luaK.setnvalue = luaK.setsvalue +luaK.sethvalue = luaK.setsvalue +luaK.setbvalue = luaK.setsvalue + +------------------------------------------------------------------------ +-- The luai_num* macros define the primitive operations over numbers. +-- * this is not the entire set of primitive operations from luaconf.h +-- * used in luaK:constfolding() +------------------------------------------------------------------------ +function luaK:numadd(a, b) return a + b end +function luaK:numsub(a, b) return a - b end +function luaK:nummul(a, b) return a * b end +function luaK:numdiv(a, b) return a / b end +function luaK:nummod(a, b) return a % b end + -- ((a) - floor((a)/(b))*(b)) /* actual, for reference */ +function luaK:numpow(a, b) return a ^ b end +function luaK:numunm(a) return -a end +function luaK:numisnan(a) return not a == a end + -- a NaN cannot equal another NaN + +--[[-------------------------------------------------------------------- +-- code generator functions +----------------------------------------------------------------------]] + +------------------------------------------------------------------------ +-- Marks the end of a patch list. It is an invalid value both as an absolute +-- address, and as a list link (would link an element to itself). +------------------------------------------------------------------------ +luaK.NO_JUMP = -1 + +------------------------------------------------------------------------ +-- grep "ORDER OPR" if you change these enums +------------------------------------------------------------------------ +luaK.BinOpr = { + OPR_ADD = 0, OPR_SUB = 1, OPR_MUL = 2, OPR_DIV = 3, OPR_MOD = 4, OPR_POW = 5, + OPR_CONCAT = 6, + OPR_NE = 7, OPR_EQ = 8, + OPR_LT = 9, OPR_LE = 10, OPR_GT = 11, OPR_GE = 12, + OPR_AND = 13, OPR_OR = 14, + OPR_NOBINOPR = 15, +} + +-- * UnOpr is used by luaK:prefix's op argument, but not directly used +-- because the function receives the symbols as strings, e.g. "OPR_NOT" +luaK.UnOpr = { + OPR_MINUS = 0, OPR_NOT = 1, OPR_LEN = 2, OPR_NOUNOPR = 3 +} + +------------------------------------------------------------------------ +-- returns the instruction object for given e (expdesc), was a macro +------------------------------------------------------------------------ +function luaK:getcode(fs, e) + return fs.f.code[e.info] +end + +------------------------------------------------------------------------ +-- codes an instruction with a signed Bx (sBx) field, was a macro +-- * used in luaK:jump(), (lparser) luaY:forbody() +------------------------------------------------------------------------ +function luaK:codeAsBx(fs, o, A, sBx) + return self:codeABx(fs, o, A, sBx + luaP.MAXARG_sBx) +end + +------------------------------------------------------------------------ +-- set the expdesc e instruction for multiple returns, was a macro +------------------------------------------------------------------------ +function luaK:setmultret(fs, e) + self:setreturns(fs, e, luaY.LUA_MULTRET) +end + +------------------------------------------------------------------------ +-- there is a jump if patch lists are not identical, was a macro +-- * used in luaK:exp2reg(), luaK:exp2anyreg(), luaK:exp2val() +------------------------------------------------------------------------ +function luaK:hasjumps(e) + return e.t ~= e.f +end + +------------------------------------------------------------------------ +-- true if the expression is a constant number (for constant folding) +-- * used in constfolding(), infix() +------------------------------------------------------------------------ +function luaK:isnumeral(e) + return e.k == "VKNUM" and e.t == self.NO_JUMP and e.f == self.NO_JUMP +end + +------------------------------------------------------------------------ +-- codes loading of nil, optimization done if consecutive locations +-- * used in luaK:discharge2reg(), (lparser) luaY:adjust_assign() +------------------------------------------------------------------------ +function luaK:_nil(fs, from, n) + if fs.pc > fs.lasttarget then -- no jumps to current position? + if fs.pc == 0 then -- function start? + if from >= fs.nactvar then + return -- positions are already clean + end + else + local previous = fs.f.code[fs.pc - 1] + if luaP:GET_OPCODE(previous) == "OP_LOADNIL" then + local pfrom = luaP:GETARG_A(previous) + local pto = luaP:GETARG_B(previous) + if pfrom <= from and from <= pto + 1 then -- can connect both? + if from + n - 1 > pto then + luaP:SETARG_B(previous, from + n - 1) + end + return + end + end + end + end + self:codeABC(fs, "OP_LOADNIL", from, from + n - 1, 0) -- else no optimization +end + +------------------------------------------------------------------------ +-- +-- * used in multiple locations +------------------------------------------------------------------------ +function luaK:jump(fs) + local jpc = fs.jpc -- save list of jumps to here + fs.jpc = self.NO_JUMP + local j = self:codeAsBx(fs, "OP_JMP", 0, self.NO_JUMP) + j = self:concat(fs, j, jpc) -- keep them on hold + return j +end + +------------------------------------------------------------------------ +-- codes a RETURN instruction +-- * used in luaY:close_func(), luaY:retstat() +------------------------------------------------------------------------ +function luaK:ret(fs, first, nret) + self:codeABC(fs, "OP_RETURN", first, nret + 1, 0) +end + +------------------------------------------------------------------------ +-- +-- * used in luaK:jumponcond(), luaK:codecomp() +------------------------------------------------------------------------ +function luaK:condjump(fs, op, A, B, C) + self:codeABC(fs, op, A, B, C) + return self:jump(fs) +end + +------------------------------------------------------------------------ +-- +-- * used in luaK:patchlistaux(), luaK:concat() +------------------------------------------------------------------------ +function luaK:fixjump(fs, pc, dest) + local jmp = fs.f.code[pc] + local offset = dest - (pc + 1) + lua_assert(dest ~= self.NO_JUMP) + if math.abs(offset) > luaP.MAXARG_sBx then + luaX:syntaxerror(fs.ls, "control structure too long") + end + luaP:SETARG_sBx(jmp, offset) +end + +------------------------------------------------------------------------ +-- returns current 'pc' and marks it as a jump target (to avoid wrong +-- optimizations with consecutive instructions not in the same basic block). +-- * used in multiple locations +-- * fs.lasttarget tested only by luaK:_nil() when optimizing OP_LOADNIL +------------------------------------------------------------------------ +function luaK:getlabel(fs) + fs.lasttarget = fs.pc + return fs.pc +end + +------------------------------------------------------------------------ +-- +-- * used in luaK:need_value(), luaK:removevalues(), luaK:patchlistaux(), +-- luaK:concat() +------------------------------------------------------------------------ +function luaK:getjump(fs, pc) + local offset = luaP:GETARG_sBx(fs.f.code[pc]) + if offset == self.NO_JUMP then -- point to itself represents end of list + return self.NO_JUMP -- end of list + else + return (pc + 1) + offset -- turn offset into absolute position + end +end + +------------------------------------------------------------------------ +-- +-- * used in luaK:need_value(), luaK:patchtestreg(), luaK:invertjump() +------------------------------------------------------------------------ +function luaK:getjumpcontrol(fs, pc) + local pi = fs.f.code[pc] + local ppi = fs.f.code[pc - 1] + if pc >= 1 and luaP:testTMode(luaP:GET_OPCODE(ppi)) ~= 0 then + return ppi + else + return pi + end +end + +------------------------------------------------------------------------ +-- check whether list has any jump that do not produce a value +-- (or produce an inverted value) +-- * return value changed to boolean +-- * used only in luaK:exp2reg() +------------------------------------------------------------------------ +function luaK:need_value(fs, list) + while list ~= self.NO_JUMP do + local i = self:getjumpcontrol(fs, list) + if luaP:GET_OPCODE(i) ~= "OP_TESTSET" then return true end + list = self:getjump(fs, list) + end + return false -- not found +end + +------------------------------------------------------------------------ +-- +-- * used in luaK:removevalues(), luaK:patchlistaux() +------------------------------------------------------------------------ +function luaK:patchtestreg(fs, node, reg) + local i = self:getjumpcontrol(fs, node) + if luaP:GET_OPCODE(i) ~= "OP_TESTSET" then + return false -- cannot patch other instructions + end + if reg ~= luaP.NO_REG and reg ~= luaP:GETARG_B(i) then + luaP:SETARG_A(i, reg) + else -- no register to put value or register already has the value + -- due to use of a table as i, i cannot be replaced by another table + -- so the following is required; there is no change to ARG_C + luaP:SET_OPCODE(i, "OP_TEST") + local b = luaP:GETARG_B(i) + luaP:SETARG_A(i, b) + luaP:SETARG_B(i, 0) + -- *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); /* C */ + end + return true +end + +------------------------------------------------------------------------ +-- +-- * used only in luaK:codenot() +------------------------------------------------------------------------ +function luaK:removevalues(fs, list) + while list ~= self.NO_JUMP do + self:patchtestreg(fs, list, luaP.NO_REG) + list = self:getjump(fs, list) + end +end + +------------------------------------------------------------------------ +-- +-- * used in luaK:dischargejpc(), luaK:patchlist(), luaK:exp2reg() +------------------------------------------------------------------------ +function luaK:patchlistaux(fs, list, vtarget, reg, dtarget) + while list ~= self.NO_JUMP do + local _next = self:getjump(fs, list) + if self:patchtestreg(fs, list, reg) then + self:fixjump(fs, list, vtarget) + else + self:fixjump(fs, list, dtarget) -- jump to default target + end + list = _next + end +end + +------------------------------------------------------------------------ +-- +-- * used only in luaK:code() +------------------------------------------------------------------------ +function luaK:dischargejpc(fs) + self:patchlistaux(fs, fs.jpc, fs.pc, luaP.NO_REG, fs.pc) + fs.jpc = self.NO_JUMP +end + +------------------------------------------------------------------------ +-- +-- * used in (lparser) luaY:whilestat(), luaY:repeatstat(), luaY:forbody() +------------------------------------------------------------------------ +function luaK:patchlist(fs, list, target) + if target == fs.pc then + self:patchtohere(fs, list) + else + lua_assert(target < fs.pc) + self:patchlistaux(fs, list, target, luaP.NO_REG, target) + end +end + +------------------------------------------------------------------------ +-- +-- * used in multiple locations +------------------------------------------------------------------------ +function luaK:patchtohere(fs, list) + self:getlabel(fs) + fs.jpc = self:concat(fs, fs.jpc, list) +end + +------------------------------------------------------------------------ +-- * l1 was a pointer, now l1 is returned and callee assigns the value +-- * used in multiple locations +------------------------------------------------------------------------ +function luaK:concat(fs, l1, l2) + if l2 == self.NO_JUMP then return l1 + elseif l1 == self.NO_JUMP then + return l2 + else + local list = l1 + local _next = self:getjump(fs, list) + while _next ~= self.NO_JUMP do -- find last element + list = _next + _next = self:getjump(fs, list) + end + self:fixjump(fs, list, l2) + end + return l1 +end + +------------------------------------------------------------------------ +-- +-- * used in luaK:reserveregs(), (lparser) luaY:forlist() +------------------------------------------------------------------------ +function luaK:checkstack(fs, n) + local newstack = fs.freereg + n + if newstack > fs.f.maxstacksize then + if newstack >= self.MAXSTACK then + luaX:syntaxerror(fs.ls, "function or expression too complex") + end + fs.f.maxstacksize = newstack + end +end + +------------------------------------------------------------------------ +-- +-- * used in multiple locations +------------------------------------------------------------------------ +function luaK:reserveregs(fs, n) + self:checkstack(fs, n) + fs.freereg = fs.freereg + n +end + +------------------------------------------------------------------------ +-- +-- * used in luaK:freeexp(), luaK:dischargevars() +------------------------------------------------------------------------ +function luaK:freereg(fs, reg) + if not luaP:ISK(reg) and reg >= fs.nactvar then + fs.freereg = fs.freereg - 1 + lua_assert(reg == fs.freereg) + end +end + +------------------------------------------------------------------------ +-- +-- * used in multiple locations +------------------------------------------------------------------------ +function luaK:freeexp(fs, e) + if e.k == "VNONRELOC" then + self:freereg(fs, e.info) + end +end + +------------------------------------------------------------------------ +-- * TODO NOTE implementation is not 100% correct, since the assert fails +-- * luaH_set, setobj deleted; direct table access used instead +-- * used in luaK:stringK(), luaK:numberK(), luaK:boolK(), luaK:nilK() +------------------------------------------------------------------------ +function luaK:addk(fs, k, v) + local L = fs.L + local idx = fs.h[k.value] + --TValue *idx = luaH_set(L, fs->h, k); /* C */ + local f = fs.f + if self:ttisnumber(idx) then + --TODO this assert currently FAILS (last tested for 5.0.2) + --lua_assert(fs.f.k[self:nvalue(idx)] == v) + --lua_assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v)); /* C */ + return self:nvalue(idx) + else -- constant not found; create a new entry + idx = {} + self:setnvalue(idx, fs.nk) + fs.h[k.value] = idx + -- setnvalue(idx, cast_num(fs->nk)); /* C */ + luaY:growvector(L, f.k, fs.nk, f.sizek, nil, + luaP.MAXARG_Bx, "constant table overflow") + -- loop to initialize empty f.k positions not required + f.k[fs.nk] = v + -- setobj(L, &f->k[fs->nk], v); /* C */ + -- luaC_barrier(L, f, v); /* GC */ + local nk = fs.nk + fs.nk = fs.nk + 1 + return nk + end + +end + +------------------------------------------------------------------------ +-- creates and sets a string object +-- * used in (lparser) luaY:codestring(), luaY:singlevar() +------------------------------------------------------------------------ +function luaK:stringK(fs, s) + local o = {} -- TValue + self:setsvalue(o, s) + return self:addk(fs, o, o) +end + +------------------------------------------------------------------------ +-- creates and sets a number object +-- * used in luaK:prefix() for negative (or negation of) numbers +-- * used in (lparser) luaY:simpleexp(), luaY:fornum() +------------------------------------------------------------------------ +function luaK:numberK(fs, r) + local o = {} -- TValue + self:setnvalue(o, r) + return self:addk(fs, o, o) +end + +------------------------------------------------------------------------ +-- creates and sets a boolean object +-- * used only in luaK:exp2RK() +------------------------------------------------------------------------ +function luaK:boolK(fs, b) + local o = {} -- TValue + self:setbvalue(o, b) + return self:addk(fs, o, o) +end + +------------------------------------------------------------------------ +-- creates and sets a nil object +-- * used only in luaK:exp2RK() +------------------------------------------------------------------------ +function luaK:nilK(fs) + local k, v = {}, {} -- TValue + self:setnilvalue(v) + -- cannot use nil as key; instead use table itself to represent nil + self:sethvalue(k, fs.h) + return self:addk(fs, k, v) +end + +------------------------------------------------------------------------ +-- +-- * used in luaK:setmultret(), (lparser) luaY:adjust_assign() +------------------------------------------------------------------------ +function luaK:setreturns(fs, e, nresults) + if e.k == "VCALL" then -- expression is an open function call? + luaP:SETARG_C(self:getcode(fs, e), nresults + 1) + elseif e.k == "VVARARG" then + luaP:SETARG_B(self:getcode(fs, e), nresults + 1); + luaP:SETARG_A(self:getcode(fs, e), fs.freereg); + luaK:reserveregs(fs, 1) + end +end + +------------------------------------------------------------------------ +-- +-- * used in luaK:dischargevars(), (lparser) luaY:assignment() +------------------------------------------------------------------------ +function luaK:setoneret(fs, e) + if e.k == "VCALL" then -- expression is an open function call? + e.k = "VNONRELOC" + e.info = luaP:GETARG_A(self:getcode(fs, e)) + elseif e.k == "VVARARG" then + luaP:SETARG_B(self:getcode(fs, e), 2) + e.k = "VRELOCABLE" -- can relocate its simple result + end +end + +------------------------------------------------------------------------ +-- +-- * used in multiple locations +------------------------------------------------------------------------ +function luaK:dischargevars(fs, e) + local k = e.k + if k == "VLOCAL" then + e.k = "VNONRELOC" + elseif k == "VUPVAL" then + e.info = self:codeABC(fs, "OP_GETUPVAL", 0, e.info, 0) + e.k = "VRELOCABLE" + elseif k == "VGLOBAL" then + e.info = self:codeABx(fs, "OP_GETGLOBAL", 0, e.info) + e.k = "VRELOCABLE" + elseif k == "VINDEXED" then + self:freereg(fs, e.aux) + self:freereg(fs, e.info) + e.info = self:codeABC(fs, "OP_GETTABLE", 0, e.info, e.aux) + e.k = "VRELOCABLE" + elseif k == "VVARARG" or k == "VCALL" then + self:setoneret(fs, e) + else + -- there is one value available (somewhere) + end +end + +------------------------------------------------------------------------ +-- +-- * used only in luaK:exp2reg() +------------------------------------------------------------------------ +function luaK:code_label(fs, A, b, jump) + self:getlabel(fs) -- those instructions may be jump targets + return self:codeABC(fs, "OP_LOADBOOL", A, b, jump) +end + +------------------------------------------------------------------------ +-- +-- * used in luaK:discharge2anyreg(), luaK:exp2reg() +------------------------------------------------------------------------ +function luaK:discharge2reg(fs, e, reg) + self:dischargevars(fs, e) + local k = e.k + if k == "VNIL" then + self:_nil(fs, reg, 1) + elseif k == "VFALSE" or k == "VTRUE" then + self:codeABC(fs, "OP_LOADBOOL", reg, (e.k == "VTRUE") and 1 or 0, 0) + elseif k == "VK" then + self:codeABx(fs, "OP_LOADK", reg, e.info) + elseif k == "VKNUM" then + self:codeABx(fs, "OP_LOADK", reg, self:numberK(fs, e.nval)) + elseif k == "VRELOCABLE" then + local pc = self:getcode(fs, e) + luaP:SETARG_A(pc, reg) + elseif k == "VNONRELOC" then + if reg ~= e.info then + self:codeABC(fs, "OP_MOVE", reg, e.info, 0) + end + else + lua_assert(e.k == "VVOID" or e.k == "VJMP") + return -- nothing to do... + end + e.info = reg + e.k = "VNONRELOC" +end + +------------------------------------------------------------------------ +-- +-- * used in luaK:jumponcond(), luaK:codenot() +------------------------------------------------------------------------ +function luaK:discharge2anyreg(fs, e) + if e.k ~= "VNONRELOC" then + self:reserveregs(fs, 1) + self:discharge2reg(fs, e, fs.freereg - 1) + end +end + +------------------------------------------------------------------------ +-- +-- * used in luaK:exp2nextreg(), luaK:exp2anyreg(), luaK:storevar() +------------------------------------------------------------------------ +function luaK:exp2reg(fs, e, reg) + self:discharge2reg(fs, e, reg) + if e.k == "VJMP" then + e.t = self:concat(fs, e.t, e.info) -- put this jump in 't' list + end + if self:hasjumps(e) then + local final -- position after whole expression + local p_f = self.NO_JUMP -- position of an eventual LOAD false + local p_t = self.NO_JUMP -- position of an eventual LOAD true + if self:need_value(fs, e.t) or self:need_value(fs, e.f) then + local fj = (e.k == "VJMP") and self.NO_JUMP or self:jump(fs) + p_f = self:code_label(fs, reg, 0, 1) + p_t = self:code_label(fs, reg, 1, 0) + self:patchtohere(fs, fj) + end + final = self:getlabel(fs) + self:patchlistaux(fs, e.f, final, reg, p_f) + self:patchlistaux(fs, e.t, final, reg, p_t) + end + e.f, e.t = self.NO_JUMP, self.NO_JUMP + e.info = reg + e.k = "VNONRELOC" +end + +------------------------------------------------------------------------ +-- +-- * used in multiple locations +------------------------------------------------------------------------ +function luaK:exp2nextreg(fs, e) + self:dischargevars(fs, e) + self:freeexp(fs, e) + self:reserveregs(fs, 1) + self:exp2reg(fs, e, fs.freereg - 1) +end + +------------------------------------------------------------------------ +-- +-- * used in multiple locations +------------------------------------------------------------------------ +function luaK:exp2anyreg(fs, e) + self:dischargevars(fs, e) + if e.k == "VNONRELOC" then + if not self:hasjumps(e) then -- exp is already in a register + return e.info + end + if e.info >= fs.nactvar then -- reg. is not a local? + self:exp2reg(fs, e, e.info) -- put value on it + return e.info + end + end + self:exp2nextreg(fs, e) -- default + return e.info +end + +------------------------------------------------------------------------ +-- +-- * used in luaK:exp2RK(), luaK:prefix(), luaK:posfix() +-- * used in (lparser) luaY:yindex() +------------------------------------------------------------------------ +function luaK:exp2val(fs, e) + if self:hasjumps(e) then + self:exp2anyreg(fs, e) + else + self:dischargevars(fs, e) + end +end + +------------------------------------------------------------------------ +-- +-- * used in multiple locations +------------------------------------------------------------------------ +function luaK:exp2RK(fs, e) + self:exp2val(fs, e) + local k = e.k + if k == "VKNUM" or k == "VTRUE" or k == "VFALSE" or k == "VNIL" then + if fs.nk <= luaP.MAXINDEXRK then -- constant fit in RK operand? + -- converted from a 2-deep ternary operator expression + if e.k == "VNIL" then + e.info = self:nilK(fs) + else + e.info = (e.k == "VKNUM") and self:numberK(fs, e.nval) + or self:boolK(fs, e.k == "VTRUE") + end + e.k = "VK" + return luaP:RKASK(e.info) + end + elseif k == "VK" then + if e.info <= luaP.MAXINDEXRK then -- constant fit in argC? + return luaP:RKASK(e.info) + end + else + -- default + end + -- not a constant in the right range: put it in a register + return self:exp2anyreg(fs, e) +end + +------------------------------------------------------------------------ +-- +-- * used in (lparser) luaY:assignment(), luaY:localfunc(), luaY:funcstat() +------------------------------------------------------------------------ +function luaK:storevar(fs, var, ex) + local k = var.k + if k == "VLOCAL" then + self:freeexp(fs, ex) + self:exp2reg(fs, ex, var.info) + return + elseif k == "VUPVAL" then + local e = self:exp2anyreg(fs, ex) + self:codeABC(fs, "OP_SETUPVAL", e, var.info, 0) + elseif k == "VGLOBAL" then + local e = self:exp2anyreg(fs, ex) + self:codeABx(fs, "OP_SETGLOBAL", e, var.info) + elseif k == "VINDEXED" then + local e = self:exp2RK(fs, ex) + self:codeABC(fs, "OP_SETTABLE", var.info, var.aux, e) + else + lua_assert(0) -- invalid var kind to store + end + self:freeexp(fs, ex) +end + +------------------------------------------------------------------------ +-- +-- * used only in (lparser) luaY:primaryexp() +------------------------------------------------------------------------ +function luaK:_self(fs, e, key) + self:exp2anyreg(fs, e) + self:freeexp(fs, e) + local func = fs.freereg + self:reserveregs(fs, 2) + self:codeABC(fs, "OP_SELF", func, e.info, self:exp2RK(fs, key)) + self:freeexp(fs, key) + e.info = func + e.k = "VNONRELOC" +end + +------------------------------------------------------------------------ +-- +-- * used in luaK:goiftrue(), luaK:codenot() +------------------------------------------------------------------------ +function luaK:invertjump(fs, e) + local pc = self:getjumpcontrol(fs, e.info) + lua_assert(luaP:testTMode(luaP:GET_OPCODE(pc)) ~= 0 and + luaP:GET_OPCODE(pc) ~= "OP_TESTSET" and + luaP:GET_OPCODE(pc) ~= "OP_TEST") + luaP:SETARG_A(pc, (luaP:GETARG_A(pc) == 0) and 1 or 0) +end + +------------------------------------------------------------------------ +-- +-- * used in luaK:goiftrue(), luaK:goiffalse() +------------------------------------------------------------------------ +function luaK:jumponcond(fs, e, cond) + if e.k == "VRELOCABLE" then + local ie = self:getcode(fs, e) + if luaP:GET_OPCODE(ie) == "OP_NOT" then + fs.pc = fs.pc - 1 -- remove previous OP_NOT + return self:condjump(fs, "OP_TEST", luaP:GETARG_B(ie), 0, cond and 0 or 1) + end + -- else go through + end + self:discharge2anyreg(fs, e) + self:freeexp(fs, e) + return self:condjump(fs, "OP_TESTSET", luaP.NO_REG, e.info, cond and 1 or 0) +end + +------------------------------------------------------------------------ +-- +-- * used in luaK:infix(), (lparser) luaY:cond() +------------------------------------------------------------------------ +function luaK:goiftrue(fs, e) + local pc -- pc of last jump + self:dischargevars(fs, e) + local k = e.k + if k == "VK" or k == "VKNUM" or k == "VTRUE" then + pc = self.NO_JUMP -- always true; do nothing + elseif k == "VFALSE" then + pc = self:jump(fs) -- always jump + elseif k == "VJMP" then + self:invertjump(fs, e) + pc = e.info + else + pc = self:jumponcond(fs, e, false) + end + e.f = self:concat(fs, e.f, pc) -- insert last jump in `f' list + self:patchtohere(fs, e.t) + e.t = self.NO_JUMP +end + +------------------------------------------------------------------------ +-- +-- * used in luaK:infix() +------------------------------------------------------------------------ +function luaK:goiffalse(fs, e) + local pc -- pc of last jump + self:dischargevars(fs, e) + local k = e.k + if k == "VNIL" or k == "VFALSE"then + pc = self.NO_JUMP -- always false; do nothing + elseif k == "VTRUE" then + pc = self:jump(fs) -- always jump + elseif k == "VJMP" then + pc = e.info + else + pc = self:jumponcond(fs, e, true) + end + e.t = self:concat(fs, e.t, pc) -- insert last jump in `t' list + self:patchtohere(fs, e.f) + e.f = self.NO_JUMP +end + +------------------------------------------------------------------------ +-- +-- * used only in luaK:prefix() +------------------------------------------------------------------------ +function luaK:codenot(fs, e) + self:dischargevars(fs, e) + local k = e.k + if k == "VNIL" or k == "VFALSE" then + e.k = "VTRUE" + elseif k == "VK" or k == "VKNUM" or k == "VTRUE" then + e.k = "VFALSE" + elseif k == "VJMP" then + self:invertjump(fs, e) + elseif k == "VRELOCABLE" or k == "VNONRELOC" then + self:discharge2anyreg(fs, e) + self:freeexp(fs, e) + e.info = self:codeABC(fs, "OP_NOT", 0, e.info, 0) + e.k = "VRELOCABLE" + else + lua_assert(0) -- cannot happen + end + -- interchange true and false lists + e.f, e.t = e.t, e.f + self:removevalues(fs, e.f) + self:removevalues(fs, e.t) +end + +------------------------------------------------------------------------ +-- +-- * used in (lparser) luaY:field(), luaY:primaryexp() +------------------------------------------------------------------------ +function luaK:indexed(fs, t, k) + t.aux = self:exp2RK(fs, k) + t.k = "VINDEXED" +end + +------------------------------------------------------------------------ +-- +-- * used only in luaK:codearith() +------------------------------------------------------------------------ +function luaK:constfolding(op, e1, e2) + local r + if not self:isnumeral(e1) or not self:isnumeral(e2) then return false end + local v1 = e1.nval + local v2 = e2.nval + if op == "OP_ADD" then + r = self:numadd(v1, v2) + elseif op == "OP_SUB" then + r = self:numsub(v1, v2) + elseif op == "OP_MUL" then + r = self:nummul(v1, v2) + elseif op == "OP_DIV" then + if v2 == 0 then return false end -- do not attempt to divide by 0 + r = self:numdiv(v1, v2) + elseif op == "OP_MOD" then + if v2 == 0 then return false end -- do not attempt to divide by 0 + r = self:nummod(v1, v2) + elseif op == "OP_POW" then + r = self:numpow(v1, v2) + elseif op == "OP_UNM" then + r = self:numunm(v1) + elseif op == "OP_LEN" then + return false -- no constant folding for 'len' + else + lua_assert(0) + r = 0 + end + if self:numisnan(r) then return false end -- do not attempt to produce NaN + e1.nval = r + return true +end + +------------------------------------------------------------------------ +-- +-- * used in luaK:prefix(), luaK:posfix() +------------------------------------------------------------------------ +function luaK:codearith(fs, op, e1, e2) + if self:constfolding(op, e1, e2) then + return + else + local o2 = (op ~= "OP_UNM" and op ~= "OP_LEN") and self:exp2RK(fs, e2) or 0 + local o1 = self:exp2RK(fs, e1) + if o1 > o2 then + self:freeexp(fs, e1) + self:freeexp(fs, e2) + else + self:freeexp(fs, e2) + self:freeexp(fs, e1) + end + e1.info = self:codeABC(fs, op, 0, o1, o2) + e1.k = "VRELOCABLE" + end +end + +------------------------------------------------------------------------ +-- +-- * used only in luaK:posfix() +------------------------------------------------------------------------ +function luaK:codecomp(fs, op, cond, e1, e2) + local o1 = self:exp2RK(fs, e1) + local o2 = self:exp2RK(fs, e2) + self:freeexp(fs, e2) + self:freeexp(fs, e1) + if cond == 0 and op ~= "OP_EQ" then + -- exchange args to replace by `<' or `<=' + o1, o2 = o2, o1 -- o1 <==> o2 + cond = 1 + end + e1.info = self:condjump(fs, op, cond, o1, o2) + e1.k = "VJMP" +end + +------------------------------------------------------------------------ +-- +-- * used only in (lparser) luaY:subexpr() +------------------------------------------------------------------------ +function luaK:prefix(fs, op, e) + local e2 = {} -- expdesc + e2.t, e2.f = self.NO_JUMP, self.NO_JUMP + e2.k = "VKNUM" + e2.nval = 0 + if op == "OPR_MINUS" then + if not self:isnumeral(e) then + self:exp2anyreg(fs, e) -- cannot operate on non-numeric constants + end + self:codearith(fs, "OP_UNM", e, e2) + elseif op == "OPR_NOT" then + self:codenot(fs, e) + elseif op == "OPR_LEN" then + self:exp2anyreg(fs, e) -- cannot operate on constants + self:codearith(fs, "OP_LEN", e, e2) + else + lua_assert(0) + end +end + +------------------------------------------------------------------------ +-- +-- * used only in (lparser) luaY:subexpr() +------------------------------------------------------------------------ +function luaK:infix(fs, op, v) + if op == "OPR_AND" then + self:goiftrue(fs, v) + elseif op == "OPR_OR" then + self:goiffalse(fs, v) + elseif op == "OPR_CONCAT" then + self:exp2nextreg(fs, v) -- operand must be on the 'stack' + elseif op == "OPR_ADD" or op == "OPR_SUB" or + op == "OPR_MUL" or op == "OPR_DIV" or + op == "OPR_MOD" or op == "OPR_POW" then + if not self:isnumeral(v) then self:exp2RK(fs, v) end + else + self:exp2RK(fs, v) + end +end + +------------------------------------------------------------------------ +-- +-- * used only in (lparser) luaY:subexpr() +------------------------------------------------------------------------ +-- table lookups to simplify testing +luaK.arith_op = { + OPR_ADD = "OP_ADD", OPR_SUB = "OP_SUB", OPR_MUL = "OP_MUL", + OPR_DIV = "OP_DIV", OPR_MOD = "OP_MOD", OPR_POW = "OP_POW", +} +luaK.comp_op = { + OPR_EQ = "OP_EQ", OPR_NE = "OP_EQ", OPR_LT = "OP_LT", + OPR_LE = "OP_LE", OPR_GT = "OP_LT", OPR_GE = "OP_LE", +} +luaK.comp_cond = { + OPR_EQ = 1, OPR_NE = 0, OPR_LT = 1, + OPR_LE = 1, OPR_GT = 0, OPR_GE = 0, +} +function luaK:posfix(fs, op, e1, e2) + -- needed because e1 = e2 doesn't copy values... + -- * in 5.0.x, only k/info/aux/t/f copied, t for AND, f for OR + -- but here, all elements are copied for completeness' sake + local function copyexp(e1, e2) + e1.k = e2.k + e1.info = e2.info; e1.aux = e2.aux + e1.nval = e2.nval + e1.t = e2.t; e1.f = e2.f + end + if op == "OPR_AND" then + lua_assert(e1.t == self.NO_JUMP) -- list must be closed + self:dischargevars(fs, e2) + e2.f = self:concat(fs, e2.f, e1.f) + copyexp(e1, e2) + elseif op == "OPR_OR" then + lua_assert(e1.f == self.NO_JUMP) -- list must be closed + self:dischargevars(fs, e2) + e2.t = self:concat(fs, e2.t, e1.t) + copyexp(e1, e2) + elseif op == "OPR_CONCAT" then + self:exp2val(fs, e2) + if e2.k == "VRELOCABLE" and luaP:GET_OPCODE(self:getcode(fs, e2)) == "OP_CONCAT" then + lua_assert(e1.info == luaP:GETARG_B(self:getcode(fs, e2)) - 1) + self:freeexp(fs, e1) + luaP:SETARG_B(self:getcode(fs, e2), e1.info) + e1.k = "VRELOCABLE" + e1.info = e2.info + else + self:exp2nextreg(fs, e2) -- operand must be on the 'stack' + self:codearith(fs, "OP_CONCAT", e1, e2) + end + else + -- the following uses a table lookup in place of conditionals + local arith = self.arith_op[op] + if arith then + self:codearith(fs, arith, e1, e2) + else + local comp = self.comp_op[op] + if comp then + self:codecomp(fs, comp, self.comp_cond[op], e1, e2) + else + lua_assert(0) + end + end--if arith + end--if op +end + +------------------------------------------------------------------------ +-- adjusts debug information for last instruction written, in order to +-- change the line where item comes into existence +-- * used in (lparser) luaY:funcargs(), luaY:forbody(), luaY:funcstat() +------------------------------------------------------------------------ +function luaK:fixline(fs, line) + fs.f.lineinfo[fs.pc - 1] = line +end + +------------------------------------------------------------------------ +-- general function to write an instruction into the instruction buffer, +-- sets debug information too +-- * used in luaK:codeABC(), luaK:codeABx() +-- * called directly by (lparser) luaY:whilestat() +------------------------------------------------------------------------ +function luaK:code(fs, i, line) + local f = fs.f + self:dischargejpc(fs) -- 'pc' will change + -- put new instruction in code array + luaY:growvector(fs.L, f.code, fs.pc, f.sizecode, nil, + luaY.MAX_INT, "code size overflow") + f.code[fs.pc] = i + -- save corresponding line information + luaY:growvector(fs.L, f.lineinfo, fs.pc, f.sizelineinfo, nil, + luaY.MAX_INT, "code size overflow") + f.lineinfo[fs.pc] = line + local pc = fs.pc + fs.pc = fs.pc + 1 + return pc +end + +------------------------------------------------------------------------ +-- writes an instruction of type ABC +-- * calls luaK:code() +------------------------------------------------------------------------ +function luaK:codeABC(fs, o, a, b, c) + lua_assert(luaP:getOpMode(o) == luaP.OpMode.iABC) + lua_assert(luaP:getBMode(o) ~= luaP.OpArgMask.OpArgN or b == 0) + lua_assert(luaP:getCMode(o) ~= luaP.OpArgMask.OpArgN or c == 0) + return self:code(fs, luaP:CREATE_ABC(o, a, b, c), fs.ls.lastline) +end + +------------------------------------------------------------------------ +-- writes an instruction of type ABx +-- * calls luaK:code(), called by luaK:codeAsBx() +------------------------------------------------------------------------ +function luaK:codeABx(fs, o, a, bc) + lua_assert(luaP:getOpMode(o) == luaP.OpMode.iABx or + luaP:getOpMode(o) == luaP.OpMode.iAsBx) + lua_assert(luaP:getCMode(o) == luaP.OpArgMask.OpArgN) + return self:code(fs, luaP:CREATE_ABx(o, a, bc), fs.ls.lastline) +end + +------------------------------------------------------------------------ +-- +-- * used in (lparser) luaY:closelistfield(), luaY:lastlistfield() +------------------------------------------------------------------------ +function luaK:setlist(fs, base, nelems, tostore) + local c = math.floor((nelems - 1)/luaP.LFIELDS_PER_FLUSH) + 1 + local b = (tostore == luaY.LUA_MULTRET) and 0 or tostore + lua_assert(tostore ~= 0) + if c <= luaP.MAXARG_C then + self:codeABC(fs, "OP_SETLIST", base, b, c) + else + self:codeABC(fs, "OP_SETLIST", base, b, 0) + self:code(fs, luaP:CREATE_Inst(c), fs.ls.lastline) + end + fs.freereg = base + 1 -- free registers with list values +end + -- cgit v1.1