mirror of
https://github.com/g012/l65.git
synced 2024-06-10 18:29:44 +00:00
442 lines
15 KiB
Lua
442 lines
15 KiB
Lua
-------------------------------------------------------------------------------
|
|
-- Copyright (c) 2005-2013 Kein-Hong Man, Fabien Fleutot and others.
|
|
--
|
|
-- All rights reserved.
|
|
--
|
|
-- This program and the accompanying materials are made available
|
|
-- under the terms of the Eclipse Public License v1.0 which
|
|
-- accompanies this distribution, and is available at
|
|
-- http://www.eclipse.org/legal/epl-v10.html
|
|
--
|
|
-- This program and the accompanying materials are also made available
|
|
-- under the terms of the MIT public license which accompanies this
|
|
-- distribution, and is available at http://www.lua.org/license.html
|
|
--
|
|
-- Contributors:
|
|
-- Kein-Hong Man - Initial implementation for Lua 5.0, part of Yueliang
|
|
-- Fabien Fleutot - Port to Lua 5.1, integration with Metalua
|
|
--
|
|
-------------------------------------------------------------------------------
|
|
|
|
--[[--------------------------------------------------------------------
|
|
|
|
$Id$
|
|
|
|
lopcodes.lua
|
|
Lua 5 virtual machine opcodes in Lua
|
|
This file is part of Yueliang.
|
|
|
|
Copyright (c) 2005 Kein-Hong Man <khman@users.sf.net>
|
|
The COPYRIGHT file describes the conditions
|
|
under which this software may be distributed.
|
|
|
|
See the ChangeLog for more information.
|
|
|
|
------------------------------------------------------------------------
|
|
|
|
[FF] Slightly modified, mainly to produce Lua 5.1 bytecode.
|
|
|
|
----------------------------------------------------------------------]]
|
|
|
|
--[[--------------------------------------------------------------------
|
|
-- Notes:
|
|
-- * an Instruction is a table with OP, A, B, C, Bx elements; this
|
|
-- should allow instruction handling to work with doubles and ints
|
|
-- * Added:
|
|
-- luaP:Instruction(i): convert field elements to a 4-char string
|
|
-- luaP:DecodeInst(x): convert 4-char string into field elements
|
|
-- * WARNING luaP:Instruction outputs instructions encoded in little-
|
|
-- endian form and field size and positions are hard-coded
|
|
----------------------------------------------------------------------]]
|
|
|
|
local function debugf() end
|
|
|
|
local luaP = { }
|
|
|
|
--[[
|
|
===========================================================================
|
|
We assume that instructions are unsigned numbers.
|
|
All instructions have an opcode in the first 6 bits.
|
|
Instructions can have the following fields:
|
|
'A' : 8 bits
|
|
'B' : 9 bits
|
|
'C' : 9 bits
|
|
'Bx' : 18 bits ('B' and 'C' together)
|
|
'sBx' : signed Bx
|
|
|
|
A signed argument is represented in excess K; that is, the number
|
|
value is the unsigned value minus K. K is exactly the maximum value
|
|
for that argument (so that -max is represented by 0, and +max is
|
|
represented by 2*max), which is half the maximum for the corresponding
|
|
unsigned argument.
|
|
===========================================================================
|
|
--]]
|
|
|
|
luaP.OpMode = {"iABC", "iABx", "iAsBx"} -- basic instruction format
|
|
|
|
------------------------------------------------------------------------
|
|
-- size and position of opcode arguments.
|
|
-- * WARNING size and position is hard-coded elsewhere in this script
|
|
------------------------------------------------------------------------
|
|
luaP.SIZE_C = 9
|
|
luaP.SIZE_B = 9
|
|
luaP.SIZE_Bx = luaP.SIZE_C + luaP.SIZE_B
|
|
luaP.SIZE_A = 8
|
|
|
|
luaP.SIZE_OP = 6
|
|
|
|
luaP.POS_C = luaP.SIZE_OP
|
|
luaP.POS_B = luaP.POS_C + luaP.SIZE_C
|
|
luaP.POS_Bx = luaP.POS_C
|
|
luaP.POS_A = luaP.POS_B + luaP.SIZE_B
|
|
|
|
--FF from 5.1
|
|
luaP.BITRK = 2^(luaP.SIZE_B - 1)
|
|
function luaP:ISK(x) return x >= self.BITRK end
|
|
luaP.MAXINDEXRK = luaP.BITRK - 1
|
|
function luaP:RKASK(x)
|
|
if x < self.BITRK then return x+self.BITRK else return x end
|
|
end
|
|
|
|
|
|
|
|
------------------------------------------------------------------------
|
|
-- limits for opcode arguments.
|
|
-- we use (signed) int to manipulate most arguments,
|
|
-- so they must fit in BITS_INT-1 bits (-1 for sign)
|
|
------------------------------------------------------------------------
|
|
-- removed "#if SIZE_Bx < BITS_INT-1" test, assume this script is
|
|
-- running on a Lua VM with double or int as LUA_NUMBER
|
|
|
|
luaP.MAXARG_Bx = math.ldexp(1, luaP.SIZE_Bx) - 1
|
|
luaP.MAXARG_sBx = math.floor(luaP.MAXARG_Bx / 2) -- 'sBx' is signed
|
|
|
|
luaP.MAXARG_A = math.ldexp(1, luaP.SIZE_A) - 1
|
|
luaP.MAXARG_B = math.ldexp(1, luaP.SIZE_B) - 1
|
|
luaP.MAXARG_C = math.ldexp(1, luaP.SIZE_C) - 1
|
|
|
|
-- creates a mask with 'n' 1 bits at position 'p'
|
|
-- MASK1(n,p) deleted
|
|
-- creates a mask with 'n' 0 bits at position 'p'
|
|
-- MASK0(n,p) deleted
|
|
|
|
--[[--------------------------------------------------------------------
|
|
Visual representation for reference:
|
|
|
|
31 | | | 0 bit position
|
|
+-----+-----+-----+----------+
|
|
| B | C | A | Opcode | iABC format
|
|
+-----+-----+-----+----------+
|
|
- 9 - 9 - 8 - 6 - field sizes
|
|
+-----+-----+-----+----------+
|
|
| [s]Bx | A | Opcode | iABx | iAsBx format
|
|
+-----+-----+-----+----------+
|
|
----------------------------------------------------------------------]]
|
|
|
|
------------------------------------------------------------------------
|
|
-- the following macros help to manipulate instructions
|
|
-- * changed to a table object representation, very clean compared to
|
|
-- the [nightmare] alternatives of using a number or a string
|
|
------------------------------------------------------------------------
|
|
|
|
-- these accept or return opcodes in the form of string names
|
|
function luaP:GET_OPCODE(i) return self.ROpCode[i.OP] end
|
|
function luaP:SET_OPCODE(i, o) i.OP = self.OpCode[o] end
|
|
|
|
function luaP:GETARG_A(i) return i.A end
|
|
function luaP:SETARG_A(i, u) i.A = u end
|
|
|
|
function luaP:GETARG_B(i) return i.B end
|
|
function luaP:SETARG_B(i, b) i.B = b end
|
|
|
|
function luaP:GETARG_C(i) return i.C end
|
|
function luaP:SETARG_C(i, b) i.C = b end
|
|
|
|
function luaP:GETARG_Bx(i) return i.Bx end
|
|
function luaP:SETARG_Bx(i, b) i.Bx = b end
|
|
|
|
function luaP:GETARG_sBx(i) return i.Bx - self.MAXARG_sBx end
|
|
function luaP:SETARG_sBx(i, b) i.Bx = b + self.MAXARG_sBx end
|
|
|
|
function luaP:CREATE_ABC(o,a,b,c)
|
|
return {OP = self.OpCode[o], A = a, B = b, C = c}
|
|
end
|
|
|
|
function luaP:CREATE_ABx(o,a,bc)
|
|
return {OP = self.OpCode[o], A = a, Bx = bc}
|
|
end
|
|
|
|
------------------------------------------------------------------------
|
|
-- Bit shuffling stuffs
|
|
------------------------------------------------------------------------
|
|
|
|
if false and pcall (require, 'bit') then
|
|
------------------------------------------------------------------------
|
|
-- Return a 4-char string little-endian encoded form of an instruction
|
|
------------------------------------------------------------------------
|
|
function luaP:Instruction(i)
|
|
--FIXME
|
|
end
|
|
else
|
|
------------------------------------------------------------------------
|
|
-- Version without bit manipulation library.
|
|
------------------------------------------------------------------------
|
|
local p2 = {1,2,4,8,16,32,64,128,256, 512, 1024, 2048, 4096}
|
|
-- keeps [n] bits from [x]
|
|
local function keep (x, n) return x % p2[n+1] end
|
|
-- shifts bits of [x] [n] places to the right
|
|
local function srb (x,n) return math.floor (x / p2[n+1]) end
|
|
-- shifts bits of [x] [n] places to the left
|
|
local function slb (x,n) return x * p2[n+1] end
|
|
|
|
------------------------------------------------------------------------
|
|
-- Return a 4-char string little-endian encoded form of an instruction
|
|
------------------------------------------------------------------------
|
|
function luaP:Instruction(i)
|
|
-- printf("Instr->string: %s %s", self.opnames[i.OP], table.tostring(i))
|
|
local c0, c1, c2, c3
|
|
-- change to OP/A/B/C format if needed
|
|
if i.Bx then i.C = keep (i.Bx, 9); i.B = srb (i.Bx, 9) end
|
|
-- c0 = 6B from opcode + 2LSB from A (flushed to MSB)
|
|
c0 = i.OP + slb (keep (i.A, 2), 6)
|
|
-- c1 = 6MSB from A + 2LSB from C (flushed to MSB)
|
|
c1 = srb (i.A, 2) + slb (keep (i.C, 2), 6)
|
|
-- c2 = 7MSB from C + 1LSB from B (flushed to MSB)
|
|
c2 = srb (i.C, 2) + slb (keep (i.B, 1), 7)
|
|
-- c3 = 8MSB from B
|
|
c3 = srb (i.B, 1)
|
|
--printf ("Instruction: %s %s", self.opnames[i.OP], tostringv (i))
|
|
--printf ("Bin encoding: %x %x %x %x", c0, c1, c2, c3)
|
|
return string.char(c0, c1, c2, c3)
|
|
end
|
|
end
|
|
------------------------------------------------------------------------
|
|
-- decodes a 4-char little-endian string into an instruction struct
|
|
------------------------------------------------------------------------
|
|
function luaP:DecodeInst(x)
|
|
error "Not implemented"
|
|
end
|
|
|
|
------------------------------------------------------------------------
|
|
-- invalid register that fits in 8 bits
|
|
------------------------------------------------------------------------
|
|
luaP.NO_REG = luaP.MAXARG_A
|
|
|
|
------------------------------------------------------------------------
|
|
-- R(x) - register
|
|
-- Kst(x) - constant (in constant table)
|
|
-- RK(x) == if x < MAXSTACK then R(x) else Kst(x-MAXSTACK)
|
|
------------------------------------------------------------------------
|
|
|
|
------------------------------------------------------------------------
|
|
-- grep "ORDER OP" if you change these enums
|
|
------------------------------------------------------------------------
|
|
|
|
--[[--------------------------------------------------------------------
|
|
Lua virtual machine opcodes (enum OpCode):
|
|
------------------------------------------------------------------------
|
|
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_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_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 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) <?= R(A+1) then PC+= sBx
|
|
OP_TFORLOOP A C R(A+2), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));
|
|
if R(A+2) ~= nil then pc++
|
|
OP_TFORPREP A sBx if type(R(A)) == table then R(A+1):=R(A), R(A):=next;
|
|
PC += sBx
|
|
OP_SETLIST A Bx R(A)[Bx-Bx%FPF+i] := R(A+i), 1 <= i <= Bx%FPF+1
|
|
OP_SETLISTO A Bx (see note)
|
|
OP_CLOSE A close all variables in the stack up to (>=) R(A)
|
|
OP_CLOSURE A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n))
|
|
----------------------------------------------------------------------]]
|
|
|
|
luaP.opnames = {} -- opcode names
|
|
luaP.OpCode = {} -- lookup name -> number
|
|
luaP.ROpCode = {} -- lookup number -> name
|
|
|
|
local i = 0
|
|
for v in string.gfind([[
|
|
MOVE -- 0
|
|
LOADK
|
|
LOADBOOL
|
|
LOADNIL
|
|
GETUPVAL
|
|
GETGLOBAL -- 5
|
|
GETTABLE
|
|
SETGLOBAL
|
|
SETUPVAL
|
|
SETTABLE
|
|
NEWTABLE -- 10
|
|
SELF
|
|
ADD
|
|
SUB
|
|
MUL
|
|
DIV -- 15
|
|
MOD
|
|
POW
|
|
UNM
|
|
NOT
|
|
LEN -- 20
|
|
CONCAT
|
|
JMP
|
|
EQ
|
|
LT
|
|
LE -- 25
|
|
TEST
|
|
TESTSET
|
|
CALL
|
|
TAILCALL
|
|
RETURN -- 30
|
|
FORLOOP
|
|
FORPREP
|
|
TFORLOOP
|
|
SETLIST
|
|
CLOSE -- 35
|
|
CLOSURE
|
|
VARARG
|
|
]], "[%a]+") do
|
|
local n = "OP_"..v
|
|
luaP.opnames[i] = v
|
|
luaP.OpCode[n] = i
|
|
luaP.ROpCode[i] = n
|
|
i = i + 1
|
|
end
|
|
luaP.NUM_OPCODES = i
|
|
|
|
--[[
|
|
===========================================================================
|
|
Notes:
|
|
(1) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1,
|
|
and can be 0: OP_CALL then sets 'top' to last_result+1, so
|
|
next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use 'top'.
|
|
|
|
(2) In OP_RETURN, if (B == 0) then return up to 'top'
|
|
|
|
(3) For comparisons, B specifies what conditions the test should accept.
|
|
|
|
(4) All 'skips' (pc++) assume that next instruction is a jump
|
|
|
|
(5) OP_SETLISTO is used when the last item in a table constructor is a
|
|
function, so the number of elements set is up to top of stack
|
|
===========================================================================
|
|
--]]
|
|
|
|
------------------------------------------------------------------------
|
|
-- masks for instruction properties
|
|
------------------------------------------------------------------------
|
|
-- was enum OpModeMask:
|
|
luaP.OpModeBreg = 2 -- B is a register
|
|
luaP.OpModeBrk = 3 -- B is a register/constant
|
|
luaP.OpModeCrk = 4 -- C is a register/constant
|
|
luaP.OpModesetA = 5 -- instruction set register A
|
|
luaP.OpModeK = 6 -- Bx is a constant
|
|
luaP.OpModeT = 1 -- operator is a test
|
|
|
|
------------------------------------------------------------------------
|
|
-- get opcode mode, e.g. "iABC"
|
|
------------------------------------------------------------------------
|
|
function luaP:getOpMode(m)
|
|
--printv(m)
|
|
--printv(self.OpCode[m])
|
|
--printv(self.opmodes [self.OpCode[m]+1])
|
|
return self.OpMode[tonumber(string.sub(self.opmodes[self.OpCode[m] + 1], 7, 7))]
|
|
end
|
|
|
|
------------------------------------------------------------------------
|
|
-- test an instruction property flag
|
|
-- * b is a string, e.g. "OpModeBreg"
|
|
------------------------------------------------------------------------
|
|
function luaP:testOpMode(m, b)
|
|
return (string.sub(self.opmodes[self.OpCode[m] + 1], self[b], self[b]) == "1")
|
|
end
|
|
|
|
-- number of list items to accumulate before a SETLIST instruction
|
|
-- (must be a power of 2)
|
|
-- * used in lparser, lvm, ldebug, ltests
|
|
luaP.LFIELDS_PER_FLUSH = 50 --FF updated to match 5.1
|
|
|
|
-- luaP_opnames[] is set above, as the luaP.opnames table
|
|
-- opmode(t,b,bk,ck,sa,k,m) deleted
|
|
|
|
--[[--------------------------------------------------------------------
|
|
Legend for luaP:opmodes:
|
|
1 T -> T (is a test?)
|
|
2 B -> B is a register
|
|
3 b -> B is an RK register/constant combination
|
|
4 C -> C is an RK register/constant combination
|
|
5 A -> register A is set by the opcode
|
|
6 K -> Bx is a constant
|
|
7 m -> 1 if iABC layout,
|
|
2 if iABx layout,
|
|
3 if iAsBx layout
|
|
----------------------------------------------------------------------]]
|
|
|
|
luaP.opmodes = {
|
|
-- TBbCAKm opcode
|
|
"0100101", -- OP_MOVE 0
|
|
"0000112", -- OP_LOADK
|
|
"0000101", -- OP_LOADBOOL
|
|
"0100101", -- OP_LOADNIL
|
|
"0000101", -- OP_GETUPVAL
|
|
"0000112", -- OP_GETGLOBAL 5
|
|
"0101101", -- OP_GETTABLE
|
|
"0000012", -- OP_SETGLOBAL
|
|
"0000001", -- OP_SETUPVAL
|
|
"0011001", -- OP_SETTABLE
|
|
"0000101", -- OP_NEWTABLE 10
|
|
"0101101", -- OP_SELF
|
|
"0011101", -- OP_ADD
|
|
"0011101", -- OP_SUB
|
|
"0011101", -- OP_MUL
|
|
"0011101", -- OP_DIV 15
|
|
"0011101", -- OP_MOD
|
|
"0011101", -- OP_POW
|
|
"0100101", -- OP_UNM
|
|
"0100101", -- OP_NOT
|
|
"0100101", -- OP_LEN 20
|
|
"0101101", -- OP_CONCAT
|
|
"0000003", -- OP_JMP
|
|
"1011001", -- OP_EQ
|
|
"1011001", -- OP_LT
|
|
"1011001", -- OP_LE 25
|
|
"1000101", -- OP_TEST
|
|
"1100101", -- OP_TESTSET
|
|
"0000001", -- OP_CALL
|
|
"0000001", -- OP_TAILCALL
|
|
"0000001", -- OP_RETURN 30
|
|
"0000003", -- OP_FORLOOP
|
|
"0000103", -- OP_FORPREP
|
|
"1000101", -- OP_TFORLOOP
|
|
"0000001", -- OP_SETLIST
|
|
"0000001", -- OP_CLOSE 35
|
|
"0000102", -- OP_CLOSURE
|
|
"0000101" -- OP_VARARG
|
|
}
|
|
|
|
return luaP |