luapy (2) instruction set

Lua VM 是基于寄存器(Register Based) 虚拟机,采用4字节定长指令(Fixed width),其中opcode 6 bits,operand 26 bits,Lua 5.3 共有47条指令。

编码模式:
iABC: A, B, C 三个操作数,分别8,9,9 bits
iABx: A, Bx两个操作数,分别8, 18 bits
iAsBx: A, sBx 两个操作数,分别8,18 bits
iAx: Ax一个操作数,26 bits

# OpMode
IABC = 0
IABx = 1
IAsBx = 2
IAx = 3

操作数类型:
OpArgN类型的操作数不表示任何信息,也就是说不会被使用。比如MOVE指令(iABC模式)只使用A和B操作数,不使用C操作数(OpArgN类型)。
OpArgR类型的操作数在iABC模式下表示寄存器索引,在iAsBx模式下表示跳转偏移。仍以MOVE指令为例,该指令用于将一个寄存器中的值移动到另一个寄存器中,其A操作数表示目标寄存器索引,B操作数(OpArgR类型)表示源寄存器索引。如果用R(N)表示寄存器访问,则MOVE指令可以表示为伪代码R(A):=R(B)。
OpArgK类型的操作数表示常量表索引或者寄存器索引,具体可以分为两种情况。第一种情况是LOADK指令(iABx模式,用于将常量表中的常量加载到寄存器中),该指令的Bx操作数表示常量表索引,如果用Kst(N)表示常量表访问,则LOADK指令可以表示为伪代码R(A):=Kst(Bx);第二种情况是部分iABC模式指令,这些指令的B或C操作数既可以表示常量表索引也可以表示寄存器索引,以加法指令ADD为例,如果用RK(N)表示常量表或者寄存器访问,则该指令可以表示为伪代码R(A):=RK(B)+RK(C)。

# OpArg
OpArgN = 0
OpArgU = 1
OpArgR = 2
OpArgK = 3

OpCode

class OpCode:
    MOVE = 0
    LOADK = 1
    LOADKX = 2
    LOADBOOL = 3
    LOADNIL = 4
    GETUPVAL = 5
    GETTABUP = 6
    GETTABLE = 7
    SETTABUP = 8
    SETUPVAL = 9
    SETTABLE = 10
    NEWTABLE = 11
    SELF = 12
    ADD = 13
    SUB = 14
    MUL = 15
    MOD = 16
    POW = 17
    DIV = 18
    IDIV = 19
    BAND = 20
    BOR = 21
    BXOR = 22
    SHL = 23
    SHR = 24
    UNM = 25
    BNOT = 26
    NOT = 27
    LEN = 28
    CONCAT = 29
    JMP = 30
    EQ = 31
    LT = 32
    LE = 33
    TEST = 34
    TESTSET = 35
    CALL = 36
    TAILCALL = 37
    RETURN = 38
    FORLOOP = 39
    FORPREP = 40
    TFORCALL = 41
    TFORLOOP = 42
    SETLIST = 43
    CLOSURE = 44
    VARARG = 45
    EXTRAARG = 46

    def __init__(self, test_flag, set_a_flag, arg_b_mode, arg_c_mode, op_mode, name):
        self.test_flag = test_flag
        self.set_a_flag = set_a_flag
        self.arg_b_mode = arg_b_mode
        self.arg_c_mode = arg_c_mode
        self.op_mode = op_mode
        self.name = name

op_codes:

