* メモ [#u10b9718] #contents * エンジンの型 [#z659e65c] 説明の際にところどころ出てくるので書いておく。 |名前|役割|h |SSObjectType|ユーザー定義型を扱うクラス。1ユーザー定義型につき1インスタンス。| |SSVariable|変数を扱うクラス。1変数につき1インスタンス。| |SSFunction|関数を扱うクラス。1関数につき1インスタンス。| |SSFunctionArg|関数の引数を扱うクラス。1引数につき1インスタンス。| |SSVirtualFuncTable|仮想関数テーブルを扱うクラス。1仮想関数テーブルにつき1インスタンス。| * コード生成 [#y3d91a37] シンプルでもいける気がしてきた。 ** レジスタ構成 [#ka053590] |Full Name|Short Name|Comment|h |Stack Register Pointer|SRP|スタックレジスタポインタ。&br; スタックレジスタの先頭アドレス。 &br;言い換えるとSR00の場所。| |Stack Pointer|SP|スタックポインタ。現在のスタック位置。| |Program Counter|PC|プログラムカウンタ。現在実行しているバイトコードのポインタ。| |Program Function|PF|プログラムの関数オブジェクトのポインタ。デバッグ用。| |Program Line|PL|プログラムのソースコードの行数。デバッグ用。| |Link Register|LR|リンクレジスタ。戻り先のバイトコードのポインタ。| |Function Register|FR|関数レジスタ。全部で16個。FR00 - FR16。| ** レジスタの概要 [#b2e56c51] - 1つのレジスタのサイズは8バイト。 - 4バイトでもいいかなと思ったが,64bit環境でポインタが1レジスタで表現できなくなるため,8バイトにした。 - ただし,メモリがきつきつの環境もあるので32bitモード用意する。その場合,64bitの整数・浮動小数,64bitのアドレス空間は扱えなくなる。 - 1つのレジスタはUNIONで表現。 #code(c,){{ struct Register { union { u32 data32; u64 data64; s32 i32val; s64 i64val; f32 f32val; f64 f64val; void* ptr; // 64bit環境だとこれは8バイト。 }; }; }} ** スタックレジスタ [#bb1584f7] - 計算の一時領域として使うレジスタはStackRegister(スタックレジスタ)呼び,SRと略す。 - スタックレジスタ数は動的に変更し,最大で256。それを越える必要がある関数は''コンパイルエラー''とする。 - SRP(Stack Register Pointer)からのオフセットがスタックレジスタの番号に相当する。 - SR01ならSRP + 0x08のアドレスとなる。(32bitモードなら+0x04) - 通常,関数の先頭でFUNCET命令を使い関数で使用するスタックレジスタの数 x レジスタのサイズ分,スタックから確保し,その先頭アドレスをSRPに設定する。 ** 変数とレジスタ [#w8f36726] - ローカル変数は全てスタックレジスタに割り当てられる。 - スコープを考慮してスタックレジスタの使用数はなるべく少なくて済むように最適化される。 - 一時変数もスタックレジスタに割り当てられる。 #code(c,){{ utility Hoge { static void func() { int a; // SR01 int b; // SR02 { int c; // SR03 } int d; // SR02 { int e; // SR03 } d = (a + b) * d; // (a + b)が一時変数としてSR03に格納される // SR03 = a + b; // SR02 = R03 * R02; } }; }} ** 戻り値とレジスタ [#lb8a56e2] - 戻り値はFR00に格納される。 - FUNCRT命令が実行されるとSR00の値はFR00にコピーされる。 #code(c,){{ utility Hoge { static int GetOne() { return 1; // FR00 = 1 } }; }} ** 引数とレジスタ [#g01df345] - 引数は関数レジスタのFR01から順番にレジスタに割り当てられる。 - 非staticなメンバ関数はFR01にthisポインタが割り当てられる。 - 関数レジスタは16個しか用意されていないので,引数の最大数はメンバ関数で14個,非メンバ関数は15個となります。(FR00は戻り値として使うため,引数に使用できない) #code(c,){{ pod Vector3 { float x; float y; float z; void func(float addValue) { // FR01 : this // FR02 : addValue } } }} ** アセンブラのイメージ [#sc9a365f] - 簡単なコード #code(c,){{ 0:int add(int a, int b) 1:{ 2: return a + b; 3:} 4:void func() 5:{ 6: int i = 3; 7: i = add(i , 4); 8:} # 命令コード Instruction: add: DFUNC 0x0000 DLINE 1 // '{'の位置 FUNCET 0x03 0x03 DLINE 2 ADDI32 R00 R01 R02 DLINE 3 // '}'の位置 FUNCLV 0x03 func: DFUNC 0x0001 DLINE 5 FUNCET 0x02 0x00 DLINE 6 LDSRC4 SR00 0x0000 DLINE 7 LDSRC4 SR01 0x0004 LDFRSR FR01 SR00 LDFRSR FR02 SR01 CALL 0x0000 LDRF SR00 FR00 FUNCLV 0x02 # コンパイル時に確定する定数のテーブル ConstantTable: 0x0000: 3 0x0004: 4 SymbolTable: 0x0000: int add(int,int) 0x0004: void func() }} ** 命令コード [#ac30d5cb] - どの命令コードも32bitで統一。 - SRegおよびFRegはu8。 |命令|書式|コメント|h |>|>|BGCOLOR(ORANGE):''ロード''| |LDSRC1|LDSRC4 SReg ConstantTableIndex(u16)|ConstantTableの値を指定したスタックレジスタにロード| |LDSRC2|~|~| |LDSRC4|~|~| |LDSRC8|~|~| |LDSRSR|LDSRSR SReg1 SReg2|SReg2の値をSReg1にロード| |LDSRSP|LDSRSP SReg1 StackPointerOffset(u16)|StackPointerから相対アドレス分移動したアドレスをReg1にロード| |LDSRP1|LDSRP1 SReg1 SReg2|SReg2の値をアドレスとみなし,SReg2が指す値を取得する| |LDSRP2|~|~| |LDSRP4|~|~| |LDSRP8|~|~| |LDSROJ|LDSROJ SReg1 SReg2|SReg2の値をobject型とみなし,SReg2が指すobjectの実体のアドレスのアドレスを取得する| |LDFRSR|LDFRSR FReg SReg|SRegの値をFRegにロード| |>|>|BGCOLOR(ORANGE):''演算''| |ADDxxx|ADDI32 SReg1 SReg2 SReg3|SReg1 = SReg2 + SReg3| |SUBxxx|SUBI32 SReg1 SReg2 SReg3|SReg1 = SReg2 - SReg3| |MULxxx|MULS32 SReg1 SReg2 SReg3|SReg1 = SReg2 * SReg3| |DIVxxx|MULS32 SReg1 SReg2 SReg3|SReg1 = SReg2 / SReg3| |MODxxx|MODS32 SReg1 SReg2 SReg3|SReg1 = SReg2 % SReg3| |>|>|BGCOLOR(ORANGE):''関数あれこれ''| |FENTER|FENTER AllocSRegNum CopyFRegNum|Function Enter. &br;まずスタックに現在のSPR,LR,PL,PFをつみ,SPを変更する。&br;AllocSRegNumで指定された数,スタックレジスタを確保し,SPRに設定する。SPを変更する。&br;CopyFRegNumで指定された数,スタックレジスタにFRに内容をコピーする。| |FLEAVE|FLEAVE FreeSRegNum|Function Leave. &br;FreeSRegNumで指定された数,スタックレジスタを解放しSPを変更する。&br;PF,PL,LR,SPR,をスタックから取り出し設定する。SPも変更する。&br;PCにLRを代入する。| |CALL|CALL SymbolTableIndex(u16)|LRにPCを代入する。 &br;SymbolTableIndexが示す関数の先頭バイトコードをPCに設定する。| |CALLVF|CALLVF SReg1 ConstantTableIndex(u16)|Call Virtual Function.&br;SReg1が指すオブジェクトの仮想関数の先頭バイトコードを求め,PCに代入する。&br;ConstantTableIndexが示す先にはSymbolTableIndex(u16)が2つ連続して存在する。&br;1つめは仮想関数の親となるSSObjectTypeが格納されているSymbolTableのIndex。&br;2つめは仮想関数自体のSSFunctionが格納されているSymbolTableのIndex。| |>|>|BGCOLOR(ORANGE):''スタック''| |PUSH|PUSH SReg ConstantTableIndex(u16)|ConstantTableIndexが指す定数サイズ(u32)減算し,指定のSRegに演算後のSPを設定する。| |POP|POP ConstantTableIndex(u16)|ConstantTableIndexが指す定数サイズ(u32)分,SPを加算する。| |>|>|BGCOLOR(ORANGE):''オブジェクト''| |OBJNEW|OBJNEW SReg SymbolIndex|Object New.&br;指定のSymbolIndexが指すObjectTypeのインスタンスを作成し,ハンドルをSReg1に代入する。| |OBJDEL|OBJDEL SReg|Object Delete.&br;指定のSRegが指すオブジェクトに対してdeleteする。| |OBJRFI|OBJRFI SReg|Object Reference Increment.&br;指定のSRegが指すオブジェクトのリファレンスカウンタをインクリメントする。| |OBJRFD|OBJRFD SReg|Object Reference Decrement.&br;指定のSRegが指すオブジェクトのリファレンスカウンタをデクリメントし,SRegに0を代入する。| |>|>|BGCOLOR(ORANGE):''デバッグ''| |DLINE|DLINE ConstantValue(u24)|Debug Line.&br;デバッグ情報のプログラム行数を代入するための命令。 &br;PLにConstantValueを代入する。| |DFUNC|DFUNC SymbolTableIndex(u16)|Debug Function.&br;デバッグ情報の関数オブジェクトを代入するための命令。&br;PFにSymbolTableIndexが示すアドレスを代入する。| * オブジェクトファイル [#sfc8fd99] - Cでいう.oのファイル。 含まれるもの - モジュール名 - 定数テーブル - シンボルテーブル - シンボル一覧 - シンボル解決情報 ** モジュール名 [#j6a7768c] - モジュール名が文字列として格納される。 ** 定数テーブル [#wf3e79a4] - 必要な定数テーブルの長さ。 - コンパイル時に解決されている定数郡。 - .oのファイルサイズ縮小のために,コンパイル時に解決されている定数郡は定数テーブルの先頭に置いておく。 - そうしておくことで,リンク時に解決される定数郡のデータ量が.oから削減される。(.sbssと同じ考え方) ** シンボルテーブル [#bfa16e2a] - 必要なシンボルテーブルの長さのみ格納される。 ** シンボル一覧 [#a5552a6f] - モジュールはユーザー定義型リストを持つ。 :ユーザー定義型リスト| - ユーザー定義型についての情報が0個以上格納されている。 - エンジンではユーザー定義型の情報が1つにつきSSObjectTypeが1つ生成される。 |項目|内容|例|h |シンボルのパス|文字列|BaseLib.Math.Vector3| |継承しているクラスのパス|文字列|Foo| |仮想関数テーブルリスト|別項:仮想関数テーブルリストを参照|| |変数リスト|別項:変数リストを参照|| |関数リスト|別項:関数リストを参照|| :仮想関数テーブルリスト| - 仮想関数テーブルについての情報が0個以上格納されている。 - エンジンでは仮想関数テーブルの情報が1つにつきSSVirutalFuncTableが生成される。 |項目|内容|例|h |シンボルのパス|文字列|BaseLib.IDrawable| |仮想関数シンボルテーブル|SymbolTableIndexの配列|| :変数リスト| - 変数についての情報が0個以上格納されている。 - エンジンでは変数の情報が1つにつきSSVariableが1つ生成される。 |項目|内容|例|h |型を示すシンボルのパス|文字列|float| |シンボル名|文字列|x| |staticフラグ|bool(staticか否か)|| |readonlyフラグ|bool(readonlyか否か)|| |constフラグ|bool(constか否か)|| :関数リスト| - 関数についての情報が0個以上格納されている。 - エンジンでは関数の情報が1つにつきSSFunctionが1つ生成される。 |項目|内容|例|h |シンボル名|文字列|add| |戻り値の型を示すシンボルのパス|文字列|BaseLib.Math.Vector3| |戻り値のconstフラグ|bool(constか否か)|| |引数リスト|別項:引数リストを参照|| |staticフラグ|bool(staticか否か)|| |constフラグ|bool(constか否か)|| |命令コード|バイトコード|| :引数リスト| - 引数についての情報が0個以上格納されている。 - エンジンでは引数の情報が1つにつきSSFunctionArgが1つ生成される。 |項目|内容|例|h |型を示すシンボルのパス|文字列|float| |constフラグ|bool(constか否か)|| |refフラグ|bool(refか否か)|| ** シンボル解決情報 [#jec91c98] - シンボルの種類は変数・関数・ユーザー定義型の3つ。 :変数| |項目|内容|例|h |代入先|定数テーブル or シンボルテーブル|-| |シンボルパス|解決するシンボルのパス|BaseLib.Math.Vector3.x| |シンボルの何を取得するのか。|・変数オブジェクト(SSVariableのポインタ)&br;・サイズ(u32) &br;・先頭からのオフセット距離(u32)|-| :関数| |項目|内容|例|h |代入先|シンボルテーブル|-| |シンボルパス|解決するシンボルのパス|BaseLib.Math.Vector3.add| |引数リスト|引数の型のリスト|| |属性|const,staticなどの属性|| |シンボルの何を取得するのか。|・関数オブジェクト(SSFunctionのポインタ) |-| :ユーザー定義型| |項目|内容|例|h |代入先|定数テーブル|-| |シンボルパス|解決するシンボルのパス|BaseLib.Math.Vector3| |シンボルの何を取得するのか。|・ユーザー定義型オブジェクト(SSObjectTypeのポインタ) &br;・サイズ(u32)|-| * 意味解析 [#xe319000] 構文解析が終わった後,コード生成より前にやること。 - ModuleをModuleReposに登録。 - TypePathを解決し,型にリンクさせる - 関数名・変数名がだぶっていないかチェック。 - 定数(enum,immutable)の確定 - ユーザー定義型のサイズの決定 - ユーザー定義型の静的・非静的メンバ変数の位置を決定 - 自動生成関数の生成 - 関数のレジスタ割り当ての決定 - 関数の定数テーブルを作成 - 関数の非値型のスタックマッピングおよびスタックサイズを決定 * 道のり [#s3b4b6c0] - 意味解析 -- まずutilityと関数だけにしぼる -- 全てのModuleをシンボルツリーに登録 -- 全ての型をシンボルツリーに登録 -- 関数をシンボルツリーに登録。 -- 関数の中身を意味解析 --- 関数の中身のTypePathやIdentPathのシンボルを解決 --- 意味解析したStatementに置き換え。 * 仕様変更履歴 [#a0f3a6ff] :2010/07/29| - prototype moduleの概念を追加。 - classの代入演算子オーバーロードを禁止に。D言語準拠にした。 - オブジェクトハンドルの概念をなくした。 - isと!isを追加。セットでIdentityExpressionも追加。 |