Upgrade to Pro — share decks privately, control downloads, hide ads and more …

あなたはJVMの気持ちを理解できるか?

 あなたはJVMの気持ちを理解できるか?

2025年1月 JJUG ナイトセミナー資料

Yuichi.Sakuraba

January 28, 2025
Tweet

More Decks by Yuichi.Sakuraba

Other Decks in Technology

Transcript

  1. Java Souce Code Java Class File javac JVM 実行 読み込み

    クラスファイル定義 JVMS Chapter 4 クラスファイルの情報 クラスの情報 コンスタントプール アトリビュート バイトコードはここに含まれる
  2. クラスファイル解析ツール 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
  3. バイトコード Java が解釈する命令形式 JVM JVMS 5.1 命令 1 byte オペコード

    使用していない数値もあるので 200 程度 命令の種類 ロード / ストア 演算 制御構造 スタック制御 生成関連 メソッド呼び出し 型変換 et al.
  4. HPの電卓で を計算するには 1 + 2 1 Enter 2 + (

    2 + 3 ) 5 + ( 4 - 2 ) 2 × ÷ 2 3 5 4 2 2 E + × E - ÷+ 逆ポーランド記法
  5. 逆ポーランド記法 ポーランド記法 Jan Łukasiewicz 中置記法 1 + 2 ポーランド記法 +

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

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

    ÷ 2 2 3 + 5 4 2 - 2 + × ÷ 2 3 2 3 + 5 4 2 - 2 + × ÷
  8. 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 + × ÷
  9. 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 + × ÷
  10. 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 + × ÷
  11. 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
  12. 4 2 3 + 5 4 2 - 2 +

    × ÷ 25 2
  13. 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
  14. 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
  15. 2 3 + 5 4 2 - 2 + ×

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

    ÷ 26 2 3 + 5 4 2 - 2 + × ÷
  17. バイトコード 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
  18. Heap Area Metaspace Stack Area Object Object Object Object Object

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

    クラス定義, メソッド定義 コンスタントプールなど JVM Stack .... Frame Frame Frame Frame Frame Frame メソッドごとに が積まれる Frame
  20. JVM 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); } }
  21. JVM 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
  22. JVM 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
  23. JVM 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.
  24. JVM 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
  25. JVM 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
  26. JVM 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
  27. JVM 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
  28. JVM 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
  29. JVM 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
  30. JVM 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
  31. JVM 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 "<init>":()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 ヒープへの参照
  32. JVM 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 "<init>":()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
  33. JVM 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 "<init>":()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
  34. JVM 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 "<init>":()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()
  35. JVM 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 "<init>":()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
  36. JVM 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 "<init>":()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
  37. JVM 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 "<init>":()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
  38. JVM 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 "<init>":()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
  39. JVM 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 "<init>":()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
  40. JVM 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 "<init>":()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
  41. JVM 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 "<init>":()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
  42. JVM 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 "<init>":()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
  43. JVM 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 "<init>":()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
  44. 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 へ インクリメント ループ
  45. バイトコードのまとめ はスタックマシン オペランドスタックとローカル変数配列で処理を行う JVM for, while は で処理 if/goto はトモダチ

    気になったら、 すぐ javap javap バージョンによりバイトコードの使い方が変化 バイトコードを書くのはとてもたいへん そこで Class-File API
  46. Class-File API クラスファイルの 書き込み をサポート 読み込み 変換 から標準 Java 24

    (JEP 484) 今まで では を利用 OpenJDK ASM に書き換えが進む Class-File API ストリーミングとランダムアクセスの双方をサポート
  47. Class-File APIのデザイン クラスファイルの木構造を でモデリング Sealed Class, Record の活用 用語の統一により理解が容易 ADT

    書き込み/変換にビルダーを使用 はビジターパターン ビルダーの使用でイミュータブル性を保持 ASM
  48. Class-File APIのデザイン 主なインタフェース (Not継承関係) ClassFile ClassModel ConstantPool FieldModel MethodModel PoolEntry

    BootstrapMethodEntry FieldElement CodeModel CodeElement ConstantBuilder ClassBuilder ClassTransform FieldBuilder FieldTransform MethodBuilder MethodTransform CodeBuilder CodeTransform
  49. クラスファイルの読み込み 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); } }
  50. クラスファイルの読み込み 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=<init>, 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] 実行結果
  51. クラスファイルの読み込み ClassModel cm = ClassFile.of() .parse(Path.of("Adder.class")); cm.constantPool().forEach(System.out::println); 10 java/lang/Object.<init>-()V 7

    java/lang/Object 12 <init>-()V java/lang/Object <init> ()V 7 Adder Adder 10 Adder.<init>-()V 10 Adder.add-(II)I 12 add-(II)I ...... 実行結果
  52. クラスファイルの読み込み 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] ..... 実行結果
  53. クラスファイルの書き込み 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_())) );
  54. クラスファイルの書き込み 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
  55. クラスファイルの書き込み 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