2

これは実際には Haskell に関する質問ではありませんが、Haskell タグをフォローしていて、これに対する答えを知っている人がたくさんいると思います...

私は現在、関数の入力出力、およびローカル変数一時的な値をすべて同じスタックに保持しながら、終了時に正しいスタック レイアウトになる方法について頭を悩ませようとしています。

通常、スタックは、最上位のスタック項目のみを変更するプッシュおよびプル操作を提供します。スタックのさらに下にあるアイテムへのランダム読み取りアクセスが許可されることもあります。(これは、そこに変数を保持し、それらにランダムアクセスする方法を説明しています。) しかし、通常、スタックのサイズを変更する唯一の方法は、そこから項目をプルすることです。スタックの一番上にアイテムを保持し、その下のものを削除したい場合、これはあまり良くありません。

実際のコンパイラはどのようにこれを行うのですか?

4

2 に答える 2

2

Haskell と直接話すことはできませんが、一般に、関数との間でデータをやり取りする方法を指定するのは、アプリケーション バイナリ インターフェイス (または ABI) の仕事です (呼び出し規約として知られています)。呼び出し規約とデータのサイズによっては、言及したものの一部またはすべてが、スタックではなくレジスタ (またはグローバル) に格納される場合があります。さらに、呼び出し元の関数への戻りアドレスと、場合によってはプロセッサの状態もスタックに格納されます。

たとえば、OS X IA-32 Function Calling Conventionsを取り上げます。スタック レイアウト:

OS X IA-32 スタック規約

この呼び出し規約では、戻り値は通常レジスタに格納されます。

于 2013-03-16T13:04:45.727 に答える
2

コール スタックフレームでは、引数が入るスペースのに戻り値用に予約されたスペースを確保し、次にローカルにスペースを確保できます。そのため、タイプを知ることは、その予約済みスペースのサイズを決定するのに役立ちます。または、Lisp のような動的言語では、ボックス化された値へのポインターがそこに移動します。これは、特定の関数呼び出しプロトコルの一部にすぎません。

ところで、クロージャを持つ言語のランタイム スタックは、通常はツリーです (「Funarg 問題」を参照してください)。

于 2013-03-16T12:48:12.507 に答える