# 探索Lua5.2內部實現:虛擬機指令(8) LOOP
Lua5.2種除了for循環之外,其他的各種循環都使用關系和邏輯指令,配合JMP指令來完成。
~~~
local?a?=?0;??
while(a?
????a?=?a?+?1;??
end??
~~~
~~~
1???????[1]?????LOADK???????????0?-1????;?0??
2???????[2]?????LT??????????????0?0?-2??;?-?10??
3???????[2]?????JMP?????????????0?2?????;?to?6??
4???????[3]?????ADD?????????????0?0?-3??;?-?1??
5???????[3]?????JMP?????????????0?-4????;?to?2??
6???????[4]?????RETURN??????????0?1??
~~~
第二行使用LT對寄存器0和敞亮10進行比較,如果小于成立,跳過第三行的JMP,運行第四行的ADD指令,將a加1,然后運行第五行的JMP,跳轉回第二行,重新判斷條件。如果小于不成立,則直接運行下一個JMP指令,跳轉到第六行結束。
對于for循環,Lua5.2使用了兩套專門的指令,分別對應numeric for loop和generic for loop。
| name | args | desc |
|---|---|---|
| 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 |
~~~
local?a;??
for?i?=?1,?10?do??
????a?=?i;??
end??
~~~
~~~
main??(8?instructions?at?0x80048eb0)??
0+?params,?5?slots,?1?upvalue,?5?locals,?2?constants,?0?functions??
????????1???????[1]?????LOADNIL?????????0?0??
????????2???????[2]?????LOADK???????????1?-1????;?1??
????????3???????[2]?????LOADK???????????2?-2????;?10??
????????4???????[2]?????LOADK???????????3?-1????;?1??
????????5???????[2]?????FORPREP?????????1?1?????;?to?7??
????????6???????[3]?????MOVE????????????0?4??
????????7???????[2]?????FORLOOP?????????1?-2????;?to?6??
????????8???????[4]?????RETURN??????????0?1??
constants?(2)?for?0x80048eb0:??
????????1???????1??
????????2???????10??
locals?(5)?for?0x80048eb0:??
????????0???????a???????2???????9??
????????1???????(for?index)?????5???????8??
????????2???????(for?limit)?????5???????8??
????????3???????(for?step)??????5???????8??
????????4???????i???????6???????7??
upvalues?(1)?for?0x80048eb0:??
????????0???????_ENV????1???????0??
~~~
Numeric for loop內部使用了3個局部變量來控制循環,他們分別是"for index",“for limit”和“for step”。“for index”用作存放初始值和循環計數器,“for limit”用作存放循環上限,“for step”用作存放循環步長。對于上面的程序,三個值分別是1,10和1。這三個局部變量對于使用者是不可見得,我們可以在生成代碼的locals表中看到這3個局部變量,他們的有效范圍為第五行道第八行,也就是整個for循環。還有一個使用到的局部變量,就是使用者自己指定的計數器,上例中為"i"。我們可以看到,這個局部變量的有效范圍為6~7行,也就是循環的內部。這個變量在每次循環時都被設置成"for index"變量來使用。
上例中2~4行初始化循環使用的3個內部局部變量。第五行FORPREP用于準備這個循環,將for index減去一個for step,然后跳轉到第七行。第七行的FORLOOP將for index加上一個for step,然后與for limit進行比較。如果小于等于for limit,則將i設置成for index,然后跳回第六行。否則就退出循環。我們可以看到,i并不用于真正的循環計數,而只是在每次循環時被賦予真正的計數器for index的值而已,所以在循環中修改i不會影響循環計數。
| name | args | desc |
|---|---|---|
| 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 } |
~~~
for?i,v?in?1,2,3?do??
????a?=?1;??
end??
~~~
~~~
main??(8?instructions?at?0x80048eb0)??
0+?params,?6?slots,?1?upvalue,?5?locals,?4?constants,?0?functions??
????????1???????[1]?????LOADK???????????0?-1????;?1??
????????2???????[1]?????LOADK???????????1?-2????;?2??
????????3???????[1]?????LOADK???????????2?-3????;?3??
????????4???????[1]?????JMP?????????????0?1?????;?to?6??
????????5???????[2]?????SETTABUP????????0?-4?-1?;?_ENV?"a"?1??
????????6???????[1]?????TFORCALL????????0?2??
????????7???????[1]?????TFORLOOP????????2?-3????;?to?5??
????????8???????[3]?????RETURN??????????0?1??
constants?(4)?for?0x80048eb0:??
????????1???????1??
????????2???????2??
????????3???????3??
????????4???????"a"??
locals?(5)?for?0x80048eb0:??
????????0???????(for?generator)?4???????8??
????????1???????(for?state)?????4???????8??
????????2???????(for?control)???4???????8??
????????3???????i???????5???????6??
????????4???????v???????5???????6??
upvalues?(1)?for?0x80048eb0:??
????????0???????_ENV????1???????0??
~~~
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的返回值。
上例中1~3行使用in后面的表達式列表(1,2,3)初始化3個內部使用的局部變量。第四行JMP調轉到第六行。TFORCALL教用寄存器0(for generator)中的closure,傳入for state和for control,并將結果返回給自定義局部變量列表i和v。第七行調用TFORLOOP進行循環條件判斷,判斷i是否為空。如果不為空,將i的值賦給for control,然后跳轉到第五行,進行循環。
- 前言
- 探索Lua5.2內部實現:TString
- 探索Lua5.2內部實現:虛擬機指令(1) 概述
- 探索Lua5.2內部實現:虛擬機指令(2) MOVE & LOAD
- 探索Lua5.2內部實現:虛擬機指令(3) Upvalues & Globals
- 探索Lua5.2內部實現:虛擬機指令(4) Table
- 探索Lua5.2內部實現:虛擬機指令(7) 關系和邏輯指令
- 探索Lua5.2內部實現:虛擬機指令(8) LOOP
- 探索Lua5.2內部實現:編譯系統(1) 概述
- 探索Lua5.2內部實現:編譯系統(2) 跳轉的處理
- 探索Lua5.2內部實現:編譯系統(3) 表達式
- 探索Lua5.2內部實現:編譯系統(4) 表達式分類
- 探索Lua5.2內部實現:Garbage Collection(1) 原理
- 探索Lua5.2內部實現:Garbage Collection(2)