一, 代码中输入的由来
这个来源通常有三个: 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 类型, 重复这个过程.
三, 看下代码
- [email protected]: cat reg.discharge.lua
- a = b + c * d
- [email protected]: ../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
- [email protected]:
来源: http://www.bubuko.com/infodetail-3191921.html