Top > C++ > スクリプト > メモ

メモ Edit

エンジンの型 Edit

説明の際にところどころ出てくるので書いておく。

名前役割
SSObjectTypeユーザー定義型を扱うクラス。1ユーザー定義型につき1インスタンス。
SSVariable変数を扱うクラス。1変数につき1インスタンス。
SSFunction関数を扱うクラス。1関数につき1インスタンス。
SSFunctionArg関数の引数を扱うクラス。1引数につき1インスタンス。
SSVirtualFuncTable仮想関数テーブルを扱うクラス。1仮想関数テーブルにつき1インスタンス。

コード生成 Edit

シンプルでもいける気がしてきた。

レジスタ構成 Edit

Full NameShort NameComment
Stack Register PointerSRPスタックレジスタポインタ。
スタックレジスタの先頭アドレス。
言い換えるとSR00の場所。
Stack PointerSPスタックポインタ。現在のスタック位置。
Program CounterPCプログラムカウンタ。現在実行しているバイトコードのポインタ。
Program FunctionPFプログラムの関数オブジェクトのポインタ。デバッグ用。
Program LinePLプログラムのソースコードの行数。デバッグ用。
Link RegisterLRリンクレジスタ。戻り先のバイトコードのポインタ。
Function RegisterFR関数レジスタ。全部で16個。FR00 - FR16。

レジスタの概要 Edit

  • 1つのレジスタのサイズは8バイト。
  • 4バイトでもいいかなと思ったが,64bit環境でポインタが1レジスタで表現できなくなるため,8バイトにした。
  • ただし,メモリがきつきつの環境もあるので32bitモード用意する。その場合,64bitの整数・浮動小数,64bitのアドレス空間は扱えなくなる。
  • 1つのレジスタはUNIONで表現。
    すべてを展開すべてを収束
      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
    
     
    -
    |
    -
    |
    |
    |
    |
    |
    |
    |
    !
    !
     
    
    struct Register
    {
        union
        {
            u32 data32;
            u64 data64;
            s32 i32val;
            s64 i64val;
            f32 f32val;
            f64 f64val;
            void*  ptr; // 64bit環境だとこれは8バイト。
        };
    };
    

スタックレジスタ Edit

  • 計算の一時領域として使うレジスタはStackRegister(スタックレジスタ)呼び,SRと略す。
  • スタックレジスタ数は動的に変更し,最大で256。それを越える必要がある関数はコンパイルエラーとする。
  • SRP(Stack Register Pointer)からのオフセットがスタックレジスタの番号に相当する。
  • SR01ならSRP + 0x08のアドレスとなる。(32bitモードなら+0x04)
  • 通常,関数の先頭でFUNCET命令を使い関数で使用するスタックレジスタの数 x レジスタのサイズ分,スタックから確保し,その先頭アドレスをSRPに設定する。

変数とレジスタ Edit

  • ローカル変数は全てスタックレジスタに割り当てられる。
  • スコープを考慮してスタックレジスタの使用数はなるべく少なくて済むように最適化される。
  • 一時変数もスタックレジスタに割り当てられる。
    すべてを展開すべてを収束
      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
    
    -
    |
    -
    |
    |
    -
    |
    !
    |
    -
    |
    !
    |
    |
    |
    |
    !
    !
    
    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;
    }
    };

戻り値とレジスタ Edit

  • 戻り値はFR00に格納される。
  • FUNCRT命令が実行されるとSR00の値はFR00にコピーされる。
    すべてを展開すべてを収束
      1
      2
      3
      4
      5
      6
      7
      8
    
     
    -
    |
    -
    |
    !
    !
     
    
    utility Hoge
    {
        static int GetOne()
        {
            return 1; // FR00 = 1
        }
    };
    

引数とレジスタ Edit

  • 引数は関数レジスタのFR01から順番にレジスタに割り当てられる。
  • 非staticなメンバ関数はFR01にthisポインタが割り当てられる。
  • 関数レジスタは16個しか用意されていないので,引数の最大数はメンバ関数で14個,非メンバ関数は15個となります。(FR00は戻り値として使うため,引数に使用できない)
    すべてを展開すべてを収束
      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
    
     
    -
    |
    |
    |
    |
    |
    -
    |
    |
    !
    !
     
    
    pod Vector3
    {
        float x;
        float y;
        float z;
     
        void func(float addValue)
        {
            // FR01 : this
            // FR02 : addValue
        }
    }
    

アセンブラのイメージ Edit

  • 簡単なコード
    すべてを展開すべてを収束
      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
    
     
    -
    |
    !
     
    -
    |
    |
    !
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
    
    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()
    

命令コード Edit

  • どの命令コードも32bitで統一。
  • SRegおよびFRegはu8。
