Slide 1

Slide 1 text

JVM あなたは の 気持ちを理解できるか? あるいはバイトコード入門 Java in the Box 櫻庭 祐一

Slide 2

Slide 2 text

バイトコード 仮想マシンが解釈する中間表記 CPU に対する機械語 / アセンブラのようなもの JVM の気持ちを理解するには バイトコードを読めることが必須 ※ バイトコードを読めても業務で役に立つことはほぼありません

Slide 3

Slide 3 text

Java Souce Code Java Class File javac JVM 実行 読み込み クラスファイル定義 JVMS Chapter 4 クラスファイルの情報 クラスの情報 コンスタントプール アトリビュート バイトコードはここに含まれる

Slide 4

Slide 4 text

クラスファイル解析ツール javap -c バイトコード出力 -v/-verbose 解析結果全部 public class Adder { public int add(int x, int y) { return x + y; } } public class Adder { public Adder(); Code: 0: aload_0 1: invokespecial #1 4: return int add(int, int); Code: 0: iload_1 1: iload_2 2: iadd 3: ireturn } javap -c

Slide 5

Slide 5 text

バイトコード Java が解釈する命令形式 JVM JVMS 5.1 命令 1 byte オペコード 使用していない数値もあるので 200 程度 命令の種類 ロード / ストア 演算 制御構造 スタック制御 生成関連 メソッド呼び出し 型変換 et al.

Slide 6

Slide 6 text

バイトコードがどのように実行されるか の前に ... HPの電卓の話をします

Slide 7

Slide 7 text

HPの電卓で を計算するには 1 + 2 1 Enter 2 +

Slide 8

Slide 8 text

HPの電卓で を計算するには 1 + 2 1 Enter 2 + ( 2 + 3 ) 5 + ( 4 - 2 ) 2 × ÷ 2 3 5 4 2 2 E + × E - ÷+ 逆ポーランド記法

Slide 9

Slide 9 text

逆ポーランド記法 ポーランド記法 Jan Łukasiewicz 中置記法 1 + 2 ポーランド記法 + 1 2 逆ポーランド記法 1 2 + (前置記法) (後置記法) 逆ポーランド記法の特徴 カッコを使用せずに数式を記述可能 スタックを使うことで容易に実装可能

Slide 10

Slide 10 text

1 2 +

Slide 11

Slide 11 text

1 2 + 数値であればスタックに積む 数値であればスタックに積む 1 2 + 1

Slide 12

Slide 12 text

1 2 + 数値であればスタックに積む 数値であればスタックに積む 1 2 + 1 1 2 + 1 2

Slide 13

Slide 13 text

1 2 + 1 2 + 3 演算子であれば 演算に必要な個数の数値を スタックから取り出して演算 結果をスタックに積む

Slide 14

Slide 14 text

2 3 + 5 4 2 - 2 + × ÷ 2 2 3 + 5 4 2 - 2 + × ÷

Slide 15

Slide 15 text

2 3 + 5 4 2 - 2 + × ÷ 2 2 3 + 5 4 2 - 2 + × ÷ 2 3 2 3 + 5 4 2 - 2 + × ÷

Slide 16

Slide 16 text

2 3 + 5 4 2 - 2 + × ÷ 2 2 3 + 5 4 2 - 2 + × ÷ 2 3 2 3 + 5 4 2 - 2 + × ÷ 5 2 3 + 5 4 2 - 2 + × ÷

Slide 17

Slide 17 text

2 3 + 5 4 2 - 2 + × ÷ 2 2 3 + 5 4 2 - 2 + × ÷ 2 3 2 3 + 5 4 2 - 2 + × ÷ 5 2 3 + 5 4 2 - 2 + × ÷ 5 5 2 3 + 5 4 2 - 2 + × ÷

Slide 18

Slide 18 text

2 3 + 5 4 2 - 2 + × ÷ 2 2 3 + 5 4 2 - 2 + × ÷ 2 3 2 3 + 5 4 2 - 2 + × ÷ 5 2 3 + 5 4 2 - 2 + × ÷ 5 5 2 3 + 5 4 2 - 2 + × ÷ 25 2 3 + 5 4 2 - 2 + × ÷

Slide 19

Slide 19 text

2 3 + 5 4 2 - 2 + × ÷ 2 2 3 + 5 4 2 - 2 + × ÷ 2 3 2 3 + 5 4 2 - 2 + × ÷ 5 2 3 + 5 4 2 - 2 + × ÷ 5 5 2 3 + 5 4 2 - 2 + × ÷ 25 2 3 + 5 4 2 - 2 + × ÷ 4 2 3 + 5 4 2 - 2 + × ÷ 25

Slide 20

Slide 20 text

4 2 3 + 5 4 2 - 2 + × ÷ 25 2

Slide 21

Slide 21 text

2 3 + 5 4 2 - 2 + × ÷ 2 2 3 + 5 4 2 - 2 + × ÷ 2 3 2 3 + 5 4 2 - 2 + × ÷ 5 2 3 + 5 4 2 - 2 + × ÷ 5 5 2 3 + 5 4 2 - 2 + × ÷ 25 2 3 + 5 4 2 - 2 + × ÷ 4 2 3 + 5 4 2 - 2 + × ÷ 25 4 2 3 + 5 4 2 - 2 + × ÷ 25 2 2 2 3 + 5 4 2 - 2 + × ÷ 25

Slide 22

Slide 22 text

2 3 + 5 4 2 - 2 + × ÷ 2 2 3 + 5 4 2 - 2 + × ÷ 2 3 2 3 + 5 4 2 - 2 + × ÷ 5 2 3 + 5 4 2 - 2 + × ÷ 5 5 2 3 + 5 4 2 - 2 + × ÷ 25 2 3 + 5 4 2 - 2 + × ÷ 4 2 3 + 5 4 2 - 2 + × ÷ 25 4 2 3 + 5 4 2 - 2 + × ÷ 25 2 2 2 3 + 5 4 2 - 2 + × ÷ 25 2 2 3 + 5 4 2 - 2 + × ÷ 25 2

Slide 23

Slide 23 text

2 3 + 5 4 2 - 2 + × ÷ 1 2 3 + 5 4 2 - 2 + × ÷ 25

Slide 24

Slide 24 text

2 3 + 5 4 2 - 2 + × ÷ 26 2 3 + 5 4 2 - 2 + × ÷

Slide 25

Slide 25 text

スタックマシン vs レジスターマシン スタックマシン メモリーをスタックとする計算モデル HP電卓, JVM, .NET Framework レジスターマシン メモリーをレジスターとする計算モデル Intel, ARM など既存のほとんどの CPU

Slide 26

Slide 26 text

バイトコード Java オペコード ロード/ストア 演算 制御構造 スタック制御 生成関連 メソッド呼び出し 型変換 load, store add, sub ifeq, goto swap, dup new, put eld invokevirtual, return i2b, f2d など 接頭辞 型を示す i, l, d, a など 接尾辞 インデックスなど _1, _x2 例) 1 番の int のローカル変数をスタックにロード iload_1

