探索Lua5.2内部实现:虚拟机指令(7) 关系和逻辑指令

以下内容转载自:https://blog.csdn.net/yuanlin2008/article/details/8504200

name    args    desc
OP_JMP    A sBx    pc+=sBx; if (A) close all upvalues >= R(A) + 1
JMP执行一个跳转,sBx表示跳转的偏移位置,被加到当前指向下一指令的指令指针上。如果sBx为0,表示没有任何跳转;1表示跳过下一个指令;-1表示重新执行当前指令。如果A>0,表示需要关闭所有从寄存器A+1开始的所有local变量。实际执行的关闭操作只对upvalue有效。

JMP最直接的使用就是对应lua5.2新加入的goto语句:

::l::
goto l;
        1       [1]     JMP             0 -1    ; to 1
        2       [2]     RETURN          0 1
这是一个无限循环。第一行JMP的sBx为-1,表示重新执行JMP。
 do
     local a;
     function f() a = 1 end
 end
main <test.lua:0,0> (5 instructions at 0x80048eb0)
0+ params, 2 slots, 1 upvalue, 1 local, 1 constant, 1 function
        1       [2]     LOADNIL         0 0
        2       [3]     CLOSURE         1 0     ; 0x80049128
        3       [3]     SETTABUP        0 -1 1  ; _ENV "f"
        4       [3]     JMP             1 0     ; to 5
        5       [4]     RETURN          0 1
constants (1) for 0x80048eb0:
        1       "f"
locals (1) for 0x80048eb0:
        0       a       2       5
upvalues (1) for 0x80048eb0:
        0       _ENV    1       0

function <test.lua:3,3> (3 instructions at 0x80049128)
0 params, 2 slots, 1 upvalue, 0 locals, 1 constant, 0 functions
        1       [3]     LOADK           0 -1    ; 1
        2       [3]     SETUPVAL        0 0     ; a
        3       [3]     RETURN          0 1
constants (1) for 0x80049128:
        1       1
locals (0) for 0x80049128:
upvalues (1) for 0x80049128:
        0       a       1       0
上面的代码在do block中创建了一个局部变量a,并且a作为upvalue在函数f中被引用到。到退出do block是,a会退出他的有效域,并且关闭他对应的upvalue。Lua5.2中去除了以前专门处理关闭upvalue的指令CLOSE,而把这个功能加入到了JMP中。所以,生成的指令第四行的JMP在这里没有执行跳转,而只是为了关闭a的upvalue。
JMP其他的功能就是配合逻辑和关系指令(统称为test指令),实现程序的条件跳转。每个test辑指令与JMP搭配,都会将接下来生成的指令分为两个集合,满足条件的为true集合,否则为false集合。当test条件满足时,指令指针回+1,跳过后面紧跟的JMP指令,然后继续执行。当test条件不满足时,则继续执行,也就到了JMP,然后跳转到分支代码。

name    args    desc
OP_EQ    A B C    if ((RK(B) == RK(C)) ~= A) then pc++
OP_LT    A B C    if ((RK(B) <  RK(C)) ~= A) then pc++
OP_LE    A B C    if ((RK(B) <= RK(C)) ~= A) then pc++
关系指令对RK(B)和RK(C)进行比较,然后将比较结果与A指定的boolean值进行比较,来决定最终的boolean值。A在这里为每个关系指令提供了两种比较目标,满足和不满足。比如OP_LT何以用来实现“<”和“>”。

local a,b,c;
a = b < c;
        1       [1]     LOADNIL         0 2
        2       [2]     LT              1 1 2
        3       [2]     JMP             0 1     ; to 5
        4       [2]     LOADBOOL        0 0 1
        5       [2]     LOADBOOL        0 1 0
        6       [2]     RETURN          0 1
第二行的LT对寄存器1和2进行LT比较,如果结果为true,则继续执行后面的JMP,跳转到第五行的LOADBOOL,将寄存器0赋值为true;如果结果为false,则跳过后面的JMP,执行第四行的LOADBOOL,将寄存器0赋值为false。我们前面讲过关于LOADBOOL,第四行执行后会跳过第五行的赋值。

name    args    desc
OP_TEST    A C    if not (R(A) <=> C) then pc++
OP_TESTSET    A B C    if (R(B) <=> C) then R(A) := R(B) else pc++
逻辑指令用于实现and和or逻辑运算符,或者在条件语句中判断一个寄存器。TESTSET将寄存器B转化成一个boolean值,然后与C进行比较。如果不相等,跳过后面的JMP指令。否则将寄存器B的值赋给寄存器A,然后继续执行。TEST是TESTSET的简化版,不需要赋值操作。

local a,b,c;
a = b and c;
        1       [1]     LOADNIL         0 2
        2       [2]     TESTSET         0 1 0
        3       [2]     JMP             0 1     ; to 5
        4       [2]     MOVE            0 2
        5       [2]     RETURN          0 1
第二行的TESTSET将寄存器1的值与false比较。如果不成立,跳过JMP,执行第四行的MOVE,将寄存器2的值赋给寄存器0。否则,将寄存器1的值赋给寄存器0;然后执行后面的JMP。
上面的代码等价于

if b then
 a = c
else
 a = b
end

--------------------- 
作者:yuanlin2008 
来源:CSDN 
原文:https://blog.csdn.net/yuanlin2008/article/details/8504200 
版权声明:本文为博主原创文章,转载请附上博文链接!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值