daisuzz.log

"コンピュータシステムの理論と実装 第8章 バーチャルマシン #2: プログラム制御" を読んだ

「コンピュータシステムの理論と実装」を読んだメモを書いていきます。

前回は↓

iikanji.hatenablog.jp

メモ

  • 前回実装したVM変換器を改良して、VM言語のサブルーチン呼び出しとプログラムフロー制御コマンドに対応するVM変換器を実装する

プログラムフロー

  • goto
    • 指定したアドレスやラベルにjumpする
  • if-goto
    • スタックの最上位の値を条件としてtrueの場合指定したアドレスやラベルにjumpする

サブルーチン

  • システムやユーザによって実装された命令
  • メソッド、プロシージャ、関数など
  • サブルーチンを呼び出すと、低レイヤでは以下が行われる
    • 呼び出し側からサブルーチンへ引数を渡す
    • サブルーチン実行前に呼び出し側の状態を保存する
    • サブルーチンのローカル変数のためのメモリを確保する
    • サブルーチンを実行する
    • サブルーチンから呼び出し側へ値を返す
    • サブルーチンによって使われたメモリを再利用できるようにする
    • 呼び出し側の状態を復帰させる
    • サブルーチンの次の場所に実行を移す
  • サブルーチン呼び出し
    • ビルトインのコマンドと同じようにサブルーチンを呼び出す
    • サブルーチンはローカル変数を使うことが一般的
    • サブルーチンが生きている間はローカル変数が使える
    • ネストしたサブルーチンや再帰呼び出しの場合も、呼び出し側の情報をスタックにpushしたあとに呼び出された側を処理すれば簡単に実装できる
  • ワーキングスタック
    • add,subなどの算術/論理演算やpush,popなどスタックに対する命令をサポートするためのメモリ領域
  • グローバルスタック
    • 処理中のサブルーチンとreturnを待つ他のすべてのサブルーチンのためのメモリ領域
  • リターンアドレス
    • サブルーチン呼び出しの次のコマンドのアドレス
    • サブルーチンの処理から呼び出し側に戻るために必要
    • サブルーチンを実行する前にリターンアドレスをスタックに格納
    • サブルーチン内部のreturnコマンドを読み込んだ場合リターンアドレスをスタックから取得してjump先を指定する

ブートストラップコード

  • ROM[0]から始まるコードセグメント
  • プログラムの最初に実行されるコード
  • VMはSys.initを最初に呼び出し、Sys.initがメイン関数を呼び出す
  • 各言語のコンパイラはSys.initから呼び出す関数を設定することで最初に実行されるコードを実現している
  • Javaで最初にmain()メソッドが呼び出されるような制御がSys.initによって実現できる

実装

サブルーチン呼び出しコマンドとプログラムフロー制御コマンドに対応したVM変換器を実装する。 Kotlinで実装した例は以下。

github.com

感想

  • 今回はスタックを利用したVM上でサブルーチン呼び出しをアセンブリに変換したが、GoのようにVM上で実行されない言語ではどのようにバイナリコードに変換しているのか仕組みが気になる

次章はこちら

iikanji.hatenablog.jp