op_codes = [
    #      T  A  B       C       mode   name
    OpCode(0, 1, OpArgR, OpArgN, IABC,  "MOVE    "),  # R(A) := R(B)
    OpCode(0, 1, OpArgK, OpArgN, IABx,  "LOADK   "),  # R(A) := Kst(Bx)
    OpCode(0, 1, OpArgN, OpArgN, IABx,  "LOADKX  "),  # R(A) := Kst(extra arg)
    OpCode(0, 1, OpArgU, OpArgU, IABC,  "LOADBOOL"),  # R(A) := (bool)B; if (C) pc++
    OpCode(0, 1, OpArgU, OpArgN, IABC,  "LOADNIL "),  # R(A), R(A+1), ..., R(A+B) := nil
    OpCode(0, 1, OpArgU, OpArgN, IABC,  "GETUPVAL"),  # R(A) := UpValue[B]
    OpCode(0, 1, OpArgU, OpArgK, IABC,  "GETTABUP"),  # R(A) := UpValue[B][RK(C)]
    OpCode(0, 1, OpArgR, OpArgK, IABC,  "GETTABLE"),  # R(A) := R(B)[RK(C)]
    OpCode(0, 0, OpArgK, OpArgK, IABC,  "SETTABUP"),  # UpValue[A][RK(B)] := RK(C)
    OpCode(0, 0, OpArgU, OpArgN, IABC,  "SETUPVAL"),  # UpValue[B] := R(A)
    OpCode(0, 0, OpArgK, OpArgK, IABC,  "SETTABLE"),  # R(A)[RK(B)] := RK(C)
    OpCode(0, 1, OpArgU, OpArgU, IABC,  "NEWTABLE"),  # R(A) := {} (size = B,C)
    OpCode(0, 1, OpArgR, OpArgK, IABC,  "SELF    "),  # R(A+1) := R(B); R(A) := R(B)[RK(C)]
    OpCode(0, 1, OpArgK, OpArgK, IABC,  "ADD     "),  # R(A) := RK(B) + RK(C)
    OpCode(0, 1, OpArgK, OpArgK, IABC,  "SUB     "),  # R(A) := RK(B) - RK(C)
    OpCode(0, 1, OpArgK, OpArgK, IABC,  "MUL     "),  # R(A) := RK(B) * RK(C)
    OpCode(0, 1, OpArgK, OpArgK, IABC,  "MOD     "),  # R(A) := RK(B) % RK(C)
    OpCode(0, 1, OpArgK, OpArgK, IABC,  "POW     "),  # R(A) := RK(B) ^ RK(C)
    OpCode(0, 1, OpArgK, OpArgK, IABC,  "DIV     "),  # R(A) := RK(B) / RK(C)
    OpCode(0, 1, OpArgK, OpArgK, IABC,  "IDIV    "),  # R(A) := RK(B) // RK(C)
    OpCode(0, 1, OpArgK, OpArgK, IABC,  "BAND    "),  # R(A) := RK(B) & RK(C)
    OpCode(0, 1, OpArgK, OpArgK, IABC,  "BOR     "),  # R(A) := RK(B) | RK(C)
    OpCode(0, 1, OpArgK, OpArgK, IABC,  "BXOR    "),  # R(A) := RK(B) ~ RK(C)
    OpCode(0, 1, OpArgK, OpArgK, IABC,  "SHL     "),  # R(A) := RK(B) << RK(C)
    OpCode(0, 1, OpArgK, OpArgK, IABC,  "SHR     "),  # R(A) := RK(B) >> RK(C)
    OpCode(0, 1, OpArgR, OpArgN, IABC,  "UNM     "),  # R(A) := -R(B)
    OpCode(0, 1, OpArgR, OpArgN, IABC,  "BNOT    "),  # R(A) := ~R(B)
    OpCode(0, 1, OpArgR, OpArgN, IABC,  "NOT     "),  # R(A) := not R(B)
    OpCode(0, 1, OpArgR, OpArgN, IABC,  "LEN     "),  # R(A) := length of R(B)
    OpCode(0, 1, OpArgR, OpArgR, IABC,  "CONCAT  "),  # R(A) := R(B).. ... ..R(C)
    OpCode(0, 0, OpArgR, OpArgN, IAsBx, "JMP     "),  # pc+=sBx; if (A) close all upvalues >= R(A - 1)
    OpCode(1, 0, OpArgK, OpArgK, IABC,  "EQ      "),  # if ((RK(B) == RK(C)) ~= A) then pc++
    OpCode(1, 0, OpArgK, OpArgK, IABC,  "LT      "),  # if ((RK(B) <  RK(C)) ~= A) then pc++
    OpCode(1, 0, OpArgK, OpArgK, IABC,  "LE      "),  # if ((RK(B) <= RK(C)) ~= A) then pc++
    OpCode(1, 0, OpArgN, OpArgU, IABC,  "TEST    "),  # if not (R(A) <=> C) then pc++
    OpCode(1, 1, OpArgR, OpArgU, IABC,  "TESTSET "),  # if (R(B) <=> C) then R(A) := R(B) else pc++
    OpCode(0, 1, OpArgU, OpArgU, IABC,  "CALL    "),  # R(A), ...,R(A+C-2) := R(A)(R(A+1), ...,R(A+B-1))
    OpCode(0, 1, OpArgU, OpArgU, IABC,  "TAILCALL"),  # return R(A)(R(A+1), ... ,R(A+B-1))
    OpCode(0, 0, OpArgU, OpArgN, IABC,  "RETURN  "),  # return R(A), ... ,R(A+B-2)
    OpCode(0, 1, OpArgR, OpArgN, IAsBx, "FORLOOP "),  # R(A)+=R(A+2); if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }
    OpCode(0, 1, OpArgR, OpArgN, IAsBx, "FORPREP "),  # R(A)-=R(A+2); pc+=sBx
    OpCode(0, 0, OpArgN, OpArgU, IABC,  "TFORCALL"),  # R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));
    OpCode(0, 1, OpArgR, OpArgN, IAsBx, "TFORLOOP"),  # if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }
    OpCode(0, 0, OpArgU, OpArgU, IABC,  "SETLIST "),  # R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B
    OpCode(0, 1, OpArgU, OpArgN, IABx,  "CLOSURE "),  # R(A) := closure(KPROTO[Bx])
    OpCode(0, 1, OpArgU, OpArgN, IABC,  "VARARG  "),  # R(A), R(A+1), ..., R(A+B-2) = vararg
    OpCode(0, 0, OpArgU, OpArgU, IAx,   "EXTRAARG"),  # extra (larger) argument for previous opcode
]

