ホーム | 機能 | ダウンロード | 拡張パッケージ | ドキュメント | 開発状況 -> English | -> Practical Scheme

VMのスタック操作 (未完)

GaucheのVMはごく単純なスタックマシンである。 だが、Schemeの場合、first class continuationを実現するために、 スタックフレームがヒープにセーブされたり、逆にヒープからスタックに復元されたりという 操作が入って来るので、うっかりすると自分でも混乱してバグを持ち込むことがある。 後で思い出せるように、ここに整理しておこう。


基本レジスタ

スタック操作に深くかかわるのは次のレジスタ群。

ScmEnvFrame *env

現在の環境のトップ。いわゆるstatic link。直接には、 最も内側の静的スコープで見えている環境を指している。 upポインタをたぐってゆけば上の環境に行ける。upポインタはNULLで終端される。

ScmContFrame *cont

現在のコンティニュエーションフレームのトップ。 いわゆるactivation record。多くのC言語実装のスタックモデルとは異なり、 Gaucheでは関数の引数フレームより前にコンティニュエーションフレームが積まれる。 すなわち、関数fooを呼び出す場合、(1) fooのコンティニュエーション をpush、(2) fooへ渡す引数を計算してpush (3) foo自体をコール、という 順序になる。

このため、ある関数が呼ばれた直後、およびその関数からリターンする直前は contはその関数の コンティニュエーションを指しているが、多くの場合は「これから呼び出される関数の コンティニュエーション」を指していることになる。

ScmEnvFrame *argp

これから呼び出すことになる関数へ渡すことになる、構築中の引数フレームへのポインタ。 引数フレームが完成していざ関数を呼ぶという段階で、この引数フレームは環境フレームへと つながれる。

Gaucheでは、引数は最初のものから順に評価されスタックに積まれる。 引数評価の途中で別の関数を呼ぶ必要がある場合は、作成中の引数フレームも コンティニュエーションの一部として扱われる。

ScmObj *sp

スタックポインタ。 Gauche VMではスタックはアドレスの低い方から高いほうへ伸びる。

ScmObj pc

プログラムカウンタ。Gaucheではプログラムは有向グラフとして表現されており、 具体的には単なるリストである。リスト終端に達した時点で現在の処理は終了し、 コンティニュエーションフレームがポップされ、そこに記録されている処理を続行する。 ポップすべきコンティニュエーションが無ければ、全てのコードの実行終了であるから、 VMのループからreturnする。

ScmObj val0

値レジスタ。式の評価結果はここに返る。push, popインストラクションは このレジスタとスタックとの間でpush/popを行う。

また、スタックに関するポインタは常に次の条件を満たす。