* 仮想マシン [#c5820a88] #contents 実装のためのメモやら設計方針やらを書いておくページ。 * 構成 [#ke3cf9b5] - 1つのScriptVM - 1つ以上のScriptContext ** ScriptVM [#bb572835] - 仮想マシン。 - コンパイル済みの命令コード,ユーザー定義型の初期化データ(.init)を持つ。 - staticなデータはこいつが持ち,複数のContextで共有することになる。 ** ScriptContext [#uc0127e1] - コンテキスト。スレッド。 - スタック,レジスタは各ScriptContextがそれぞれ持つ。 * ScriptVM [#hae3d592] ** 手順 [#i4dc4609] - セットアップ前準備(ユーザーがやる) -- コンパイル済みのスクリプトコードの追加。 -- 関数,クラス類,変数類のC++とのバインド。 - セットアップ -- 1) リンク&未解決シンボルのチェック。 -- 2) staticデータに.initデータをコピー。 -- 3) 各クラスのstaticコンストラクタ&statinc invariant()を実行。 - ファイナライズ -- 1) 全ScriptContextが終了していることを確認。 -- 2) ガベージコレクトを実行。 -- 3) 各クラスのstatic invariant()&staticデストラクタを実行。 -- 4) ガベージコレクトを実行。 -- 5) ゴミが残っていないかチェック。 * ScriptContext [#q24e9b98] ** 実行開始手順 [#xe3c6b37] - (ユーザーがやる) - エントリーポイントとなる関数とその引数を設定。 ** インスタンスの生成手順 [#e0c3e509] - メモリ領域は確保済みとする。 - 1) .initデータを領域にコピー。 - 2) コンストラクタがあれば実行。 - 3) invariantがあれば実行。 - 4) scopeなclassもしくはstructなオブジェクトならデストラクタスタックに自身を追加 ** 関数に入るときの手順 [#v722abbb] - 1) 関数スタックにプッシュ ** 関数から抜けるときの手順 [#saac6cfb] - 1) 関数スタックの情報を元に,デストラクタスタックに積まれているオブジェクトを必要なだけポップ&実行 - 2) 関数スタックからポップ ** メンバ関数に入るときの手順 [#e65b2f19] - 1) publicなメンバ関数の呼び出しならinvariantがあれば実行。 - 2) 『関数に入るときの手順』を実行 ** メンバ関数から抜けるときの手順 [#yf66bb06] - 1) 『関数から抜けるときの手順』を実行 - 2) publicな関数の呼び出しならinvariantがあれば実行。 ** コンストラクタの手順 [#e7a580bf] - 1) 『関数に入るときの手順』を実行 - 2) structメンバ変数をデストラクタスタックにプッシュ - 3) 関数本体を実行 - 4) invariantがあれば実行 - 5) コンストラクトが正常に終了したと判断したので,デストラクタスタックに追加済みのstructメンバ変数をポップ。 - 6) 『関数から抜けるときの手順』を実行 ** デストラクタの手順 [#m98537bc] - 1) 『関数に入るときの手順』を実行 - 2) invariantがあれば実行 - 3) 関数本体を実行 - 4) 『関数から抜けるときの手順』を実行 ** tryキーワードの手順 [#yf2daf24] - 1) catchポイントを関数スタックにプッシュ ** catchキーワードの手順 [#q55cec00] - 1) catchポイントを関数スタックからポップ - 2) 必要な数だけデストラクタスタックをポップ&実行 ** finalyキーワードの手順 [#ne5b51a9] - 1) catchポイントを関数スタックからポップ ** throwキーワードの手順 [#r72394de] - 1) throwされたIExceptionをひかえておく - 1) throwされたStd.IExceptionをひかえておく - 2) 関数スタックをなめていき,該当するcatchポイントを探す。見つからなければContext停止。 - 3) 該当のcatchポイントまで関数スタックをポップ&デストラクタスタックのポップ&実行を繰り返す。 - このとき,デストラクタ実行中に新しい例外がthrowされたら再び1に戻り,古いIExceptionは上書きされる。(C#の挙動にあわせた) - このとき,デストラクタ実行中に新しい例外がthrowされたら再び1に戻り,古いStd.IExceptionは上書きされる。(C#の挙動にあわせた) * メモ [#k2ac7658] ** 例外発生時のデストラクトでさらに例外が発生したとき [#n30c1192] C#の挙動にあわせよう。 #code(csharp,){{ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace CSharpTest { class Program { class ExceptionA : Exception { public ExceptionA( string msg ) : base( "ExceptionA:" + msg) { } }; class ExceptionB : Exception { public ExceptionB( string msg ) : base( "ExceptionB:" + msg) { } }; class Hoge : IDisposable { string str; public Hoge(string aStr) { str = aStr; } public void Dispose() { System.Console.WriteLine(str + " Hoge Dispose Enter"); throw new ExceptionA(str + " hoge dispose exp"); System.Console.WriteLine(str + " Hoge Dispose Exit"); } }; static void Main(string[] args) { try { using (var hogeA = new Hoge("a")) { using (var hogeB = new Hoge("b")) { System.Console.WriteLine("Enter Scope"); throw new ExceptionB("throw exp"); System.Console.WriteLine("Exit Scope"); } } } catch (ExceptionA exp) { System.Console.WriteLine("Catch A"); } catch (ExceptionB exp) { System.Console.WriteLine("Catch B"); } finally { } } } } }} 実行結果 #code(){{ Enter Scope b Hoge Dispose Enter a Hoge Dispose Enter Catch A 続行するには何かキーを押してください . . . }} ってことで最後に投げられた例外が有効になるみたい。 |