命令書式コメント
ロード
LDSRC1LDSRC4 SReg ConstantTableIndex(u16)ConstantTableの値を指定したスタックレジスタにロード
LDSRC2
LDSRC4
LDSRC8
LDSRSRLDSRSR SReg1 SReg2SReg2の値をSReg1にロード
LDSRSPLDSRSP SReg1 StackPointerOffset(u16)StackPointerから相対アドレス分移動したアドレスをReg1にロード
LDSRP1LDSRP1 SReg1 SReg2SReg2の値をアドレスとみなし,SReg2が指す値を取得する
LDSRP2
LDSRP4
LDSRP8
LDSROJLDSROJ SReg1 SReg2SReg2の値をobject型とみなし,SReg2が指すobjectの実体のアドレスのアドレスを取得する
LDFRSRLDFRSR FReg SRegSRegの値をFRegにロード
演算
ADDxxxADDI32 SReg1 SReg2 SReg3SReg1 = SReg2 + SReg3
SUBxxxSUBI32 SReg1 SReg2 SReg3SReg1 = SReg2 - SReg3
MULxxxMULS32 SReg1 SReg2 SReg3SReg1 = SReg2 * SReg3
DIVxxxMULS32 SReg1 SReg2 SReg3SReg1 = SReg2 / SReg3
MODxxxMODS32 SReg1 SReg2 SReg3SReg1 = SReg2 % SReg3
関数あれこれ
FENTERFENTER AllocSRegNum CopyFRegNumFunction Enter.
まずスタックに現在のSPR,LR,PL,PFをつみ,SPを変更する。
AllocSRegNumで指定された数,スタックレジスタを確保し,SPRに設定する。SPを変更する。
CopyFRegNumで指定された数,スタックレジスタにFRに内容をコピーする。
FLEAVEFLEAVE FreeSRegNumFunction Leave.
FreeSRegNumで指定された数,スタックレジスタを解放しSPを変更する。
PF,PL,LR,SPR,をスタックから取り出し設定する。SPも変更する。
PCにLRを代入する。
CALLCALL SymbolTableIndex(u16)LRにPCを代入する。
SymbolTableIndexが示す関数の先頭バイトコードをPCに設定する。
CALLVFCALLVF SReg1 ConstantTableIndex(u16)Call Virtual Function.
SReg1が指すオブジェクトの仮想関数の先頭バイトコードを求め,PCに代入する。
ConstantTableIndexが示す先にはSymbolTableIndex(u16)が2つ連続して存在する。
1つめは仮想関数の親となるSSObjectTypeが格納されているSymbolTableのIndex。
2つめは仮想関数自体のSSFunctionが格納されているSymbolTableのIndex。
スタック
PUSHPUSH SReg ConstantTableIndex(u16)ConstantTableIndexが指す定数サイズ(u32)減算し,指定のSRegに演算後のSPを設定する。
POPPOP ConstantTableIndex(u16)ConstantTableIndexが指す定数サイズ(u32)分,SPを加算する。
オブジェクト
OBJNEWOBJNEW SReg SymbolIndexObject New.
指定のSymbolIndexが指すObjectTypeのインスタンスを作成し,ハンドルをSReg1に代入する。
OBJDELOBJDEL SRegObject Delete.
指定のSRegが指すオブジェクトに対してdeleteする。
OBJRFIOBJRFI SRegObject Reference Increment.
指定のSRegが指すオブジェクトのリファレンスカウンタをインクリメントする。
OBJRFDOBJRFD SRegObject Reference Decrement.
指定のSRegが指すオブジェクトのリファレンスカウンタをデクリメントし,SRegに0を代入する。
デバッグ
DLINEDLINE ConstantValue(u24)Debug Line.
デバッグ情報のプログラム行数を代入するための命令。
PLにConstantValueを代入する。
DFUNCDFUNC SymbolTableIndex(u16)Debug Function.
デバッグ情報の関数オブジェクトを代入するための命令。
PFにSymbolTableIndexが示すアドレスを代入する。

オブジェクトファイル Edit

  • Cでいう.oのファイル。

含まれるもの

  • モジュール名
  • 定数テーブル
  • シンボルテーブル
  • シンボル一覧
  • シンボル解決情報

モジュール名 Edit

  • モジュール名が文字列として格納される。

定数テーブル Edit

  • 必要な定数テーブルの長さ。
  • コンパイル時に解決されている定数郡。
  • .oのファイルサイズ縮小のために,コンパイル時に解決されている定数郡は定数テーブルの先頭に置いておく。
  • そうしておくことで,リンク時に解決される定数郡のデータ量が.oから削減される。(.sbssと同じ考え方)