Slide 27

Slide 27 text

Heap Area Metaspace Stack Area Object Object Object Object Object クラス定義, メソッド定義 コンスタントプールなど Java Stack .... はスレッドごとに作られる Java Stack

Slide 28

Slide 28 text

Heap Area Metaspace Stack Area Object Object Object Object Object クラス定義, メソッド定義 コンスタントプールなど Java Stack .... Frame Frame Frame Frame Frame Frame メソッドごとに が積まれる Frame

Slide 29

Slide 29 text

Java Stack public class Adder { public int add(int x, int y) { int z = x + y; return z; } public void static main(String... args) { Adder adder = new Adder(); int result = adder.add(2, 3); System.out.println(result); } }

Slide 30

Slide 30 text

Java Stack public class Adder { public int add(int x, int y) { int z = x + y; return z; } public void static main(String... args) { Adder adder = new Adder(); int result = adder.add(2, 3); System.out.println(result); } } main add

Slide 31

Slide 31 text

Java Stack main add public int add(int, int); Code: stack=2, locals=4, args_size=3 0: iload_1 1: iload_2 2: iadd 3: istore_3 4: iload_3 5: ireturn LocalVariableTable: Start Length Slot Name Signature 0 6 0 this LAdder; 0 6 1 x I 0 6 2 y I 4 2 3 z I

