这个来源通常有三个:upvalue、const、local。除了local变量天然对应寄存器之外,另外的const和upvalue在使用的时候都需要专门的指令来加载到寄存器中,因为大部分的机器操作都是基于寄存器实现。这一点在lua-5.3.4\src\lopcodes.h可以看到。当需要使用一个非寄存器变量时,需要先通过luaK_dischargevars来保证它是“万事俱备,只欠寄存器分配”,在luaK_dischargevars函数中,如果变量是在upvalue中,则需要先生成从up列表中加载该变量的机器指令,但是并没有分配寄存器,也即是它的结果可以放在任意寄存器中,之后该表达式的类型为VRELOCABLE void luaK_dischargevars (FuncState *fs, expdesc *e) { …… case VUPVAL: { /* move value to some (pending) register */ e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0); e->k = VRELOCABLE; break; } …… }
二、复杂表达式的指令生成
以下面表达式为例: a + b * c ,假设b和c都是upvalue,则首先 对于表达式,当需要使用的时候,在subexpr函数中首先根据算符优先级获得子子表达式,然后调用codebinexpval函数: static void codebinexpval (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2, int line) { int rk2 = luaK_exp2RK(fs, e2); /* both operands are "RK" */ int rk1 = luaK_exp2RK(fs, e1); freeexps(fs, e1, e2); e1->u.info = luaK_codeABC(fs, op, 0, rk1, rk2); /* generate opcode */ e1->k = VRELOCABLE; /* all those operations are relocatable */ luaK_fixline(fs, line); } 对于a+b*c,则codebinexpval函数开始的e1和e2分别表示b和c,所以luaK_exp2RK会为它们分配upvalue的加载和寄存器分配,并且discharge2reg函数会修正之前生成的up加载指令中使用的寄存器。函数codebinexpval之后,b*c作为一个VRELOCABLE类型,重复这个过程。
三、看下代码
tsecer@harry: cat reg.discharge.lua a = b + c * d tsecer@harry: ../src/luac -l -l reg.discharge.lua
main <reg.discharge.lua:0,0> (7 instructions at 0x926a70) 0+ params, 3 slots, 1 upvalue, 0 locals, 4 constants, 0 functions 1 [1] GETTABUP 0 0 -2 ; _ENV "b" 2 [1] GETTABUP 1 0 -3 ; _ENV "c" 3 [1] GETTABUP 2 0 -4 ; _ENV "d" 4 [1] MUL 1 1 2 5 [1] ADD 0 0 1 6 [1] SETTABUP 0 -1 0 ; _ENV "a" 7 [1] RETURN 0 1 constants (4) for 0x926a70: 1 "a" 2 "b" 3 "c" 4 "d" locals (0) for 0x926a70: upvalues (1) for 0x926a70: 0 _ENV 1 0 tsecer@harry:
|
请发表评论