Next: , Previous: , Up: Programming Tools   [Contents][Index]


6.26.4 Examining compiled code

そして最後に、 see とそのファミリーが、 コンパイル済のコードの表示を行います。 ソース・コード内の一部の内容は、 コンパイルされたコードには存在しません(書式設定やコメント等)。 しかし、 これは、 マクロや Gforth の最適化機能によってどのようなスレッド化コード(threaded code)やネイティブ・コード(native code)が生成されるかを確認するのに役立ちます。

see ( "<spaces>name" –  ) tools “see”

現在の検索順序(search order)を使用して namelocate します。 locate できたら、 その定義を表示します。 これは定義を逆コンパイルすることで実現されるため、 書式は機械化され、 一部のソース情報(コメントや定義内のインタプリトされたシーケンスなど)は失われます。

xt-see ( xt –  ) gforth-0.2 “xt-see”

xt で表される定義を逆コンパイルします。

simple-see ( "name" –  ) gforth-0.6 “simple-see”

コロン定義 name を逆コンパイルして各セルごとに行表示し、 セルの意味を推測してそれを表示します。

xt-simple-see ( xt –  ) gforth-1.0 “xt-simple-see”

simple-see のようにコロン定義 xt を逆コンパイルします。

simple-see-range ( addr1 addr2 –  ) gforth-0.6 “simple-see-range”

[addr1,addr2) ( addr1 <= and < addr2 )の範囲のコードを simple-see のように逆コンパイルします

see-code ( "name" –  ) gforth-0.7 “see-code”

simple-see と似ていますが、 インライン化されたプリミティブの動的ネイティブ・コード(dynamic native code)も表示されます。 静的命令融合(superinstructions)の場合、 最初のプリミティブではなくプリミティブ・シーケンスが表示されます(命令融合(superinstructions)の他のプリミティブも表示されます)。 ネイティブ・コードが生成されるプリミティブの場合、 最初と最後のレジスタ内のスタック項目の数が表示されます(たとえば、 1->1 は、 最初と最後のレジスタに 1 つのスタック項目があることを意味します)。 ネイティブ・コードを使用した各プリミティブまたは命令融合(superinstructions)については、 インライン引数とコンポーネント・プリミティブが最初に表示され、 次にネイティブ・コードが表示されます。

xt-see-code ( xt –  ) gforth-1.0 “xt-see-code”

コロン定義 xtsee-code のように逆コンパイルします。

see-code-range ( addr1 addr2 –  ) gforth-0.7 “see-code-range”

[addr1,addr2) ( addr1 <= and < addr2 )の範囲のコードを see-code のように逆コンパイルします。

例として、 以下について考えてみましょう:

: foo x f@ fsin drop over ;

この例は特に役に立つわけではありませんが、 さまざまなコード生成の違いを示しています。 これを AMD64 の gforth-fast でコンパイルし、 see-code foo を使用すると以下の出力が得られます(訳注: OSのコマンドラインから、 gforth ではなくて gforth-fast で起動する):

$7FD0CEE8C510 lit f@     1->1 
$7FD0CEE8C518 x
$7FD0CEE8C520 f@
7FD0CEB51697:   movsd   [r12],xmm15
7FD0CEB5169D:   mov     rax,$00[r13]
7FD0CEB516A1:   sub     r12,$08
7FD0CEB516A5:   add     r13,$18
7FD0CEB516A9:   movsd   xmm15,[rax]
7FD0CEB516AE:   mov     rcx,-$08[r13]
7FD0CEB516B2:   jmp     ecx
$7FD0CEE8C528 fsin
$7FD0CEE8C530 drop    1->0 
7FD0CEB516B4:   add     r13,$08
$7FD0CEE8C538 over    0->1 
7FD0CEB516B8:   mov     r8,$10[r15]
7FD0CEB516BC:   add     r13,$08
$7FD0CEE8C540 ;s    1->1 
7FD0CEB516C0:   mov     r10,[rbx]
7FD0CEB516C3:   add     rbx,$08
7FD0CEB516C7:   lea     r13,$08[r10]
7FD0CEB516CB:   mov     rcx,-$08[r13]
7FD0CEB516CF:   jmp     ecx

まず、 コンポーネント litf@ を含む静的命令融合(superinstruction)のスレッド化コード・セルが表示されます。 それは、 レジスタ内の 1 つのデータ・スタック項目 (1->1) で始まり・終わります。 )。 これに、lit の引数 x のセルと、 命令融合の f@ コンポーネントのセルが続きます。 後者のセルは使用されませんが、 Gforth 内部の理由により存在します。

その次に、 命令融合 lit f@ に対して動的に生成されたネイティブ・コードを表示します。 注意: アドレスを比較するとわかるように、 このネイティブ・コードはメモリ内のスレッド化コードと混合されていない(not mixed)ことに注意してください。

ここに表示されているネイティブ・コードを理解するには、以下のレジスタについて知っておくべきです:
スレッド化コードの命令ポインタは r13
データ・スタック・ポインタは r15
最初(TOS)のデータ・スタック・レジスタは r8 (データ・スタックのTOS、 つまり、 レジスタにデータ・スタック項目が 1 つある場合、 スタックのTOSがそこに存在します)
リターン・スタック ポインタは rbx
FP スタック・ポインタは r12
FP スタックの先頭(TOS)は xmm15
注意: レジスタの割り当てはエンジンによって異なるため、 コード表示においては異なるレジスタの割り当てが表示される場合があることに注意してください。

lit f@ の動的ネイティブ・コードは、 ディスパッチ・ジャンプ(dispatch jump;別名 NEXT)(訳注: 古典的には内部インタプリタへ制御を戻すためのジャンプ)で終了します。 これは、 定義内の次のワード fsin のネイティブ・コードは動的に生成しないためです。

次に、 fsin のスレッド化コード・セルが表示されます。 このワードには動的に生成されるネイティブ・コードはなく、 see-code では静的ネイティブ・コードは表示されません(fsin の静的ネイティブ・コードを確認したければ see fsin)。 gforth-fast 内の静的ネイティブ・コードを含むすべてのワードと同様、 データ・スタック表現への影響は 1->1 (gforth エンジンでは 0->0) です。 しかし、 これは表示されません。

次に、 drop のスレッド化コード・セルが表示されます。 ここで使用されるネイティブ・コード版のバリエーションは、 レジスタ内の 1 つのデータ・スタック項目で始まり、 レジスタ内の 0 個のデータ スタック項目で終わります(1->0)。 この後に drop のこのバリエーションのネイティブ・コードが続きます。 ここのネイティブ・コードは次のワードのコードに続くため、 ここには NEXT はありません。

次に、 over のスレッド化コード・セルと、 その後に 0->1 バリエーションで動的に生成されたネイティブ・コードが表示されます。

最後に、 ;s のスレッド化されたネイティブ・コード(foo 内の ; 用にコンパイルされたプリミティブ)が表示されます。 ;s は制御フローを実行する(制御フローからリターンする)ため、 NEXT で終了する必要があります。


Next: Examining data and code, Previous: Locating exception source, Up: Programming Tools   [Contents][Index]