Slide 32

Slide 32 text

Java Stack main add public int add(int, int); Code: stack=2, locals=4, args_size=3 0: iload_1 1: iload_2 2: iadd 3: istore_3 4: iload_3 5: ireturn LocalVariableTable: Start Length Slot Name Signature 0 6 0 this LAdder; 0 6 1 x I 0 6 2 y I 4 2 3 z I Operand Stack Local Var.

Slide 33

Slide 33 text

Java Stack main add public int add(int, int); Code: stack=2, locals=4, args_size=3 0: iload_1 1: iload_2 2: iadd 3: istore_3 4: iload_3 5: ireturn LocalVariableTable: Start Length Slot Name Signature 0 6 0 this LAdder; 0 6 1 x I 0 6 2 y I 4 2 3 z I Operand Stack Local Var. this x y z 2 3 1 2 3 0

Slide 34

Slide 34 text

Java Stack main add public int add(int, int); Code: stack=2, locals=4, args_size=3 0: iload_1 1: iload_2 2: iadd 3: istore_3 4: iload_3 5: ireturn LocalVariableTable: Start Length Slot Name Signature 0 6 0 this LAdder; 0 6 1 x I 0 6 2 y I 4 2 3 z I Operand Stack Local Var. this x y z 2 3 1 2 3 0 1 のローカル変数を スタックにロード 2

Slide 35

Slide 35 text

Java Stack main add public int add(int, int); Code: stack=2, locals=4, args_size=3 0: iload_1 1: iload_2 2: iadd 3: istore_3 4: iload_3 5: ireturn LocalVariableTable: Start Length Slot Name Signature 0 6 0 this LAdder; 0 6 1 x I 0 6 2 y I 4 2 3 z I Operand Stack Local Var. this x y z 2 3 1 2 3 0 3 2

Slide 36

Slide 36 text

Java Stack main add public int add(int, int); Code: stack=2, locals=4, args_size=3 0: iload_1 1: iload_2 2: iadd 3: istore_3 4: iload_3 5: ireturn LocalVariableTable: Start Length Slot Name Signature 0 6 0 this LAdder; 0 6 1 x I 0 6 2 y I 4 2 3 z I Operand Stack Local Var. this x y z 2 3 1 2 3 0 スタックの値を加算 結果をスタックに積む 2 3 5

Slide 37

Slide 37 text

Java Stack main add public int add(int, int); Code: stack=2, locals=4, args_size=3 0: iload_1 1: iload_2 2: iadd 3: istore_3 4: iload_3 5: ireturn LocalVariableTable: Start Length Slot Name Signature 0 6 0 this LAdder; 0 6 1 x I 0 6 2 y I 4 2 3 z I Operand Stack Local Var. this x y z 2 3 1 2 3 0 スタックの値を 3 にストア 5

Slide 38

Slide 38 text

Java Stack main add public int add(int, int); Code: stack=2, locals=4, args_size=3 0: iload_1 1: iload_2 2: iadd 3: istore_3 4: iload_3 5: ireturn LocalVariableTable: Start Length Slot Name Signature 0 6 0 this LAdder; 0 6 1 x I 0 6 2 y I 4 2 3 z I Operand Stack Local Var. this x y z 2 3 1 2 3 0 5 5

Slide 39

Slide 39 text

Java Stack main add public int add(int, int); Code: stack=2, locals=4, args_size=3 0: iload_1 1: iload_2 2: iadd 3: istore_3 4: iload_3 5: ireturn LocalVariableTable: Start Length Slot Name Signature 0 6 0 this LAdder; 0 6 1 x I 0 6 2 y I 4 2 3 z I Operand Stack Local Var. this x y z 2 3 1 2 3 0 スタックの値を戻し add のフレーム削除 5

Slide 40

Slide 40 text