Instruction

class Instruction:
    MAXARG_Bx = 1 << 18 - 1
    MAXARG_sBx = MAXARG_Bx >> 1

    def __init__(self, code):
        self.code = code

    def op_code(self):
        return self.code & 0x3f

    def a_b_c(self):
        return (self.code >> 6) & 0xff, (self.code >> 23) & 0x1ff, (self.code >> 14) & 0x1ff

    def a_bx(self):
        return (self.code >> 6) & 0xff, (self.code >> 14)

    def as_bx(self):
        a, bx = self.a_bx()
        return a, bx - Instruction.MAXARG_sBx

    def ax(self):
        return self.code >> 6

    def op_name(self):
        return op_codes[self.op_code()].name

    def op_mode(self):
        return op_codes[self.op_code()].op_mode

    def arg_b_mode(self):
        return op_codes[self.op_code()].arg_b_mode

    def arg_c_mode(self):
        return op_codes[self.op_code()].arg_c_mode

    def dump(self):
        print(self.op_name(), end=' ')
        if self.op_mode() == IABC:
            a, b, c = self.a_b_c()
            print('%8d' % a, end='')
            if self.arg_b_mode() != OpArgN:
                if b > 0xff:
                    print(' %8d' % (-1 - (b & 0xff)), end='')
                else:
                    print(' %8d' % b, end='')
            if self.arg_c_mode() != OpArgN:
                if c > 0xff:
                    print(' %8d' % (-1 - (c & 0xff)), end='')
                else:
                    print(' %8d' % c, end='')
        elif self.op_mode() == IABx:
            a, bx = self.a_bx()
            print('%8d' % a, end='')
            if self.arg_b_mode() == OpArgK:
                print(' %8d' % (-1 - bx), end='')
            elif self.arg_b_mode() == OpArgU:
                print(' %8d' % bx, end='')
        elif self.op_mode() == IAsBx:
            a, sbx = self.as_bx()
            print('%8d %8d' % (a, sbx), end='')
        elif self.op_mode() == IAx:
            ax = self.ax()
            print('%8d' % (-1 - ax), end='')
        print()

prototype

    def print_code(self):
        for i in range(len(self.code)):
            line = self.line_infos[i] if len(self.line_infos) > 0 else '-'
            # print('\t%d\t[%s]\t0x%08x' % (i+1, line, self.code[i]))
            inst = Instruction(self.code[i])
            print('\t%d\t[%s]\t' % (i+1, line), end='')
            inst.dump()

test result

main <@hello.lua:0,0> (4 instructions)
0+ params, 2 slots, 1 upvalues, 0 locals, 2 constants, 0 functions
	1	[1]	GETTABUP        0        0       -1
	2	[1]	LOADK           1       -2
	3	[1]	CALL            0        2        1
	4	[1]	RETURN          0        1
constants (2):
	1	"print"
	2	"Hello World"
locals (0):
upvalues (1):
	1	_ENV	1	0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值