本篇文章,主要探討一下lua中的指令系統(涉及到的檔案 lopcodes.c )。
在lua中,用32位的unsigned int類型來表示一條指令作業碼,32位值包含了6位的作業碼和26位的指令欄位兩部分內容。
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
enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */
依據上面的枚舉值,指令碼目前有三種形式,即iABC,iABx,iAsBx,結構圖如下:
對於指令欄位A,B,C,有以下三種形式的取值來源:
/*
** R(x) - register
** Kst(x) - constant (in constant table)
** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x)
*/
其中,用R來表示寄存器值,Kst表示常量表,RK表示可能是常量表或者寄存器。
lua5.14中總共擁有38條指令作業碼,作業碼名稱如下:
const char *const luaP_opnames[NUM_OPCODES+1] = {<br /> "MOVE",<br /> "LOADK",<br /> "LOADBOOL",<br /> "LOADNIL",<br /> "GETUPVAL",<br /> "GETGLOBAL",<br /> "GETTABLE",<br /> "SETGLOBAL",<br /> "SETUPVAL",<br /> "SETTABLE",<br /> "NEWTABLE",<br /> "SELF",<br /> "ADD",<br /> "SUB",<br /> "MUL",<br /> "DIV",<br /> "MOD",<br /> "POW",<br /> "UNM",<br /> "NOT",<br /> "LEN",<br /> "CONCAT",<br /> "JMP",<br /> "EQ",<br /> "LT",<br /> "LE",<br /> "TEST",<br /> "TESTSET",<br /> "CALL",<br /> "TAILCALL",<br /> "RETURN",<br /> "FORLOOP",<br /> "FORPREP",<br /> "TFORLOOP",<br /> "SETLIST",<br /> "CLOSE",<br /> "CLOSURE",<br /> "VARARG",<br /> NULL<br />};<br />
作業碼枚舉值,和上面的作業碼名稱一一對應,方便調用:
typedef enum {<br />/*----------------------------------------------------------------------<br />nameargsdescription<br />------------------------------------------------------------------------*/<br />OP_MOVE,/*A BR(A) := R(B)*/<br />OP_LOADK,/*A BxR(A) := Kst(Bx)*/<br />OP_LOADBOOL,/*A B CR(A) := (Bool)B; if (C) pc++*/<br />OP_LOADNIL,/*A BR(A) := ... := R(B) := nil*/<br />OP_GETUPVAL,/*A BR(A) := UpValue[B]*/</p><p>OP_GETGLOBAL,/*A BxR(A) := Gbl[Kst(Bx)]*/<br />OP_GETTABLE,/*A B CR(A) := R(B)[RK(C)]*/</p><p>OP_SETGLOBAL,/*A BxGbl[Kst(Bx)] := R(A)*/<br />OP_SETUPVAL,/*A BUpValue[B] := R(A)*/<br />OP_SETTABLE,/*A B CR(A)[RK(B)] := RK(C)*/</p><p>OP_NEWTABLE,/*A B CR(A) := {} (size = B,C)*/</p><p>OP_SELF,/*A B CR(A+1) := R(B); R(A) := R(B)[RK(C)]*/</p><p>OP_ADD,/*A B CR(A) := RK(B) + RK(C)*/<br />OP_SUB,/*A B CR(A) := RK(B) - RK(C)*/<br />OP_MUL,/*A B CR(A) := RK(B) * RK(C)*/<br />OP_DIV,/*A B CR(A) := RK(B) / RK(C)*/<br />OP_MOD,/*A B CR(A) := RK(B) % RK(C)*/<br />OP_POW,/*A B CR(A) := RK(B) ^ RK(C)*/<br />OP_UNM,/*A BR(A) := -R(B)*/<br />OP_NOT,/*A BR(A) := not R(B)*/<br />OP_LEN,/*A BR(A) := length of R(B)*/</p><p>OP_CONCAT,/*A B CR(A) := R(B).. ... ..R(C)*/</p><p>OP_JMP,/*sBxpc+=sBx*/</p><p>OP_EQ,/*A B Cif ((RK(B) == RK(C)) ~= A) then pc++*/<br />OP_LT,/*A B Cif ((RK(B) < RK(C)) ~= A) then pc++ */<br />OP_LE,/*A B Cif ((RK(B) <= RK(C)) ~= A) then pc++ */</p><p>OP_TEST,/*A Cif not (R(A) <=> C) then pc++*/<br />OP_TESTSET,/*A B Cif (R(B) <=> C) then R(A) := R(B) else pc++*/ </p><p>OP_CALL,/*A B CR(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */<br />OP_TAILCALL,/*A B Creturn R(A)(R(A+1), ... ,R(A+B-1))*/<br />OP_RETURN,/*A Breturn R(A), ... ,R(A+B-2)(see note)*/</p><p>OP_FORLOOP,/*A sBxR(A)+=R(A+2);<br />if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/<br />OP_FORPREP,/*A sBxR(A)-=R(A+2); pc+=sBx*/</p><p>OP_TFORLOOP,/*A CR(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));<br /> if R(A+3) ~= nil then R(A+2)=R(A+3) else pc++*/<br />OP_SETLIST,/*A B CR(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B*/</p><p>OP_CLOSE,/*A close all variables in the stack up to (>=) R(A)*/<br />OP_CLOSURE,/*A BxR(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n))*/</p><p>OP_VARARG/*A BR(A), R(A+1), ..., R(A+B-1) = vararg*/<br />} OpCode;<br />
38條作業碼對應的操作模式如下:
#define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m))</p><p>const lu_byte luaP_opmodes[NUM_OPCODES] = {<br />/* T A B C mode opcode*/<br /> opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */<br /> ,opmode(0, 1, OpArgK, OpArgN, iABx)/* OP_LOADK */<br /> ,opmode(0, 1, OpArgU, OpArgU, iABC)/* OP_LOADBOOL */<br /> ,opmode(0, 1, OpArgR, OpArgN, iABC)/* OP_LOADNIL */<br /> ,opmode(0, 1, OpArgU, OpArgN, iABC)/* OP_GETUPVAL */<br /> ,opmode(0, 1, OpArgK, OpArgN, iABx)/* OP_GETGLOBAL */<br /> ,opmode(0, 1, OpArgR, OpArgK, iABC)/* OP_GETTABLE */<br /> ,opmode(0, 0, OpArgK, OpArgN, iABx)/* OP_SETGLOBAL */<br /> ,opmode(0, 0, OpArgU, OpArgN, iABC)/* OP_SETUPVAL */<br /> ,opmode(0, 0, OpArgK, OpArgK, iABC)/* OP_SETTABLE */<br /> ,opmode(0, 1, OpArgU, OpArgU, iABC)/* OP_NEWTABLE */<br /> ,opmode(0, 1, OpArgR, OpArgK, iABC)/* OP_SELF */<br /> ,opmode(0, 1, OpArgK, OpArgK, iABC)/* OP_ADD */<br /> ,opmode(0, 1, OpArgK, OpArgK, iABC)/* OP_SUB */<br /> ,opmode(0, 1, OpArgK, OpArgK, iABC)/* OP_MUL */<br /> ,opmode(0, 1, OpArgK, OpArgK, iABC)/* OP_DIV */<br /> ,opmode(0, 1, OpArgK, OpArgK, iABC)/* OP_MOD */<br /> ,opmode(0, 1, OpArgK, OpArgK, iABC)/* OP_POW */<br /> ,opmode(0, 1, OpArgR, OpArgN, iABC)/* OP_UNM */<br /> ,opmode(0, 1, OpArgR, OpArgN, iABC)/* OP_NOT */<br /> ,opmode(0, 1, OpArgR, OpArgN, iABC)/* OP_LEN */<br /> ,opmode(0, 1, OpArgR, OpArgR, iABC)/* OP_CONCAT */<br /> ,opmode(0, 0, OpArgR, OpArgN, iAsBx)/* OP_JMP */<br /> ,opmode(1, 0, OpArgK, OpArgK, iABC)/* OP_EQ */<br /> ,opmode(1, 0, OpArgK, OpArgK, iABC)/* OP_LT */<br /> ,opmode(1, 0, OpArgK, OpArgK, iABC)/* OP_LE */<br /> ,opmode(1, 1, OpArgR, OpArgU, iABC)/* OP_TEST */<br /> ,opmode(1, 1, OpArgR, OpArgU, iABC)/* OP_TESTSET */<br /> ,opmode(0, 1, OpArgU, OpArgU, iABC)/* OP_CALL */<br /> ,opmode(0, 1, OpArgU, OpArgU, iABC)/* OP_TAILCALL */<br /> ,opmode(0, 0, OpArgU, OpArgN, iABC)/* OP_RETURN */<br /> ,opmode(0, 1, OpArgR, OpArgN, iAsBx)/* OP_FORLOOP */<br /> ,opmode(0, 1, OpArgR, OpArgN, iAsBx)/* OP_FORPREP */<br /> ,opmode(1, 0, OpArgN, OpArgU, iABC)/* OP_TFORLOOP */<br /> ,opmode(0, 0, OpArgU, OpArgU, iABC)/* OP_SETLIST */<br /> ,opmode(0, 0, OpArgN, OpArgN, iABC)/* OP_CLOSE */<br /> ,opmode(0, 1, OpArgU, OpArgN, iABx)/* OP_CLOSURE */<br /> ,opmode(0, 1, OpArgU, OpArgN, iABC)/* OP_VARARG */<br />};</p><p>
操作模式計算公式如下:
#define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m))
用8位值來表示
/*
** masks for instruction properties. The format is:
** bits 0-1: op mode
** bits 2-3: C arg mode
** bits 4-5: B arg mode
** bit 6: instruction set register A
** bit 7: operator is a test
*/
依次從低位到高位表示如下含義:
第0,1位表示作業碼模式,取值於 enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */
第2,3位表示參數C模式,取值於 enum OpArgMask {
OpArgN, /* argument is not used */
OpArgU, /* argument is used */
OpArgR, /* argument is a register or a jump offset */
OpArgK /* argument is a constant or register/constant */
};
其中OpArgN表示未用參數,OpArgU表示可用參數,OpArgR表示寄存器參數或者跳轉指令,OpArgK表示常量表或者寄存器參數,
第4,5位表示參數B模式,取值於C取值範圍一致。
第6位表示寄存器參數A是否被設定。
第7位表示是否測試操作。