Java Stack main public static void main(java.lang.String...); Code: stack=3, locals=3, args_size=1 0: new #7 // class Adder 3: dup 4: invokespecial #9 // Method "":()V 7: astore_1 8: aload_1 9: iconst_2 10: iconst_3 11: invokevirtual #10 // Method add:(II)I 14: istore_2 15: getstatic #14 // Field System.out 18: iload_2 19: invokevirtual #20 // Method println:(I)V 22: return LocalVariableTable: Start Length Slot Name Signature 0 23 0 args [LString; 8 15 1 adder LAdder; 15 8 2 result I Operand Stack Local Var. args 1 2 0 ヒープへの参照

Slide 41

Slide 41 text

Java Stack main public static void main(java.lang.String...); Code: stack=3, locals=3, args_size=1 0: new #7 // class Adder 3: dup 4: invokespecial #9 // Method "":()V 7: astore_1 8: aload_1 9: iconst_2 10: iconst_3 11: invokevirtual #10 // Method add:(II)I 14: istore_2 15: getstatic #14 // Field System.out 18: iload_2 19: invokevirtual #20 // Method println:(I)V 22: return LocalVariableTable: Start Length Slot Name Signature 0 23 0 args [LString; 8 15 1 adder LAdder; 15 8 2 result I Operand Stack Local Var. args 1 2 0 adder

Slide 42

Slide 42 text

Java Stack main public static void main(java.lang.String...); Code: stack=3, locals=3, args_size=1 0: new #7 // class Adder 3: dup 4: invokespecial #9 // Method "":()V 7: astore_1 8: aload_1 9: iconst_2 10: iconst_3 11: invokevirtual #10 // Method add:(II)I 14: istore_2 15: getstatic #14 // Field System.out 18: iload_2 19: invokevirtual #20 // Method println:(I)V 22: return LocalVariableTable: Start Length Slot Name Signature 0 23 0 args [LString; 8 15 1 adder LAdder; 15 8 2 result I Operand Stack Local Var. args 1 2 0 adder adder

Slide 43

Slide 43 text

Java Stack main public static void main(java.lang.String...); Code: stack=3, locals=3, args_size=1 0: new #7 // class Adder 3: dup 4: invokespecial #9 // Method "":()V 7: astore_1 8: aload_1 9: iconst_2 10: iconst_3 11: invokevirtual #10 // Method add:(II)I 14: istore_2 15: getstatic #14 // Field System.out 18: iload_2 19: invokevirtual #20 // Method println:(I)V 22: return LocalVariableTable: Start Length Slot Name Signature 0 23 0 args [LString; 8 15 1 adder LAdder; 15 8 2 result I Operand Stack Local Var. args 1 2 0 Adder()

Slide 44

Slide 44 text

Java Stack main public static void main(java.lang.String...); Code: stack=3, locals=3, args_size=1 0: new #7 // class Adder 3: dup 4: invokespecial #9 // Method "":()V 7: astore_1 8: aload_1 9: iconst_2 10: iconst_3 11: invokevirtual #10 // Method add:(II)I 14: istore_2 15: getstatic #14 // Field System.out 18: iload_2 19: invokevirtual #20 // Method println:(I)V 22: return LocalVariableTable: Start Length Slot Name Signature 0 23 0 args [LString; 8 15 1 adder LAdder; 15 8 2 result I Operand Stack Local Var. args 1 2 0 adder

Slide 45

Slide 45 text

Java Stack main public static void main(java.lang.String...); Code: stack=3, locals=3, args_size=1 0: new #7 // class Adder 3: dup 4: invokespecial #9 // Method "":()V 7: astore_1 8: aload_1 9: iconst_2 10: iconst_3 11: invokevirtual #10 // Method add:(II)I 14: istore_2 15: getstatic #14 // Field System.out 18: iload_2 19: invokevirtual #20 // Method println:(I)V 22: return LocalVariableTable: Start Length Slot Name Signature 0 23 0 args [LString; 8 15 1 adder LAdder; 15 8 2 result I Operand Stack Local Var. args 1 2 0 adder

Slide 46

Slide 46 text

