Javaバイトコードは、 Java仮想マシン(JVM)の命令セットであり、 Javaやその他のJVM互換のソースコードがコンパイルされる言語です。[1]各命令は1バイトで表され、バイトコードと呼ばれることから、コンパクトなデータ形式となっています。[2]
バイトコードの性質上、Java バイトコードプログラムは、ソース コードからコンパイルするという長いプロセスなしで、互換性のある JVM を搭載した任意のマシンで実行できます。
Java バイトコードは実行時に使用され、 JVM によって解釈されるか、ジャストインタイム(JIT) コンパイルによってマシン コードにコンパイルされてネイティブ アプリケーションとして実行されます。
Javaバイトコードはクロスプラットフォームの互換性とセキュリティを考慮して設計されているため、Javaバイトコードアプリケーションはさまざまなハードウェアおよびソフトウェア構成で一貫して実行される傾向があります。[3]
Javaとの関係
一般的に、JavaプログラマーはJava バイトコードを理解する必要はなく、またそれを意識する必要もありません。しかし、IBM developerWorks ジャーナルで示唆されているように、「バイトコードと、 Java コンパイラーによって生成される可能性のあるバイトコードを理解することは、アセンブリの知識がCまたはC++プログラマーに役立つのと同じように、Java プログラマーに役立ちます。」[4]
命令セットアーキテクチャ
バイトコードは、データ操作、制御転送、オブジェクトの作成と操作、メソッドの呼び出しなど、Javaのオブジェクト指向プログラミングモデルに不可欠なさまざまな命令タイプで構成されています。[1]
JVM はスタック マシンとレジスタ マシンの両方です。メソッド呼び出しの各フレームには、「オペランド スタック」と「ローカル変数」の配列があります。 [5] : 2.6 [2]オペランド スタックは、計算にオペランドを渡すため、および呼び出されたメソッドの戻り値を受け取るために使用されます。一方、ローカル変数はレジスタと同じ目的を果たし、メソッド引数を渡すためにも使用されます。コンパイラによって計算されるオペランド スタックとローカル変数配列の最大サイズは、各メソッドの属性の一部です。[5] : 4.7.3 それぞれは、0 から 65535 の値まで独立してサイズ設定できます。各値は 32 ビットです。64ビットlongのdouble型は、連続する 2 つのローカル変数[5] : 2.6.1 (ローカル変数配列で 64 ビットに揃える必要はありません) またはオペランド スタック内の 1 つの値 (ただし、スタックの深さでは 2 単位としてカウントされます) を占めます。[5] : 2.6.2
命令セット
各バイトコードは、オペコードを表す1バイトと、オペランド用の0バイト以上で構成される。[5] : 2.11
2015年現在、 256個のバイト長オペコード[アップデート]のうち、202個が使用中(約79%)、51個が将来の使用のために予約済み(約20%)、3個の命令(約1%)がJVM実装で使用するために恒久的に予約されています。[5] :6.2 これらのうち2つ(impdep1およびimpdep2)は、それぞれ実装固有のソフトウェアとハードウェアにトラップを提供するためのものです。3つ目は、デバッガがブレークポイントを実装するために使用されます。
指示はいくつかの広範なグループに分類されます。
- ロードして保存する(
aload_0例istore:) - 算術と論理(例
ladd:)fcmpl - 型変換(
i2b例d2i:) - オブジェクトの作成と操作 (
new、putfield) - オペランドスタック管理(
swap例dup2:) - 制御の移行(
ifeq例goto:) - メソッドの呼び出しと戻り(
invokespecial例areturn:)
例外のスロー、同期など、より特殊なタスクのための命令もいくつかあります。
多くの命令には、演算対象となるオペランドの種類を示す接頭辞や接尾辞が付いています。[5] : 2.11.1 これらは次のとおりです。
たとえば、iaddは 2 つの整数を加算しますが、 はdadd2 つの倍精度数を加算します。const、、loadおよびstore命令には、 という形式の接尾辞が付く場合もあります。ここで、n はおよびの場合、0~3 の数字です。 の場合のn の最大値は、型によって異なります。
_nloadstoreconst
命令constは、指定された型の値をスタックにプッシュします。たとえば、iconst_5は値 5 の整数 (32 ビット値) をスタックにプッシュし、はdconst_1値 1 の double (64 ビット浮動小数点値) をスタックにプッシュします。また、参照aconst_nullをプッシュする もありますnull。および命令のnは、読み込み元または格納先のローカル変数配列のインデックスを指定します。 命令は、ローカル変数 0 のオブジェクトをスタックにプッシュします (これは通常、オブジェクトです)。は、スタックの一番上の整数をローカル変数 1 に格納します。3 を超えるローカル変数の場合、サフィックスは削除され、オペランドを使用する必要があります。
loadstoreaload_0thisistore_1
例
次の Java コードを検討してください。
外側:
for ( int i = 2 ; i < 1000 ; i ++ ) { for ( int j = 2 ; j < i ; j ++ ) { if ( i % j == 0 )外側を続行; } System.out.println ( i ) ; }
Java コンパイラは、上記の Java コードをメソッド内に配置した場合、次のようにバイトコードに変換する可能性があります。
0 : iconst_2 1 : istore_1 2 : iload_1 3 : sipush 1000 6 : if_icmpge 44 9 : iconst_2 10 : istore_2 11 : iload_2 12 : iload_1 13 : if_icmpge 31 16 : iload_1 17 : iload_2 18 : irem 19 : ifne 25 22 : goto 38 25 : iinc 2, 1 28 : goto 11 31 : getstatic #84; //フィールドjava/lang/System.out : Ljava/io/PrintStream; 34 : iload_1 35 : invokevirtual #85 ; // メソッド java/io/PrintStream.println:(I)V 38 : iinc 1, 1 41 : goto 2 44 : return
世代
Java バイトコードを生成することでJava 仮想マシンをターゲットとする最も一般的な言語はJava です。元々はJava ソース コードを Java バイトコードにコンパイルするコンパイラはSun Microsystemsのjavacコンパイラのみでしたが、現在では Java バイトコードの仕様がすべて公開されているため、他社も Java バイトコードを生成するコンパイラを提供しています。その他のコンパイラの例を次に示します。
- Java 用 Eclipse コンパイラ (ECJ)
- Jikes は、Java から Java バイトコードにコンパイルします ( IBMによって開発され、C++で実装されています)
- Espresso は、Java から Java バイトコードにコンパイルします (Java 1.0 のみ)
- GNU Compiler for Java (GCJ) は、Java から Java バイトコードにコンパイルします。ネイティブマシン コードにコンパイルすることもでき、バージョン 6 まではGNU Compiler Collection (GCC)の一部でした。
一部のプロジェクトでは、Java バイトコードを手動で記述できるように Java アセンブラを提供しています。アセンブリ コードは、 Java 仮想マシンをターゲットとするコンパイラなどによって機械で生成されることもあります。注目すべき Java アセンブラには次のものがあります。
- Jasminは、Java仮想マシン命令セットを使用して単純なアセンブリのような構文で書かれたJavaクラスのテキスト記述を受け取り、Javaクラスファイルを生成します[6]
- JamaicaはJava仮想マシン用のマクロ アセンブリ言語です。Java構文はクラスやインターフェースの定義に使用されます。メソッド本体はバイトコード命令を使用して指定されます。[7]
- Krakatau Bytecode Toolsには現在、Javaクラスファイル用のデコンパイラと逆アセンブラ、およびクラスファイルを作成するためのアセンブラの3つのツールが含まれています。[8]
- Lilac、 Java仮想マシン用のアセンブラおよび逆アセンブラ。[9]
他にも、Java 仮想マシンをターゲットとするさまざまなプログラミング言語用のコンパイラを開発している企業があります。たとえば、次のようなものがあります。
- コールドフュージョン
- JRubyとJython は、RubyとPythonをベースにした2 つのスクリプト言語です。
- Apache Groovy は、静的型付けと静的コンパイル機能を備えた、オプションで型付けされた動的な汎用言語です。
- Scala は、オブジェクト指向と関数型プログラミングをサポートする型安全な汎用プログラミング言語です。
- JGNATとAppletMagicは、 Ada言語からJavaバイトコードにコンパイルします。
- C から Java バイトコード コンパイラ [リンク切れ ]
- Clojure は、 Lispファミリーの関数型、不変、汎用プログラミング言語であり、並行性を重視しています。
- Kawa は、 Schemeプログラミング言語の実装であり、 Lispの方言でもあります。
- MIDlet パスカル
- JavaFX ScriptコードはJavaバイトコードにコンパイルされます
- Kotlin、型推論を備えた静的型付けの汎用プログラミング言語
- Object PascalのソースコードはFree Pascal 3.0+コンパイラを使用してJavaバイトコードにコンパイルされます。 [10] [11]
実行
現在、Java バイトコードを実行するための Java 仮想マシンは、無料製品と商用製品の両方でいくつかあります。仮想マシンでバイトコードを実行するのが望ましくない場合、開発者はGNU Compiler for Java (GCJ) などのツールを使用して、Java ソース コードまたはバイトコードをネイティブ マシン コードに直接コンパイルすることもできます。一部のプロセッサは、Java バイトコードをネイティブに実行できます。このようなプロセッサは、 Java プロセッサと呼ばれます。
動的言語のサポート
Java仮想マシンは動的型付け言語をある程度サポートしています。現在のJVM命令セットのほとんどは静的型付けです。つまり、メソッド呼び出しのシグネチャはコンパイル時に型チェックされ、この決定を実行時に延期したり、別の方法でメソッドディスパッチを選択したりするメカニズムはありません。 [12]
JSR 292 ( Javaプラットフォームでの動的型付け言語のサポート) [13]invokedynamicでは、JVMレベルで新しい命令が追加され、既存の静的型チェック命令の代わりに動的型チェックinvokevirtualに依存するメソッド呼び出しが可能になりました。Da Vinci Machineは、動的言語のサポートを目的としたJVM拡張機能をホストするプロトタイプの仮想マシン実装です。JSE 7をサポートするすべてのJVMには、オペコードも含まれていますinvokedynamic。
参照
- バイトコードエンジニアリングライブラリ
- 共通中間言語(CIL)、Microsoft の Java バイトコードのライバル
- Java バックポートツール
- Javaクラスファイル
- Java仮想マシン
- JStik さん
- オブジェクトウェブASM
- Javaバイトコード命令のリスト
- JVM言語のリスト
参考文献
- ^ ab 「Java仮想マシン仕様」。Oracle 。 2023年11月14日閲覧。
- ^ ab Lindholm, Tim (2015). Java仮想マシン仕様. Oracle. ISBN 978-0133905908。
- ^ Arnold, Ken (1996). 「Javaプログラミング言語」. Sun Microsystems . 1 (1): 30– 40.
- ^ 「IBM Developer」. developer.ibm.com . 2006年2月20日閲覧。
- ^ abcdefg Lindholm, Tim; Yellin, Frank; Bracha, Gilad; Buckley, Alex (2015 年 2 月 13 日). Java 仮想マシン仕様 (Java SE 8 版).
- ^ 「Jasminホームページ」. jasmin.sourceforge.net . 2024年6月2日閲覧。
- ^ 「ジャマイカ:Java仮想マシン(JVM)マクロアセンブラー」。2024年6月2日閲覧。
- ^ “ストーリーイヤー/クラカタウ”. 2024 年 6 月 1 日。2024 年6 月 2 日に取得– GitHub 経由。
- ^ 「Lilac - Java アセンブラー」lilac.sourceforge.net . 2024 年6 月 2 日閲覧。
- ^ 「FPC 新機能 3.0.0 - Free Pascal wiki」. wiki.freepascal.org . 2024年6月2日閲覧。
- ^ 「FPC JVM - Free Pascal wiki」. wiki.freepascal.org . 2024年6月2日閲覧。
- ^ Nutter, Charles (2007 年 1 月 3 日). 「InvokeDynamic: 実際役に立つのか?」. 2008 年1 月 25 日閲覧。
- ^ 「Java Community Process(SM) プログラム - JSR: Java 仕様リクエスト - 詳細 JSR# 292」。www.jcp.org。2024年6 月 2 日閲覧。
外部リンク
- Oracle の Java 仮想マシン仕様
- Java 仮想マシンのプログラミング言語
- バイトコード ビジュアライザー – バイトコード ビューアおよびデバッガー (無料の Eclipse プラグイン)
- AdaptJ StackTrace – スタック、ローカル変数、実行フローを完全に制御できるバイトコードレベルのデバッグ
- Java Class Unpacker – Total Commanderのプラグイン。クラスファイルを圧縮アーカイブとして開き、フィールドとメソッドをファイルとして表示します。バイトコードはF3を使用してテキストとして表示できます。
