探索Lua 5.2内部実装:仮想マシン命令(8)LOOP
テキスト
Lua5.2種類のforループを除いて、その他の各種ループはすべて関係と論理命令を使って、JMP命令に協力して完成します.
forループについてLua 5.2 numeric for loopとgeneric for loopに対応する2つの専用命令を使用した.
name
args
desc
OP_FORLOOP
A sBx
R(A)+=R(A+2); if R(A) OP_FORPREP
A sBx
R(A)-=R(A+2); pc+=sBx
上記の例では2~4行の初期化サイクルで使用した3つの内部局所変数を用いた.5行目のFOREPREPは、このループを準備するために使用され、for indexからfor stepを減算し、7行目にジャンプします.7行目のFORLOPはfor indexにfor stepを追加し、for limitと比較します.for limit以下の場合は、iをfor indexに設定し、6行目に戻ります.そうでなければループを終了します.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 }
Generic for loop内部でも3つの局所変数を用いてループを制御し,それぞれ「for generator」、「for state」および「for control」です.for generatorは反復で使用されるclosureを格納するために使用され、反復のたびにこのclosureが呼び出されます.for stateとfor controlはfor generatorに渡される2つのパラメータを格納するために使用されます.Generic for loopはまた、for generatorの戻り値を格納するためにカスタムローカル変数i,vを使用します.
前例の1~3行はinの後の式リスト(1,2,3)を用いて3つの内部で使用される局所変数を初期化した.4行目のJMPは6行目に移行します.TFORCAL教用レジスタ0(for generator)のclosureは、for stateおよびfor controlに渡され、結果をカスタムローカル変数リストiおよびvに返す.7行目はTFOROLOOPを呼び出してループ条件判断を行い,iが空であるか否かを判断する.空でない場合は、iの値をfor controlに割り当て、5行目にジャンプしてループします.
Lua5.2種類のforループを除いて、その他の各種ループはすべて関係と論理命令を使って、JMP命令に協力して完成します.
local a = 0;
while(a < 10) do
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
2行目はLTを用いてレジスタ0とオープン10を比較し、成立より小さい場合は3行目のJMPをスキップし、4行目のADD命令を実行し、aを1加算して5行目のJMPを実行し、2行目にジャンプして条件を再判断する.以下が成立しない場合は、次のJMP命令を直接実行し、6行目の終了にジャンプします.forループについてLua 5.2 numeric for loopとgeneric for loopに対応する2つの専用命令を使用した.
name
args
desc
OP_FORLOOP
A sBx
R(A)+=R(A+2); if R(A) OP_FORPREP
A sBx
R(A)-=R(A+2); pc+=sBx
local a;
for i = 1, 10 do
a = i;
end
main <test.lua:0,0> (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内部では、「for index」、「for limit」、「for step」の3つのローカル変数を使用してループを制御します.「for index」は初期値とループカウンタを格納し、「for limit」は格納サイクル上限とし、「for step」は格納サイクルステップ長として使用します.上記のプログラムでは,3つの値はそれぞれ1,10,1である.この3つのローカル変数は使用者には見えません.コードを生成するlocalsテーブルにこの3つのローカル変数を見ることができます.彼らの有効範囲は5行目の8行目、つまりforサイクル全体です.もう1つ使用するローカル変数は,ユーザが自分で指定したカウンタであり,前例では「i」である.この局所変数の有効範囲は6~7行,すなわちループの内部であることがわかる.この変数は、ループのたびに「for index」変数に設定されて使用されます.上記の例では2~4行の初期化サイクルで使用した3つの内部局所変数を用いた.5行目のFOREPREPは、このループを準備するために使用され、for indexからfor stepを減算し、7行目にジャンプします.7行目のFORLOPはfor indexにfor stepを追加し、for limitと比較します.for limit以下の場合は、iをfor indexに設定し、6行目に戻ります.そうでなければループを終了します.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 <test.lua:0,0> (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に渡される2つのパラメータを格納するために使用されます.Generic for loopはまた、for generatorの戻り値を格納するためにカスタムローカル変数i,vを使用します.
前例の1~3行はinの後の式リスト(1,2,3)を用いて3つの内部で使用される局所変数を初期化した.4行目のJMPは6行目に移行します.TFORCAL教用レジスタ0(for generator)のclosureは、for stateおよびfor controlに渡され、結果をカスタムローカル変数リストiおよびvに返す.7行目はTFOROLOOPを呼び出してループ条件判断を行い,iが空であるか否かを判断する.空でない場合は、iの値をfor controlに割り当て、5行目にジャンプしてループします.