Java Stack main public static void main(java.lang.String...); Code: stack=3, locals=3, args_size=1 0: new #7 // class Adder 3: dup 4: invokespecial #9 // Method "":()V 7: astore_1 8: aload_1 9: iconst_2 10: iconst_3 11: invokevirtual #10 // Method add:(II)I 14: istore_2 15: getstatic #14 // Field System.out 18: iload_2 19: invokevirtual #20 // Method println:(I)V 22: return LocalVariableTable: Start Length Slot Name Signature 0 23 0 args [LString; 8 15 1 adder LAdder; 15 8 2 result I Operand Stack Local Var. args 1 2 0 adder adder

Slide 47

Slide 47 text

Java Stack main public static void main(java.lang.String...); Code: stack=3, locals=3, args_size=1 0: new #7 // class Adder 3: dup 4: invokespecial #9 // Method "":()V 7: astore_1 8: aload_1 9: iconst_2 10: iconst_3 11: invokevirtual #10 // Method add:(II)I 14: istore_2 15: getstatic #14 // Field System.out 18: iload_2 19: invokevirtual #20 // Method println:(I)V 22: return LocalVariableTable: Start Length Slot Name Signature 0 23 0 args [LString; 8 15 1 adder LAdder; 15 8 2 result I Operand Stack Local Var. args 1 2 0 adder adder 2 adder adder 2 3

Slide 48

Slide 48 text

Java Stack main public static void main(java.lang.String...); Code: stack=3, locals=3, args_size=1 0: new #7 // class Adder 3: dup 4: invokespecial #9 // Method "":()V 7: astore_1 8: aload_1 9: iconst_2 10: iconst_3 11: invokevirtual #10 // Method add:(II)I 14: istore_2 15: getstatic #14 // Field System.out 18: iload_2 19: invokevirtual #20 // Method println:(I)V 22: return LocalVariableTable: Start Length Slot Name Signature 0 23 0 args [LString; 8 15 1 adder LAdder; 15 8 2 result I Operand Stack Local Var. args 1 2 0 add adder

Slide 49

Slide 49 text

Java Stack main public static void main(java.lang.String...); Code: stack=3, locals=3, args_size=1 0: new #7 // class Adder 3: dup 4: invokespecial #9 // Method "":()V 7: astore_1 8: aload_1 9: iconst_2 10: iconst_3 11: invokevirtual #10 // Method add:(II)I 14: istore_2 15: getstatic #14 // Field System.out 18: iload_2 19: invokevirtual #20 // Method println:(I)V 22: return LocalVariableTable: Start Length Slot Name Signature 0 23 0 args [LString; 8 15 1 adder LAdder; 15 8 2 result I Operand Stack Local Var. args 1 2 0 adder adder 5

Slide 50

Slide 50 text

Java Stack main public static void main(java.lang.String...); Code: stack=3, locals=3, args_size=1 0: new #7 // class Adder 3: dup 4: invokespecial #9 // Method "":()V 7: astore_1 8: aload_1 9: iconst_2 10: iconst_3 11: invokevirtual #10 // Method add:(II)I 14: istore_2 15: getstatic #14 // Field System.out 18: iload_2 19: invokevirtual #20 // Method println:(I)V 22: return LocalVariableTable: Start Length Slot Name Signature 0 23 0 args [LString; 8 15 1 adder LAdder; 15 8 2 result I Operand Stack Local Var. args 1 2 0 adder 5

Slide 51

Slide 51 text

Java Stack main public static void main(java.lang.String...); Code: stack=3, locals=3, args_size=1 0: new #7 // class Adder 3: dup 4: invokespecial #9 // Method "":()V 7: astore_1 8: aload_1 9: iconst_2 10: iconst_3 11: invokevirtual #10 // Method add:(II)I 14: istore_2 15: getstatic #14 // Field System.out 18: iload_2 19: invokevirtual #20 // Method println:(I)V 22: return LocalVariableTable: Start Length Slot Name Signature 0 23 0 args [LString; 8 15 1 adder LAdder; 15 8 2 result I Operand Stack Local Var. args 1 2 0 adder 5 System.out

Slide 52

Slide 52 text

