Hatena::Groupxn--272ax3f

スクリプト言語の作り方13日目中間コード・インタプリタを作る

スクリプト言語の作り方13日目中間コード・インタプリタを作る

プレゼンテーション

中間コードと機械語

  • これまでは抽象構文木をたどりながら実行してきた
    • 遅そう
  • 構文木の節を一列に並べ直して、中間コードをつくる
    • 実行時はこの中間コードを用いる
    • Storeでは中間コードは実行時毎に生成する
      • Javaではファイルに保存している
  • 今回は中間コードの最適化はしない

Stone仮想機械

オペコード

命令は命令種別(オペコード)とレジスタの番号等のオペランドで構成される 整数67を2番目のレジスタr2に格納する命令
iconst 67 r2
実際に格納される命令
1 0 0 0 67 -3

コードを見よ

Opecode.java

  • 命令からbyteへのencode, decode

StoneVM.java

スタックによる環境の実現

  • 環境をスタックとヒープ領域に実現する
  • 変数の値の格納場所を事前に決めておき、名前でなく番号で環境を引く
  • 大域変数の環境はヒープを使う

StoneVMEnv

f:id:ninjinkun:20120808090632p:image

レジスタの利用

その上位の断片が現在0番目からi番目までのレジスタを計算の途中結果を保存するために使用中として、i+1番目以降のレジスタを自由に使って計算を行い、計算結果をi+1番目のレジスタに格納して終わる

変数の値の参照

if文とwhile文

  • pcの値を書き換えてジャンプさせる
  • ifzero
    • 指定されたレジスタの値が0のときにpcを書き換える
  • goto
    • 無条件にpcを書き換える

if else文

f:id:ninjinkun:20120808090630p:image

while文

f:id:ninjinkun:20120808090631p:image
  • ifnonzero文も追加すれば簡単に書ける

関数の定義と呼び出し

f:id:ninjinkun:20120808090629p:image f:id:ninjinkun:20120808090628p:image
  • call 関数呼び出し命令
    • retに戻る位置を格納
    • 関数を呼び出し
  • save 全てのレジスタを待避する
  • restrore 待避されたレジスタを戻す
    • fpをspにコピー
    • 汎用レジスタとretとfpを元の値に戻す
  • return
    • retの位置に戻る
  • StoneVM.javaのコードを見ると処理が書いてございます

仮想機械語への変更

  • 仮想機械語への変換も実行時間に含まれる
  • 関数が呼び出されたときだけ関数本体を仮想機械で実行する
  • 通常の部分はこれまで通りevalする
  • VmFunctionクラス
    • 仮想機械語の先頭位置を記録する
  • 実際には各節のcompileメソッドが変換を行う
  • Code.java
    • リスト13.7
    • VMにコードの実体を保存していくクラス
    • スタックフレームの大きさやレジスタの数も保持する

仮想機械を使った実行

  • defの宣言時に変換が走るということは、最初に抽象構文木を全部変換するイメージとは違いますね…

結果

  • 結果的に特に速くならないらしい
    • 最適化をまったくしていないため
  • メモリリークもしているらしい