Lua5.3 虚拟机指令分析(八)循环
来源:互联网 发布:剑网三捏脸数据免费 编辑:程序博客网 时间:2024/06/05 14:35
Lua5.3 虚拟机指令分析(八)循环
while
Lua 处了 for 循环之外的其它各种循环(while)都使用关系和逻辑指令,配合JMP 指令来完成。
TTcs-Mac-mini:OpCode ttc$ cat tOP_WHILE.lualocal a = 0; while(a < 10) do a = a + 1; end print(a)TTcs-Mac-mini:OpCode ttc$ ./luac -l -l tOP_WHILE.luamain <tOP_WHILE.lua:0,0> (9 instructions at 0x7ff365c039c0)0+ params, 3 slots, 1 upvalue, 1 local, 4 constants, 0 functions 1 [1] LOADK (iABx) [A]0 [K]-1 ; 0 2 [2] LT (iABC) [A]0 [ISK]0[B]0[ISK]256[C]-2 ; - 10 3 [2] JMP (iAsBx) [A]0 [sBx]2 ; to 6 4 [3] ADD (iABC) [A]0 [ISK]0[B]0[ISK]256[C]-3 ; - 1 5 [3] JMP (iAsBx) [A]0 [sBx]-4 ; to 2 6 [6] GETTABUP (iABC) [A]1 [ISK]0[B]0[ISK]256[C]-4 ; _ENV "print" 7 [6] MOVE (iABC) [A]2 [ISK]0[B]0[ISK]0 8 [6] CALL (iABC) [A]1 [ISK]0[B]2[ISK]0[C]1 9 [6] RETURN (iABC) [A]0 [ISK]0[B]1[ISK]0constants (4) for 0x7ff365c039c0: 1(idx) 0 2(idx) 10 3(idx) 1 4(idx) "print"locals (1) for 0x7ff365c039c0: 0 a(name) 2(startpc) 10(endpc)upvalues (1) for 0x7ff365c039c0: 0 _ENV(name) 1(instack) 0(idx)TTcs-Mac-mini:OpCode ttc$
第二条指令 使用LT 对寄存器 0 和 常量 10 比较,如果结果 与 A 为 1 (true) 比较 不相等(false),则跳过第三条指令 JMP ,执行第四条指令 ADD ,将寄存器 0 的值 加一 后,执行第五条指令 JMP ,sBx = -4,说明向前跳转 4条指令,跳转到 第二条指令, 这里就是循环,直到第二条LT 指令的结果 与 A 为1(true)比较 相等(true),则执行 第三条指令 JMP,sBx = 2,向后跳转 2条指令,跳转到第6条指令。 循环结束。
for 相关指令
for 循环分为两类:
1. 一种是 numeric for loop,循环变量以某个长度来递增,直到某个阈值时 退出 for 循环。
2. 另一种 generic for loop,每次循环开始时调用一个函数,只有当返回值部位 nil 时才继续进行循环。
numeric for loop
'' '' OP_FORLOOP,/* A sBx R(A)+=R(A+2);' if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/'' '' '' OP_FORPREP,/* A sBx R(A)-=R(A+2); pc+=sBx */TTcs-Mac-mini:OpCode ttc$ cat tOP_FORLOOP.lualocal afor i = 1,10 do a=iendprint(a)TTcs-Mac-mini:OpCode ttc$ ./luac -l -l tOP_FORLOOP.luamain <tOP_FORLOOP.lua:0,0> (11 instructions at 0x7fd3aa4039d0)0+ params, 5 slots, 1 upvalue, 5 locals, 3 constants, 0 functions 1 [1] LOADNIL (iABC) [A]0 [ISK]0[B]0[ISK]0 2 [2] LOADK (iABx) [A]1 [K]-1 ; 1 3 [2] LOADK (iABx) [A]2 [K]-2 ; 10 4 [2] LOADK (iABx) [A]3 [K]-1 ; 1 5 [2] FORPREP (iAsBx) [A]1 [sBx]1 ; to 7 6 [3] MOVE (iABC) [A]0 [ISK]0[B]4[ISK]0 7 [2] FORLOOP (iAsBx) [A]1 [sBx]-2 ; to 6 8 [5] GETTABUP (iABC) [A]1 [ISK]0[B]0[ISK]256[C]-3 ; _ENV "print" 9 [5] MOVE (iABC) [A]2 [ISK]0[B]0[ISK]0 10 [5] CALL (iABC) [A]1 [ISK]0[B]2[ISK]0[C]1 11 [5] RETURN (iABC) [A]0 [ISK]0[B]1[ISK]0constants (3) for 0x7fd3aa4039d0: 1(idx) 1 2(idx) 10 3(idx) "print"locals (5) for 0x7fd3aa4039d0: 0 a(name) 2(startpc) 12(endpc) 1 (for index)(name) 5(startpc) 8(endpc) 2 (for limit)(name) 5(startpc) 8(endpc) 3 (for step)(name) 5(startpc) 8(endpc) 4 i(name) 6(startpc) 7(endpc)upvalues (1) for 0x7fd3aa4039d0: 0 _ENV(name) 1(instack) 0(idx)TTcs-Mac-mini:OpCode ttc$
Numeric for loop内部使用了3个局部变量来控制循环,他们分别是”for index”,“for limit”和“for step”。
1. “for index”用作存放初始值和循环计数器;
2. “for limit”用作存放循环上限;
3. “for step”用作存放循环改变长度。
对于上面的代码,三个值分别为 1,20,1,这三个局部变量对于使用者是不可见得,我们可以在生成代码的locals表中看到这3个局部变量,他们的有效作用范围为第五条指令 到 第八条指令,也就是整个for循环 子结构(block)。
还有一个使用到的局部变量,就是使用者自己指定的计数器(i)。可以看到,这个局部变量的有效作用范围 为第六条指令 到 第七条指令,也就是 循环内部。这个变量在每次循环时都被设置成”for index”变量来使用。
第二条指令到 第四条指令 初始化循环使用的3个 内部局部变量。
第五条FORPREP 指令将 寄存器 1 “for index” 减去一个 寄存器 3 “for step” 的值 赋给 寄存器 1 ,sBx= 1,PC +1 ,跳转到第七条指令 FORLOOP 执行,将 寄存器 1 “for index” 加上一个 寄存器 3 “for step” 的值 赋给 寄存器 1 ,然后与 “for limit” 比较,如果小于等于 “for limit”,则将 i 设置成 “for index”,sBx = -2 向前跳转两条指令, PC -2 = 6 ,然后跳回 第 六条指令。否则就退出循环。
可以看出来,i 并不用于真正的循环计数,而只是在每次循环时被赋予真正的计数器 “for index” 的值而已,所以在循环中修改 i 不会影响循环计数。
generic for loop
'' OP_TFORCALL,/* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */'' OP_TFORLOOP,/* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }*/TTcs-Mac-mini:OpCode ttc$ cat tOP_TFORCALL.lualocal t = {1,2,3,4}for i,v in ipairs(t) do print(i,v)endTTcs-Mac-mini:OpCode ttc$ ./luac -l -l tOP_TFORCALL.luamain <tOP_TFORCALL.lua:0,0> (17 instructions at 0x7ff1504039e0)0+ params, 9 slots, 1 upvalue, 6 locals, 6 constants, 0 functions 1 [1] NEWTABLE (iABC) [A]0 [ISK]0[B]4[ISK]0[C]0 2 [1] LOADK (iABx) [A]1 [K]-1 ; 1 3 [1] LOADK (iABx) [A]2 [K]-2 ; 2 4 [1] LOADK (iABx) [A]3 [K]-3 ; 3 5 [1] LOADK (iABx) [A]4 [K]-4 ; 4 6 [1] SETLIST (iABC) [A]0 [ISK]0[B]4[ISK]0[C]1 ; 1 7 [2] GETTABUP (iABC) [A]1 [ISK]0[B]0[ISK]256[C]-5 ; _ENV "ipairs" 8 [2] MOVE (iABC) [A]2 [ISK]0[B]0[ISK]0 9 [2] CALL (iABC) [A]1 [ISK]0[B]2[ISK]0[C]4 10 [2] JMP (iAsBx) [A]0 [sBx]4 ; to 15 11 [3] GETTABUP (iABC) [A]6 [ISK]0[B]0[ISK]256[C]-6 ; _ENV "print" 12 [3] MOVE (iABC) [A]7 [ISK]0[B]4[ISK]0 13 [3] MOVE (iABC) [A]8 [ISK]0[B]5[ISK]0 14 [3] CALL (iABC) [A]6 [ISK]0[B]3[ISK]0[C]1 15 [2] TFORCALL (iABC) [A]1 [ISK]0[ISK]0[C]2 16 [2] TFORLOOP (iAsBx) [A]3 [sBx]-6 ; to 11 17 [4] RETURN (iABC) [A]0 [ISK]0[B]1[ISK]0constants (6) for 0x7ff1504039e0: 1(idx) 1 2(idx) 2 3(idx) 3 4(idx) 4 5(idx) "ipairs" 6(idx) "print"locals (6) for 0x7ff1504039e0: 0 t(name) 7(startpc) 18(endpc) 1 (for generator)(name) 10(startpc) 17(endpc) 2 (for state)(name) 10(startpc) 17(endpc) 3 (for control)(name) 10(startpc) 17(endpc) 4 i(name) 11(startpc) 15(endpc) 5 v(name) 11(startpc) 15(endpc)upvalues (1) for 0x7ff1504039e0: 0 _ENV(name) 1(instack) 0(idx)TTcs-Mac-mini:OpCode ttc$
Generic for loop内部也使用了3个局部变量来控制循环,分别是”for generator”,“for state”和“for control”。
- “for generator”,用来存放迭代使用的closure,每次迭代都会调用这个closure;
- “for state”, “for control”,用于存放传给 “for generator”的两个参数
Generic for loop还使用自定义的局部变量i,v,用来存储”for generator”的返回值。
前8条指令 初始化 表 t 。
第10条指令 JMP sBx = 4, PC+4 = 15,跳转到第15条指令 TFORCALL 开始执行,使用寄存器 1 “for generator” 中的 closure,传入 A+1 = 2 寄存器 “for state”,和 A+2 = 3 寄存器 “for control” ,然后将结果返回给 A+3 = 4 寄存器 表示的局部变量 i 和 A+2+C = 5 寄存器表示的 局部变量 v。 然后执行第17条指令 TFORLOOP 进行循环条件判断,判断 A+1 = 4 寄存器 也就是局部变量 i 是否为 nil,如果不为空,则将寄存器 4 ,也就是局部变量 i 的值赋给 寄存器 3 “for control”, sBx = -6 , PC-6 = 11 ,然后跳转 第11条指令 开始进行循环。
- Lua5.3 虚拟机指令分析(八)循环
- Lua5.3 虚拟机指令分析(二)赋值指令
- Lua5.3 虚拟机指令分析(十)表相关指令
- Lua5.3 VM 分析(八)For 循环
- Lua5.3 虚拟机指令分析(一)概述
- Lua5.3 虚拟机指令分析(三)表达式运算
- Lua5.3 虚拟机指令分析(四)分支与跳转
- Lua5.3 虚拟机指令分析(五)函数调用
- Lua5.3 虚拟机指令分析(六)不定参数
- 探索Lua5.2内部实现:虚拟机指令(3) Upvalues & Globals
- 探索Lua5.2内部实现:虚拟机指令(5)Arithmetic
- 探索Lua5.2内部实现:虚拟机指令(6)FUNCTION
- 探索Lua5.2内部实现:虚拟机指令(1) 概述
- 探索Lua5.2内部实现:虚拟机指令(2) MOVE & LOAD
- 探索Lua5.2内部实现:虚拟机指令(4) Table
- 探索Lua5.2内部实现:虚拟机指令(8) LOOP
- Lua5.3 VM 分析(一)字节码运行
- Lua5.3 VM 分析(二)表处理
- Java虚拟机二:垃圾回收机制
- Django中models文件中的字段
- Lua5.3 虚拟机指令分析(五)函数调用
- 搭建javaweb服务器
- Lua5.3 虚拟机指令分析(六)不定参数
- Lua5.3 虚拟机指令分析(八)循环
- Lua5.3 虚拟机指令分析(十)表相关指令
- Linux后台开发具备能力集锦
- Lua 5.3 源文件加载
- cocos studio 3.10
- 怎样理解阻塞非阻塞与同步异步的区别?(个人理解)
- java学习——java基础(五)之集合类
- 正则表达式学习笔记
- DecimalFormat用法