Lua5.3 VM 分析(三)表达式运算
二元运算
+、-、*、%、^、/、//、&、 |、\~、\<\<、>> 这 12 种二元运算
OP_ADD、OP_SUB、OP_MUL、OP_DIV、OP_POW、OP_MOD、OP_IDIV、OP_BAND、OP_BOR、OP_BXOR、OP_SHL、OP_SHR
###
vmcase(OP_ADD) {
TValue *rb = RKB(i);
TValue *rc = RKC(i);
lua_Number nb; lua_Number nc;
if (ttisinteger(rb) && ttisinteger(rc)) {
lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
setivalue(ra, intop(+, ib, ic));
}
else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
setfltvalue(ra, luai_numadd(L, nb, nc));
}
else {
Protect(luaT_trybinTM(L, rb, rc, ra, TM_ADD));
}
vmbreak;
}
这些操作类似,都是以两个对象作为操作对象,经过运算后,将结果放入寄存器 A 中。
对于这些数值类型之间的运算,做了优化,不会判断和出发元方法。这样可以提高效率。
1、首先取出 两个参数的值 rb 与 rc ,利用 ttisinteger 宏判断是不是 lua_Integer 小类型,如果是则利用 ivalue 宏 转换成 lua_Integer 类型的值。
TValue *io=ra; val_(ra).i=(ib+ic); settt_(io, LUA_TNUMINT);
将 ib 与 ic 做数值运算后的结果赋值给 ra.i (lua_Integer 类型 Value 结构中定义)
最后对ra->tt_ 设置类型标志。
2、如果不是 LUA_TNUMINT 子类型 则可能是 LUA_TNUMFLT 子类型
(float),利用tonumber 宏将 rb 与 rc 转换后存储在 lua_Number nb;
lua_Number nc; 最后
TValue *io=(ra); val_(io).n=(nb+nc); settt_(io, LUA_TNUMFLT);
3、其他情况 触发 元方法,有点复杂。用Call_binTM 函数做了一些封装。
函数逻辑: 先判断第一个对象是否有需要的元方法,如果找不到则去第二个函