LOCAL_ENV_JUMP (addr)
このインストラクションは、ローカル関数の最適化に現れる。この命令は、引数分のスタックを持つ環境フレームを作成し、addr(SPポインタとARGPポインタの差で分かる)にジャンプする。
i. 変数の個数を命令から取り出す。
ii. 変数の個数分のローカル環境を作成する。
iii. addrにジャンプする。
以下にこのインストラクションでの動作を記述する。
インストラクションコードから引数を取り出し、引数のデータ数分だけ、ENVポインタのアップし、環境フレームを示す変数tenvに代入。
以下の条件によって処理を分岐する
i. 環境フレームがスタックにあり、継続フレームが環境フレームの上にある場合、引数フレームを継続フレームの最上部にシフトする。
ii. 環境フレームがスタックにあるが、継続フレームが環境フレームの上にない場合、引数フレームを環境フレームの最上段にシフトする。
iii. 環境フレームがヒープにある場合、引数フレームを現在の継続レフームの最上段にシフトする。
iiii. それ以外の場合、引数フレームをスタックベースにシフトする。
SP−ARGPが0以上なら、上記操作を行った環境ヘッダを環境フレームにプッシュする。それ以外では、tenvの値を環境フレームのアドレスとする。
この後、SP、ARGPポインタを上記操作に基づいて得たアドレスを基準として、addr分シフトする。
使用例については、以下の操作を行い、disasmを実施。
ここで、取り上げた例は、リストの操作を行うfoldの実装例である。例の中でコアとなるのは、(loop (proc seed (car lis) (cdr lis))である。この部分が以下ではLOCAL-ENV-JUMP命令を使った単なるループになっている。
詳細は、川合史朗さんのインタビュー記事よりを参照のこと。
(define (fold proc seed lis) (define (loop seed lis) (if (null? lis) seed (loop (proc seed (car lis)) (cdr lis)))) (loop seed lis))
(disasm fold)
main_code (name=fold, code=0x105f00, size=22, const=0, stack=23):
args: #f
0 LREF1-PUSH ; seed
1 LREF0-PUSH ; lis
2 LOCAL-ENV(2) ; (loop seed lis)
3 LREF0 ; lis
4 BNNULL 8 ; (null? lis)
6 LREF1 ; seed
7 RET
8 PRE-CALL(2) 15
10 LREF1-PUSH ; seed
11 LREF0 ; lis
12 CAR-PUSH ; (car lis)
13 LREF12 ; proc
14 CALL(2) ; (proc seed (car lis))
15 PUSH
16 LREF0 ; lis
17 CDR-PUSH ; (cdr lis)
18 LOCAL-ENV-JUMP(1) 3 ; (loop (proc seed (car lis)) (cdr lis))
20 RET
21 RET
#<undef>
コメントはありません。 コメント/Reading Gauche/vm/insn/LOCAL_ENV_JUMP?