Lua5.3 虚拟机指令分析(二)赋值指令
Lua VM 是基于寄存器结构实现的,也就是说,每段 Lua chunk 代码都被翻译为一组对256 个寄存器的操作指令。这有点类似于我们为Lua编写 C 扩展。
C 函数通常是从 lua_State 中取出参数逐个记录在 C 的局部变量中,然后利用C 代码直接对这些值进行操作。
可以类比 把寄存器类比于 Lua 的寄存器。它们的确有相似之处, C 中的局部变量处于C 堆栈上,而Lua 的寄存器则处于 Lua 的数据栈中。
给Lua 局部变量赋值的过程,是由 OP_MOVE 、 OP_LOADK 、 OP_LOADKX 、 OP_LOADBOOL、 OP_LOADNIL、 OP_GETUPVAL、 OP_SETUPVAL 这组操作码完成的。
值得来源有三处:
第一:其它寄存器,即局部变量。OP_MOVE 可以完成这个工作
OP_MOVE A B R(A) := R(B)
OP_MOVE 用来将寄存器B中的值拷贝到寄存器A中。
由于Lua是register based vm,大部分的指令都是直接对寄存器进行操作,而不需要对数据进行压栈和弹栈,所以需要OP_MOVE 指令的地方并不多。
最直接的使用之处就是将一个local变量复制给另一个local变量时:
TTcs-Mac-mini:OpCode ttc$ cat tOP_MOVE.lua
local a
local b = a
TTcs-Mac-mini:OpCode ttc$ ./luac -l -l tOP_MOVE.lua
main <tOP_MOVE.lua:0,0> (3 instructions at 0x7f905ac039b0)
0+ params, 2 slots, 1 upvalue, 2 locals, 0 constants, 0 functions
1 [1] LOADNIL (iABC) [A]0 [ISK]0[B]0[ISK]0
2 [2] MOVE (iABC) [A]1 [ISK]0[B]0[ISK]0
3 [2] RETURN (iABC) [A]0 [ISK]0[B]1[ISK]0
constants (0) for 0x7f905ac039b0:
locals (2) for 0x7f905ac039b0:
0 a(name) 2(startpc) 4(endpc)
1 b(name) 3(startpc) 4(endpc)
upvalues (1) for 0x7f905ac039b0:
0 _ENV(name) 1(instack) 0(idx)
TTcs-Mac-mini:OpCode ttc$
在编译过程中,Lua会将每个local变量都分配到一个指定的寄存器中。在运行期,lua使用local变量所对应的寄存器id来操作local变量,而local变量的名字除了提供debug信息外,没有其他作用。
在这里a被分配给register 0,b被分配给register 1。MOVE表示将a(register 0)的值赋给b(register 1)。其他使用的地方基本都是对寄存器的位置有特殊要求的地方,比如函数参数的传递等等。
第二: 常量,nil 和 bool 类型的数据比较短,可以通过指令直接加载(不需要先加载常量表到寄存器)。
OP_LOADBOOL A B C R(A) := (Bool)B; if (C) pc++
LOADBOOL 将 B 所表示的 boolean 值装载到寄存器 A 中。B 使用 0 和 1 分别代表 false 和 true。C 也表示一个boolean值,如果C为1,就跳过下一个指令。
TTcs-Mac-mini:OpCode ttc$ cat tOP_LOADBOOL.lua
local a = true
TTcs-Mac-mini:OpCode ttc$ ./luac -l -l tOP_LOADBOOL.lua
main <tOP_LOADBOOL.lua:0,0> (2 instructions at 0x7ff1754039d0)
0+ params, 2 slots, 1 upvalue, 1 local, 0 constants, 0 functions
1 [1] LOADBOOL (iABC) [A]0 [ISK]0[B]1[ISK]0[C]0
2 [1] RETURN (iABC) [A]0 [ISK]0[B]1[ISK]0
constants (0) for 0x7ff1754039d0:
locals (1) for 0x7ff1754039d0:
0 a(name) 2(startpc) 3(endpc)
upvalues (1) for 0x7ff1754039d0:
0 _ENV(name) 1(instack) 0(idx)
TTcs-Mac-mini:OpCode ttc$
TTcs-Mac-mini:OpCode ttc$ cat tOP_LOADBOOL_2.lua
local b = 1 < 2
TTcs-Mac-mini:OpCode ttc$ ./luac -l -l tOP_LOADBOOL_2.lua
main <tOP_LOADBOOL_2.lua:0,0> (5 instructions at 0x7fda7d4039d0)
0+ params, 2 slots, 1 upvalue, 1 local, 2 constants, 0 functions
1 [2] LT (iABC) [A]1 [ISK]256[B]-1[ISK]256[C]-2 ; 1 2
2 [2] JMP (iAsBx) [A]0 [sBx]1 ; to 4
3 [2] LO