Lua5.3 VM 分析(四)分支和跳转
Lua VM 定义了 OP_EQ、OP_LT、OP_LE、OP_TEST、OP_TESTSET 五种分支操作。
这五个分支指令必须与 之后的 跳转指令 JMP 看做一个整体解释。也就是说:当条件成立时,继续运行;条件不成立时,跳转到指定位置。
如果条件成立跳转到L1, 否则跳转到L2:
L1:
success()
jmp exit
L2:
fail()
jmp exit
exit:
exit()
OP_JMP
OP_JMP 可以单独使用, 做无条件跳转指令。跳转地址使用的是相对量,负数表示向前跳转。0 表示下一条指令。
vmcase(OP_JMP) {
dojump(ci, i, 0);
vmbreak;
}
define dojump(ci,i,e) \
{ int a = GETARG_A(i); \
if (a > 0) luaF_close(L, ci->u.l.base + a - 1); \
ci->u.l.savedpc += GETARG_sBx(i) + e; }
define donextjump(ci) { i = *ci->u.l.savedpc; dojump(ci, i, 1); }
无条件跳转和条件跳转分别用 dojump 宏 与 donextjump 两个宏实现。
donextjump 读出下一条指令,必定是JMP。
dojump 宏负责 指令的偏移 ( ci->u.l.savedpc += GETARG_sBx(i) + e; )。
当 a (Instruction 的 A 部分)大于 0 时,调用luaF_close 函数关闭 A 层次的 upvalue 。
OP_EQ
vmcase(OP_EQ) {
TValue *rb = RKB(i);
TValue *rc = RKC(i);
Protect(
if (cast_int(luaV_equalobj(L, rb, rc)) != GETARG_A(i))
ci->u.l.savedpc++;
else
donextjump(ci);
)
vmbreak;
}
利用 luaV_equalobj 函数判断条件是否成立,当不成立时,执行 donextjump 。反则根据 类型不同比较算法不同。
int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
const TValue *tm;
if (ttype(t1) != ttype