Java Stack main public static void main(java.lang.String...); Code: stack=3, locals=3, args_size=1 0: new #7 // class Adder 3: dup 4: invokespecial #9 // Method "":()V 7: astore_1 8: aload_1 9: iconst_2 10: iconst_3 11: invokevirtual #10 // Method add:(II)I 14: istore_2 15: getstatic #14 // Field System.out 18: iload_2 19: invokevirtual #20 // Method println:(I)V 22: return LocalVariableTable: Start Length Slot Name Signature 0 23 0 args [LString; 8 15 1 adder LAdder; 15 8 2 result I Operand Stack Local Var. args 1 2 0 adder 5 System.out 5

Slide 53

Slide 53 text

public int summate(int start, int end) { int sum = 0; for (int i = start; i < end; i++) { sum += i; } return sum; } public int summate(int, int); descriptor: (II)I flags: (0x0001) ACC_PUBLIC Code: stack=2, locals=5, args_size=3 0: iconst_0 1: istore_3 2: iload_1 3: istore 4 5: iload 4 7: iload_2 8: if_icmpge 22 11: iload_3 12: iload 4 14: iadd 15: istore_3 16: iinc 4, 1 19: goto 5 22: iload_3 23: ireturn LocalVariableTable: Start Length Slot Name Signature 0 24 0 this LAdder; 0 24 1 start I 0 24 2 end I 2 22 3 sum I 5 17 4 i I if 文 ≧ 条件満たせば 22 へ インクリメント ループ

Slide 54

Slide 54 text

バイトコードのまとめ はスタックマシン オペランドスタックとローカル変数配列で処理を行う JVM for, while は で処理 if/goto はトモダチ 気になったら、 すぐ javap javap バージョンによりバイトコードの使い方が変化 バイトコードを書くのはとてもたいへん そこで Class-File API

Slide 55

Slide 55 text

Class-File API

Slide 56

Slide 56 text

Class-File API クラスファイルの 書き込み をサポート 読み込み 変換 から標準 Java 24 (JEP 484) 今まで では を利用 OpenJDK ASM に書き換えが進む Class-File API ストリーミングとランダムアクセスの双方をサポート

Slide 57

Slide 57 text

Class-File APIのデザイン クラスファイルの木構造を でモデリング Sealed Class, Record の活用 用語の統一により理解が容易 ADT 書き込み/変換にビルダーを使用 はビジターパターン ビルダーの使用でイミュータブル性を保持 ASM

Slide 58

Slide 58 text

Class-File APIのデザイン 主なインタフェース (Not継承関係) ClassFile ClassModel ConstantPool FieldModel MethodModel PoolEntry BootstrapMethodEntry FieldElement CodeModel CodeElement ConstantBuilder ClassBuilder ClassTransform FieldBuilder FieldTransform MethodBuilder MethodTransform CodeBuilder CodeTransform

Slide 59

Slide 59 text

クラスファイルの読み込み public class Adder { public int add(int x, int y) { int z = x + y; return z; } public void static main(String... args) { Adder adder = new Adder(); int result = adder.add(2, 3); System.out.println(result); } }

Slide 60

Slide 60 text

