Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare a Scribd company logo
わかる !Java バイトコード ―  30 分でわからない ?Java バイトコード入門 筑波大学大学院 システム情報工学研究科 博士後期課程 水島宏太
自己紹介とか Twitter: @kmizu はてな : id:kmizushima github: http://github.com/kmizu/ 大学院生 構文解析の研究とかやってます 特に Packrat Parsing Scala 好き Scala の布教活動をあちこちでやったり JVM 好き JVM 上で動作する言語処理系 Onion を開発
Agenda プログラミング言語としての Java バイトコード マシンモデル 型システム 命令セット クラスファイルベリファイア ベリファイアがはじく操作の例 簡単なプログラムを javap で逆アセンブルする 役に立つかもしれない javap のオプション解説 クラスファイル仕様については省略 時間が足りないので…
Javaバイトコードとは Java仮想マシン(JVM)の機械語命令 オペコード が1 バイト である事に由来 1命令 が必ずしも1バイトなわけではない(後述) 特徴: スタックマシン オブジェクト指向的(Java的)な型システム 安全でない操作が(基本的に)できない クラスファイルベリファイアによる事前チェック
Hello, World!を逆アセンブルする public class Hello { public static void main(String[] args){ System.out.println("Hello, World!"); } } ↓ public static void main(java.lang.String[]); Code: 0:  getstatic  #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3:  ldc  #3; //String Hello, World! 5:  invokevirtual  #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 8:  return
Hello, World!を読む 0:  getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream; 0:  バイトコード配列の 0 番目を意味している getstatic:  オペコードのニーモニック java/lang/System.out: System.out の完全限定名 Ljava/io/PrintStream;: System.out の型 System.out をスタックにロード 3:  ldc   #3; //String Hello, World! //←1: ではなく 3: である点に注意 文字列定数 "Hello, World!" をスタックにロード 5:  invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V PrintStream のメソッド println を呼び出す 8:  return メソッドから return する
スタックマシン 演算対象( オペランド )がスタックに置かれる ←->レジスタマシン オペランドが置かれるスタック= オペランドスタック おおざっぱに言って、以下の繰り返し 1. 命令( オペコード )を取り出す 2. オペランドスタックから値をポップ 3. 命令を実行 4. 実行結果をオペランドスタックにプッシュ 5. 1.に戻る
スタックマシンの動作イメージ var pc: int var ops: byte[] ... while(pc < ops.length) { switch(ops[pc]) { case ADD: r = pop; l = pop; push(l + r); case SUB: r = pop; l = pop; push(l - r); case DIV: ... } pc++; }
型システム プリミティブ型 byte, short, int, long, char float, double void boolean 参照型 配列型 クラス型 インタフェース型 だいたい Java と同じだけど細かい所が違う
実際の型と計算上の型とカテゴリ 演算命令が直接サポートしていない型が存在 byte, short, char, boolean int 型の値として計算される カテゴリ おおざっぱに言うと、オペランドスタック上における値のサイズ boolean, byte, char, short, int, float,  参照型は 1 long, double は 2 命令のオペランドは特定のカテゴリでないと受け付けないものがある
実際の型と計算上の型とカテゴリ 2 double double 2 long long 1 returnAddress returnAddress 1 reference reference 1 float float 1 int int 1 int short 1 int char 1 int byte 1 int boolean カテゴリ 計算上の型 実際の型
命令の分類 大体 Java 仮想マシン仕様第 2 版に沿ってるが、一部独自に分類 ロード / ストア命令 算術命令 型変換命令 配列関係の命令 オブジェクトの生成・操作 制御命令 例外のスロー 同期化命令 メソッド呼び出し関係の命令 使われなくなった命令
ロード / ストア命令  (1) –  定数をオペランドスタックにロードする命令 bipush … byte の即値をプッシュ sipush … short の即値をプッシュ iconst_<i> … -1,0,...,5 をプッシュ aconst_null … null をプッシュ ldc, ldc_w, ldc2_w 文字列定数 , 整数 , 浮動小数点数を 実行時コンスタントプール からプッシュする など
bipush byte の即値をプッシュ フォーマット:  <0x10, byte> オペランドスタック:  ... ⇒ ..., value byte の即値が int の value へと符号拡張され、プッシュされる
ldc 実行時コンスタントプールから値をプッシュする フォーマット:  <0x18, index> index が示すエントリは、 int 型または float 型の実行時定数か、文字列リテラルへのシンボル参照でなければならない オペランドスタック:  ... ⇒ ..., value エントリが int 型または float 型の実行時定数の場合、該当する定数が int 型あるいは float 型としてプッシュされる エントリが文字列リテラルへのシンボル参照の場合、そのインスタンスへの参照がプッシュされる
ロード / ストア命令  (2) –  ローカル変数の値をオペランドスタックにロードする iload …  ローカル変数から int をロード iload_<n> …  ローカル変数から int をロード n = 0 ~ 3 fload …  ローカル変数から float をロード fload_<n> …  ローカル変数から float をロード n = 0 ~ 3 aload …  ローカル変数から参照型の値をロード など
iload ローカル変数から int をロードする フォーマット:  <0x15,index> オペランドスタック:  ..., ⇒ ..., value index 番目のローカル変数の値がスタックにプッシュされる index 番目のローカル変数には int 型の値が保持されていなければならない
fload ローカル変数から float をロードする フォーマット:  <0x17,index> オペランドスタック:  ..., ⇒ ..., value index 番目のローカル変数の値がスタックにプッシュされる index 番目のローカル変数には float 型の値が保持されていなければならない
ロード / ストア命令  (3) –  値をローカル変数にストアする istore …  ローカル変数に int をストア istore_<n> …  ローカル変数から int をロード n = 0 ~ 3 fstore …  ローカル変数に float をストア fstore_<n> …  ローカルに float をストア n = 0 ~ 3 astore …  ローカル変数に参照型の値をストア など
istore ローカル変数に int をストアする フォーマット:  <0x36,index> オペランドスタック:  ..., value ⇒ ..., スタックトップの値が、 index 番目のローカル変数にストアされる スタックトップの値は int 型 でなければならない
fstore ローカル変数に float をストアする フォーマット:  <0x38,index> オペランドスタック:  ..., value ⇒ ..., スタックトップの値が、 index 番目のローカル変数にストアされる スタックトップの値は float 型 でなければならない
算術命令 iadd, ladd, fadd, dadd …  加算 isub, lsub, fsub, dsub …  減算 imul, lmul, fmul, dmul …  乗算 idiv, ldiv, fdiv, ddiv …  除算 irem, lrem, frem, drem …  剰余 ineg, lneg, fneg, dneg …  符号反転 など
iadd int の加算を行う フォーマット:  <0x60> オペランドスタック:  ..., value1, value2 ⇒ ..., result value1 + value2 の結果がスタックにプッシュされる value1 と value2 は int 型 でなければならない
lsub long の加算を行う フォーマット:  <0x65> オペランドスタック:  ..., value1, value2 ⇒ ..., result value1 - value2 の結果がスタックにプッシュされる value1 と value2 は long 型 でなければならない
型変換命令 ワイドニング数値変換命令 i2l … int から long への型変換を行う i2f … int から float への型変換を行う … ナローイング数値変換命令 i2b … int から byte への変換を行う i2c … int から char への変換を行う …
i2l int を long に変換する フォーマット:  <0x85> オペランドスタック:  ..., value ⇒ ..., result value が long へと符号拡張された結果がプッシュされる value は int 型 でなければならない
i2b int を byte に変換する フォーマット:  <0x91> オペランドスタック:  ..., value ⇒ ..., result value が byte へ切り捨てられ、 int へと符号拡張された結果がプッシュされる value は int 型 でなければならない
配列関係の命令 配列を生成する命令 newarray … 1 次元配列を生成する … 配列の要素をロードする命令 baload … byte 型の配列要素をロードする … 配列の要素に値をストアする命令 bastore … byte 型の配列要素に値をストアする … arraylength …  配列の長さを取得する
newarray 配列を生成する フォーマット:  <0xbc,atype> atype は生成する配列の型 ( プリミティブ型 ) を表したコード 4,5,6,7,8,9,10,11 のいずれか オペランドスタック:  ..., count ⇒ ..., objectref count は int 型でなければならない 要素型が atype で長さが count の配列が生成されて、配列への参照がプッシュされる
arraylength 配列の長さを取得する フォーマット:  <0xbe> オペランドスタック:  ..., arrayref ⇒ ..., length arrayref は配列への参照でなければならない arrayref が参照する配列の長さがスタックにプッシュされる
オブジェクトの生成・操作 new …  オブジェクトを生成 getfield …  フィールドを取得 putfield …  フィールドに値をストア getstatic … static フィールドを取得 putstatic … static フィールドに値をストア instanceof … Java の instanceof 相当 checkcast …  参照型のキャストを行う
new オブジェクトを生成する フォーマット:  <0xbb,indexbyte1,indexbyte2> indexbyte はクラス型へのシンボル参照でなければならない オペランドスタック:  ..., ⇒ ..., objectref 指定された型のオブジェクトが生成されて、スタックにプッシュされる
getstatic static フィールドを取得する フォーマット:  <0xb2,indexbyte1,indexbyte2> indexbyte は該当するフィールドへのシンボル参照でなければならない オペランドスタック:  ..., ⇒ ..., value static フィールドの値がスタックにプッシュされる
スタック管理命令 スタック上の値の順番を入れ替えたりする pop, pop2 …  スタックから値をポップする dup, dup2 …  スタックトップの値を複製 dup_x1 …  スタックトップの値を複製して、トップの二つ下の値として挿入 dup_x2 …
pop スタックトップの値をポップする フォーマット:  <0x57> オペランドスタック:  ..., value ⇒ ... スタックトップの値がカテゴリ 1 の場合のみ使用可
dup スタックトップの値を複製する フォーマット:  <0x59> オペランドスタック:  ..., value ⇒ ..., value, value スタックトップの値がカテゴリ 1 の場合のみ使用可
制御命令 条件分岐命令 ifeq, iflt, ifne, ifgt, ifge, ... 複合条件分岐命令 tableswitch, lookupswitch switch 文に対応 無条件分岐命令 goto, goto_w,  jsr, jsr_w, ret
goto 無条件ジャンプを行う フォーマット:  <0xa7,branchbyte1,branchbyte2> branchbyte(1|2) から、分岐オフセットが生成される オペランドスタック:  ... ⇒ ...
ifeq スタックトップと 0 が等しい場合に該当アドレスにジャンプする 成功しない場合、次の命令があるアドレスから実行が再開 フォーマット:  <0x99,branchbyte1,branchbyte2> branchbyte(1|2) から、分岐オフセットが生成される オペランドスタック:  ..., value ⇒ ...
例外のスロー athrow …  例外を投げる命令 Java の throw 文に相当
athrow 例外を throw する 適合するハンドラが見つかるまでメソッドを巻き戻る throw された例外 フォーマット:  <0xbf> オペランドスタック:  ..., objectref ⇒ objectref ハンドラにジャンプする際に、現在のオペランドスタックがクリアされる ハンドラにジャンプする際に、 throw された例外オブジェクトへの参照がプッシュされる
同期化命令 要は synchronized 文を実装するための命令 monitorenter …  モニタに入る monitorexit …  モニタから抜ける monitor(enter/exit) を対応させるのはコンパイラ (javac など ) の責任 ベリファイアはチェックしない 例外や break/continue などで synchronized を抜けるときにもちゃんと対応する箇所で monitorexit を生成してあげないといけない…
メソッド呼び出し関係の命令 invokestatic … static メソッド呼び出し invokespecial …  コンストラクタ ( 等 ) 呼び出し invokevirtual …  インスタンスメソッド呼び出し invokeinterface …  インタフェースのメソッド呼び出し ireturn, lreturn, freturn, dreturn, areturn, return …  メソッドからの return
invokestatic static メソッドを呼び出す フォーマット:  <0xb8,indexbyte1,indexbyte2> indexbyte は、メソッドへのシンボル参照がある実行時コンスタントプールへのインデックス オペランドスタック:  ..., arg1, arg2, ..., arg n  ⇒ ... arg1, arg2, ... が引数 メソッドの返り値の型に応じて結果がスタックにプッシュされる
invokevirtual インスタンスメソッドを呼び出す フォーマット:  <0xb6,indexbyte1,indexbyte2> indexbyte は、メソッドへのシンボル参照がある実行時コンスタントプールへのインデックス オペランドスタック:  ..., objectref, arg1, arg2, ..., arg n  ⇒ ... objectref はオブジェクトへの参照 arg1, arg2, ... が引数 メソッドの返り値の型に応じて結果がスタックにプッシュされる interface 型の参照に対しては使えない 点に注意 invokeinterface を使う
使われなくなった命令 jsr, ret …  元々は finally の実装に使われていた JDK 1.4.2 から使われなくなった ベリファイア絡みで不具合があることが判明したため http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4381996   finally は code duplication によって実装されるように変更
クラスファイルベリファイア クラスファイル (.class) のフォーマットが Java 仮想マシン仕様に従っているかどうかを 該当クラスの初期化より前に チェック たとえば: 同じ pc におけるオペランド・スタックのサイズは常に一定でなければならない オペランド・スタックのオーバーフローやアンダーフローは原理的に発生しない 存在しないローカル変数に対するアクセスは無い 未初期化のローカル変数に対するアクセスは無い
jasmin 用のプログラム jasmin: Java バイトコードアセンブラ >java Overflow Exception in thread &quot;main&quot;  java.lang.VerifyError : (class: Overflow, method: main signature: ([Ljava/lang/String;)V)  Inconsistent stack height 1 != 0 ベリファイアがはねるプログラム (1) –  スタックオーバーフロー .class public Overflow .super java/lang/Object .method public static main([Ljava/lang/String;)V .limit stack 2 LABEL: ldc &quot;Hello, World!&quot; goto LABEL return .end method
>java Uninitialized Exception in thread &quot;main&quot;  java.lang.VerifyError : (class: Uninitialized, method: main signature: ([L java/lang/String;)V)  Accessing value from uninitialized register 1 ベリファイアがはねるプログラム (2) –  未初期化ローカル変数へのアクセス .class public Uninitialized .super java/lang/Object .method public static main([Ljava/lang/String;)V .limit stack 2 .limit locals 3 iload_1 return .end method
>java Incompatible Exception in thread &quot;main&quot;  java.lang.VerifyError : (class: Incompatible, method: main signature: ([Lj ava/lang/String;)V)  Expecting to find integer on stack ベリファイアがはねるプログラム (3)  -  型エラー .class public Incompatible .super java/lang/Object .method public static main([Ljava/lang/String;)V .limit stack 2 ldc 3.5 ldc 4.0 iadd return .end method
>java PopLong Exception in thread &quot;main&quot;  java.lang.VerifyError : (class: PopLong, method: main signature: ([Ljava/lang/String;)V)  Attempt to split long or double on the stack ベリファイアがはねるプログラム (4)  -  カテゴリ間違い .class public PopLong .super java/lang/Object .method public static main([Ljava/lang/String;)V .limit stack 3 invokestatic java/lang/System/currentTimeMillis()J pop  ; pop2 なら OK . pop はカテゴリ 1 の値しか pop できないが long はカテゴリ 2 return .end method
練習問題 ↓ のコンパイル結果を逆アセンブルしたものを読んでみる ',' で区切られた項目 ( 整数 ) の合計値を計算 import java.util.Scanner; public class CalcSum { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); while(scanner.hasNext()) { int result = 0; String[] line = scanner.nextLine().split(&quot;,&quot;); for(String element:line) result += Integer.parseInt(element); System.out.println(&quot;result:&quot; + result); } } }
練習問題 逆アセンブル (javap –c CalcSum) した結果 public class CalcSum { ↓ Compiled from &quot;CalcSum.java&quot; public class CalcSum extends java.lang.Object{ public CalcSum(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object.&quot;<init>&quot;:()V 4: return
練習問題 逆アセンブル (javap –c CalcSum) した結果 public static void main(String[] args) { Scanner scanner = new Scanner(System.in); ↓ public static void main(java.lang.String[]); Code: 0: new #2; //class java/util/Scanner 3: dup 4: getstatic #3; //Field java/lang/System.in:Ljava/io/InputStream; 7: invokespecial #4; //Method java/util/Scanner.&quot;<init>&quot;:(Ljava/io/InputStream;)V 10: astore_1
練習問題 逆アセンブル (javap –c CalcSum) した結果 while(scanner.hasNext()) { ↓ 11: aload_1 12: invokevirtual #5; //Method java/util/Scanner.hasNext:()Z 15: ifeq 97
練習問題 逆アセンブル (javap –c CalcSum) した結果 int result = 0; String[] line = scanner.nextLine().split(&quot;,&quot;); ↓ 18: iconst_0 19: istore_2 20: aload_1 21: invokevirtual #6; //Method java/util/Scanner.nextLine:()Ljava/lang/String; 24: ldc #7; //String , 26: invokevirtual #8; //Method java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String; 29: astore_3 30: aload_3 31: astore 4
練習問題 逆アセンブル (javap –c CalcSum) した結果 for(String element:line) result += Integer.parseInt(element); ↓ 33: aload 4 35: arraylength 36: istore 5 38: iconst_0 39: istore 6 41: iload 6 43: iload 5 45: if_icmpge 69 48: aload 4 50: iload 6 52: aaload 53: astore 7 55: iload_2 56: aload 7 58: invokestatic #9; //Method java/lang/Integer.parseInt:(Ljava/lang/String;)I 61: iadd 62: istore_2 63: iinc 6, 1 66: goto 41
練習問題 逆アセンブル (javap –c CalcSum) した結果 System.out.println(&quot;result:&quot; + result); } } } ↓ 69: getstatic #10; //Field java/lang/System.out:Ljava/io/PrintStream; 72: new #11; //class java/lang/StringBuilder 75: dup 76: invokespecial #12; //Method java/lang/StringBuilder.&quot;<init>&quot;:()V 79: ldc #13; //String result: 81: invokevirtual #14; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 84: iload_2 85: invokevirtual #15; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; 88: invokevirtual #16; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 91: invokevirtual #17; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 94: goto 11 97: return }
知っていると役に立つ ( かもしれない )javap のオプション -c:  逆アセンブルする。一番よく使う -private: private なものを含む全てのメンバを表示 -c などと組み合わせて使う事が多い -verbose:  クラスファイルのバージョン、コンスタントプールなどの詳細な情報を表示 -s:  内部的な型シグネチャの情報を表示 public static void main(java.lang.String[]) ->  ([Ljava/lang/String;)V
何が嬉しいの? Java バイトコードにコンパイルする俺言語 / フレームワーク等を作れるようになる バイトコード変換を利用したツールやフレームワークを作れるようになる AOP とか バイトコードにコンパイルする言語処理系やツールのバグなどを発見できるようになる 発表者は、 scala が生成したコードをよく javap している 面白い
まとめ Java バイトコードの マシンモデル 命令セット 型システム について簡単に解説 クラスファイルベリファイアの概要を説明 簡単なサンプルコードを逆アセンブルしてみた 知っていると役に立つかもしれない javap オプション 参考文献:  Java 仮想マシン仕様第2版,ティム・リンドホルム、フランク・イェリン,ピアソン・エデュケーション Web で無料公開 http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html   されてるので、そちらでも可 ( ただし英語 )

More Related Content

What's hot (20)

すごい constexpr たのしくレイトレ!
すごい constexpr たのしくレイトレ!すごい constexpr たのしくレイトレ!
すごい constexpr たのしくレイトレ!
Genya Murakami
 
WebAssembly向け多倍長演算の実装
WebAssembly向け多倍長演算の実装WebAssembly向け多倍長演算の実装
WebAssembly向け多倍長演算の実装
MITSUNARI Shigeo
 
分散システムについて語らせてくれ
分散システムについて語らせてくれ分散システムについて語らせてくれ
分散システムについて語らせてくれ
Kumazaki Hiroki
 
一人でもはじめるGitでバージョン管理
一人でもはじめるGitでバージョン管理一人でもはじめるGitでバージョン管理
一人でもはじめるGitでバージョン管理
Takafumi Yoshida
 
Intro to SVE 富岳のA64FXを触ってみた
Intro to SVE 富岳のA64FXを触ってみたIntro to SVE 富岳のA64FXを触ってみた
Intro to SVE 富岳のA64FXを触ってみた
MITSUNARI Shigeo
 
DockerコンテナでGitを使う
DockerコンテナでGitを使うDockerコンテナでGitを使う
DockerコンテナでGitを使う
Kazuhiro Suga
 
プログラムの処方箋~健康なコードと病んだコード
プログラムの処方箋~健康なコードと病んだコードプログラムの処方箋~健康なコードと病んだコード
プログラムの処方箋~健康なコードと病んだコード
Shigenori Sagawa
 
何となく勉強した気分になれるパーサ入門
何となく勉強した気分になれるパーサ入門何となく勉強した気分になれるパーサ入門
何となく勉強した気分になれるパーサ入門
masayoshi takahashi
 
PFNのML/DL基盤を支えるKubernetesにおける自動化 / DevOpsDays Tokyo 2021
PFNのML/DL基盤を支えるKubernetesにおける自動化 / DevOpsDays Tokyo 2021PFNのML/DL基盤を支えるKubernetesにおける自動化 / DevOpsDays Tokyo 2021
PFNのML/DL基盤を支えるKubernetesにおける自動化 / DevOpsDays Tokyo 2021
Preferred Networks
 
CUDAプログラミング入門
CUDAプログラミング入門CUDAプログラミング入門
CUDAプログラミング入門
NVIDIA Japan
 
マルチレイヤコンパイラ基盤による、エッジ向けディープラーニングの実装と最適化について
マルチレイヤコンパイラ基盤による、エッジ向けディープラーニングの実装と最適化についてマルチレイヤコンパイラ基盤による、エッジ向けディープラーニングの実装と最適化について
マルチレイヤコンパイラ基盤による、エッジ向けディープラーニングの実装と最適化について
Fixstars Corporation
 
Java仮想マシンの実装技術
Java仮想マシンの実装技術Java仮想マシンの実装技術
Java仮想マシンの実装技術
Kiyokuni Kawachiya
 
テスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるなテスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるな
Kentaro Matsui
 
Unified JVM Logging
Unified JVM LoggingUnified JVM Logging
Unified JVM Logging
Yuji Kubota
 
世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture
Atsushi Nakamura
 
デキるプログラマだけが知っているコードレビュー7つの秘訣
デキるプログラマだけが知っているコードレビュー7つの秘訣デキるプログラマだけが知っているコードレビュー7つの秘訣
デキるプログラマだけが知っているコードレビュー7つの秘訣
Masahiro Nishimi
 
CyberChefの使い方(HamaCTF2019 WriteUp編)
CyberChefの使い方(HamaCTF2019 WriteUp編)CyberChefの使い方(HamaCTF2019 WriteUp編)
CyberChefの使い方(HamaCTF2019 WriteUp編)
Shota Shinogi
 
メタプログラミングって何だろう
メタプログラミングって何だろうメタプログラミングって何だろう
メタプログラミングって何だろう
Kota Mizushima
 
実践イカパケット解析
実践イカパケット解析実践イカパケット解析
実践イカパケット解析
Yuki Mizuno
 
高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装
MITSUNARI Shigeo
 
すごい constexpr たのしくレイトレ!
すごい constexpr たのしくレイトレ!すごい constexpr たのしくレイトレ!
すごい constexpr たのしくレイトレ!
Genya Murakami
 
WebAssembly向け多倍長演算の実装
WebAssembly向け多倍長演算の実装WebAssembly向け多倍長演算の実装
WebAssembly向け多倍長演算の実装
MITSUNARI Shigeo
 
分散システムについて語らせてくれ
分散システムについて語らせてくれ分散システムについて語らせてくれ
分散システムについて語らせてくれ
Kumazaki Hiroki
 
一人でもはじめるGitでバージョン管理
一人でもはじめるGitでバージョン管理一人でもはじめるGitでバージョン管理
一人でもはじめるGitでバージョン管理
Takafumi Yoshida
 
Intro to SVE 富岳のA64FXを触ってみた
Intro to SVE 富岳のA64FXを触ってみたIntro to SVE 富岳のA64FXを触ってみた
Intro to SVE 富岳のA64FXを触ってみた
MITSUNARI Shigeo
 
DockerコンテナでGitを使う
DockerコンテナでGitを使うDockerコンテナでGitを使う
DockerコンテナでGitを使う
Kazuhiro Suga
 
プログラムの処方箋~健康なコードと病んだコード
プログラムの処方箋~健康なコードと病んだコードプログラムの処方箋~健康なコードと病んだコード
プログラムの処方箋~健康なコードと病んだコード
Shigenori Sagawa
 
何となく勉強した気分になれるパーサ入門
何となく勉強した気分になれるパーサ入門何となく勉強した気分になれるパーサ入門
何となく勉強した気分になれるパーサ入門
masayoshi takahashi
 
PFNのML/DL基盤を支えるKubernetesにおける自動化 / DevOpsDays Tokyo 2021
PFNのML/DL基盤を支えるKubernetesにおける自動化 / DevOpsDays Tokyo 2021PFNのML/DL基盤を支えるKubernetesにおける自動化 / DevOpsDays Tokyo 2021
PFNのML/DL基盤を支えるKubernetesにおける自動化 / DevOpsDays Tokyo 2021
Preferred Networks
 
CUDAプログラミング入門
CUDAプログラミング入門CUDAプログラミング入門
CUDAプログラミング入門
NVIDIA Japan
 
マルチレイヤコンパイラ基盤による、エッジ向けディープラーニングの実装と最適化について
マルチレイヤコンパイラ基盤による、エッジ向けディープラーニングの実装と最適化についてマルチレイヤコンパイラ基盤による、エッジ向けディープラーニングの実装と最適化について
マルチレイヤコンパイラ基盤による、エッジ向けディープラーニングの実装と最適化について
Fixstars Corporation
 
Java仮想マシンの実装技術
Java仮想マシンの実装技術Java仮想マシンの実装技術
Java仮想マシンの実装技術
Kiyokuni Kawachiya
 
テスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるなテスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるな
Kentaro Matsui
 
Unified JVM Logging
Unified JVM LoggingUnified JVM Logging
Unified JVM Logging
Yuji Kubota
 
世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture
Atsushi Nakamura
 
デキるプログラマだけが知っているコードレビュー7つの秘訣
デキるプログラマだけが知っているコードレビュー7つの秘訣デキるプログラマだけが知っているコードレビュー7つの秘訣
デキるプログラマだけが知っているコードレビュー7つの秘訣
Masahiro Nishimi
 
CyberChefの使い方(HamaCTF2019 WriteUp編)
CyberChefの使い方(HamaCTF2019 WriteUp編)CyberChefの使い方(HamaCTF2019 WriteUp編)
CyberChefの使い方(HamaCTF2019 WriteUp編)
Shota Shinogi
 
メタプログラミングって何だろう
メタプログラミングって何だろうメタプログラミングって何だろう
メタプログラミングって何だろう
Kota Mizushima
 
実践イカパケット解析
実践イカパケット解析実践イカパケット解析
実践イカパケット解析
Yuki Mizuno
 
高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装
MITSUNARI Shigeo
 

Viewers also liked (20)

JVMの中身を可視化してみた
JVMの中身を可視化してみたJVMの中身を可視化してみた
JVMの中身を可視化してみた
Kengo Toda
 
JJUG CCC 2015 Spring 「新人エンジニア奮闘記 - Javaって何?からwebサービスを公開するまで -」発表スライド
JJUG CCC 2015 Spring 「新人エンジニア奮闘記 - Javaって何?からwebサービスを公開するまで -」発表スライドJJUG CCC 2015 Spring 「新人エンジニア奮闘記 - Javaって何?からwebサービスを公開するまで -」発表スライド
JJUG CCC 2015 Spring 「新人エンジニア奮闘記 - Javaって何?からwebサービスを公開するまで -」発表スライド
ToshiakiArai
 
Javaはどのように動くのか~スライドでわかるJVMの仕組み
Javaはどのように動くのか~スライドでわかるJVMの仕組みJavaはどのように動くのか~スライドでわかるJVMの仕組み
Javaはどのように動くのか~スライドでわかるJVMの仕組み
Chihiro Ito
 
10のJava9で変わるJava8の嫌なとこ!
10のJava9で変わるJava8の嫌なとこ!10のJava9で変わるJava8の嫌なとこ!
10のJava9で変わるJava8の嫌なとこ!
bitter_fox
 
先駆的研究テーマ mruby/c
先駆的研究テーマ mruby/c先駆的研究テーマ mruby/c
先駆的研究テーマ mruby/c
shimane-itoc
 
クラスローダーについて
クラスローダーについてクラスローダーについて
クラスローダーについて
Suguru ARAKAWA
 
Vimから見たemacs
Vimから見たemacsVimから見たemacs
Vimから見たemacs
Shougo
 
プログラミング超超超入門
プログラミング超超超入門プログラミング超超超入門
プログラミング超超超入門
rigibun
 
情報編集 (web) 第4回:HTML入門 3 情報を整理する - リスト、テーブル
情報編集 (web) 第4回:HTML入門 3 情報を整理する - リスト、テーブル情報編集 (web) 第4回:HTML入門 3 情報を整理する - リスト、テーブル
情報編集 (web) 第4回:HTML入門 3 情報を整理する - リスト、テーブル
Atsushi Tadokoro
 
Google検索だけで満足しない、一歩先をいく収集・整理術(1day)
Google検索だけで満足しない、一歩先をいく収集・整理術(1day)Google検索だけで満足しない、一歩先をいく収集・整理術(1day)
Google検索だけで満足しない、一歩先をいく収集・整理術(1day)
龍太郎(Ryutaro) 井元(Imoto)
 
Java の Collection 関連について整理してみました
Java の Collection 関連について整理してみましたJava の Collection 関連について整理してみました
Java の Collection 関連について整理してみました
Gaprot
 
僕のデスクトップ整理方法
僕のデスクトップ整理方法僕のデスクトップ整理方法
僕のデスクトップ整理方法
Kenta Komori
 
データを整理するための基礎知識
データを整理するための基礎知識データを整理するための基礎知識
データを整理するための基礎知識
Gen Fujita
 
再入門、サーバープッシュ技術
再入門、サーバープッシュ技術再入門、サーバープッシュ技術
再入門、サーバープッシュ技術
Shin Sekaryo
 
201412ことばの理解とワーキングメモリ:基本概念の整理(公開)
201412ことばの理解とワーキングメモリ:基本概念の整理(公開)201412ことばの理解とワーキングメモリ:基本概念の整理(公開)
201412ことばの理解とワーキングメモリ:基本概念の整理(公開)
Kosuke Sugai
 
再入門!RESTとSpringMVC
再入門!RESTとSpringMVC再入門!RESTとSpringMVC
再入門!RESTとSpringMVC
terahide
 
SSL入門
SSL入門SSL入門
SSL入門
Takeru Ujinawa
 
Docker超入門
Docker超入門Docker超入門
Docker超入門
Katsunori Kanda
 
HTTP/2入門
HTTP/2入門HTTP/2入門
HTTP/2入門
渉 米須
 
JVMの中身を可視化してみた
JVMの中身を可視化してみたJVMの中身を可視化してみた
JVMの中身を可視化してみた
Kengo Toda
 
JJUG CCC 2015 Spring 「新人エンジニア奮闘記 - Javaって何?からwebサービスを公開するまで -」発表スライド
JJUG CCC 2015 Spring 「新人エンジニア奮闘記 - Javaって何?からwebサービスを公開するまで -」発表スライドJJUG CCC 2015 Spring 「新人エンジニア奮闘記 - Javaって何?からwebサービスを公開するまで -」発表スライド
JJUG CCC 2015 Spring 「新人エンジニア奮闘記 - Javaって何?からwebサービスを公開するまで -」発表スライド
ToshiakiArai
 
Javaはどのように動くのか~スライドでわかるJVMの仕組み
Javaはどのように動くのか~スライドでわかるJVMの仕組みJavaはどのように動くのか~スライドでわかるJVMの仕組み
Javaはどのように動くのか~スライドでわかるJVMの仕組み
Chihiro Ito
 
10のJava9で変わるJava8の嫌なとこ!
10のJava9で変わるJava8の嫌なとこ!10のJava9で変わるJava8の嫌なとこ!
10のJava9で変わるJava8の嫌なとこ!
bitter_fox
 
先駆的研究テーマ mruby/c
先駆的研究テーマ mruby/c先駆的研究テーマ mruby/c
先駆的研究テーマ mruby/c
shimane-itoc
 
クラスローダーについて
クラスローダーについてクラスローダーについて
クラスローダーについて
Suguru ARAKAWA
 
Vimから見たemacs
Vimから見たemacsVimから見たemacs
Vimから見たemacs
Shougo
 
プログラミング超超超入門
プログラミング超超超入門プログラミング超超超入門
プログラミング超超超入門
rigibun
 
情報編集 (web) 第4回:HTML入門 3 情報を整理する - リスト、テーブル
情報編集 (web) 第4回:HTML入門 3 情報を整理する - リスト、テーブル情報編集 (web) 第4回:HTML入門 3 情報を整理する - リスト、テーブル
情報編集 (web) 第4回:HTML入門 3 情報を整理する - リスト、テーブル
Atsushi Tadokoro
 
Google検索だけで満足しない、一歩先をいく収集・整理術(1day)
Google検索だけで満足しない、一歩先をいく収集・整理術(1day)Google検索だけで満足しない、一歩先をいく収集・整理術(1day)
Google検索だけで満足しない、一歩先をいく収集・整理術(1day)
龍太郎(Ryutaro) 井元(Imoto)
 
Java の Collection 関連について整理してみました
Java の Collection 関連について整理してみましたJava の Collection 関連について整理してみました
Java の Collection 関連について整理してみました
Gaprot
 
僕のデスクトップ整理方法
僕のデスクトップ整理方法僕のデスクトップ整理方法
僕のデスクトップ整理方法
Kenta Komori
 
データを整理するための基礎知識
データを整理するための基礎知識データを整理するための基礎知識
データを整理するための基礎知識
Gen Fujita
 
再入門、サーバープッシュ技術
再入門、サーバープッシュ技術再入門、サーバープッシュ技術
再入門、サーバープッシュ技術
Shin Sekaryo
 
201412ことばの理解とワーキングメモリ:基本概念の整理(公開)
201412ことばの理解とワーキングメモリ:基本概念の整理(公開)201412ことばの理解とワーキングメモリ:基本概念の整理(公開)
201412ことばの理解とワーキングメモリ:基本概念の整理(公開)
Kosuke Sugai
 
再入門!RESTとSpringMVC
再入門!RESTとSpringMVC再入門!RESTとSpringMVC
再入門!RESTとSpringMVC
terahide
 

Similar to Javaバイトコード入門 (8)

BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdf
Hiroshi Ono
 
详细介绍什么是Java虚拟机(JVM)介绍资料
详细介绍什么是Java虚拟机(JVM)介绍资料详细介绍什么是Java虚拟机(JVM)介绍资料
详细介绍什么是Java虚拟机(JVM)介绍资料
wensheng wei
 
How did yarv2llvm fail
How did yarv2llvm failHow did yarv2llvm fail
How did yarv2llvm fail
miura1729
 
Boostのあるプログラミング生活
Boostのあるプログラミング生活Boostのあるプログラミング生活
Boostのあるプログラミング生活
Akira Takahashi
 
帰って来たNemerle
帰って来たNemerle帰って来たNemerle
帰って来たNemerle
Kota Mizushima
 
C++模板与泛型编程
C++模板与泛型编程C++模板与泛型编程
C++模板与泛型编程
deer hope
 
C++模板与泛型编程
C++模板与泛型编程C++模板与泛型编程
C++模板与泛型编程
deer hope
 
BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdf
Hiroshi Ono
 
详细介绍什么是Java虚拟机(JVM)介绍资料
详细介绍什么是Java虚拟机(JVM)介绍资料详细介绍什么是Java虚拟机(JVM)介绍资料
详细介绍什么是Java虚拟机(JVM)介绍资料
wensheng wei
 
How did yarv2llvm fail
How did yarv2llvm failHow did yarv2llvm fail
How did yarv2llvm fail
miura1729
 
Boostのあるプログラミング生活
Boostのあるプログラミング生活Boostのあるプログラミング生活
Boostのあるプログラミング生活
Akira Takahashi
 
帰って来たNemerle
帰って来たNemerle帰って来たNemerle
帰って来たNemerle
Kota Mizushima
 
C++模板与泛型编程
C++模板与泛型编程C++模板与泛型编程
C++模板与泛型编程
deer hope
 
C++模板与泛型编程
C++模板与泛型编程C++模板与泛型编程
C++模板与泛型编程
deer hope
 

More from Kota Mizushima (20)

ドワンゴにおける新卒エンジニア向けScala研修について
ドワンゴにおける新卒エンジニア向けScala研修についてドワンゴにおける新卒エンジニア向けScala研修について
ドワンゴにおける新卒エンジニア向けScala研修について
Kota Mizushima
 
kollectionの紹介
kollectionの紹介kollectionの紹介
kollectionの紹介
Kota Mizushima
 
株式会社ドワンゴにおけるScala教育の現状
株式会社ドワンゴにおけるScala教育の現状株式会社ドワンゴにおけるScala教育の現状
株式会社ドワンゴにおけるScala教育の現状
Kota Mizushima
 
Macros in nemerle
Macros in nemerleMacros in nemerle
Macros in nemerle
Kota Mizushima
 
Scala Daysに行ってみて - あるいはスイス旅行記 -
Scala Daysに行ってみて - あるいはスイス旅行記 -Scala Daysに行ってみて - あるいはスイス旅行記 -
Scala Daysに行ってみて - あるいはスイス旅行記 -
Kota Mizushima
 
Introduction to PEG
Introduction to PEGIntroduction to PEG
Introduction to PEG
Kota Mizushima
 
Scalaの現状と今後
Scalaの現状と今後Scalaの現状と今後
Scalaの現状と今後
Kota Mizushima
 
Power of Scala
Power of ScalaPower of Scala
Power of Scala
Kota Mizushima
 
Scala Performance Tuning Tips
Scala Performance Tuning TipsScala Performance Tuning Tips
Scala Performance Tuning Tips
Kota Mizushima
 
こわくない型クラス
こわくない型クラスこわくない型クラス
こわくない型クラス
Kota Mizushima
 
こわくないScala
こわくないScalaこわくないScala
こわくないScala
Kota Mizushima
 
About Capabilities for Uniqueness and Borrowing
About Capabilities for Uniqueness and BorrowingAbout Capabilities for Uniqueness and Borrowing
About Capabilities for Uniqueness and Borrowing
Kota Mizushima
 
Scala Macros makes it easy to provide useful libraries
Scala Macros makes it easy to provide useful librariesScala Macros makes it easy to provide useful libraries
Scala Macros makes it easy to provide useful libraries
Kota Mizushima
 
Scala + Finagleの魅力
Scala + Finagleの魅力Scala + Finagleの魅力
Scala + Finagleの魅力
Kota Mizushima
 
Scalaの現状と課題
Scalaの現状と課題Scalaの現状と課題
Scalaの現状と課題
Kota Mizushima
 
Scalaでのプログラム開発
Scalaでのプログラム開発Scalaでのプログラム開発
Scalaでのプログラム開発
Kota Mizushima
 
日本Scalaユーザーズグループ発足
日本Scalaユーザーズグループ発足日本Scalaユーザーズグループ発足
日本Scalaユーザーズグループ発足
Kota Mizushima
 
Implicit Implicit Scala
Implicit Implicit ScalaImplicit Implicit Scala
Implicit Implicit Scala
Kota Mizushima
 
Implicit Explicit Scala
Implicit Explicit ScalaImplicit Explicit Scala
Implicit Explicit Scala
Kota Mizushima
 
ドワンゴにおける新卒エンジニア向けScala研修について
ドワンゴにおける新卒エンジニア向けScala研修についてドワンゴにおける新卒エンジニア向けScala研修について
ドワンゴにおける新卒エンジニア向けScala研修について
Kota Mizushima
 
株式会社ドワンゴにおけるScala教育の現状
株式会社ドワンゴにおけるScala教育の現状株式会社ドワンゴにおけるScala教育の現状
株式会社ドワンゴにおけるScala教育の現状
Kota Mizushima
 
Scala Daysに行ってみて - あるいはスイス旅行記 -
Scala Daysに行ってみて - あるいはスイス旅行記 -Scala Daysに行ってみて - あるいはスイス旅行記 -
Scala Daysに行ってみて - あるいはスイス旅行記 -
Kota Mizushima
 
Scalaの現状と今後
Scalaの現状と今後Scalaの現状と今後
Scalaの現状と今後
Kota Mizushima
 
Scala Performance Tuning Tips
Scala Performance Tuning TipsScala Performance Tuning Tips
Scala Performance Tuning Tips
Kota Mizushima
 
こわくない型クラス
こわくない型クラスこわくない型クラス
こわくない型クラス
Kota Mizushima
 
About Capabilities for Uniqueness and Borrowing
About Capabilities for Uniqueness and BorrowingAbout Capabilities for Uniqueness and Borrowing
About Capabilities for Uniqueness and Borrowing
Kota Mizushima
 
Scala Macros makes it easy to provide useful libraries
Scala Macros makes it easy to provide useful librariesScala Macros makes it easy to provide useful libraries
Scala Macros makes it easy to provide useful libraries
Kota Mizushima
 
Scala + Finagleの魅力
Scala + Finagleの魅力Scala + Finagleの魅力
Scala + Finagleの魅力
Kota Mizushima
 
Scalaの現状と課題
Scalaの現状と課題Scalaの現状と課題
Scalaの現状と課題
Kota Mizushima
 
Scalaでのプログラム開発
Scalaでのプログラム開発Scalaでのプログラム開発
Scalaでのプログラム開発
Kota Mizushima
 
日本Scalaユーザーズグループ発足
日本Scalaユーザーズグループ発足日本Scalaユーザーズグループ発足
日本Scalaユーザーズグループ発足
Kota Mizushima
 
Implicit Implicit Scala
Implicit Implicit ScalaImplicit Implicit Scala
Implicit Implicit Scala
Kota Mizushima
 
Implicit Explicit Scala
Implicit Explicit ScalaImplicit Explicit Scala
Implicit Explicit Scala
Kota Mizushima
 

Javaバイトコード入門

  • 1. わかる !Java バイトコード ― 30 分でわからない ?Java バイトコード入門 筑波大学大学院 システム情報工学研究科 博士後期課程 水島宏太
  • 2. 自己紹介とか Twitter: @kmizu はてな : id:kmizushima github: http://github.com/kmizu/ 大学院生 構文解析の研究とかやってます 特に Packrat Parsing Scala 好き Scala の布教活動をあちこちでやったり JVM 好き JVM 上で動作する言語処理系 Onion を開発
  • 3. Agenda プログラミング言語としての Java バイトコード マシンモデル 型システム 命令セット クラスファイルベリファイア ベリファイアがはじく操作の例 簡単なプログラムを javap で逆アセンブルする 役に立つかもしれない javap のオプション解説 クラスファイル仕様については省略 時間が足りないので…
  • 4. Javaバイトコードとは Java仮想マシン(JVM)の機械語命令 オペコード が1 バイト である事に由来 1命令 が必ずしも1バイトなわけではない(後述) 特徴: スタックマシン オブジェクト指向的(Java的)な型システム 安全でない操作が(基本的に)できない クラスファイルベリファイアによる事前チェック
  • 5. Hello, World!を逆アセンブルする public class Hello { public static void main(String[] args){ System.out.println(&quot;Hello, World!&quot;); } } ↓ public static void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String Hello, World! 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return
  • 6. Hello, World!を読む 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 0: バイトコード配列の 0 番目を意味している getstatic: オペコードのニーモニック java/lang/System.out: System.out の完全限定名 Ljava/io/PrintStream;: System.out の型 System.out をスタックにロード 3: ldc #3; //String Hello, World! //←1: ではなく 3: である点に注意 文字列定数 &quot;Hello, World!&quot; をスタックにロード 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V PrintStream のメソッド println を呼び出す 8: return メソッドから return する
  • 7. スタックマシン 演算対象( オペランド )がスタックに置かれる ←->レジスタマシン オペランドが置かれるスタック= オペランドスタック おおざっぱに言って、以下の繰り返し 1. 命令( オペコード )を取り出す 2. オペランドスタックから値をポップ 3. 命令を実行 4. 実行結果をオペランドスタックにプッシュ 5. 1.に戻る
  • 8. スタックマシンの動作イメージ var pc: int var ops: byte[] ... while(pc < ops.length) { switch(ops[pc]) { case ADD: r = pop; l = pop; push(l + r); case SUB: r = pop; l = pop; push(l - r); case DIV: ... } pc++; }
  • 9. 型システム プリミティブ型 byte, short, int, long, char float, double void boolean 参照型 配列型 クラス型 インタフェース型 だいたい Java と同じだけど細かい所が違う
  • 10. 実際の型と計算上の型とカテゴリ 演算命令が直接サポートしていない型が存在 byte, short, char, boolean int 型の値として計算される カテゴリ おおざっぱに言うと、オペランドスタック上における値のサイズ boolean, byte, char, short, int, float, 参照型は 1 long, double は 2 命令のオペランドは特定のカテゴリでないと受け付けないものがある
  • 11. 実際の型と計算上の型とカテゴリ 2 double double 2 long long 1 returnAddress returnAddress 1 reference reference 1 float float 1 int int 1 int short 1 int char 1 int byte 1 int boolean カテゴリ 計算上の型 実際の型
  • 12. 命令の分類 大体 Java 仮想マシン仕様第 2 版に沿ってるが、一部独自に分類 ロード / ストア命令 算術命令 型変換命令 配列関係の命令 オブジェクトの生成・操作 制御命令 例外のスロー 同期化命令 メソッド呼び出し関係の命令 使われなくなった命令
  • 13. ロード / ストア命令 (1) – 定数をオペランドスタックにロードする命令 bipush … byte の即値をプッシュ sipush … short の即値をプッシュ iconst_<i> … -1,0,...,5 をプッシュ aconst_null … null をプッシュ ldc, ldc_w, ldc2_w 文字列定数 , 整数 , 浮動小数点数を 実行時コンスタントプール からプッシュする など
  • 14. bipush byte の即値をプッシュ フォーマット: <0x10, byte> オペランドスタック: ... ⇒ ..., value byte の即値が int の value へと符号拡張され、プッシュされる
  • 15. ldc 実行時コンスタントプールから値をプッシュする フォーマット: <0x18, index> index が示すエントリは、 int 型または float 型の実行時定数か、文字列リテラルへのシンボル参照でなければならない オペランドスタック: ... ⇒ ..., value エントリが int 型または float 型の実行時定数の場合、該当する定数が int 型あるいは float 型としてプッシュされる エントリが文字列リテラルへのシンボル参照の場合、そのインスタンスへの参照がプッシュされる
  • 16. ロード / ストア命令 (2) – ローカル変数の値をオペランドスタックにロードする iload … ローカル変数から int をロード iload_<n> … ローカル変数から int をロード n = 0 ~ 3 fload … ローカル変数から float をロード fload_<n> … ローカル変数から float をロード n = 0 ~ 3 aload … ローカル変数から参照型の値をロード など
  • 17. iload ローカル変数から int をロードする フォーマット: <0x15,index> オペランドスタック: ..., ⇒ ..., value index 番目のローカル変数の値がスタックにプッシュされる index 番目のローカル変数には int 型の値が保持されていなければならない
  • 18. fload ローカル変数から float をロードする フォーマット: <0x17,index> オペランドスタック: ..., ⇒ ..., value index 番目のローカル変数の値がスタックにプッシュされる index 番目のローカル変数には float 型の値が保持されていなければならない
  • 19. ロード / ストア命令 (3) – 値をローカル変数にストアする istore … ローカル変数に int をストア istore_<n> … ローカル変数から int をロード n = 0 ~ 3 fstore … ローカル変数に float をストア fstore_<n> … ローカルに float をストア n = 0 ~ 3 astore … ローカル変数に参照型の値をストア など
  • 20. istore ローカル変数に int をストアする フォーマット: <0x36,index> オペランドスタック: ..., value ⇒ ..., スタックトップの値が、 index 番目のローカル変数にストアされる スタックトップの値は int 型 でなければならない
  • 21. fstore ローカル変数に float をストアする フォーマット: <0x38,index> オペランドスタック: ..., value ⇒ ..., スタックトップの値が、 index 番目のローカル変数にストアされる スタックトップの値は float 型 でなければならない
  • 22. 算術命令 iadd, ladd, fadd, dadd … 加算 isub, lsub, fsub, dsub … 減算 imul, lmul, fmul, dmul … 乗算 idiv, ldiv, fdiv, ddiv … 除算 irem, lrem, frem, drem … 剰余 ineg, lneg, fneg, dneg … 符号反転 など
  • 23. iadd int の加算を行う フォーマット: <0x60> オペランドスタック: ..., value1, value2 ⇒ ..., result value1 + value2 の結果がスタックにプッシュされる value1 と value2 は int 型 でなければならない
  • 24. lsub long の加算を行う フォーマット: <0x65> オペランドスタック: ..., value1, value2 ⇒ ..., result value1 - value2 の結果がスタックにプッシュされる value1 と value2 は long 型 でなければならない
  • 25. 型変換命令 ワイドニング数値変換命令 i2l … int から long への型変換を行う i2f … int から float への型変換を行う … ナローイング数値変換命令 i2b … int から byte への変換を行う i2c … int から char への変換を行う …
  • 26. i2l int を long に変換する フォーマット: <0x85> オペランドスタック: ..., value ⇒ ..., result value が long へと符号拡張された結果がプッシュされる value は int 型 でなければならない
  • 27. i2b int を byte に変換する フォーマット: <0x91> オペランドスタック: ..., value ⇒ ..., result value が byte へ切り捨てられ、 int へと符号拡張された結果がプッシュされる value は int 型 でなければならない
  • 28. 配列関係の命令 配列を生成する命令 newarray … 1 次元配列を生成する … 配列の要素をロードする命令 baload … byte 型の配列要素をロードする … 配列の要素に値をストアする命令 bastore … byte 型の配列要素に値をストアする … arraylength … 配列の長さを取得する
  • 29. newarray 配列を生成する フォーマット: <0xbc,atype> atype は生成する配列の型 ( プリミティブ型 ) を表したコード 4,5,6,7,8,9,10,11 のいずれか オペランドスタック: ..., count ⇒ ..., objectref count は int 型でなければならない 要素型が atype で長さが count の配列が生成されて、配列への参照がプッシュされる
  • 30. arraylength 配列の長さを取得する フォーマット: <0xbe> オペランドスタック: ..., arrayref ⇒ ..., length arrayref は配列への参照でなければならない arrayref が参照する配列の長さがスタックにプッシュされる
  • 31. オブジェクトの生成・操作 new … オブジェクトを生成 getfield … フィールドを取得 putfield … フィールドに値をストア getstatic … static フィールドを取得 putstatic … static フィールドに値をストア instanceof … Java の instanceof 相当 checkcast … 参照型のキャストを行う
  • 32. new オブジェクトを生成する フォーマット: <0xbb,indexbyte1,indexbyte2> indexbyte はクラス型へのシンボル参照でなければならない オペランドスタック: ..., ⇒ ..., objectref 指定された型のオブジェクトが生成されて、スタックにプッシュされる
  • 33. getstatic static フィールドを取得する フォーマット: <0xb2,indexbyte1,indexbyte2> indexbyte は該当するフィールドへのシンボル参照でなければならない オペランドスタック: ..., ⇒ ..., value static フィールドの値がスタックにプッシュされる
  • 34. スタック管理命令 スタック上の値の順番を入れ替えたりする pop, pop2 … スタックから値をポップする dup, dup2 … スタックトップの値を複製 dup_x1 … スタックトップの値を複製して、トップの二つ下の値として挿入 dup_x2 …
  • 35. pop スタックトップの値をポップする フォーマット: <0x57> オペランドスタック: ..., value ⇒ ... スタックトップの値がカテゴリ 1 の場合のみ使用可
  • 36. dup スタックトップの値を複製する フォーマット: <0x59> オペランドスタック: ..., value ⇒ ..., value, value スタックトップの値がカテゴリ 1 の場合のみ使用可
  • 37. 制御命令 条件分岐命令 ifeq, iflt, ifne, ifgt, ifge, ... 複合条件分岐命令 tableswitch, lookupswitch switch 文に対応 無条件分岐命令 goto, goto_w, jsr, jsr_w, ret
  • 38. goto 無条件ジャンプを行う フォーマット: <0xa7,branchbyte1,branchbyte2> branchbyte(1|2) から、分岐オフセットが生成される オペランドスタック: ... ⇒ ...
  • 39. ifeq スタックトップと 0 が等しい場合に該当アドレスにジャンプする 成功しない場合、次の命令があるアドレスから実行が再開 フォーマット: <0x99,branchbyte1,branchbyte2> branchbyte(1|2) から、分岐オフセットが生成される オペランドスタック: ..., value ⇒ ...
  • 40. 例外のスロー athrow … 例外を投げる命令 Java の throw 文に相当
  • 41. athrow 例外を throw する 適合するハンドラが見つかるまでメソッドを巻き戻る throw された例外 フォーマット: <0xbf> オペランドスタック: ..., objectref ⇒ objectref ハンドラにジャンプする際に、現在のオペランドスタックがクリアされる ハンドラにジャンプする際に、 throw された例外オブジェクトへの参照がプッシュされる
  • 42. 同期化命令 要は synchronized 文を実装するための命令 monitorenter … モニタに入る monitorexit … モニタから抜ける monitor(enter/exit) を対応させるのはコンパイラ (javac など ) の責任 ベリファイアはチェックしない 例外や break/continue などで synchronized を抜けるときにもちゃんと対応する箇所で monitorexit を生成してあげないといけない…
  • 43. メソッド呼び出し関係の命令 invokestatic … static メソッド呼び出し invokespecial … コンストラクタ ( 等 ) 呼び出し invokevirtual … インスタンスメソッド呼び出し invokeinterface … インタフェースのメソッド呼び出し ireturn, lreturn, freturn, dreturn, areturn, return … メソッドからの return
  • 44. invokestatic static メソッドを呼び出す フォーマット: <0xb8,indexbyte1,indexbyte2> indexbyte は、メソッドへのシンボル参照がある実行時コンスタントプールへのインデックス オペランドスタック: ..., arg1, arg2, ..., arg n ⇒ ... arg1, arg2, ... が引数 メソッドの返り値の型に応じて結果がスタックにプッシュされる
  • 45. invokevirtual インスタンスメソッドを呼び出す フォーマット: <0xb6,indexbyte1,indexbyte2> indexbyte は、メソッドへのシンボル参照がある実行時コンスタントプールへのインデックス オペランドスタック: ..., objectref, arg1, arg2, ..., arg n ⇒ ... objectref はオブジェクトへの参照 arg1, arg2, ... が引数 メソッドの返り値の型に応じて結果がスタックにプッシュされる interface 型の参照に対しては使えない 点に注意 invokeinterface を使う
  • 46. 使われなくなった命令 jsr, ret … 元々は finally の実装に使われていた JDK 1.4.2 から使われなくなった ベリファイア絡みで不具合があることが判明したため http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4381996 finally は code duplication によって実装されるように変更
  • 47. クラスファイルベリファイア クラスファイル (.class) のフォーマットが Java 仮想マシン仕様に従っているかどうかを 該当クラスの初期化より前に チェック たとえば: 同じ pc におけるオペランド・スタックのサイズは常に一定でなければならない オペランド・スタックのオーバーフローやアンダーフローは原理的に発生しない 存在しないローカル変数に対するアクセスは無い 未初期化のローカル変数に対するアクセスは無い
  • 48. jasmin 用のプログラム jasmin: Java バイトコードアセンブラ >java Overflow Exception in thread &quot;main&quot; java.lang.VerifyError : (class: Overflow, method: main signature: ([Ljava/lang/String;)V) Inconsistent stack height 1 != 0 ベリファイアがはねるプログラム (1) – スタックオーバーフロー .class public Overflow .super java/lang/Object .method public static main([Ljava/lang/String;)V .limit stack 2 LABEL: ldc &quot;Hello, World!&quot; goto LABEL return .end method
  • 49. >java Uninitialized Exception in thread &quot;main&quot; java.lang.VerifyError : (class: Uninitialized, method: main signature: ([L java/lang/String;)V) Accessing value from uninitialized register 1 ベリファイアがはねるプログラム (2) – 未初期化ローカル変数へのアクセス .class public Uninitialized .super java/lang/Object .method public static main([Ljava/lang/String;)V .limit stack 2 .limit locals 3 iload_1 return .end method
  • 50. >java Incompatible Exception in thread &quot;main&quot; java.lang.VerifyError : (class: Incompatible, method: main signature: ([Lj ava/lang/String;)V) Expecting to find integer on stack ベリファイアがはねるプログラム (3) - 型エラー .class public Incompatible .super java/lang/Object .method public static main([Ljava/lang/String;)V .limit stack 2 ldc 3.5 ldc 4.0 iadd return .end method
  • 51. >java PopLong Exception in thread &quot;main&quot; java.lang.VerifyError : (class: PopLong, method: main signature: ([Ljava/lang/String;)V) Attempt to split long or double on the stack ベリファイアがはねるプログラム (4) - カテゴリ間違い .class public PopLong .super java/lang/Object .method public static main([Ljava/lang/String;)V .limit stack 3 invokestatic java/lang/System/currentTimeMillis()J pop ; pop2 なら OK . pop はカテゴリ 1 の値しか pop できないが long はカテゴリ 2 return .end method
  • 52. 練習問題 ↓ のコンパイル結果を逆アセンブルしたものを読んでみる ',' で区切られた項目 ( 整数 ) の合計値を計算 import java.util.Scanner; public class CalcSum { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); while(scanner.hasNext()) { int result = 0; String[] line = scanner.nextLine().split(&quot;,&quot;); for(String element:line) result += Integer.parseInt(element); System.out.println(&quot;result:&quot; + result); } } }
  • 53. 練習問題 逆アセンブル (javap –c CalcSum) した結果 public class CalcSum { ↓ Compiled from &quot;CalcSum.java&quot; public class CalcSum extends java.lang.Object{ public CalcSum(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object.&quot;<init>&quot;:()V 4: return
  • 54. 練習問題 逆アセンブル (javap –c CalcSum) した結果 public static void main(String[] args) { Scanner scanner = new Scanner(System.in); ↓ public static void main(java.lang.String[]); Code: 0: new #2; //class java/util/Scanner 3: dup 4: getstatic #3; //Field java/lang/System.in:Ljava/io/InputStream; 7: invokespecial #4; //Method java/util/Scanner.&quot;<init>&quot;:(Ljava/io/InputStream;)V 10: astore_1
  • 55. 練習問題 逆アセンブル (javap –c CalcSum) した結果 while(scanner.hasNext()) { ↓ 11: aload_1 12: invokevirtual #5; //Method java/util/Scanner.hasNext:()Z 15: ifeq 97
  • 56. 練習問題 逆アセンブル (javap –c CalcSum) した結果 int result = 0; String[] line = scanner.nextLine().split(&quot;,&quot;); ↓ 18: iconst_0 19: istore_2 20: aload_1 21: invokevirtual #6; //Method java/util/Scanner.nextLine:()Ljava/lang/String; 24: ldc #7; //String , 26: invokevirtual #8; //Method java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String; 29: astore_3 30: aload_3 31: astore 4
  • 57. 練習問題 逆アセンブル (javap –c CalcSum) した結果 for(String element:line) result += Integer.parseInt(element); ↓ 33: aload 4 35: arraylength 36: istore 5 38: iconst_0 39: istore 6 41: iload 6 43: iload 5 45: if_icmpge 69 48: aload 4 50: iload 6 52: aaload 53: astore 7 55: iload_2 56: aload 7 58: invokestatic #9; //Method java/lang/Integer.parseInt:(Ljava/lang/String;)I 61: iadd 62: istore_2 63: iinc 6, 1 66: goto 41
  • 58. 練習問題 逆アセンブル (javap –c CalcSum) した結果 System.out.println(&quot;result:&quot; + result); } } } ↓ 69: getstatic #10; //Field java/lang/System.out:Ljava/io/PrintStream; 72: new #11; //class java/lang/StringBuilder 75: dup 76: invokespecial #12; //Method java/lang/StringBuilder.&quot;<init>&quot;:()V 79: ldc #13; //String result: 81: invokevirtual #14; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 84: iload_2 85: invokevirtual #15; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; 88: invokevirtual #16; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 91: invokevirtual #17; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 94: goto 11 97: return }
  • 59. 知っていると役に立つ ( かもしれない )javap のオプション -c: 逆アセンブルする。一番よく使う -private: private なものを含む全てのメンバを表示 -c などと組み合わせて使う事が多い -verbose: クラスファイルのバージョン、コンスタントプールなどの詳細な情報を表示 -s: 内部的な型シグネチャの情報を表示 public static void main(java.lang.String[]) -> ([Ljava/lang/String;)V
  • 60. 何が嬉しいの? Java バイトコードにコンパイルする俺言語 / フレームワーク等を作れるようになる バイトコード変換を利用したツールやフレームワークを作れるようになる AOP とか バイトコードにコンパイルする言語処理系やツールのバグなどを発見できるようになる 発表者は、 scala が生成したコードをよく javap している 面白い
  • 61. まとめ Java バイトコードの マシンモデル 命令セット 型システム について簡単に解説 クラスファイルベリファイアの概要を説明 簡単なサンプルコードを逆アセンブルしてみた 知っていると役に立つかもしれない javap オプション 参考文献: Java 仮想マシン仕様第2版,ティム・リンドホルム、フランク・イェリン,ピアソン・エデュケーション Web で無料公開 http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html されてるので、そちらでも可 ( ただし英語 )