3種類のコンパイルプロセスにおける同等の代表的なコンパイラ
- フロントエンドコンパイラ:SunのJavac、Eclipse JDTインクリメンタルコンパイラ(ECJ)
- JITコンパイラ:HotSpot VMのC1、C2コンパイラ
- AOT编译器:Java用のGUNコンパイラ(GCJ)、Excelsior JET
Javacコンパイラ
Sun Javacコードの観点から見ると、コンパイルプロセスは大きく3つのプロセスに分けることができます。
- シンボルテーブルプロセスの解析と入力
- プラグインアノテーションプロセッサのアノテーション処理
- 分析とバイトコード生成プロセス
シンボルテーブルの解析と入力
1.語彙および文法の分析
字句解析とは、ソースコードの文字ストリームを一連のトークンに変換することです。単一の文字はプログラムの作成プロセスにおける最小要素であり、トークンはコンパイルプロセスの最小要素です。キーワード、変数名、リテラル、および演算子マークにすることができます。Javaソースコードでは、字句解析プロセスはcom.sun.tools.javac.Scannerクラスによって実装されます。
文法分析は、トークンシーケンスに従って抽象構文ツリーを構築するプロセスです。抽象構文ツリー(AST)は、プログラムコードの構文構造を記述するために使用されるツリー表現です。構文ツリーの各ノードは、プログラムコードを表します(構築)の文法構造(パッケージ、型、修飾子、演算子、インターフェイス、戻り値、コードコメントなど)も、文法構造にすることができます。構文分析は、com.sun.tools.javac.parser.Parserクラスによって実装されます
2.シンボルテーブルに入力します
シンボルテーブル(Symbol Table)は、シンボルアドレスとシンボル情報のグループで構成されるテーブルです。シンボルテーブルに登録された情報は、コンパイルのさまざまな段階で使用されます。セマンティック分析では、シンボルテーブルに登録されたコンテンツがセマンティックインスペクション(名前の使用が元の説明と一致しているかどうかの確認など)および中間コードの生成に使用されます。ターゲットコード生成段階では、シンボル名がアドレスに割り当てられると、シンボルテーブルがアドレス割り当ての基礎になります。シンボルテーブルの入力は、クラスcom.sun.tools.javac.comp.Enterによって実装されます。
注釈プロセッサ
jdk1.5以降、Java言語は注釈(注釈)のサポートを提供しますこれらの注釈は、通常のJavaコードと同様に、実行時に役割を果たします。jdk1.6にJSR-269仕様を実装し、プラグインアノテーションプロセッサがコンパイル中にアノテーションを処理するための一連の標準APIを提供します。これらは、これらのプラグインのコンパイラプラグインのセットと考えることができます。 、抽象構文ツリーの任意の要素を自由に読み取り、変更、追加できます。
これらのプラグインが注釈処理中に構文を変更すると、コンパイラはシンボルテーブルの解析と入力のプロセスに戻り、すべてのプラグイン注釈プロセッサが構文ツリーを変更しなくなるまで再処理します。各サイクルが呼び出されますラウンド。
セマンティック分析とバイトコード生成
構文解析後、コンパイラーはプログラムコードの抽象構文ツリー表現を取得します。構文ツリーは適切に構造化されたソースプログラムの抽象化を表すことができますが、ソースプログラムが論理的である保証はありません。セマンティック分析の主なタスクは、タイプレビューなど、構造的に正しいソースプログラムのコンテキストの性質をレビューすることです。
1.マーキング検査
ラベルチェック手順の内容には、変数が使用前に宣言されているかどうか、変数と割り当ての間のデータ型を一致させることができるかどうかなどが含まれます。マークのチェック段階では、として知られている重要な操作がある一定の折りたたみは:私たちは定義されたコードを記述する場合は、次のように:int型のA = 1 + 2;それはまだリテラル構文木で見ることができる「1」、 " 2 "および演算子" + "、ただし定数の折りたたみ後、リテラルに折りたたまれます" 3 "。
2.データおよび制御フロー分析
データと制御フローの分析は、プログラムコンテキストロジックをさらに検証するものです。プログラムのローカル変数が使用前に割り当てられているかどうか、メソッドの各パスに戻り値があるかどうか、チェックされたすべての例外が正しく処理されているかどうかなどをチェックできます問題を待っています。
コンパイル時のデータおよび制御フロー分析の目的は、基本的にクラスローディングのデータおよび制御フロー分析と同じですが、検証範囲が異なります。一部の検証項目は、コンパイラーまたはランタイム中にのみ実行できます。
3.構文糖を解く
Javaで最も一般的な構文シュガーは主に前述のジェネリックです(ジェネリックは必ずしもC#のジェネリックがCLRで直接サポートされているようなすべての構文シュガー実装ではありません)、可変長パラメーター、自動ボックス化\解凍ボックスなど、これらの文法は仮想マシンの実行中はサポートされていません。コンパイル段階で単純な基本的な文法構造に復元されます。このプロセスは、非構文糖と呼ばれます。
4.バイトコードの生成
バイトコード生成は、javacコンパイルプロセスの最終段階であり、javacソースコードのcom.sun.tools.javac.jvm.Genクラスによって完了します。バイトコード生成段階では、前の手順で生成された情報(構文ツリー、シンボルテーブル)をバイトコードに変換してディスクに書き込むだけでなく、コンパイラーが少量のコード追加および変換作業も実行します。
構文ツリーの走査と調整が完了すると、必要なすべての情報が入力されたシンボルテーブルがcom.sun.tools.javac.jvm.ClassWriterクラスに渡され、このクラスのwriteClass()メソッドがバイトコードを出力します、最終的なクラスファイルを生成し、コンパイルプロセス全体がここで終了します。
Java構文砂糖
1.ジェネリックスと型消去
Genericsはjdk1.5の新機能であり、その本質はパラメーター化された型(Parametersized Type)の適用です。つまり、操作されるデータ型はパラメーターとして指定されます。このタイプのパラメーターは、それぞれジェネリッククラス、ジェネリックインターフェース、ジェネリックメソッドと呼ばれるクラス、インターフェース、およびメソッドの作成に使用できます。
2.自動ボクシング、ボックス化解除、およびトラバーサルサイクル
3.条件付きコンパイル
Java言語は、一定の条件を持つifステートメントを使用して条件付きでコンパイルすることもできます。コードリスト10-9に示すように、このコードのifステートメントは他のJavaコードとは異なり、コンパイル段階で「実行」され、生成されたバイトコードには「System.out.println(」ブロック1のみが含まれます。 ");"ステートメント。
注:上記の効果が得られるのは、条件付き定数のif文のみであり、条件付き判定能力を持つ他の文と組み合わせて使用すると、制御フロー解析でエラーとなり、コンパイルできない場合があります。
プラグインアノテーションプロセッサ
JSR-269組み込み注釈プロセッサAPIでサポートされるプロジェクトには、Hibernateタグの正確さを検証するHibernate Validator注釈プロセッサ、フィールドのゲッターメソッドとセッターメソッドを自動的に生成するProject Lombok(既存の要素に基づいて新しい構文ツリー要素を生成)が含まれます)待って。
–上記の知識ポイントは、「Java仮想マシンの詳細な理解」から引用