クラスファイルの読み込み ClassModel cm = ClassFile.of() .parse(Path.of("Adder.class")); ClassModel cm = ClassFile.of() .parse(Path.of("Adder.class")); cm.forEach(System.out::println); AccessFlags[flags=33] ClassFileVersion[majorVersion=68, minorVersion=0] Superclass[superclassEntry=java/lang/Object] Interfaces[interfaces=] MethodModel[methodName=, methodType=()V, flags=1] MethodModel[methodName=add, methodType=(II)I, flags=1] MethodModel[methodName=main, methodType=([Ljava/lang/String;)V, flags=137] Attribute[name=SourceFile] 実行結果

Slide 61

Slide 61 text

クラスファイルの読み込み ClassModel cm = ClassFile.of() .parse(Path.of("Adder.class")); cm.constantPool().forEach(System.out::println); 10 java/lang/Object.-()V 7 java/lang/Object 12 -()V java/lang/Object ()V 7 Adder Adder 10 Adder.-()V 10 Adder.add-(II)I 12 add-(II)I ...... 実行結果

Slide 62

Slide 62 text

クラスファイルの読み込み ClassModel cm = ClassFile.of() .parse(Path.of("Adder.class")); cm.methods().stream() .filter(m -> m.methodName().equalsString("add")) .flatMap(m -> m.code().get().elementStream()) .forEach(System.out::println); LocalVariable[name=this, slot=0, type=LAdder;] LocalVariable[name=x, slot=1, type=I] LocalVariable[name=y, slot=2, type=I] LocalVariable[name=z, slot=3, type=I] Label[context=CodeModel[id=1706234378], bci=0] LineNumber[line=3] Load[OP=ILOAD_1, slot=1] Load[OP=ILOAD_2, slot=2] UnboundOperatorInstruction[op=IADD] Store[OP=ISTORE_3, slot=3] ..... 実行結果

Slide 63

Slide 63 text

クラスファイルの書き込み Hello, World! byte[] classBytes = ClassFile.of().build( ClassDesc.of("Hello"), builder -> builder.withFlags(ClassFile.ACC_PUBLIC) .withMethod(INIT_NAME, MTD_void, ClassFile.ACC_PUBLIC, mb -> mb.withCode( cob -> cob.aload(0) .invokespecial(CD_Object, INIT_NAME, MTD_void) .return_())) .withMethod("main", MethodTypeDesc.of(CD_void, ClassDesc.of("java.lang.String").arrayType()), ClassFile.ACC_PUBLIC + ClassFile.ACC_STATIC, mb -> mb.withCode( cob -> cob.getstatic(ClassDesc.of("java.lang.System"), "out", ClassDesc.of("java.io.PrintStream")) .ldc("Hello, World!") .invokevirtual(ClassDesc.of("java.io.PrintStream"), "println", MethodTypeDesc.of(CD_void, ClassDesc.of("java.lang.String"))) .return_())) );

Slide 64

Slide 64 text

クラスファイルの書き込み Hello, World! byte[] classBytes = ClassFile.of().build( ClassDesc.of("Hello"), builder -> builder.withFlags(ClassFile.ACC_PUBLIC) .withMethod(INIT_NAME, MTD_void, ClassFile.ACC_PUBLIC, mb -> mb.withCode( cob -> cob.aload(0) .invokespecial(CD_Object, INIT_NAME, MTD_void) .return_())) .withMethod("main", MethodTypeDesc.of(CD_void, ClassDesc.of("java.lang.String").arrayType()), ClassFile.ACC_PUBLIC + ClassFile.ACC_STATIC, mb -> mb.withCode( cob -> cob.getstatic(ClassDesc.of("java.lang.System"), "out", ClassDesc.of("java.io.PrintStream")) .ldc("Hello, World!") .invokevirtual(ClassDesc.of("java.io.PrintStream"), "println", MethodTypeDesc.of(CD_void, ClassDesc.of("java.lang.String"))) .return_())) ); XXBuilder

Slide 65

Slide 65 text

クラスファイルの書き込み Hello, World! byte[] classBytes = ClassFile.of().build( ClassDesc.of("Hello"), builder -> builder.withFlags(ClassFile.ACC_PUBLIC) .withMethod(INIT_NAME, MTD_void, ClassFile.ACC_PUBLIC, mb -> mb.withCode( cob -> cob.aload(0) .invokespecial(CD_Object, INIT_NAME, MTD_void) .return_())) .withMethod("main", MethodTypeDesc.of(CD_void, ClassDesc.of("java.lang.String").arrayType()), ClassFile.ACC_PUBLIC + ClassFile.ACC_STATIC, mb -> mb.withCode( cob -> cob.getstatic(ClassDesc.of("java.lang.System"), "out", ClassDesc.of("java.io.PrintStream")) .ldc("Hello, World!") .invokevirtual(ClassDesc.of("java.io.PrintStream"), "println", MethodTypeDesc.of(CD_void, ClassDesc.of("java.lang.String"))) .return_())) ); ByteCode Opecode

Slide 66

Slide 66 text

Class-File APIの使い道 動的クラス生成 Wrapper, Adapter 最適化 の自動生成 クラス改変 プロファイラーのプローブ埋め込み DI, AOP

Slide 67

Slide 67 text

まとめ バイトコード読めても役に立たないけど、 おもしろい はスタックマシン JVM javap 気軽に バイトコード書くなら めんどうなところをよしなに Class-File API それでもバイトコードの知識は必要