仮想マシン
実装のためのメモやら設計方針やらを書いておくページ。
構成
- 1つのScriptVM
- 1つ以上のScriptContext
ScriptVM
- 仮想マシン。
- コンパイル済みの命令コード,ユーザー定義型の初期化データ(.init)を持つ。
- staticなデータはこいつが持ち,複数のContextで共有することになる。
ScriptContext
- コンテキスト。スレッド。
- スタック,レジスタは各ScriptContextがそれぞれ持つ。
ScriptVMのセットアップ
ScriptVM
手順
- セットアップ前準備(ユーザーがやる)
- コンパイル済みのスクリプトコードの追加。
- 関数,クラス類,変数類のC++とのバインド。
- セットアップ
- 未解決シンボルのチェック。
- staticデータに.initデータをコピー。
- 各クラスのstaticコンストラクタを呼び出す。
- 1) リンク&未解決シンボルのチェック。
- 2) staticデータに.initデータをコピー。
- 3) 各クラスのstaticコンストラクタ&statinc invariant()を実行。
- ファイナライズ
- 1) 全ScriptContextが終了していることを確認。
- 2) ガベージコレクトを実行。
- 3) 各クラスのstatic invariant()&staticデストラクタを実行。
- 4) ガベージコレクトを実行。
- 5) ゴミが残っていないかチェック。
ScriptContext
実行開始手順
- (ユーザーがやる)
- エントリーポイントとなる関数とその引数を設定。
インスタンスの生成手順
- メモリ領域は確保済みとする。
- 1) .initデータを領域にコピー。
- 2) コンストラクタがあれば実行。
- 3) invariantがあれば実行。
- 4) scopeなclassもしくはstructなオブジェクトならデストラクタスタックに自身を追加
関数に入るときの手順
関数から抜けるときの手順
- 1) 関数スタックの情報を元に,デストラクタスタックに積まれているオブジェクトを必要なだけポップ&実行
- 2) 関数スタックからポップ
メンバ関数に入るときの手順
- 1) publicなメンバ関数の呼び出しならinvariantがあれば実行。
- 2) 『関数に入るときの手順』を実行
メンバ関数から抜けるときの手順
- 1) 『関数から抜けるときの手順』を実行
- 2) publicな関数の呼び出しならinvariantがあれば実行。
コンストラクタの手順
- 1) 『関数に入るときの手順』を実行
- 2) structメンバ変数をデストラクタスタックにプッシュ
- 3) 関数本体を実行
- 4) invariantがあれば実行
- 5) コンストラクトが正常に終了したと判断したので,デストラクタスタックに追加済みのstructメンバ変数をポップ。
- 6) 『関数から抜けるときの手順』を実行
デストラクタの手順
- 1) 『関数に入るときの手順』を実行
- 2) invariantがあれば実行
- 3) 関数本体を実行
- 4) 『関数から抜けるときの手順』を実行
tryキーワードの手順
catchキーワードの手順
- 1) catchポイントを関数スタックからポップ
- 2) 必要な数だけデストラクタスタックをポップ&実行
finalyキーワードの手順
throwキーワードの手順
- 1) throwされたStd.IExceptionをひかえておく
- 2) 関数スタックをなめていき,該当するcatchポイントを探す。見つからなければContext停止。
- 3) 該当のcatchポイントまで関数スタックをポップ&デストラクタスタックのポップ&実行を繰り返す。
- このとき,デストラクタ実行中に新しい例外がthrowされたら再び1に戻り,古いStd.IExceptionは上書きされる。(C#の挙動にあわせた)
メモ
例外発生時のデストラクトでさらに例外が発生したとき
C#の挙動にあわせよう。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
-
|
|
-
|
-
|
-
!
!
|
-
|
-
!
!
|
|
|
|
-
|
|
-
|
!
|
|
|
|
-
|
|
|
!
!
|
-
|
-
|
-
|
-
|
|
|
!
!
!
|
-
|
!
|
-
|
!
|
-
!
!
!
|
!
| #spanend
#spanadd
using System;
#spanend
#spanadd
using System.Collections.Generic;
#spanend
#spanadd
using System.Linq;
#spanend
#spanadd
using System.Text;
#spanend
#spanadd
#spanend
#spanadd
namespace CSharpTest
#spanend
#spanadd
{
#spanend
class Program
{
class ExceptionA : Exception
{
public ExceptionA( string msg ) : base( "ExceptionA:" + msg)
{
}
};
class ExceptionB : Exception
{
public ExceptionB( string msg ) : base( "ExceptionB:" + msg)
{
}
};
#spanadd
#spanend
class Hoge : IDisposable
{
string str;
public Hoge(string aStr)
{
str = aStr;
}
#spanadd
#spanend
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
{
}
}
}
#spanadd
}
#spanend
#spanadd
|
実行結果
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| #spanend
#spanadd
Enter Scope
#spanend
#spanadd
b Hoge Dispose Enter
#spanend
#spanadd
a Hoge Dispose Enter
#spanend
#spanadd
Catch A
#spanend
#spanadd
続行するには何かキーを押してください . . .
#spanend
#spanadd
|
ってことで最後に投げられた例外が有効になるみたい。
|