High-level Overview of the Native-Code Generation Process
Representation of Pointers
オブジェクトファイルにコードを出力する際、ポインタは再配置として出力されます。デシリアライズコードは、これらの定数のいずれかを指していたオブジェクトが再作成され、正しいランタイムポインタを含むことを保証します。
そうでなければ、それらはリテラル定数として出力されます。
これらのオブジェクトのいずれかを発行するには、literal_pointer_val
を呼び出します。これにより、Juliaの値とLLVMのグローバルを追跡し、現在のランタイムとデシリアライズ後の両方で有効であることが保証されます。
オブジェクトファイルに出力されると、これらのグローバルは大きな gvals
テーブルに参照として格納されます。これにより、デシリアライザーはインデックスでそれらを参照し、グローバルオフセットテーブル(GOT)に似たカスタム手動メカニズムを実装してそれらを復元することができます。
関数ポインタも同様に扱われます。これらは大きな fvals
テーブルに値として格納されます。グローバルと同様に、これによりデシリアライザはインデックスで参照することができます。
extern
関数は、通常のシンボル解決メカニズムを介してリンカーで名前が別々に処理されることに注意してください。
ccall
関数も手動の GOT および手続きリンクテーブル (PLT) を介して別途処理されることに注意してください。
Representation of Intermediate Values
値は jl_cgval_t
構造体で渡されます。これは R 値を表し、どのようにそれをどこかに割り当てたり渡したりするかを決定するのに十分な情報を含んでいます。
それらは、通常、mark_julia_type
(即時値用)および mark_julia_slot
(値へのポインタ用)のいずれかのヘルパーコンストラクタを介して作成されます。
関数 convert_julia_type
は、任意の2つの型の間で変換を行うことができます。これは、cgval.typ
が typ
に設定されたR値を返します。オブジェクトを要求された表現にキャストし、必要に応じてヒープボックスを作成し、スタックコピーを割り当て、タグ付きユニオンを計算して表現を変更します。
対照的に update_julia_type
は、cgval.typ
を typ
に変更しますが、それがゼロコスト(すなわち、コードを生成せずに)で行える場合のみです。
Union representation
推論されたユニオン型は、タグ付き型表現を介してスタックに割り当てられる場合があります。
タグ付き共用体を処理できる必要がある基本的なルーチンは次のとおりです:
- マークタイプ
- ローカルを読み込む
- ストアローカル
- isa
- は
- emit_typeof
- emit_sizeof
- ボックス化された
- アンボックス
- スペシャライズド CC-RET
すべての他のことは、これらのプリミティブを使用してユニオン分割を実装することで推論で処理できるはずです。
タグ付きユニオンの表現は、< void* union, byte selector >
のペアとして表されます。セレクタは byte & 0x7f
として固定サイズであり、最初の126のisbitsをユニオンタグします。これは、内部のisbitsオブジェクトの型ユニオンへの深さ優先の1ベースのカウントを記録します。インデックスがゼロの場合、union*
は実際にはタグ付きのヒープ割り当てされた jl_value_t*
であり、タグ付きユニオンとしてではなく、ボックス化されたオブジェクトとして通常通り扱う必要があります。
セレクタの高ビット(byte & 0x80
)をテストすることで、void*
が実際にヒープに割り当てられた(jl_value_t*
)ボックスであるかどうかを判断できるため、ボックスの再割り当てのコストを回避しつつ、低ビットに基づくユニオン分割を効率的に処理する能力を維持できます。
byte & 0x7f
は、値がタグで表現できる場合に型を正確にテストすることが保証されています - byte = 0x80
とマークされることは決してありません。isa
をテストする際に型タグをテストする必要はありません。
union*
メモリ領域は 任意の サイズで割り当てることができます。唯一の制約は、selector
によって現在指定されているデータを含むのに十分な大きさであることです。関連する Union 型フィールドに従ってそこに格納できるすべての型のユニオンを含むには十分でない場合があります。コピーする際は適切な注意を払ってください。
Specialized Calling Convention Signature Representation
jl_returninfo_t
オブジェクトは、呼び出し可能なものの呼び出し規約の詳細を説明します。
メソッドの引数または戻り値の型がアンボックス可能であり、メソッドが可変引数でない場合、そのメソッドは specTypes
および rettype
フィールドに基づいて最適化された呼び出し規約のシグネチャが与えられます。
一般的な原則は次のとおりです:
- プリミティブ型はint/floatレジスタに渡されます。
- VecElement型のタプルはベクタレジスタに渡されます。
- 構造体はスタック上で渡されます。
- 戻り値は引数と同様に扱われ、サイズのカットオフがあり、そのサイズを超える場合は隠れたsret引数を介して返されます。
この全体のロジックは get_specsig_function
と deserves_sret
によって実装されています。
さらに、戻り値の型が共用体である場合、値のペア(ポインタとタグ)として返されることがあります。共用体の値がスタックに割り当て可能な場合、それらを格納するのに十分なスペースも隠れた最初の引数として渡されます。戻り値のポインタがこのスペース、ボックス化されたオブジェクト、または他の定数メモリを指すかどうかは、呼び出し側に委ねられます。