シンボルテーブル Edit

  • 必要なシンボルテーブルの長さのみ格納される。

シンボル一覧 Edit

  • モジュールはユーザー定義型リストを持つ。
ユーザー定義型リスト
  • ユーザー定義型についての情報が0個以上格納されている。
  • エンジンではユーザー定義型の情報が1つにつきSSObjectTypeが1つ生成される。
    項目内容
    シンボルのパス文字列BaseLib.Math.Vector3
    継承しているクラスのパス文字列Foo
    仮想関数テーブルリスト別項:仮想関数テーブルリストを参照
    変数リスト別項:変数リストを参照
    関数リスト別項:関数リストを参照
仮想関数テーブルリスト
  • 仮想関数テーブルについての情報が0個以上格納されている。
  • エンジンでは仮想関数テーブルの情報が1つにつきSSVirutalFuncTableが生成される。
    項目内容
    シンボルのパス文字列BaseLib.IDrawable
    仮想関数シンボルテーブルSymbolTableIndexの配列
変数リスト
  • 変数についての情報が0個以上格納されている。
  • エンジンでは変数の情報が1つにつきSSVariableが1つ生成される。
    項目内容
    型を示すシンボルのパス文字列float
    シンボル名文字列x
    staticフラグbool(staticか否か)
    readonlyフラグbool(readonlyか否か)
    constフラグbool(constか否か)
関数リスト
  • 関数についての情報が0個以上格納されている。
  • エンジンでは関数の情報が1つにつきSSFunctionが1つ生成される。
    項目内容
    シンボル名文字列add
    戻り値の型を示すシンボルのパス文字列BaseLib.Math.Vector3
    戻り値のconstフラグbool(constか否か)
    引数リスト別項:引数リストを参照
    staticフラグbool(staticか否か)
    constフラグbool(constか否か)
    命令コードバイトコード
引数リスト
  • 引数についての情報が0個以上格納されている。
  • エンジンでは引数の情報が1つにつきSSFunctionArgが1つ生成される。
    項目内容
    型を示すシンボルのパス文字列float
    constフラグbool(constか否か)
    refフラグbool(refか否か)

シンボル解決情報 Edit

  • シンボルの種類は変数・関数・ユーザー定義型の3つ。
変数
項目内容
代入先定数テーブル or シンボルテーブル-
シンボルパス解決するシンボルのパスBaseLib.Math.Vector3.x
シンボルの何を取得するのか。・変数オブジェクト(SSVariableのポインタ)
・サイズ(u32)
・先頭からのオフセット距離(u32)
-
関数
項目内容
代入先シンボルテーブル-
シンボルパス解決するシンボルのパスBaseLib.Math.Vector3.add
引数リスト引数の型のリスト
属性const,staticなどの属性
シンボルの何を取得するのか。・関数オブジェクト(SSFunctionのポインタ)-
ユーザー定義型
項目内容
代入先定数テーブル-
シンボルパス解決するシンボルのパスBaseLib.Math.Vector3
シンボルの何を取得するのか。・ユーザー定義型オブジェクト(SSObjectTypeのポインタ)
・サイズ(u32)
-

意味解析 Edit

構文解析が終わった後,コード生成より前にやること。

  • ModuleをModuleReposに登録。
  • TypePathを解決し,型にリンクさせる
  • 関数名・変数名がだぶっていないかチェック。
  • 定数(enum,immutable)の確定
  • ユーザー定義型のサイズの決定
  • ユーザー定義型の静的・非静的メンバ変数の位置を決定
  • 自動生成関数の生成
  • 関数のレジスタ割り当ての決定
  • 関数の定数テーブルを作成
  • 関数の非値型のスタックマッピングおよびスタックサイズを決定

道のり Edit

  • 意味解析
    • まずutilityと関数だけにしぼる
    • 全てのModuleをシンボルツリーに登録
    • 全ての型をシンボルツリーに登録
    • 関数をシンボルツリーに登録。
    • 関数の中身を意味解析
      • 関数の中身のTypePathやIdentPathのシンボルを解決
      • 意味解析したStatementに置き換え。

仕様変更履歴 Edit

2010/07/29
  • prototype moduleの概念を追加。
  • classの代入演算子オーバーロードを禁止に。D言語準拠にした。
  • オブジェクトハンドルの概念をなくした。
  • isと!isを追加。セットでIdentityExpressionも追加。

リロード   新規 下位ページ作成 編集 凍結 差分 添付 コピー 名前変更   ホーム 一覧 検索 最終更新 バックアップ リンク元   ヘルプ   最終更新のRSS
Last-modified: Sat, 31 Jul 2010 19:27:18 JST (5018d)