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

InvokeDynamic完全に理解した / Completely Understand InvokeDynamic

Ikuo Suyama
February 22, 2022

InvokeDynamic完全に理解した / Completely Understand InvokeDynamic

JVMにおけるinvokedynamicインストラクションについて、ClassファイルとdデコンパイルしたJVMマシン語を読み解き、詳細な解説を試みました。
また例としてLambda関数がinvokedynamicで実行される際の挙動について、BootStrapMethodとして指定されるLambdaMetafactory.metafactoryのコードから実際に何が行われるのかを解説しています。

Ikuo Suyama

February 22, 2022
Tweet

More Decks by Ikuo Suyama

Other Decks in Programming

Transcript

  1. ࿦ΑΓίʔυ w ؀ڥɿ ❯ java -version openjdk version "11.0.9" 2020-10-20

    OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.9+11) OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.9+11, mixed mode) w *OWPLFTKBWB package invoke.others; public class Invokes implements IInvoke { public static void main(String[] args) { int i = 1; Invokes.staticMethod(i); Invokes invs = new Invokes(); invs.method(i); IInvoke iinvs = invs; iinvs.interfaceMethod(i); } public int method(int i) { return i; } public static int staticMethod(int i) { return i; } @Override public int interfaceMethod(int i) { return i; } } interface IInvoke { int interfaceMethod(int i); }
  2. +7.ϚγϯޠΛ೷͍ͯΈΔ *OWPLFTKBWB package invoke.others; public class Invokes implements IInvoke {

    public static void main(String[] args) { int i = 1; Invokes.staticMethod(i); Invokes invs = new Invokes(); invs.method(i); IInvoke iinvs = invs; iinvs.interfaceMethod(i); } public int method(int i) { return i; } public static int staticMethod(int i) { return i; } @Override public int interfaceMethod(int i) { return i; } } interface IInvoke { int interfaceMethod(int i); } ❯ javac Invokes.java ❯ javap -v -p -s -constants Invokes.class > Invokes.jvm Compiled from "Invokes.java" public class invoke.others.Invokes implements invoke.others.IInvoke { : public static void main(java.lang.String[]); Code: 0: iconst_1 1: istore_1 2: iload_1 3: invokestatic #2 // Method staticMethod:(I)I 6: pop 7: new #3 // class invoke/others/Invokes 10: dup 11: invokespecial #4 // Method "<init>":()V 14: astore_2 15: aload_2 16: iload_1 17: invokevirtual #5 // Method method:(I)I 20: pop 21: aload_2 22: astore_3 23: aload_3 24: iload_1 25: invokeinterface #6, 2 // InterfaceMethod invoke/others/ IInvoke.interfaceMethod:(I)I 30: pop 31: return *OWPLFTKWN NBJOϝιουͷΈൈਮ
  3. +7.ϚγϯޠΛ೷͍ͯΈΔ *OWPLFTKBWB package invoke.others; public class Invokes implements IInvoke {

    public static void main(String[] args) { int i = 1; Invokes.staticMethod(i); Invokes invs = new Invokes(); invs.method(i); IInvoke iinvs = invs; iinvs.interfaceMethod(i); } public int method(int i) { return i; } public static int staticMethod(int i) { return i; } @Override public int interfaceMethod(int i) { return i; } } interface IInvoke { int interfaceMethod(int i); } ❯ javac Invokes.java ❯ javap -v -p -s -constants Invokes.class > Invokes.jvm Compiled from "Invokes.java" public class invoke.others.Invokes implements invoke.others.IInvoke { : public static void main(java.lang.String[]); Code: 0: iconst_1 1: istore_1 2: iload_1 3: invokestatic #2 // Method staticMethod:(I)I 6: pop 7: new #3 // class invoke/others/Invokes 10: dup 11: invokespecial #4 // Method "<init>":()V 14: astore_2 15: aload_2 16: iload_1 17: invokevirtual #5 // Method method:(I)I 20: pop 21: aload_2 22: astore_3 23: aload_3 24: iload_1 25: invokeinterface #6, 2 // InterfaceMethod invoke/others/ IInvoke.interfaceMethod:(I)I 30: pop 31: return *OWPLFTKWN NBJOϝιουͷΈൈਮ
  4. JOWPLFWJSUVBMΛৄ͘͠ public class invoke.others.Invokes implements invoke.others.IInvoke minor version: 0 major

    version: 55 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #3 // invoke/others/Invokes super_class: #7 // java/lang/Object interfaces: 1, fields: 0, methods: 5, attributes: 1 Constant pool: #3 = Class #23 // invoke/others/Invokes #5 = Methodref #3.#24 // invoke/others/Invokes.method:(I)I : #15 = Utf8 method #16 = Utf8 (I)I : #24 = NameAndType #15:#16 // method:(I)I : { public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=4, args_size=1 : 11: invokespecial #4 // Method "<init>":()V 14: astore_2 15: aload_2 16: iload_1 17: invokevirtual #5 // Method method:(I)I : invokevirtual Operation Invoke instance method; dispatch based on class Format 
 invokevirtual
 indexbyte1
 indexbyte2
 Forms invokevirtual = 182 (0xb6) Operand Stack ..., objectref, [arg1, [arg2 ...]] → ... Description The unsigned indexbyte1 and indexbyte2 are used to construct an index into the run-time constant pool of the current class (§2.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. *OWPLFTKWN ൈਮ 3FGJOWPLFWJSUVBM
  5. public class invoke.others.Invokes implements invoke.others.IInvoke minor version: 0 major version:

    55 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #3 // invoke/others/Invokes super_class: #7 // java/lang/Object interfaces: 1, fields: 0, methods: 5, attributes: 1 Constant pool: #3 = Class #23 // invoke/others/Invokes #5 = Methodref #3.#24 // invoke/others/Invokes.method:(I)I : #15 = Utf8 method #16 = Utf8 (I)I : #24 = NameAndType #15:#16 // method:(I)I : { public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=4, args_size=1 : 11: invokespecial #4 // Method "<init>":()V 14: astore_2 15: aload_2 16: iload_1 17: invokevirtual #5 // Method method:(I)I : JOWPLFWJSUVBMΛৄ͘͠ aload_<n> Operation Load reference from local variable Forms aload_2 = 44 (0x2c) Operand Stack ... → ..., objectref Description The <n> must be an index into the local variable array of the current frame (§2.6). iload_<n> Operation Load int from local variable 
 Forms iload_1 = 27 (0x1b) Operand Stack ... → ..., value Description The <n> must be an index into the local variable array of the current frame (§2.6). *OWPLFTKWN ൈਮ *OWPLFTDMBTT ൈਮ astore_<n> Operation Store reference into local variable Forms astore_2 = 77 (0x4d) Operand Stack ..., objectref → ... Description The <n> must be an index into the local variable array of the current frame (§2.6).
  6. +BWB$MBTTϑΝΠϧͷߏ଄ $IBQUFS5IFDMBTT'JMF'PSNBU ClassFile { u4 magic; u2 minor_version; u2 major_version;

    u2 constant_pool_count; cp_info constant_pool[constant_pool_count-1]; u2 access_flags; u2 this_class; u2 super_class; u2 interfaces_count; u2 interfaces[interfaces_count]; u2 fields_count; field_info fields[fields_count]; u2 methods_count; method_info methods[methods_count]; u2 attributes_count; attribute_info attributes[attributes_count]; } *OWPLFTDMBTT ൈਮ
  7. +BWB$MBTTϑΝΠϧͷߏ଄ $IBQUFS5IFDMBTT'JMF'PSNBU ClassFile { u4 magic; u2 minor_version; u2 major_version;

    u2 constant_pool_count; cp_info constant_pool[constant_pool_count-1]; u2 access_flags; u2 this_class; u2 super_class; u2 interfaces_count; u2 interfaces[interfaces_count]; u2 fields_count; field_info fields[fields_count]; u2 methods_count; method_info methods[methods_count]; u2 attributes_count; attribute_info attributes[attributes_count]; } *OWPLFTDMBTT ൈਮ +BWBWFS ݸ $POTUBOU1PPM഑ྻ
  8. $POTUBOU1PPM cp_info { u1 tag; u1 info[]; } 5IF$POTUBOU1PPM Constant

    pool: #1 = Methodref #7.#21 // java/lang/Object."<init>":()V #2 = Methodref #3.#22 // invoke/others/Invokes.staticMethod:(I)I #3 = Class #23 // invoke/others/Invokes #4 = Methodref #3.#21 // invoke/others/Invokes."<init>":()V #5 = Methodref #3.#24 // invoke/others/Invokes.method:(I)I #6 = InterfaceMethodref #8.#25 // invoke/others/IInvoke.interfaceMethod:(I)I #7 = Class #26 // java/lang/Object #8 = Class #27 // invoke/others/IInvoke #9 = Utf8 <init> #10 = Utf8 ()V #11 = Utf8 Code #12 = Utf8 LineNumberTable #13 = Utf8 main #14 = Utf8 ([Ljava/lang/String;)V #15 = Utf8 method #16 = Utf8 (I)I #17 = Utf8 staticMethod #18 = Utf8 interfaceMethod #19 = Utf8 SourceFile #20 = Utf8 Invokes.java #21 = NameAndType #9:#10 // "<init>":()V #22 = NameAndType #17:#16 // staticMethod:(I)I #23 = Utf8 invoke/others/Invokes #24 = NameAndType #15:#16 // method:(I)I #25 = NameAndType #18:#16 // interfaceMethod:(I)I #26 = Utf8 java/lang/Object #27 = Utf8 invoke/others/IInvoke *OWPLFTKWN ൈਮ
  9. $POTUBOU1PPMάϥϑߏ଄ *OWPLFTKWN ൈਮ JOWPLFWJSUVBMͷҾ਺ͩͬͨ͸ʜ Constant pool: #1 = Methodref #7.#21

    // java/lang/Object."<init>":()V #2 = Methodref #3.#22 // invoke/others/Invokes.staticMethod:(I)I #3 = Class #23 // invoke/others/Invokes #4 = Methodref #3.#21 // invoke/others/Invokes."<init>":()V #5 = Methodref #3.#24 // invoke/others/Invokes.method:(I)I #6 = InterfaceMethodref #8.#25 // invoke/others/IInvoke.interfaceMethod:(I)I #7 = Class #26 // java/lang/Object #8 = Class #27 // invoke/others/IInvoke #9 = Utf8 <init> #10 = Utf8 ()V #11 = Utf8 Code #12 = Utf8 LineNumberTable #13 = Utf8 main #14 = Utf8 ([Ljava/lang/String;)V #15 = Utf8 method #16 = Utf8 (I)I #17 = Utf8 staticMethod #18 = Utf8 interfaceMethod #19 = Utf8 SourceFile #20 = Utf8 Invokes.java #21 = NameAndType #9:#10 // "<init>":()V #22 = NameAndType #17:#16 // staticMethod:(I)I #23 = Utf8 invoke/others/Invokes #24 = NameAndType #15:#16 // method:(I)I #25 = NameAndType #18:#16 // interfaceMethod:(I)I #26 = Utf8 java/lang/Object #27 = Utf8 invoke/others/IInvoke
  10. $POTUBOU1PPMάϥϑߏ଄ Constant pool: #1 = Methodref #7.#21 // java/lang/Object."<init>":()V #2

    = Methodref #3.#22 // invoke/others/Invokes.staticMethod:(I)I #3 = Class #23 // invoke/others/Invokes #4 = Methodref #3.#21 // invoke/others/Invokes."<init>":()V #5 = Methodref #3.#24 // invoke/others/Invokes.method:(I)I #6 = InterfaceMethodref #8.#25 // invoke/others/IInvoke.interfaceMethod:(I)I #7 = Class #26 // java/lang/Object #8 = Class #27 // invoke/others/IInvoke #9 = Utf8 <init> #10 = Utf8 ()V #11 = Utf8 Code #12 = Utf8 LineNumberTable #13 = Utf8 main #14 = Utf8 ([Ljava/lang/String;)V #15 = Utf8 method #16 = Utf8 (I)I #17 = Utf8 staticMethod #18 = Utf8 interfaceMethod #19 = Utf8 SourceFile #20 = Utf8 Invokes.java #21 = NameAndType #9:#10 // "<init>":()V #22 = NameAndType #17:#16 // staticMethod:(I)I #23 = Utf8 invoke/others/Invokes #24 = NameAndType #15:#16 // method:(I)I #25 = NameAndType #18:#16 // interfaceMethod:(I)I #26 = Utf8 java/lang/Object #27 = Utf8 invoke/others/IInvoke *OWPLFTKWN ൈਮ JOWPLFWJSUVBMͷҾ਺ͩͬͨ͸ʜ
  11. $POTUBOU1PPMάϥϑߏ଄ Constant pool: #1 = Methodref #7.#21 // java/lang/Object."<init>":()V #2

    = Methodref #3.#22 // invoke/others/Invokes.staticMethod:(I)I #3 = Class #23 // invoke/others/Invokes #4 = Methodref #3.#21 // invoke/others/Invokes."<init>":()V #5 = Methodref #3.#24 // invoke/others/Invokes.method:(I)I #6 = InterfaceMethodref #8.#25 // invoke/others/IInvoke.interfaceMethod:(I)I #7 = Class #26 // java/lang/Object #8 = Class #27 // invoke/others/IInvoke #9 = Utf8 <init> #10 = Utf8 ()V #11 = Utf8 Code #12 = Utf8 LineNumberTable #13 = Utf8 main #14 = Utf8 ([Ljava/lang/String;)V #15 = Utf8 method #16 = Utf8 (I)I #17 = Utf8 staticMethod #18 = Utf8 interfaceMethod #19 = Utf8 SourceFile #20 = Utf8 Invokes.java #21 = NameAndType #9:#10 // "<init>":()V #22 = NameAndType #17:#16 // staticMethod:(I)I #23 = Utf8 invoke/others/Invokes #24 = NameAndType #15:#16 // method:(I)I #25 = NameAndType #18:#16 // interfaceMethod:(I)I #26 = Utf8 java/lang/Object #27 = Utf8 invoke/others/IInvoke *OWPLFTKWN ൈਮ JOWPLFWJSUVBMͷҾ਺ͩͬͨ͸ʜ
  12. $POTUBOU1PPM.FUIPESFG cp_info { u1 tag; u1 info[]; } // CONSTANT_Methodref_info

    (Extends cp_info) CONSTANT_Methodref_info { u1 tag; u2 class_index; u2 name_and_type_index; } 5IF$0/45"/[email protected]@JOGP TUSVDUVSFT tag The tag item of a CONSTANT_Methodref_info structure has the value CONSTANT_Methodref (10). class_index The value of the class_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Class_info structure (§4.4.1) In a CONSTANT_Methodref_info structure, the class_index item must be a class type, not an interface type. name_and_type_index The value of the name_and_type_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_NameAndType_info structure (§4.4.6). *OWPLFTDMBTT ൈਮ Constant pool: : #5 = Methodref #3.#24 // invoke/others/Invokes.method:(I)I :
  13. .FUIPET method_info { u2 access_flags; u2 name_index; u2 descriptor_index; u2

    attributes_count; attribute_info attributes[attributes_count]; } .FUIPET access_flags The value of the access_flags item is a mask of flags used to denote access permission to and properties of this method. The interpretation of each flag, when set, is specified in Table 4.6-A. name_index The value of the name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure (§4.4.7). descriptor_index The value of the descriptor_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure representing a valid method descriptor (§4.3.3). attributes_count The value of the attributes_count item indicates the number of additional attributes of this method. attributes[] Each value of the attributes table must be an attribute_info structure (§4.7). Constant Pool: #15 = Utf8 method #16 = Utf8 (I)I public int method(int); descriptor: (I)I flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=2, args_size=2 0: iload_1 1: ireturn LineNumberTable: line 13: 0 public int method(int i) { return i; }
  14. .FUIPET method_info { u2 access_flags; u2 name_index; u2 descriptor_index; u2

    attributes_count; attribute_info attributes[attributes_count]; } .FUIPET access_flags The value of the access_flags item is a mask of flags used to denote access permission to and properties of this method. The interpretation of each flag, when set, is specified in Table 4.6-A. name_index The value of the name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure (§4.4.7). descriptor_index The value of the descriptor_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure representing a valid method descriptor (§4.3.3). attributes_count The value of the attributes_count item indicates the number of additional attributes of this method. attributes[] Each value of the attributes table must be an attribute_info structure (§4.7). Constant Pool: #15 = Utf8 method #16 = Utf8 (I)I public int method(int); descriptor: (I)I flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=2, args_size=2 0: iload_1 1: ireturn LineNumberTable: line 13: 0 public int method(int i) { return i; } BDDFTT@ fl BHTYQVCMJD OBNF@JOEFY $1NFUIPE EFTDSJQUPS@JOEFY $1 * * BUUSJCVUF<>$PEF BUUSJCVUFT@DPVOU
  15. $PEF"UUSJCVUF Code_attribute { u2 attribute_name_index; u4 attribute_length; u2 max_stack; u2

    max_locals; u4 code_length; u1 code[code_length]; u2 exception_table_length; { u2 start_pc; u2 end_pc; u2 handler_pc; u2 catch_type; } exception_table[exception_table_length]; u2 attributes_count; attribute_info attributes[attributes_count]; } 5IF$PEF"UUSJCVUF Constant Pool: #11 = Utf8 Code public int method(int); descriptor: (I)I flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=2, args_size=2 0: iload_1 1: ireturn LineNumberTable: line 13: 0 public int method(int i) { return i; } attribute_name_index The constant_pool entry at that index must be a CONSTANT_Utf8_info structure (§4.4.7) representing the string "Code". attribute_length The value of the attribute_length item indicates the length of the attribute, excluding the initial six bytes. max_stack The value of the max_stack item gives the maximum depth of the operand stack of this method (§2.6.2) at any point during execution of the method. max_locals The value of the max_locals item gives the number of local variables in the local variable array allocated upon invocation of this method (§2.6.1), including the local variables used to pass parameters to the method on its invocation. code_length The value of the code_length item gives the number of bytes in the code array for this method. code[] The code array gives the actual bytes of Java Virtual Machine code that implement the method.
  16. $PEF"UUSJCVUF Code_attribute { u2 attribute_name_index; u4 attribute_length; u2 max_stack; u2

    max_locals; u4 code_length; u1 code[code_length]; u2 exception_table_length; { u2 start_pc; u2 end_pc; u2 handler_pc; u2 catch_type; } exception_table[exception_table_length]; u2 attributes_count; attribute_info attributes[attributes_count]; } 5IF$PEF"UUSJCVUF Constant Pool: #11 = Utf8 Code public int method(int); descriptor: (I)I flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=2, args_size=2 0: iload_1 1: ireturn LineNumberTable: line 13: 0 public int method(int i) { return i; } attribute_name_index The constant_pool entry at that index must be a CONSTANT_Utf8_info structure (§4.4.7) representing the string "Code". attribute_length The value of the attribute_length item indicates the length of the attribute, excluding the initial six bytes. max_stack The value of the max_stack item gives the maximum depth of the operand stack of this method (§2.6.2) at any point during execution of the method. max_locals The value of the max_locals item gives the number of local variables in the local variable array allocated upon invocation of this method (§2.6.1), including the local variables used to pass parameters to the method on its invocation. code_length The value of the code_length item gives the number of bytes in the code array for this method. code[] The code array gives the actual bytes of Java Virtual Machine code that implement the method. BUUSJCVUF@OBNF@JOEFY  $1$PEF BUUSJCVUF@MFOHUI NBY@MPDBMT NBY@TUBDL DPEF@MFOHUI DPEF<> JMPBE@Y#  JSFUVSOY"$ FYDFQUJPO@UBCMF@MFOHUI  BUUSJCVUFT@DPVOU BUUSJCVUFT<> -JOF/VNCFS5BCMF
  17. public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC

    Code: stack=2, locals=4, args_size=1 0: iconst_1 1: istore_1 : 11: invokespecial #4 // Method "<init>":()V 14: astore_2 15: aload_2 16: iload_1 17: invokevirtual #5 // Method method:(I)I : 3FJOWPLFWJSUVBMΛৄ͘͠ *OWPLFTKWN ൈਮ *OWPLFTDMBTT ൈਮ public static void main(String[] args) { int i = 1; : Invokes invs = new Invokes(); invs.method(i); *OWPLFTKBWB -PDBM7BSJBCMFT<> 0QFSBOE4UBDL 4USJOH<> BSHT  *OU     *OWPLFT JOWT 1$JOWPLFTQFDJBM YC ͷ࣮ߦ௚ޙ $VSSFOU'SBNF 1$
  18. public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC

    Code: stack=2, locals=4, args_size=1 0: iconst_1 1: istore_1 : 11: invokespecial #4 // Method "<init>":()V 14: astore_2 15: aload_2 16: iload_1 17: invokevirtual #5 // Method method:(I)I : 3FJOWPLFWJSUVBMΛৄ͘͠ *OWPLFTKWN ൈਮ *OWPLFTDMBTT ൈਮ public static void main(String[] args) { int i = 1; : Invokes invs = new Invokes(); invs.method(i); *OWPLFTKBWB -PDBM7BSJBCMFT<> 0QFSBOE4UBDL 4USJOH<> BSHT  *OU   *OWPLFT JOWT   *OWPLFT JOWT 1$BTUPSF@ YE $VSSFOU'SBNF 1$ Operation Store reference into local variable
  19. public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC

    Code: stack=2, locals=4, args_size=1 0: iconst_1 1: istore_1 : 11: invokespecial #4 // Method "<init>":()V 14: astore_2 15: aload_2 16: iload_1 17: invokevirtual #5 // Method method:(I)I : 3FJOWPLFWJSUVBMΛৄ͘͠ *OWPLFTKWN ൈਮ *OWPLFTDMBTT ൈਮ public static void main(String[] args) { int i = 1; : Invokes invs = new Invokes(); invs.method(i); *OWPLFTKBWB -PDBM7BSJBCMFT<> 0QFSBOE4UBDL 4USJOH<> BSHT  *OU   *OWPLFT JOWT   1$BMPBE@ YD *OWPLFT JOWT $VSSFOU'SBNF 1$ Operation Load reference from local variable
  20. public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC

    Code: stack=2, locals=4, args_size=1 0: iconst_1 1: istore_1 : 11: invokespecial #4 // Method "<init>":()V 14: astore_2 15: aload_2 16: iload_1 17: invokevirtual #5 // Method method:(I)I : 3FJOWPLFWJSUVBMΛৄ͘͠ *OWPLFTKWN ൈਮ *OWPLFTDMBTT ൈਮ public static void main(String[] args) { int i = 1; : Invokes invs = new Invokes(); invs.method(i); *OWPLFTKBWB -PDBM7BSJBCMFT<> 0QFSBOE4UBDL 4USJOH<> BSHT  *OU   *OWPLFT JOWT   1$JMPBE@ YC *OWPLFT JOWT *OU  $VSSFOU'SBNF 1$ Operation Load int from local variable
  21. public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC

    Code: stack=2, locals=4, args_size=1 0: iconst_1 1: istore_1 : 11: invokespecial #4 // Method "<init>":()V 14: astore_2 15: aload_2 16: iload_1 17: invokevirtual #5 // Method method:(I)I : 3FJOWPLFWJSUVBMΛৄ͘͠ *OWPLFTKWN ൈਮ *OWPLFTDMBTT ൈਮ public static void main(String[] args) { int i = 1; : Invokes invs = new Invokes(); invs.method(i); *OWPLFTKBWB -PDBM7BSJBCMFT<> 0QFSBOE4UBDL 4USJOH<> BSHT  *OU   *OWPLFT JOWT   1$JOWPLFWJSUVBM YC -PPLVQUIFNFUIPE DSFBUFOFX'SBNF *OWPLFT JOWT *OU  $VSSFOU'SBNF 1$ /FX 'SBNF Operation Invoke instance method; dispatch based on class
  22. 3FJOWPLFWJSUVBMΛৄ͘͠ *OWPLFTKWN ൈਮ *OWPLFTDMBTT ൈਮ *OWPLFTKBWB -PDBM7BSJBCMFT<> 0QFSBOE4UBDL *OWPLFT JOWT

     *OU     1$JOWPLFWJSUVBM YC KVNQUPUIFNFUIPET JOWPLF public int method(int); descriptor: (I)I flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=2, args_size=2 0: iload_1 1: ireturn LineNumberTable: line 13: 0 public int method(int i) { return i; } $VSSFOU'SBNF 1$ 1SFW 'SBNF NBJO
  23. 3FJOWPLFWJSUVBMΛৄ͘͠ *OWPLFTKWN ൈਮ *OWPLFTDMBTT ൈਮ *OWPLFTKBWB -PDBM7BSJBCMFT<> 0QFSBOE4UBDL *OWPLFT JOWT

     *OU     1$JMPBE@ YC public int method(int); descriptor: (I)I flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=2, args_size=2 0: iload_1 1: ireturn LineNumberTable: line 13: 0 public int method(int i) { return i; } $VSSFOU'SBNF 1$ 1SFW 'SBNF NBJO *OU 
  24. 3FJOWPLFWJSUVBMΛৄ͘͠ *OWPLFTKWN ൈਮ *OWPLFTDMBTT ൈਮ *OWPLFTKBWB -PDBM7BSJBCMFT<> 0QFSBOE4UBDL *OWPLFT JOWT

     *OU     1$JSFUVSO YBD public int method(int); descriptor: (I)I flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=2, args_size=2 0: iload_1 1: ireturn LineNumberTable: line 13: 0 public int method(int i) { return i; } $VSSFOU'SBNF 1$ 1SFW 'SBNF NBJO *OU  Operation Return int from method
  25. public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC

    Code: stack=2, locals=4, args_size=1 0: iconst_1 1: istore_1 : 11: invokespecial #4 // Method "<init>":()V 14: astore_2 15: aload_2 16: iload_1 17: invokevirtual #5 // Method method:(I)I : 3FJOWPLFWJSUVBMΛৄ͘͠ *OWPLFTKWN ൈਮ *OWPLFTDMBTT ൈਮ public static void main(String[] args) { int i = 1; : Invokes invs = new Invokes(); invs.method(i); *OWPLFTKBWB -PDBM7BSJBCMFT<> 0QFSBOE4UBDL 4USJOH<> BSHT  *OU   *OWPLFT JOWT   1$JOWPLFWJSUVBM YC QVTISFUVSFOEWBMVFUPPQFSBOETUBDL $VSSFOU'SBNF 1$ *OU  1SFW 'SBNF
  26. ࿦ΑΓίʔυɿϚγϯޠΛ೷͍ͯΈΔ package invoke.dynamic; public class InvokeDynamicSimple { public static void

    main(String[] args) { Runnable r = () -> System.out.println("Hello"); r.run(); } } ❯ javac InvokeDynamicSimple.java ❯ javap -v -s -constants InvokeDynamicSimple.class > InvokeDynamicSimple.jvm public class invoke.dynamic.InvokeDynamicSimple Constant Pool: #2 = InvokeDynamic #0:#23 // #0:run:()Ljava/lang/Runnable; #23 = NameAndType #35:#36 // run:()Ljava/lang/Runnable; : { public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=2, args_size=1 0: invokedynamic #2, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable; 5: astore_1 6: aload_1 7: invokeinterface #3, 1 // InterfaceMethod java/lang/Runnable.run:()V 12: return } SourceFile: "InvokeDynamicSimple.java" InnerClasses: public static final #50= #49 of #53; // Lookup=class java/lang/invoke/ MethodHandles$Lookup of class java/lang/invoke/MethodHandles BootstrapMethods: 0: #20 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/ MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/ MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/ CallSite; Method arguments: #21 ()V #22 REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #21 ()V *OWPLF%ZOBNJD4JNQMFKBWB *OWPLF%ZOBNJD4JNQMFKWN w -BNCEB͕*OWPLF%ZOBNJDͰ࣮ݱ͞Εͯ ͍Δ͜ͱ͸Α͘஌ΒΕ͍ͯΔͷͰɺͱΓ͋ ͑ͣίϯύΠϧσίϯύΠϧ
  27. ࿦ΑΓίʔυɿϚγϯޠΛ೷͍ͯΈΔ package invoke.dynamic; public class InvokeDynamicSimple { public static void

    main(String[] args) { Runnable r = () -> System.out.println("Hello"); r.run(); } } ❯ javac InvokeDynamicSimple.java ❯ javap -v -s -constants InvokeDynamicSimple.class > InvokeDynamicSimple.jvm public class invoke.dynamic.InvokeDynamicSimple Constant Pool: #2 = InvokeDynamic #0:#23 // #0:run:()Ljava/lang/Runnable; #23 = NameAndType #35:#36 // run:()Ljava/lang/Runnable; : { public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=2, args_size=1 0: invokedynamic #2, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable; 5: astore_1 6: aload_1 7: invokeinterface #3, 1 // InterfaceMethod java/lang/Runnable.run:()V 12: return } SourceFile: "InvokeDynamicSimple.java" InnerClasses: public static final #50= #49 of #53; // Lookup=class java/lang/invoke/ MethodHandles$Lookup of class java/lang/invoke/MethodHandles BootstrapMethods: 0: #20 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/ MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/ MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/ CallSite; Method arguments: #21 ()V #22 REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #21 ()V *OWPLF%ZOBNJD4JNQMFKBWB *OWPLF%ZOBNJD4JNQMFKWN w 'PVOEJOWPLFEZOBNJD w $1Λࢀর͍ͯ͠Δ͜ͱ͸૝૾͕ͭ͘ w SVO -KBWBMBOH3VOOBCMF  w *OWPLF%ZOBNJD$1   w #PPUTUSBQ.FUIPET  w 4ZTUFNPVUQSJOUMO Ͳ͍ͬͨ͜ ͜Μͳγάωνϟͷϝιουͳ͍Ͱ͢ ୭Ͱ͔͢ʁʁʁ ୭Ͱ͔͢ʁʁʁ
  28. ࿦ΑΓίʔυɿϚγϯޠΛ೷͍ͯΈΔ ❯ javac InvokeDynamicSimple.java ❯ javap -v -s -constants InvokeDynamicSimple.class

    > InvokeDynamicSimple.jvm public class invoke.dynamic.InvokeDynamicSimple Constant Pool: #2 = InvokeDynamic #0:#23 // #0:run:()Ljava/lang/Runnable; #23 = NameAndType #35:#36 // run:()Ljava/lang/Runnable; : { public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=2, args_size=1 0: invokedynamic #2, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable; 5: astore_1 6: aload_1 7: invokeinterface #3, 1 // InterfaceMethod java/lang/Runnable.run:()V 12: return } SourceFile: "InvokeDynamicSimple.java" InnerClasses: public static final #50= #49 of #53; // Lookup=class java/lang/invoke/ MethodHandles$Lookup of class java/lang/invoke/MethodHandles BootstrapMethods: 0: #20 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/ MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/ MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/ CallSite; Method arguments: #21 ()V #22 REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #21 ()V *OWPLF%ZOBNJD4JNQMFKWN invokedynamic Operation Invoke a dynamically-computed call site Format invokedynamic
 indexbyte1
 indexbyte2
 0
 0
 Description First, the unsigned indexbyte1 and indexbyte2 are used to construct an index into the run-time constant pool of the current class (§2.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The run-time constant pool entry at the index must be a symbolic reference to a dynamically-computed call site (§5.1). The values of the third and fourth operand bytes must always be zero. : The symbolic reference is resolved (§5.4.3.6) for this specific invokedynamic instruction to obtain a reference to an instance of java.lang.invoke.CallSite. The instance of java.lang.invoke. The instance of java.lang.invoke.CallSite indicates a target method handle. The invocation occurs as if by execution of an invokevirtual instruction that indicates a run-time constant pool index to a symbolic reference R JOWPLFEZOBNJD w $BMM4JUFͱ΍ΒΛJOWPLFWJSUVBMͰ࣮ߦ͢Δ Β͍͠ʜ ͜Μͳγάωνϟͷϝιουͳ͍Ͱ͢ ୭Ͱ͔͢ʁʁʁ ୭Ͱ͔͢ʁʁʁ
  29. #PPU4USBQ.FUIPE#4. +BWBԾ૝ϚγϯɾΨΠυඇ+BWBݴޠͷαϙʔτ ϒʔτετϥοϓɾϝιουͷ໭Γܕ͸java.lang.invoke.CallSiteͰ͋Δඞཁ͕͋Γ·͢ɻCallSiteΦϒδΣΫτ͸ɺinvokedynamic໋ྩͱͦΕ͕ϦϯΫ ͞ΕΔϝιουɾϋϯυϧͷϦϯΫঢ়ଶΛද͠·͢ɻ ϒʔτετϥοϓɾϝιου͸ɺ࣍ͷύϥϝʔλΛ3ͭҎ্औΓ·͢ɻ • MethodHandles.LookupΦϒδΣΫτ: invokedynamic໋ྩͷίϯςΩετ಺ͰϝιουɾϋϯυϧΛ࡞੒͢ΔϑΝΫτϦɻ • StringΦϒδΣΫτ:

    ಈతίʔϧɾαΠτ಺Ͱݴٴ͞ΕΔϝιου໊ɻ • MethodTypeΦϒδΣΫτ: ಈతίʔϧɾαΠτͷղܾࡁܕγάχνϟɻ • invokedynamic໋ྩʹର͢Δ1ͭҎ্ͷ௥Ճͷ੩తҾ਺: ఆ਺ϓʔϧ͔ΒऔΓग़͞ΕΔΦϓγϣϯͷҾ਺ͷ໨త͸ɺݴޠ࣮૷ऀ͕ϒʔτετϥο ϓɾϝιουʹศརͳ௥ՃϝλσʔλΛ҆શ͔ͭίϯύΫτʹΤϯίʔυ͢ΔͷΛࢧԉ͢Δ͜ͱͰ͢ɻ֤ίʔϧɾαΠτʹ͸ಠࣗͷϒʔτετϥο ϓɾϝιου͕ࢦఆ͞ΕΔՄೳੑ͕͋ΔͨΊɺݪଇͱ໊ͯ͠લͱ௥ՃҾ਺͸৑௕ʹͳΓ·͢ɻͨͩ͠ɺͦͷΑ͏ͳӡ༻Ͱ͸͓ͦΒ͘ɺେ͖ͳΫϥ εɾϑΝΠϧ΍ఆ਺ϓʔϧ͕ੜ੒͞Ε·͢ɻ BootstrapMethods: 0: #20 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:( Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; Ljava/lang/invoke/MethodType; Ljava/lang/invoke/MethodHandle; Ljava/lang/invoke/MethodType )Ljava/lang/invoke/CallSite; Method arguments: #21 ()V #22 REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #21 ()V
  30. #PPU4USBQ.FUIPE#4. +BWBԾ૝ϚγϯɾΨΠυඇ+BWBݴޠͷαϙʔτ ϒʔτετϥοϓɾϝιουͷ໭Γܕ͸java.lang.invoke.CallSiteͰ͋Δඞཁ͕͋Γ·͢ɻCallSiteΦϒδΣΫτ͸ɺinvokedynamic໋ྩͱͦΕ͕ϦϯΫ ͞ΕΔϝιουɾϋϯυϧͷϦϯΫঢ়ଶΛද͠·͢ɻ ϒʔτετϥοϓɾϝιου͸ɺ࣍ͷύϥϝʔλΛ3ͭҎ্औΓ·͢ɻ • MethodHandles.LookupΦϒδΣΫτ: invokedynamic໋ྩͷίϯςΩετ಺ͰϝιουɾϋϯυϧΛ࡞੒͢ΔϑΝΫτϦɻ • StringΦϒδΣΫτ:

    ಈతίʔϧɾαΠτ಺Ͱݴٴ͞ΕΔϝιου໊ɻ • MethodTypeΦϒδΣΫτ: ಈతίʔϧɾαΠτͷղܾࡁܕγάχνϟɻ • invokedynamic໋ྩʹର͢Δ1ͭҎ্ͷ௥Ճͷ੩తҾ਺: ఆ਺ϓʔϧ͔ΒऔΓग़͞ΕΔΦϓγϣϯͷҾ਺ͷ໨త͸ɺݴޠ࣮૷ऀ͕ϒʔτετϥο ϓɾϝιουʹศརͳ௥ՃϝλσʔλΛ҆શ͔ͭίϯύΫτʹΤϯίʔυ͢ΔͷΛࢧԉ͢Δ͜ͱͰ͢ɻ֤ίʔϧɾαΠτʹ͸ಠࣗͷϒʔτετϥο ϓɾϝιου͕ࢦఆ͞ΕΔՄೳੑ͕͋ΔͨΊɺݪଇͱ໊ͯ͠લͱ௥ՃҾ਺͸৑௕ʹͳΓ·͢ɻͨͩ͠ɺͦͷΑ͏ͳӡ༻Ͱ͸͓ͦΒ͘ɺେ͖ͳΫϥ εɾϑΝΠϧ΍ఆ਺ϓʔϧ͕ੜ੒͞Ε·͢ɻ BootstrapMethods: 0: #20 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:( Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; Ljava/lang/invoke/MethodType; Ljava/lang/invoke/MethodHandle; Ljava/lang/invoke/MethodType; )Ljava/lang/invoke/CallSite; Method arguments: #21 ()V #22 REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #21 ()V ௥Ճͷ੩తҾ਺ σϑΥϧτҾ਺ +7.͕ܭࢉऔಘ ฦΓ஋
  31. KBWBMBOHJOWPLFQBDLBHF $BMM4JUF .FUIPE)BOEMF .FUIPE5ZQF package invoke.dynamic; import java.lang.invoke.CallSite; import java.lang.invoke.ConstantCallSite;

    import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; public class InvokeViaCallSite { public static void main(String[] args) throws Throwable { InvokeViaCallSite ivcs = new InvokeViaCallSite(); CallSite cs = ivcs.getPrintHelloCallSite(); // invoke the method using bundled method handle cs.getTarget().invoke(ivcs, "Ikuo"); } private CallSite getPrintHelloCallSite() throws Exception { MethodHandles.Lookup lk = MethodHandles.lookup(); // return type, arguments MethodType mt = MethodType.methodType(void.class, String.class); // ׬શम০ࢠʹඞཁͳΫϥε৘ใɺϝιου໊ɺϝιουγάωνϟΛ౉͠ɺϝιουΛLookup͢Δ MethodHandle mh = lk.findVirtual(getClass(), "printHello", mt); return new ConstantCallSite(mh); } private void printHello(String name) { System.out.println("Hello " + name + "!"); } } *OWPLF7JB$BMM4JUFKBWB
  32. KBWBMBOHJOWPLFQBDLBHF $BMM4JUF .FUIPE)BOEMF .FUIPE5ZQF package invoke.dynamic; import java.lang.invoke.CallSite; import java.lang.invoke.ConstantCallSite;

    import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; public class InvokeViaCallSite { public static void main(String[] args) throws Throwable { InvokeViaCallSite ivcs = new InvokeViaCallSite(); CallSite cs = ivcs.getPrintHelloCallSite(); // invoke the method using bundled method handle cs.getTarget().invoke(ivcs, "Ikuo"); } private CallSite getPrintHelloCallSite() throws Exception { MethodHandles.Lookup lk = MethodHandles.lookup(); // return type, arguments MethodType mt = MethodType.methodType(void.class, String.class); // ׬શम০ࢠʹඞཁͳΫϥε৘ใɺϝιου໊ɺϝιουγάωνϟΛ౉͠ɺϝιουΛLookup͢Δ MethodHandle mh = lk.findVirtual(getClass(), "printHello", mt); return new ConstantCallSite(mh); } private void printHello(String name) { System.out.println("Hello " + name + "!"); } } *OWPLF7JB$BMM4JUFKBWB NFUIPEΛݕࡧ͢ΔͨΊͷ0CKFDU NFUIPEͷܕʢEFTDSJQUPS NFUIPE΁ͷࢀর .FUIPE)BOEMFͷίϯςφ UBSHFU.FUIPE)BOEMF ϝιουΛ࣮ߦ
  33. w $BMM4JUF w .FUIPE)BOEMFͷίϯςφΫϥεʢ$BMM4JUFIBTB.FUIPE)BOEMFʣ w .FUIPE)BOEMF w .FUIPE΁ͷࢀর w .FUIPE5ZQF

    w ϝιουσΟεΫϦϓλʢฦΓ஋ͱҾ਺ͷܕʣ KBWBMBOHJOWPLFQBDLBHF $BMM4JUF .FUIPE)BOEMF .FUIPE5ZQF
  34. package invoke.dynamic; public class InvokeDynamicSimple { public static void main(String[]

    args) { Runnable r = () -> System.out.println("Hello"); r.run(); } } ❯ javac InvokeDynamicSimple.java ❯ javap -v -s -constants InvokeDynamicSimple.class > InvokeDynamicSimple.jvm public class invoke.dynamic.InvokeDynamicSimple Constant Pool: #2 = InvokeDynamic #0:#23 // #0:run:()Ljava/lang/Runnable; #21 = MethodType #10 // ()V #22 = MethodHandle 6:#34 // REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #23 = NameAndType #35:#36 // run:()Ljava/lang/Runnable; : { public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=2, args_size=1 0: invokedynamic #2, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable; 5: astore_1 6: aload_1 7: invokeinterface #3, 1 // InterfaceMethod java/lang/Runnable.run:()V 12: return } SourceFile: "InvokeDynamicSimple.java" InnerClasses: public static final #50= #49 of #53; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/ invoke/MethodHandles BootstrapMethods: 0: #20 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/ MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/ MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; Method arguments: #21 ()V #22 REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #21 ()V *OWPLF%ZOBNJD4JNQMFKBWB *OWPLF%ZOBNJD4JNQMFKWN w ݟ׳Εͳ͍ਓͨͪ w *OWPLF%ZOBNJD$1 w .FUIPE)BOEMF$1 w *OWPLFEZOBNJDJOTUSVDUJPO w *OOFS$MBTT-PPLVQ w #PPUTUSBQ.FUIPE ࿦ΑΓόΠφϦJOWPLFEZOBNJD
  35. package invoke.dynamic; public class InvokeDynamicSimple { public static void main(String[]

    args) { Runnable r = () -> System.out.println("Hello"); r.run(); } } ❯ javac InvokeDynamicSimple.java ❯ javap -v -s -constants InvokeDynamicSimple.class > InvokeDynamicSimple.jvm public class invoke.dynamic.InvokeDynamicSimple Constant Pool: #2 = InvokeDynamic #0:#23 // #0:run:()Ljava/lang/Runnable; #21 = MethodType #10 // ()V #22 = MethodHandle 6:#34 // REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #23 = NameAndType #35:#36 // run:()Ljava/lang/Runnable; : { public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=2, args_size=1 0: invokedynamic #2, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable; 5: astore_1 6: aload_1 7: invokeinterface #3, 1 // InterfaceMethod java/lang/Runnable.run:()V 12: return } SourceFile: "InvokeDynamicSimple.java" InnerClasses: public static final #50= #49 of #53; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/ invoke/MethodHandles BootstrapMethods: 0: #20 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/ MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/ MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; Method arguments: #21 ()V #22 REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #21 ()V *OWPLF%ZOBNJD4JNQMFKBWB w ݟ׳Εͳ͍ਓͨͪ w *OWPLF%ZOBNJD$1 w .FUIPE)BOEMF$1 w *OWPLFEZOBNJDJOTUSVDUJPO w *OOFS$MBTT-PPLVQ w #PPUTUSBQ.FUIPE ࿦ΑΓόΠφϦJOWPLFEZOBNJD *OWPLF%ZOBNJD4JNQMFKWN
  36. ࿦ΑΓόΠφϦ package invoke.dynamic; public class InvokeDynamicSimple { public static void

    main(String[] args) { Runnable r = () -> System.out.println("Hello"); r.run(); } } *OWPLF%ZOBNJD4JNQMFKBWB invokedynamic Operation Invoke a dynamically-computed call site Format invokedynamic
 indexbyte1
 indexbyte2
 0
 0
 Forms invokedynamic = 186 (0xba) Description First, the unsigned indexbyte1 and indexbyte2 are used to construct an index into the run-time constant pool of the current class (§2.6), The values of the third and fourth operand bytes must always be zero. JOWPLFEZOBNJD YCB public class invoke.dynamic.InvokeDynamicSimple Constant Pool: #2 = InvokeDynamic #0:#23 // #0:run:()Ljava/lang/Runnable; #23 = NameAndType #35:#36 // run:()Ljava/lang/Runnable; : { public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=2, args_size=1 0: invokedynamic #2, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable; *OWPLF%ZOBNJD4JNQMFDMBTT *OWPLF%ZOBNJD4JNQMFKWN
  37. ࿦ΑΓόΠφϦ package invoke.dynamic; public class InvokeDynamicSimple { public static void

    main(String[] args) { Runnable r = () -> System.out.println("Hello"); r.run(); } } public class invoke.dynamic.InvokeDynamicSimple Constant Pool: #2 = InvokeDynamic #0:#23 // #0:run:()Ljava/lang/Runnable; #23 = NameAndType #35:#36 // run:()Ljava/lang/Runnable; : { public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=2, args_size=1 0: invokedynamic #2, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable; *OWPLF%ZOBNJD4JNQMFKBWB invokedynamic Operation Invoke a dynamically-computed call site Format invokedynamic
 indexbyte1
 indexbyte2
 0
 0
 Forms invokedynamic = 186 (0xba) Description First, the unsigned indexbyte1 and indexbyte2 are used to construct an index into the run-time constant pool of the current class (§2.6), The values of the third and fourth operand bytes must always be zero. JOWPLFEZOBNJD YCB *OWPLF%ZOBNJD4JNQMFDMBTT *OWPLF%ZOBNJD4JNQMFKWN
  38. ࿦ΑΓόΠφϦ CONSTANT_InvokeDynamic_info { u1 tag; u2 bootstrap_method_attr_index; u2 name_and_type_index; }

    public class invoke.dynamic.InvokeDynamicSimple Constant Pool: #2 = InvokeDynamic #0:#23 // #0:run:()Ljava/lang/Runnable; #23 = NameAndType #35:#36 // run:()Ljava/lang/Runnable; : { public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=2, args_size=1 0: invokedynamic #2, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable; : BootstrapMethods: 0: #20 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:( : )Ljava/lang/invoke/CallSite; 5IF$0/45"/5@*OWPLF%ZOBNJD@JOGP 4USVDUVSFT tag The tag item of a CONSTANT_InvokeDynamic_info structure has the value CONSTANT_InvokeDynamic (18). bootstrap_method_attr_index The value of the bootstrap_method_attr_index item must be a valid index into the bootstrap_methods array of the bootstrap method table of this class file (§4.7.23). name_and_type_index The value of the name_and_type_index item must be a valid index into the constant_pool table. In a CONSTANT_InvokeDynamic_info structure, the indicated descriptor must be a method descriptor (§4.3.3). *OWPLF%ZOBNJD$POTUBOU1PPM *OWPLF%ZOBNJD4JNQMFDMBTT *OWPLF%ZOBNJD4JNQMFKWN
  39. ࿦ΑΓόΠφϦ CONSTANT_InvokeDynamic_info { u1 tag; u2 bootstrap_method_attr_index; u2 name_and_type_index; }

    public class invoke.dynamic.InvokeDynamicSimple Constant Pool: #2 = InvokeDynamic #0:#23 // #0:run:()Ljava/lang/Runnable; #23 = NameAndType #35:#36 // run:()Ljava/lang/Runnable; : { public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=2, args_size=1 0: invokedynamic #2, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable; : BootstrapMethods: 0: #20 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:( : )Ljava/lang/invoke/CallSite; 5IF$0/45"/5@*OWPLF%ZOBNJD@JOGP 4USVDUVSFT tag The tag item of a CONSTANT_InvokeDynamic_info structure has the value CONSTANT_InvokeDynamic (18). bootstrap_method_attr_index The value of the bootstrap_method_attr_index item must be a valid index into the bootstrap_methods array of the bootstrap method table of this class file (§4.7.23). name_and_type_index The value of the name_and_type_index item must be a valid index into the constant_pool table. In a CONSTANT_InvokeDynamic_info structure, the indicated descriptor must be a method descriptor (§4.3.3). *OWPLF%ZOBNJD$POTUBOU1PPM *OWPLF%ZOBNJD4JNQMFDMBTT *OWPLF%ZOBNJD4JNQMFKWN
  40. ࿦ΑΓόΠφϦ BootstrapMethods_attribute { u2 attribute_name_index; u4 attribute_length; u2 num_bootstrap_methods; {

    u2 bootstrap_method_ref; u2 num_bootstrap_arguments; u2 bootstrap_arguments[num_bootstrap_arguments]; } bootstrap_methods[num_bootstrap_methods]; } Constant pool: #2 = InvokeDynamic #0:#23 // #0:run:()Ljava/lang/Runnable; #19 = Utf8 BootstrapMethods #20 = MethodHandle 6:#33 // REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:( Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; Ljava/lang/invoke/MethodType; Ljava/lang/invoke/MethodHandle; Ljava/lang/invoke/MethodType )Ljava/lang/invoke/CallSite; #21 = MethodType #10 // ()V #22 = MethodHandle 6:#34 // REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #23 = NameAndType #35:#36 // run:()Ljava/lang/Runnable; BootstrapMethods: 0: #20 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/ MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/ MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType)Ljava/lang/invoke/CallSite; Method arguments: #21 ()V #22 REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #21 ()V 5IF#PPUTUSBQ.FUIPET"UUSJCVUF attribute_name_index The value of the attribute_name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure (§4.4.7) representing the string "BootstrapMethods". attribute_length The value of the attribute_length item indicates the length of the attribute, excluding the initial six bytes. num_bootstrap_methods The value of the num_bootstrap_methods item determines the number of bootstrap method specifiers in the bootstrap_methods array. bootstrap_methods[] Each entry in the bootstrap_methods table contains an index to a CONSTANT_MethodHandle_info structure which specifies a bootstrap method, and a sequence (perhaps empty) of indexes to static arguments for the bootstrap method. #PPUTUSBQ.FUIPET *OWPLF%ZOBNJD4JNQMFDMBTT *OWPLF%ZOBNJD4JNQMFKWN
  41. Constant pool: #2 = InvokeDynamic #0:#23 // #0:run:()Ljava/lang/Runnable; #19 =

    Utf8 BootstrapMethods #20 = MethodHandle 6:#33 // REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:( Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; Ljava/lang/invoke/MethodType; Ljava/lang/invoke/MethodHandle; Ljava/lang/invoke/MethodType )Ljava/lang/invoke/CallSite; #21 = MethodType #10 // ()V #22 = MethodHandle 6:#34 // REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #23 = NameAndType #35:#36 // run:()Ljava/lang/Runnable; BootstrapMethods: 0: #20 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/ MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/ MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType)Ljava/lang/invoke/CallSite; Method arguments: #21 ()V #22 REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #21 ()V ࿦ΑΓόΠφϦ BootstrapMethods_attribute { u2 attribute_name_index; u4 attribute_length; u2 num_bootstrap_methods; { u2 bootstrap_method_ref; u2 num_bootstrap_arguments; u2 bootstrap_arguments[num_bootstrap_arguments]; } bootstrap_methods[num_bootstrap_methods]; } 5IF#PPUTUSBQ.FUIPET"UUSJCVUF attribute_name_index The value of the attribute_name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure (§4.4.7) representing the string "BootstrapMethods". attribute_length The value of the attribute_length item indicates the length of the attribute, excluding the initial six bytes. num_bootstrap_methods The value of the num_bootstrap_methods item determines the number of bootstrap method specifiers in the bootstrap_methods array. bootstrap_methods[] Each entry in the bootstrap_methods table contains an index to a CONSTANT_MethodHandle_info structure which specifies a bootstrap method, and a sequence (perhaps empty) of indexes to static arguments for the bootstrap method. #PPUTUSBQ.FUIPET BUUSJCVUF@OBNF@JOEFY BUUSJCVUF@MFOHUI OVN@CPPUTUSBQ@NFUIPET  *OWPLF%ZOBNJD4JNQMFDMBTT *OWPLF%ZOBNJD4JNQMFKWN
  42. Constant pool: #2 = InvokeDynamic #0:#23 // #0:run:()Ljava/lang/Runnable; #19 =

    Utf8 BootstrapMethods #20 = MethodHandle 6:#33 // REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:( Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; Ljava/lang/invoke/MethodType; Ljava/lang/invoke/MethodHandle; Ljava/lang/invoke/MethodType )Ljava/lang/invoke/CallSite; #21 = MethodType #10 // ()V #22 = MethodHandle 6:#34 // REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #23 = NameAndType #35:#36 // run:()Ljava/lang/Runnable; BootstrapMethods: 0: #20 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/ MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/ MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType)Ljava/lang/invoke/CallSite; Method arguments: #21 ()V #22 REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #21 ()V ࿦ΑΓόΠφϦ BootstrapMethods_attribute { u2 attribute_name_index; u4 attribute_length; u2 num_bootstrap_methods; { u2 bootstrap_method_ref; u2 num_bootstrap_arguments; u2 bootstrap_arguments[num_bootstrap_arguments]; } bootstrap_methods[num_bootstrap_methods]; } 5IF#PPUTUSBQ.FUIPET"UUSJCVUF bootstrap_methods[] bootstrap_method_ref The value of the bootstrap_method_ref item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_MethodHandle_info structure (§4.4.8). The method handle will be resolved during resolution of a dynamically- computed constant or call site (§5.4.3.6), and then invoked as if by invocation of invokeWithArguments in java.lang.invoke.MethodHandle. num_bootstrap_arguments The value of the num_bootstrap_arguments item gives the number of items in the bootstrap_arguments array. bootstrap_arguments[] Each entry in the bootstrap_arguments array must be a valid index into the constant_pool table. The constant_pool entry at that index must be loadable (§4.4). #PPUTUSBQ.FUIPET CPPUTUSBQ@NFUIPE@SFG CPPUTUSBQ@BSHVNFOUT<>  CPPUTUSBQ@BSHVNFOUT<>  OVN@CPPUTUSBQ@NFUIPE @BSHVNFOUT *OWPLF%ZOBNJD4JNQMFDMBTT *OWPLF%ZOBNJD4JNQMFKWN
  43. Constant pool: #22 = MethodHandle 6:#34 // REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #34

    = Methodref #7.#46 // invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V BootstrapMethods: 0: #20 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(…)Ljava/lang/invoke/ CallSite; Method arguments: #21 ()V #22 REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #21 ()V ࿦ΑΓόΠφϦ CONSTANT_MethodHandle_info { u1 tag; u1 reference_kind; u2 reference_index; } 5IF$0/45"/[email protected])BOEMF@JOGP 4USVDUVSF The CONSTANT_MethodHandle_info structure is used to represent a method handle: tag The tag item has the value CONSTANT_MethodHandle (15). reference_kind The value of the reference_kind item must be in the range 1 to 9. The value denotes the kind of this method handle, which characterizes its bytecode behavior (§5.4.3.5). reference_index The value of the reference_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be as follows: If the value of the reference_kind item is 6 (REF_invokeStatic) or 7 (REF_invokeSpecial), then if the class file version number is 52.0 or above, the constant_pool entry at that index must be either a CONSTANT_Methodref_info structure or a CONSTANT_InterfaceMethodref_info structure (§4.4.2) representing a class's or interface's method for which a method handle is to be created. .FUIPE)BOEMF$POTUBOU1PPM *OWPLF%ZOBNJD4JNQMFDMBTT *OWPLF%ZOBNJD4JNQMFKWN
  44. Constant pool: #22 = MethodHandle 6:#34 // REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #34

    = Methodref #7.#46 // invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V BootstrapMethods: 0: #20 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(…)Ljava/lang/invoke/ CallSite; Method arguments: #21 ()V #22 REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #21 ()V ࿦ΑΓόΠφϦ .FUIPE)BOEMF$POTUBOU1PPM CONSTANT_MethodHandle_info { u1 tag; u1 reference_kind; u2 reference_index; } 5IF$0/45"/[email protected])BOEMF@JOGP 4USVDUVSF The CONSTANT_MethodHandle_info structure is used to represent a method handle: tag The tag item has the value CONSTANT_MethodHandle (15). reference_kind The value of the reference_kind item must be in the range 1 to 9. The value denotes the kind of this method handle, which characterizes its bytecode behavior (§5.4.3.5). reference_index The value of the reference_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be as follows: If the value of the reference_kind item is 6 (REF_invokeStatic) or 7 (REF_invokeSpecial), then if the class file version number is 52.0 or above, the constant_pool entry at that index must be either a CONSTANT_Methodref_info structure or a CONSTANT_InterfaceMethodref_info structure (§4.4.2) representing a class's or interface's method for which a method handle is to be created. *OWPLF%ZOBNJD4JNQMFDMBTT *OWPLF%ZOBNJD4JNQMFKWN
  45. ࿦ΑΓόΠφϦ InnerClasses_attribute { u2 attribute_name_index; u4 attribute_length; u2 number_of_classes; {

    u2 inner_class_info_index; u2 outer_class_info_index; u2 inner_name_index; u2 inner_class_access_flags; } classes[number_of_classes]; } 5IF*OOFS$MBTTFT"UUSJCVUF *OOFS$MBTTFT attribute_name_index The value of the attribute_name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure (§4.4.7) representing the string "InnerClasses". attribute_length The value of the attribute_length item indicates the length of the attribute, excluding the initial six bytes. number_of_classes The value of the number_of_classes item indicates the number of entries in the classes array. classes[] Every CONSTANT_Class_info entry in the constant_pool table which represents a class or interface C that is not a package member must have exactly one corresponding entry in the classes array. Constant pool: #49 = Class #54 // java/lang/invoke/MethodHandles$Lookup #50 = Utf8 Lookup #51 = Utf8 InnerClasses #53 = Class #55 // java/lang/invoke/MethodHandles InnerClasses: public static final #50= #49 of #53; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles *OWPLF%ZOBNJD4JNQMFDMBTT *OWPLF%ZOBNJD4JNQMFKWN
  46. Constant pool: #49 = Class #54 // java/lang/invoke/MethodHandles$Lookup #50 =

    Utf8 Lookup #51 = Utf8 InnerClasses #53 = Class #55 // java/lang/invoke/MethodHandles InnerClasses: public static final #50= #49 of #53; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles ࿦ΑΓόΠφϦ InnerClasses_attribute { u2 attribute_name_index; u4 attribute_length; u2 number_of_classes; { u2 inner_class_info_index; u2 outer_class_info_index; u2 inner_name_index; u2 inner_class_access_flags; } classes[number_of_classes]; } 5IF*OOFS$MBTTFT"UUSJCVUF *OOFS$MBTTFT attribute_name_index The value of the attribute_name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure (§4.4.7) representing the string "InnerClasses". attribute_length The value of the attribute_length item indicates the length of the attribute, excluding the initial six bytes. number_of_classes The value of the number_of_classes item indicates the number of entries in the classes array. classes[] Every CONSTANT_Class_info entry in the constant_pool table which represents a class or interface C that is not a package member must have exactly one corresponding entry in the classes array. ͜Ε͸ͳΜͩΖ͏🤔 BUUSJCVUF@OBNF@JOEFY  JOOFS@DMBTT@JOGP@JOEFY  PVUFS@DMBTT@JOGP@JOEFY  JOOFS@OBNF@JOEFY  JOOFS@DMBTT@BDDFTT@ fl BHT C QVCMJDTUBUJD fi OBM *OWPLF%ZOBNJD4JNQMFDMBTT *OWPLF%ZOBNJD4JNQMFKWN
  47. Constant pool: #49 = Class #54 // java/lang/invoke/MethodHandles$Lookup #50 =

    Utf8 Lookup #51 = Utf8 InnerClasses #53 = Class #55 // java/lang/invoke/MethodHandles InnerClasses: public static final #50= #49 of #53; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles ࿦ΑΓόΠφϦ InnerClasses_attribute { u2 attribute_name_index; u4 attribute_length; u2 number_of_classes; { u2 inner_class_info_index; u2 outer_class_info_index; u2 inner_name_index; u2 inner_class_access_flags; } classes[number_of_classes]; } 5IF*OOFS$MBTTFT"UUSJCVUF *OOFS$MBTTFT attribute_name_index The value of the attribute_name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Utf8_info structure (§4.4.7) representing the string "InnerClasses". attribute_length The value of the attribute_length item indicates the length of the attribute, excluding the initial six bytes. number_of_classes The value of the number_of_classes item indicates the number of entries in the classes array. classes[] Every CONSTANT_Class_info entry in the constant_pool table which represents a class or interface C that is not a package member must have exactly one corresponding entry in the classes array. BUUSJCVUF@OBNF@JOEFY  JOOFS@DMBTT@JOGP@JOEFY  PVUFS@DMBTT@JOGP@JOEFY  If the constant pool of a class or interface C contains at least one CONSTANT_Class_info entry (§4.4.1) which represents a class or interface that is not a member of a package, then there must be exactly one InnerClasses attribute in the attributes table of the ClassFile structure for C. 1BDLBHF.FNCFSͰͳ͍$MBTT΍*OUFSGBDFͷࢀরͷࡍ͸ *OOFS$MBTTFTʹॻ͍͓ͯ͘ඞཁ͕͋Δ *OWPLF%ZOBNJD4JNQMFDMBTT *OWPLF%ZOBNJD4JNQMFKWN
  48. public class invoke.dynamic.InvokeDynamicSimple Constant Pool: #2 = InvokeDynamic #0:#23 //

    #0:run:()Ljava/lang/Runnable; #20 = MethodHandle 6:#33 // REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(…)Ljava/lang/invoke/ CallSite; #21 = MethodType #10 // ()V #22 = MethodHandle 6:#34 // REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #23 = NameAndType #35:#36 // run:()Ljava/lang/Runnable; : public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=2, args_size=1 0: invokedynamic #2, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable; : } SourceFile: "InvokeDynamicSimple.java" InnerClasses: public static final #50= #49 of #53; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles BootstrapMethods: 0: #20 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:( Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; Ljava/lang/invoke/MethodType; Ljava/lang/invoke/MethodHandle; Ljava/lang/invoke/MethodType; )Ljava/lang/invoke/CallSite; Method arguments: #21 ()V #22 REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #21 ()V ͭ·Γʜ *OWPLF%ZOBNJD4JNQMFKWN
  49. public class invoke.dynamic.InvokeDynamicSimple Constant Pool: #2 = InvokeDynamic #0:#23 //

    #0:run:()Ljava/lang/Runnable; #20 = MethodHandle 6:#33 // REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(…)Ljava/lang/invoke/ CallSite; #21 = MethodType #10 // ()V #22 = MethodHandle 6:#34 // REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #23 = NameAndType #35:#36 // run:()Ljava/lang/Runnable; : public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=2, args_size=1 0: invokedynamic #2, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable; : } SourceFile: "InvokeDynamicSimple.java" InnerClasses: public static final #50= #49 of #53; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles BootstrapMethods: 0: #20 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:( Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; Ljava/lang/invoke/MethodType; Ljava/lang/invoke/MethodHandle; Ljava/lang/invoke/MethodType; )Ljava/lang/invoke/CallSite; Method arguments: #21 ()V #22 REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #21 ()V ͭ·Γʜ ᶃJOWPLFEZOBNJD *OWPLF%ZOBNJD4JNQMFKWN
  50. public class invoke.dynamic.InvokeDynamicSimple Constant Pool: #2 = InvokeDynamic #0:#23 //

    #0:run:()Ljava/lang/Runnable; #20 = MethodHandle 6:#33 // REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(…)Ljava/lang/invoke/ CallSite; #21 = MethodType #10 // ()V #22 = MethodHandle 6:#34 // REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #23 = NameAndType #35:#36 // run:()Ljava/lang/Runnable; : public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=2, args_size=1 0: invokedynamic #2, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable; : } SourceFile: "InvokeDynamicSimple.java" InnerClasses: public static final #50= #49 of #53; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles BootstrapMethods: 0: #20 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:( Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; Ljava/lang/invoke/MethodType; Ljava/lang/invoke/MethodHandle; Ljava/lang/invoke/MethodType; )Ljava/lang/invoke/CallSite; Method arguments: #21 ()V #22 REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #21 ()V ͭ·Γʜ ᶄҾ਺/BNF"OE5ZQFSVO -KBWBMBOH3VOOBCMF Λऔͬͯ#PPU4USBQ.FUIPET *OWPLF%ZOBNJD4JNQMFKWN
  51. public class invoke.dynamic.InvokeDynamicSimple Constant Pool: #2 = InvokeDynamic #0:#23 //

    #0:run:()Ljava/lang/Runnable; #20 = MethodHandle 6:#33 // REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(…)Ljava/lang/invoke/ CallSite; #21 = MethodType #10 // ()V #22 = MethodHandle 6:#34 // REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #23 = NameAndType #35:#36 // run:()Ljava/lang/Runnable; : public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=2, args_size=1 0: invokedynamic #2, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable; : } SourceFile: "InvokeDynamicSimple.java" InnerClasses: public static final #50= #49 of #53; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles BootstrapMethods: 0: #20 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:( Ljava/lang/invoke/MethodHandles$Lookup; // MethodHandles.lookup() Ljava/lang/String; // “run” Ljava/lang/invoke/MethodType; // ()Ljava/lang/Runnable; Ljava/lang/invoke/MethodType; // ()V Ljava/lang/invoke/MethodHandle; // REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V Ljava/lang/invoke/MethodType; // ()V )Ljava/lang/invoke/CallSite; Method arguments: #21 ()V #22 REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #21 ()V ͭ·Γʜ ᶅҾ਺Λ͔͖ूΊͯɺΦϖϥϯυελοΫʹੵΜͰ *OWPLF%ZOBNJD4JNQMFKWN
  52. public class invoke.dynamic.InvokeDynamicSimple Constant Pool: #2 = InvokeDynamic #0:#23 //

    #0:run:()Ljava/lang/Runnable; #20 = MethodHandle 6:#33 // REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(…)Ljava/lang/invoke/ CallSite; #21 = MethodType #10 // ()V #22 = MethodHandle 6:#34 // REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #23 = NameAndType #35:#36 // run:()Ljava/lang/Runnable; : public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=2, args_size=1 0: invokedynamic #2, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable; : } SourceFile: "InvokeDynamicSimple.java" InnerClasses: public static final #50= #49 of #53; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles BootstrapMethods: 0: #20 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:( Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; Ljava/lang/invoke/MethodType; Ljava/lang/invoke/MethodHandle; Ljava/lang/invoke/MethodType; )Ljava/lang/invoke/CallSite; Method arguments: #21 ()V #22 REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #21 ()V ͭ·Γʜ ᶆ.FUIPE)BOEMFΛΠϯελϯεԽͯ͠ɺ NIJOWPLF8JUI"SHVNFOUT Λ࣮ߦ *OWPLF%ZOBNJD4JNQMFKWN
  53. public class invoke.dynamic.InvokeDynamicSimple Constant Pool: #2 = InvokeDynamic #0:#23 //

    #0:run:()Ljava/lang/Runnable; #20 = MethodHandle 6:#33 // REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(…)Ljava/lang/invoke/ CallSite; #21 = MethodType #10 // ()V #22 = MethodHandle 6:#34 // REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #23 = NameAndType #35:#36 // run:()Ljava/lang/Runnable; : public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=2, args_size=1 0: invokedynamic #2, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable; : } SourceFile: "InvokeDynamicSimple.java" InnerClasses: public static final #50= #49 of #53; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles BootstrapMethods: 0: #20 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:( Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; Ljava/lang/invoke/MethodType; Ljava/lang/invoke/MethodHandle; Ljava/lang/invoke/MethodType; )Ljava/lang/invoke/CallSite; Method arguments: #21 ()V #22 REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #21 ()V ͭ·Γʜ ᶇTUBUJDNFUIPEͷ -BNCEB.FUBGBDUPSZNFUBGBDUPSZ ͕࣮ߦ͞Εɺ $BMM4JUFΛฦ͢ *OWPLF%ZOBNJD4JNQMFKWN
  54. public class invoke.dynamic.InvokeDynamicSimple Constant Pool: #2 = InvokeDynamic #0:#23 //

    #0:run:()Ljava/lang/Runnable; #20 = MethodHandle 6:#33 // REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(…)Ljava/lang/invoke/ CallSite; #21 = MethodType #10 // ()V #22 = MethodHandle 6:#34 // REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #23 = NameAndType #35:#36 // run:()Ljava/lang/Runnable; : public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=2, args_size=1 0: invokedynamic #2, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable; : } SourceFile: "InvokeDynamicSimple.java" InnerClasses: public static final #50= #49 of #53; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles BootstrapMethods: 0: #20 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:( Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; Ljava/lang/invoke/MethodType; Ljava/lang/invoke/MethodHandle; Ljava/lang/invoke/MethodType; )Ljava/lang/invoke/CallSite; Method arguments: #21 ()V #22 REF_invokeStatic invoke/dynamic/InvokeDynamicSimple.lambda$main$0:()V #21 ()V ͭ·Γʜ ᶈ$BMM4JUFDTHFU5BSHFUJOWPLF  Λ࣮ߦ͢Δ͜ͱͰɺ໨తͷ SVO -KBWBMBOH3VOOBCMF ͷ݁ՌΛಘΔʂʂʂ *OWPLF%ZOBNJD4JNQMFKWN
  55. ͔ͤͬ͘ͳͷͰʜ -BNCEB͸ͲͷΑ͏ʹ࣮૷͞Ε͍ͯΔ͔ʁ public class invoke.dynamic.InvokeDynamicComplicated Constant pool: #4 = InvokeDynamic

    #0:#27 // #0:apply:(J)Ljava/util/function/Function; #23 = MethodHandle 6:#37 // REF_invokeStatic java/lang/invoke/ LambdaMetafactory.metafactory:(…)Ljava/lang/invoke/CallSite; #24 = MethodType #38 // (Ljava/lang/Object;)Ljava/lang/Object; #25 = MethodHandle 6:#39 // REF_invokeStatic invoke/dynamic/ InvokeDynamicComplicated.lambda$main$0:(JLjava/lang/Integer;)Ljava/lang/Double; #26 = MethodType #40 // (Ljava/lang/Integer;)Ljava/lang/Double; #27 = NameAndType #41:#42 // apply:(J)Ljava/util/function/Function; { public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=4, args_size=1 0: ldc2_w #2 // long 10l 3: lstore_1 4: lload_1 5: invokedynamic #4, 0 // InvokeDynamic #0:apply:(J)Ljava/util/ function/Function; } BootstrapMethods: 0: #23 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/ invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/ invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/ lang/invoke/CallSite; Method arguments: #24 (Ljava/lang/Object;)Ljava/lang/Object; #25 REF_invokeStatic invoke/dynamic/InvokeDynamicComplicated.lambda$main$0:(JLjava/ lang/Integer;)Ljava/lang/Double; #26 (Ljava/lang/Integer;)Ljava/lang/Double; package invoke.dynamic; import java.util.function.Function; public class InvokeDynamicComplicated { public static void main(String[] args) { long l = 10L; Function<Integer, Double> f = (i) -> (double)i / (double)l; f.apply(1); } } *OWPLF%ZOBNJD$PNQMJDBUFEKBWB *OWPLF%ZOBNJD$PNQMJDBUFEKWN w ͍ΘΏΔؔ਺ܕ*OUFSGBDF w *OWPLF%ZOBNJDʹͳ͕ͬͨɺҾ਺͕ੜ͑ͨ w JMͷܭࢉ͸Ͳ͜΁ߦͬͨ   BQQMZ͕JOUͰ͸ͳ͘ɺ MPOHҾ਺Λऔ͍ͬͯΔ
  56. λω໌͔͠ w -BNCEBͷ࣮ଶ͸ɺQSJWBUFTUBUJDNFUIPEͱͯ͠$MBTT'JMFʹଘࡏ͢Δʂ w ίϯύΠϥ͕MBNCEBຊମΛQSJWBUFTUBUJDͱͯ͠࿉੒ͨ͠ w Ͱ͸#4.͸͜ͷϝιουͷࢀরΛฦ٫͍ͯ͠Δͷ͔ʁ w ͔͠͠ɺҾ਺͕ҟͳΔʜ private

    static java.lang.Double lambda$main$0(long, java.lang.Integer); descriptor: (JLjava/lang/Integer;)Ljava/lang/Double; flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC Code: stack=4, locals=3, args_size=2 0: aload_2 1: invokevirtual #7 // Method java/lang/Integer.intValue:()I 4: i2d 5: lload_0 6: l2d 7: ddiv 8: invokestatic #8 // Method java/lang/Double.valueOf: (D)Ljava/lang/Double; 11: areturn LineNumberTable: line 8: 0 ❯ javac InvokeDynamicComplecated.java ❯ javap -v -p —s -constants InvokeDynamicComplecated.class > InvokeDynamicComplecatedWithPrivate.jvm *OWPLF%ZOBNJD$PNQMJDBUFE8JUI1SJWBUFKWN QŠQSJWBUFPQUJPO͕ඞཁ package invoke.dynamic; import java.util.function.Function; public class InvokeDynamicComplicated { public static void main(String[] args) { long l = 10L; Function<Integer, Double> f = (i) -> (double)i / (double)l; f.apply(1); } } *OWPLF%ZOBNJD$PNQMJDBUFEKBWB
  57. ΋͏Ұ౓#4.ΛݟͯΈΔ w -BNCEB.FUBGBDUPSZNFUBGBDUPSZ Λ࣮ߦ͍ͯ͠Δ w Ҿ਺͸ઌͷઆ໌͔Βɺ͜Μͳ͔Μ͕ͩ͡ʜ public class invoke.dynamic.InvokeDynamicComplicated Constant

    pool: #4 = InvokeDynamic #0:#27 // #0:apply:(J)Ljava/util/function/Function; #23 = MethodHandle 6:#37 // REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(…)Ljava/lang/invoke/CallSite; #24 = MethodType #38 // (Ljava/lang/Object;)Ljava/lang/Object; #25 = MethodHandle 6:#39 // REF_invokeStatic invoke/dynamic/InvokeDynamicComplicated.lambda$main$0:(JLjava/lang/Integer;)Ljava/lang/Double; #26 = MethodType #40 // (Ljava/lang/Integer;)Ljava/lang/Double; #27 = NameAndType #41:#42 // apply:(J)Ljava/util/function/Function; } BootstrapMethods: 0: #23 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:( Ljava/lang/invoke/MethodHandles$Lookup; // MethodHandles.lookup() Ljava/lang/String; // apply Ljava/lang/invoke/MethodType; // (J)Ljava/util/function/Function; Ljava/lang/invoke/MethodType; // (Ljava/lang/Object;)Ljava/lang/Object; Ljava/lang/invoke/MethodHandle; // InvokeDynamicComplicated.lambda$main$0:(JLjava/lang/Integer;)Ljava/lang/Double; Ljava/lang/invoke/MethodType; // (Ljava/lang/Integer;)Ljava/lang/Double; )Ljava/lang/invoke/CallSite; Method arguments: #24 (Ljava/lang/Object;)Ljava/lang/Object; #25 REF_invokeStatic invoke/dynamic/InvokeDynamicComplicated.lambda$main$0:(JLjava/lang/Integer;)Ljava/lang/Double; #26 (Ljava/lang/Integer;)Ljava/lang/Double;
  58. ΋͏Ұ౓#4.ΛݟͯΈΔ w -BNCEB.FUBGBDUPSZNFUBGBDUPSZ Λ࣮ߦ͍ͯ͠Δ w Ҿ਺͸ઌͷઆ໌͔Βɺ͜Μͳ͔Μ͕ͩ͡ʜ public class invoke.dynamic.InvokeDynamicComplicated Constant

    pool: #4 = InvokeDynamic #0:#27 // #0:apply:(J)Ljava/util/function/Function; #23 = MethodHandle 6:#37 // REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(…)Ljava/lang/invoke/CallSite; #24 = MethodType #38 // (Ljava/lang/Object;)Ljava/lang/Object; #25 = MethodHandle 6:#39 // REF_invokeStatic invoke/dynamic/InvokeDynamicComplicated.lambda$main$0:(JLjava/lang/Integer;)Ljava/lang/Double; #26 = MethodType #40 // (Ljava/lang/Integer;)Ljava/lang/Double; #27 = NameAndType #41:#42 // apply:(J)Ljava/util/function/Function; } BootstrapMethods: 0: #23 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:( Ljava/lang/invoke/MethodHandles$Lookup; // MethodHandles.lookup() Ljava/lang/String; // apply Ljava/lang/invoke/MethodType; // (J)Ljava/util/function/Function; Ljava/lang/invoke/MethodType; // (Ljava/lang/Object;)Ljava/lang/Object; Ljava/lang/invoke/MethodHandle; // InvokeDynamicComplicated.lambda$main$0:(JLjava/lang/Integer;)Ljava/lang/Double; Ljava/lang/invoke/MethodType; // (Ljava/lang/Integer;)Ljava/lang/Double; )Ljava/lang/invoke/CallSite; Method arguments: #24 (Ljava/lang/Object;)Ljava/lang/Object; #25 REF_invokeStatic invoke/dynamic/InvokeDynamicComplicated.lambda$main$0:(JLjava/lang/Integer;)Ljava/lang/Double; #26 (Ljava/lang/Integer;)Ljava/lang/Double; ୭ʁ ίϯύΠϥ͕࿉੒ͨ͠MBNCEBຊମɹ MPOH *OUFHFS %PVCMF ίʔυ্ͷMBNCEBͷܕ *OUFHFS %PVCMF
  59. -BNCEB.FUBGBDUPSZͷ࣮૷Λ֬ೝ͢Δ public static CallSite metafactory(MethodHandles.Lookup caller, String invokedName, MethodType invokedType,

    MethodType samMethodType, MethodHandle implMethod, MethodType instantiatedMethodType) throws LambdaConversionException { AbstractValidatingLambdaMetafactory mf; mf = new InnerClassLambdaMetafactory(caller, invokedType, invokedName, samMethodType, implMethod, instantiatedMethodType, false, EMPTY_CLASS_ARRAY, EMPTY_MT_ARRAY); mf.validateMetafactoryArgs(); return mf.buildCallSite(); } -BNCEB.FUBGBDUPSZKBWB w *OOFS$MBTT-BNCEB.FUBGBDUPSZΛ࣮ߦ͍ͯ͠Δ w *OWPLFE TBN JNQM🤔
  60. 4JOHMF"CTUSBDU.FUIPE4". /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {

    } abstract class AbstractValidatingLambdaMetafactory { /* * For context, the comments for the following fields are marked in quotes * with their values, given this program: * interface II<T> { Object foo(T x); } * interface JJ<R extends Number> extends II<R> { } * class CC { String impl(int i) { return "impl:"+i; }} * class X { * public static void main(String[] args) { * JJ<Integer> iii = (new CC())::impl; * System.out.printf(">>> %s\n", iii.foo(44)); * }} */ final Class<?> targetClass; // The class calling the meta-factory via invokedynamic "class X" final MethodType invokedType; // The type of the invoked method "(CC)II" final Class<?> samBase; // The type of the returned instance "interface JJ" final String samMethodName; // Name of the SAM method "foo" final MethodType samMethodType; // Type of the SAM method "(Object)Object" final MethodHandle implMethod; // Raw method handle for the implementation method final MethodType implMethodType; // Type of the implMethod MethodHandle "(CC,int)String" w 4".4JOHMF"CTUSBDU.FUIPE w ͜͜Ͱ΍͍ͬͯΔͷ͸͍ΘΏΔl4".ม׵z "CTUSBDU7BMJEBUJOH-BNCEB.FUBGBDUPSZKBWB
  61. 4JOHMF"CTUSBDU.FUIPE4". /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {

    } abstract class AbstractValidatingLambdaMetafactory { /* * For context, the comments for the following fields are marked in quotes * with their values, given this program: * interface II<T> { Object foo(T x); } * interface JJ<R extends Number> extends II<R> { } * class CC { String impl(int i) { return "impl:"+i; }} * class X { * public static void main(String[] args) { * JJ<Integer> iii = (new CC())::impl; * System.out.printf(">>> %s\n", iii.foo(44)); * }} */ final Class<?> targetClass; // The class calling the meta-factory via invokedynamic "class X" final MethodType invokedType; // The type of the invoked method "(CC)II" final Class<?> samBase; // The type of the returned instance "interface JJ" final String samMethodName; // Name of the SAM method "foo" final MethodType samMethodType; // Type of the SAM method "(Object)Object" final MethodHandle implMethod; // Raw method handle for the implementation method final MethodType implMethodType; // Type of the implMethod MethodHandle "(CC,int)String" ͜͜Ͱ࣮ߦ͞ΕΔϝιου͸ɺ$$ΛҾ਺ʹͱͬͯ**Λฦ͢΋ͷͱΈͳͤΔ 4JOHMF"CTUSBDU.FUIPE ࣮૷͞Εͨϝιου w 4".4JOHMF"CTUSBDU.FUIPE w ͜͜Ͱ΍͍ͬͯΔͷ͸͍ΘΏΔl4".ม׵z "CTUSBDU7BMJEBUJOH-BNCEB.FUBGBDUPSZKBWB
  62. ࠓͷίϯςΩετͰ͸ public static CallSite metafactory(MethodHandles.Lookup caller, String invokedName, MethodType invokedType,

    MethodType samMethodType, MethodHandle implMethod, MethodType instantiatedMethodType) throws LambdaConversionException { } package invoke.dynamic; import java.util.function.Function; public class InvokeDynamicComplicated { public static void main(String[] args) { long l = 10L; Function<Integer, Double> f = (i) -> (double)i / (double)l; f.apply(1); } } @FunctionalInterface public interface Function<T, R> { R apply(T t); -BNCEB.FUBGBDUPSZKBWB 0: #23 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:( Ljava/lang/invoke/MethodHandles$Lookup; // MethodHandles.lookup() Ljava/lang/String; // apply Ljava/lang/invoke/MethodType; // (J)Ljava/util/function/Function; Ljava/lang/invoke/MethodType; // (Ljava/lang/Object;)Ljava/lang/Object; Ljava/lang/invoke/MethodHandle; // InvokeDynamicComplicated.lambda$main$0: (JLjava/lang/Integer;)Ljava/lang/Double; Ljava/lang/invoke/MethodType; // (Ljava/lang/Integer;)Ljava/lang/Double; )Ljava/lang/invoke/CallSite; w ͜͜Ͱى͜Δ΂͖ݱ৅͸ʜ w 'VODUJPO*OUFSGBDFΛ࣮૷ͨ͠Πϯελϯε͕ฦ͞ΕΔ͜ͱ
  63. ࠓͷίϯςΩετͰ͸ public static CallSite metafactory(MethodHandles.Lookup caller, String invokedName, MethodType invokedType,

    MethodType samMethodType, MethodHandle implMethod, MethodType instantiatedMethodType) throws LambdaConversionException { } -BNCEB.FUBGBDUPSZKBWB package invoke.dynamic; import java.util.function.Function; public class InvokeDynamicComplicated { public static void main(String[] args) { long l = 10L; Function<Integer, Double> f = (i) -> (double)i / (double)l; f.apply(1); } } *OWPLF%ZOBNJD$PNQMJDBUFEKBWB @FunctionalInterface public interface Function<T, R> { R apply(T t); 0: #23 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:( Ljava/lang/invoke/MethodHandles$Lookup; // MethodHandles.lookup() Ljava/lang/String; // apply Ljava/lang/invoke/MethodType; // (J)Ljava/util/function/Function; Ljava/lang/invoke/MethodType; // (Ljava/lang/Object;)Ljava/lang/Object; Ljava/lang/invoke/MethodHandle; // InvokeDynamicComplicated.lambda$main$0: (JLjava/lang/Integer;)Ljava/lang/Double; Ljava/lang/invoke/MethodType; // (Ljava/lang/Integer;)Ljava/lang/Double; )Ljava/lang/invoke/CallSite; w DBMMFS+7.͕࿉੒ͨ͠.FUIPE)BOEMFT-PPLVQ w JOWPLFE/BNF࣮ߦ͞Ε͍ͯΔϝιουͷ໊લɻ4".ϝιου໊͔ΒऔΒΕΔ w JOWPLFE5ZQF࣮ߦ͞Ε͍ͯΔܕɻ4".*OUFSGBDFͷΠϯελϯεΛฦ͢ w TBN.FUIPE5ZQFΦϦδφϧͷ4".ϝιουͷܕɻܕফڈʹΑΓδΣωϦΫεܕ͕མͪɺ 0CKFDU 0CKFDUʹͳΔ w JNQM.FUIPEMBNCEB࣮૷ຊମ΁ͷࢀর w JOTUBODJBUFE.FUIPE5ZQFΠϯελϯεԽ͞Εͨ͋ͱͷBQQMZϝιουͷܕɻΦϦδφϧͷMBNCEB࣮૷ͱಉҰ
  64. *OOFS$MBTT-BNCEB.FUBGBDUPSZͷ࣮૷ public static CallSite metafactory(MethodHandles.Lookup caller, String invokedName, MethodType invokedType,

    MethodType samMethodType, MethodHandle implMethod, MethodType instantiatedMethodType) throws LambdaConversionException { AbstractValidatingLambdaMetafactory mf; mf = new InnerClassLambdaMetafactory(caller, invokedType, invokedName, samMethodType, implMethod, instantiatedMethodType, false, EMPTY_CLASS_ARRAY, EMPTY_MT_ARRAY); mf.validateMetafactoryArgs(); return mf.buildCallSite(); } CallSite buildCallSite() throws LambdaConversionException { final Class<?> innerClass = spinInnerClass(); if (invokedType.parameterCount() == 0 && !disableEagerInitialization) { // In the case of a non-capturing lambda, we optimize linkage by pre-computing a single instance, // unless we've suppressed eager initialization final Constructor<?>[] ctrs = AccessController.doPrivileged( new PrivilegedAction<>() { @Override public Constructor<?>[] run() { Constructor<?>[] ctrs = innerClass.getDeclaredConstructors(); if (ctrs.length == 1) { // The lambda implementing inner class constructor is private, set // it accessible (by us) before creating the constant sole instance ctrs[0].setAccessible(true); } return ctrs; } }); if (ctrs.length != 1) { throw new LambdaConversionException("Expected one lambda constructor for " + innerClass.getCanonicalName() + ", got " + ctrs.length); } try { Object inst = ctrs[0].newInstance(); return new ConstantCallSite(MethodHandles.constant(samBase, inst)); } catch (ReflectiveOperationException e) { throw new LambdaConversionException("Exception instantiating lambda object", e); } } else { try { if (!disableEagerInitialization) { UNSAFE.ensureClassInitialized(innerClass); } return new ConstantCallSite( MethodHandles.Lookup.IMPL_LOOKUP .findStatic(innerClass, NAME_FACTORY, invokedType)); } catch (ReflectiveOperationException e) { throw new LambdaConversionException("Exception finding constructor", e); } } } w *OOFS$MBTT-BNCEB'BDUPSZΛੜ੒ w CVJME$BMM4JUFͰ$BMM4JUFΛ࡞੒ͯ͠ฦ͢ w CVJME$BMM4JUF  w TQJOO*OFS$MBTT ͰΫϥεΛੜ੒͍ͯ͠Δ
  65. *OOFS$MBTT-BNCEB.FUBGBDUPSZͷ࣮૷ public static CallSite metafactory(MethodHandles.Lookup caller, String invokedName, MethodType invokedType,

    MethodType samMethodType, MethodHandle implMethod, MethodType instantiatedMethodType) throws LambdaConversionException { AbstractValidatingLambdaMetafactory mf; mf = new InnerClassLambdaMetafactory(caller, invokedType, invokedName, samMethodType, implMethod, instantiatedMethodType, false, EMPTY_CLASS_ARRAY, EMPTY_MT_ARRAY); mf.validateMetafactoryArgs(); return mf.buildCallSite(); } CallSite buildCallSite() throws LambdaConversionException { final Class<?> innerClass = spinInnerClass(); if (invokedType.parameterCount() == 0 && !disableEagerInitialization) { // In the case of a non-capturing lambda, we optimize linkage by pre-computing a single instance, // unless we've suppressed eager initialization final Constructor<?>[] ctrs = AccessController.doPrivileged( new PrivilegedAction<>() { @Override public Constructor<?>[] run() { Constructor<?>[] ctrs = innerClass.getDeclaredConstructors(); if (ctrs.length == 1) { // The lambda implementing inner class constructor is private, set // it accessible (by us) before creating the constant sole instance ctrs[0].setAccessible(true); } return ctrs; } }); if (ctrs.length != 1) { throw new LambdaConversionException("Expected one lambda constructor for " + innerClass.getCanonicalName() + ", got " + ctrs.length); } try { Object inst = ctrs[0].newInstance(); return new ConstantCallSite(MethodHandles.constant(samBase, inst)); } catch (ReflectiveOperationException e) { throw new LambdaConversionException("Exception instantiating lambda object", e); } } else { try { if (!disableEagerInitialization) { UNSAFE.ensureClassInitialized(innerClass); } return new ConstantCallSite( MethodHandles.Lookup.IMPL_LOOKUP .findStatic(innerClass, NAME_FACTORY, invokedType)); } catch (ReflectiveOperationException e) { throw new LambdaConversionException("Exception finding constructor", e); } } } w TQJOO*OFS$MBTT Ͱੜ੒ͨ͠Ϋϥε͕ʜ w Ҿ਺ͳ͠ w γϯάϧτϯΛੜ੒ɺݻఆ஋ͱͯ͠ฦ͢ w Ҿ਺͋ΓʢΫϩʔδϟ͋Γʣ w ϑΝΫτϦϝιου /".&@'"$503: Λόϯυϧ
  66. private Class<?> spinInnerClass() throws LambdaConversionException { String[] interfaces; String samIntf

    = samBase.getName().replace('.', '/'); boolean accidentallySerializable = !isSerializable && Serializable.class.isAssignableFrom(samBase); if (markerInterfaces.length == 0) { interfaces = new String[]{samIntf}; } else { : cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC, lambdaClassName, null, JAVA_LANG_OBJECT, interfaces); // Generate final fields to be filled in by constructor for (int i = 0; i < argDescs.length; i++) { FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL, argNames[i], argDescs[i], null, null); fv.visitEnd(); } generateConstructor(); if (invokedType.parameterCount() != 0 || disableEagerInitialization) { generateFactory(); } // Forward the SAM method MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName, samMethodType.toMethodDescriptorString(), null, null); mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true); new ForwardingMethodGenerator(mv).generate(samMethodType); : cw.visitEnd(); // Define the generated class in this VM. final byte[] classBytes = cw.toByteArray(); : return UNSAFE.defineAnonymousClass(targetClass, classBytes, null); } w $MBTT8SJUFSΛར༻ͯ͠ɺҎԼͷόΠφϦΛੜ੒͢Δ w 4".ͷJOUFSGBDFΛJNQMFNFOUͨ͠*OOFS$MBTT w AQSJWBUFDMBTT0VUFS$MBTT-BNCEB/ JNQMFNFOUT4".*OUFSGBDFA w ͦͷίϯετϥΫλ w ʢίϯετϥΫλύϥϝλ͕͋ΔΫϩʔδϟ͕͋ Δ৔߹ʣΠϯελϯεΛ࡞ΔͨΊͷ GBDUPSZNFUIPEAQSJWBUFTUBUJD fi OBM HFU-BNCEBA w ίϯετϥΫλύϥϝλ͕͋Δ৔߹ɺͦΕΛ֨ೲ͢Δϑ Οʔϧυ w 4".ΠϯλʔϑΣʔε༻ͷϝιου w ࣮ߦͨ͠ࡍɺMBNCEBຊମʢQSJWBUFTUBUJD NBJOMBNCEB Λ࣮ߦ͢Δ w Ϋϥεϩʔμʹొ࿥ʂ TQJO*OOFS$MBTT ͷ࣮૷
  67. private Class<?> spinInnerClass() throws LambdaConversionException { String[] interfaces; String samIntf

    = samBase.getName().replace('.', '/'); boolean accidentallySerializable = !isSerializable && Serializable.class.isAssignableFrom(samBase); if (markerInterfaces.length == 0) { interfaces = new String[]{samIntf}; } else { : cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC, lambdaClassName, null, JAVA_LANG_OBJECT, interfaces); // Generate final fields to be filled in by constructor for (int i = 0; i < argDescs.length; i++) { FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL, argNames[i], argDescs[i], null, null); fv.visitEnd(); } generateConstructor(); if (invokedType.parameterCount() != 0 || disableEagerInitialization) { generateFactory(); } // Forward the SAM method MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName, samMethodType.toMethodDescriptorString(), null, null); mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true); new ForwardingMethodGenerator(mv).generate(samMethodType); : cw.visitEnd(); // Define the generated class in this VM. final byte[] classBytes = cw.toByteArray(); : return UNSAFE.defineAnonymousClass(targetClass, classBytes, null); } w $MBTT8SJUFSΛར༻ͯ͠ɺҎԼͷόΠφϦΛੜ੒͢Δ w 4".ͷJOUFSGBDFΛJNQMFNFOUͨ͠*OOFS$MBTT w AQSJWBUFDMBTT0VUFS$MBTT-BNCEB/ JNQMFNFOUT4".*OUFSGBDFA w ͦͷίϯετϥΫλ w ʢίϯετϥΫλύϥϝλ͕͋ΔΫϩʔδϟ͕͋ Δ৔߹ʣΠϯελϯεΛ࡞ΔͨΊͷ GBDUPSZNFUIPEAQSJWBUFTUBUJD fi OBM HFU-BNCEBA w ίϯετϥΫλύϥϝλ͕͋Δ৔߹ɺͦΕΛ֨ೲ͢Δϑ Οʔϧυ w 4".ΠϯλʔϑΣʔε༻ͷϝιου w ࣮ߦͨ͠ࡍɺMBNCEBຊମʢQSJWBUFTUBUJD NBJOMBNCEB Λ࣮ߦ͢Δ w Ϋϥεϩʔμʹొ࿥ʂ TQJO*OOFS$MBTT ͷ࣮૷
  68. private void generateConstructor() { // Generate constructor MethodVisitor ctor =

    cw.visitMethod(ACC_PRIVATE, NAME_CTOR, constructorType.toMethodDescriptorString(), null, null); ctor.visitCode(); ctor.visitVarInsn(ALOAD, 0); ctor.visitMethodInsn(INVOKESPECIAL, JAVA_LANG_OBJECT, NAME_CTOR, METHOD_DESCRIPTOR_VOID, false); int parameterCount = invokedType.parameterCount(); for (int i = 0, lvIndex = 0; i < parameterCount; i++) { ctor.visitVarInsn(ALOAD, 0); Class<?> argType = invokedType.parameterType(i); ctor.visitVarInsn(getLoadOpcode(argType), lvIndex + 1); lvIndex += getParameterSize(argType); ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argDescs[i]); } ctor.visitInsn(RETURN); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored ctor.visitMaxs(-1, -1); ctor.visitEnd(); } w ίϯετϥΫλϝιουΛੜ੒ w ҎԼͷΠϯετϥΫγϣϯΛੜ੒ w 4VQFSDMBTT KBWBMBOH0CKFDU ͷί ϯετϥΫλΛJOWPLFTUBUJDͰ࣮ߦ w Ҿ਺ʢʹΫϩʔδϟม਺ͷ਺ʣͩ ͚ɺϑΟʔϧυม਺΁ϩʔυ TQJO*OOFS$MBTT ͷ࣮૷ HFOFSBUF$POTUSVDUPS
  69. private void generateConstructor() { // Generate constructor MethodVisitor ctor =

    cw.visitMethod(ACC_PRIVATE, NAME_CTOR, constructorType.toMethodDescriptorString(), null, null); ctor.visitCode(); ctor.visitVarInsn(ALOAD, 0); ctor.visitMethodInsn(INVOKESPECIAL, JAVA_LANG_OBJECT, NAME_CTOR, METHOD_DESCRIPTOR_VOID, false); int parameterCount = invokedType.parameterCount(); for (int i = 0, lvIndex = 0; i < parameterCount; i++) { ctor.visitVarInsn(ALOAD, 0); Class<?> argType = invokedType.parameterType(i); ctor.visitVarInsn(getLoadOpcode(argType), lvIndex + 1); lvIndex += getParameterSize(argType); ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argDescs[i]); } ctor.visitInsn(RETURN); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored ctor.visitMaxs(-1, -1); ctor.visitEnd(); } w ίϯετϥΫλϝιουΛੜ੒ w ҎԼͷΠϯετϥΫγϣϯΛੜ੒ w 4VQFSDMBTT KBWBMBOH0CKFDU ͷί ϯετϥΫλΛJOWPLFTUBUJDͰ࣮ߦ w Ҿ਺ʢʹΫϩʔδϟม਺ͷ਺ʣͩ ͚ɺϑΟʔϧυม਺΁ϩʔυ TQJO*OOFS$MBTT ͷ࣮૷ HFOFSBUF$POTUSVDUPS
  70. private void generateFactory() { MethodVisitor m = cw.visitMethod(ACC_PRIVATE | ACC_STATIC,

    NAME_FACTORY, invokedType.toMethodDescriptorString(), null, null); m.visitCode(); m.visitTypeInsn(NEW, lambdaClassName); m.visitInsn(Opcodes.DUP); int parameterCount = invokedType.parameterCount(); for (int typeIndex = 0, varIndex = 0; typeIndex < parameterCount; typeIndex++) { Class<?> argType = invokedType.parameterType(typeIndex); m.visitVarInsn(getLoadOpcode(argType), varIndex); varIndex += getParameterSize(argType); } m.visitMethodInsn(INVOKESPECIAL, lambdaClassName, NAME_CTOR, constructorType.toMethodDescriptorString(), false); m.visitInsn(ARETURN); m.visitMaxs(-1, -1); m.visitEnd(); } TQJO*OOFS$MBTT ͷ࣮૷ HFOFSBUF'BDUPSZ w ϑΝΫτϦϝιουΛੜ੒ w ϝιου໊ /".&@'"$503:HFU-BNCEB w ҎԼͷΠϯετϥΫγϣϯΛੜ੒ w ΠϯελϯεԽ w Ҿ਺ʢϩʔΧϧม਺ʣΛΦϖϥϯυʹϩʔυ w ίϯετϥΫλΛJOWPLFTQFDJBMͰ࣮ߦ
  71. private void generateFactory() { MethodVisitor m = cw.visitMethod(ACC_PRIVATE | ACC_STATIC,

    NAME_FACTORY, invokedType.toMethodDescriptorString(), null, null); m.visitCode(); m.visitTypeInsn(NEW, lambdaClassName); m.visitInsn(Opcodes.DUP); int parameterCount = invokedType.parameterCount(); for (int typeIndex = 0, varIndex = 0; typeIndex < parameterCount; typeIndex++) { Class<?> argType = invokedType.parameterType(typeIndex); m.visitVarInsn(getLoadOpcode(argType), varIndex); varIndex += getParameterSize(argType); } m.visitMethodInsn(INVOKESPECIAL, lambdaClassName, NAME_CTOR, constructorType.toMethodDescriptorString(), false); m.visitInsn(ARETURN); m.visitMaxs(-1, -1); m.visitEnd(); } w ϑΝΫτϦϝιουΛੜ੒ w ϝιου໊ /".&@'"$503:HFU-BNCEB w ҎԼͷΠϯετϥΫγϣϯΛੜ੒ w ΠϯελϯεԽ w Ҿ਺ʢϩʔΧϧม਺ʣΛΦϖϥϯυʹϩʔυ w ίϯετϥΫλΛJOWPLFTQFDJBMͰ࣮ߦ TQJO*OOFS$MBTT ͷ࣮૷ HFOFSBUF'BDUPSZ
  72. void generate(MethodType methodType) { visitCode(); if (implKind == MethodHandleInfo.REF_newInvokeSpecial) {

    visitTypeInsn(NEW, implMethodClassName); visitInsn(DUP); } for (int i = 0; i < argNames.length; i++) { visitVarInsn(ALOAD, 0); visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]); } convertArgumentTypes(methodType); // Invoke the method we want to forward to visitMethodInsn(invocationOpcode(), implMethodClassName, implMethodName, implMethodDesc, implClass.isInterface()); // Convert the return value (if any) and return it // Note: if adapting from non-void to void, the 'return' // instruction will pop the unneeded result Class<?> implReturnClass = implMethodType.returnType(); Class<?> samReturnClass = methodType.returnType(); convertType(implReturnClass, samReturnClass, samReturnClass); visitInsn(getReturnOpcode(samReturnClass)); // Maxs computed by ClassWriter.COMPUTE_MAXS,these arguments ignored visitMaxs(-1, -1); visitEnd(); } w 4".ͷ࣮૷Λੜ੒ w ͜͜Ͱ͸BQQMZ JOU  w ҎԼͷΠϯετϥΫγϣϯΛੜ੒ w -BNCEB'PSN)JEEFOΞϊςʔγϣϯΛ෇༩ w 4UBDL5SBDFʹදࣔ͞Εͳ͍ w ϑΟʔϧυBSH/͔Β஋Λϩʔυ w ίϯετϥΫλҾ਺Ͱ౉͞Εͨ஋Ϋϩʔδϟ w Ҿ਺ʢϩʔΧϧม਺ʣΛΦϖϥϯυελοΫʹϩʔ υ w 4".ͱ-BNCEBຊମͷҾ਺ܕͷҧ͍ΛνΣοΫ w JOWPLFTUBUJDͰ-BNCEBຊମϝιουΛ࣮ߦʂʂ TQJO*OOFS$MBTT ͷ࣮૷ 'PSXBSEJOH.FUIPE(FOFSBUPSHFOFSBUF // Forward the SAM method MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName, samMethodType.toMethodDescriptorString(), null, null); mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true); new ForwardingMethodGenerator(mv).generate(samMethodType);
  73. void generate(MethodType methodType) { visitCode(); if (implKind == MethodHandleInfo.REF_newInvokeSpecial) {

    visitTypeInsn(NEW, implMethodClassName); visitInsn(DUP); } for (int i = 0; i < argNames.length; i++) { visitVarInsn(ALOAD, 0); visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]); } convertArgumentTypes(methodType); // Invoke the method we want to forward to visitMethodInsn(invocationOpcode(), implMethodClassName, implMethodName, implMethodDesc, implClass.isInterface()); // Convert the return value (if any) and return it // Note: if adapting from non-void to void, the 'return' // instruction will pop the unneeded result Class<?> implReturnClass = implMethodType.returnType(); Class<?> samReturnClass = methodType.returnType(); convertType(implReturnClass, samReturnClass, samReturnClass); visitInsn(getReturnOpcode(samReturnClass)); // Maxs computed by ClassWriter.COMPUTE_MAXS,these arguments ignored visitMaxs(-1, -1); visitEnd(); } TQJO*OOFS$MBTT ͷ࣮૷ 'PSXBSEJOH.FUIPE(FOFSBUPSHFOFSBUF // Forward the SAM method MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName, samMethodType.toMethodDescriptorString(), null, null); mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true); new ForwardingMethodGenerator(mv).generate(samMethodType); w 4".ͷ࣮૷Λੜ੒ w ͜͜Ͱ͸BQQMZ JOU  w ҎԼͷΠϯετϥΫγϣϯΛੜ੒ w -BNCEB'PSN)JEEFOΞϊςʔγϣϯΛ෇༩ w 4UBDL5SBDFʹදࣔ͞Εͳ͍ w ϑΟʔϧυBSH/͔Β஋Λϩʔυ w ίϯετϥΫλҾ਺Ͱ౉͞Εͨ஋Ϋϩʔδϟ w Ҿ਺ʢϩʔΧϧม਺ʣΛΦϖϥϯυελοΫʹϩʔ υ w 4".ͱ-BNCEBຊମͷҾ਺ܕͷҧ͍ΛνΣοΫ w JOWPLFTUBUJDͰ-BNCEBຊମϝιουΛ࣮ߦʂʂ
  74. 5JQT#4.͕࡞੒͢Δ$MBTTΛϑΝΠϧʹు͘ .FDIBOJTNUPEVNQHFOFSBUFEMBNCEB DMBTTFTMPHMBNCEBDPEFHFOFSBUJPO // For dumping generated classes to disk,

    for debugging purposes private static final ProxyClassesDumper dumper; static { final String dumpProxyClassesKey = "jdk.internal.lambda.dumpProxyClasses"; String dumpPath = GetPropertyAction.privilegedGetProperty(dumpProxyClassesKey); dumper = (null == dumpPath) ? null : ProxyClassesDumper.getInstance(dumpPath); : private Class<?> spinInnerClass() throws LambdaConversionException { : if (dumper != null) { AccessController.doPrivileged(new PrivilegedAction<>() { @Override public Void run() { dumper.dumpClass(lambdaClassName, classBytes); return null; } }, null, new FilePermission("<<ALL FILES>>", "read, write"), // createDirectories may need it new PropertyPermission("user.dir", "read")); } *OOFS$MBTT-BNCEB.FUBGBDUPSZKBWB ❯ java -Djdk.internal.lambda.dumpProxyClasses=./ InvokeDynamicComplicated ❯ javap -v -p -s -constants 'InvokeDynamicComplicated$$Lambda$1.class' w KELJOUFSOBMMBNCEBEVNQ1SP YZ$MBTTFTΦϓγϣϯͰࢦఆͨ͠ σΟϨΫτϦʹɺ *OOFS$MBTT-BNCEB.FUBGBDUPSZ ͕ੜ੒͢ΔΫϥεΛϑΝΠϧʹు͘ w +BWBίϚϯυ࣮ߦޙʹϑΝΠϧ ͕ੜ੒͞ΕΔ
  75. 5JQT#4.͕࡞੒͢Δ$MBTTΛϑΝΠϧʹు͘ final class InvokeDynamicComplicated$$Lambda$1 implements java.util.function.Function : flags: (0x1030) ACC_FINAL,

    ACC_SUPER, ACC_SYNTHETIC { private final long arg$1; descriptor: J flags: (0x0012) ACC_PRIVATE, ACC_FINAL private InvokeDynamicComplicated$$Lambda$1(long); descriptor: (J)V flags: (0x0002) ACC_PRIVATE Code: stack=3, locals=3, args_size=2 0: aload_0 1: invokespecial #13 // Method java/lang/ Object."<init>":()V 4: aload_0 5: lload_1 6: putfield #15 // Field arg$1:J 9: return } த਎Λ೷͍ͯΈΔ w 'VODJUPO*OUFSGBDFΛ࣮૷ͨ͠ fi OBMDMBTT w MPOHBSHϑΟʔϧυ w MPOHҾ਺ΛऔΔQSJWBUFDPOTUSVDUPS w Ҿ਺MPOHΛϑΟʔϧυBSHʹηοτ͢ Δ ACC_SUPER The ACC_SUPER flag exists for backward compatibility with code compiled by older compilers for the Java programming language. In JDK releases prior to 1.0.2, the compiler generated access_flags in which the flag now representing ACC_SUPER had no assigned meaning, and Oracle's Java Virtual Machine implementation ignored the flag if it was set. ACC_SYNTHETIC The ACC_SYNTHETIC flag indicates that this class or interface was generated by a compiler and does not appear in source code. Table 4.1-B. Class access and property modifiers *OWPLF%ZOBNJD$PNQMJDBUFE-BNCEBKBWB
  76. 5JQT#4.͕࡞੒͢Δ$MBTTΛϑΝΠϧʹు͘ final class InvokeDynamicComplicated$$Lambda$1 implements java.util.function.Function : flags: (0x1030) ACC_FINAL,

    ACC_SUPER, ACC_SYNTHETIC { private final long arg$1; descriptor: J flags: (0x0012) ACC_PRIVATE, ACC_FINAL private InvokeDynamicComplicated$$Lambda$1(long); descriptor: (J)V flags: (0x0002) ACC_PRIVATE Code: stack=3, locals=3, args_size=2 0: aload_0 1: invokespecial #13 // Method java/lang/ Object."<init>":()V 4: aload_0 5: lload_1 6: putfield #15 // Field arg$1:J 9: return } த਎Λ೷͍ͯΈΔ w 'VODJUPO*OUFSGBDFΛ࣮૷ͨ͠ fi OBMDMBTT w MPOHBSHϑΟʔϧυ w MPOHҾ਺ΛऔΔQSJWBUFDPOTUSVDUPS w Ҿ਺MPOHΛϑΟʔϧυBSHʹηοτ͢ Δ ACC_SUPER The ACC_SUPER flag exists for backward compatibility with code compiled by older compilers for the Java programming language. In JDK releases prior to 1.0.2, the compiler generated access_flags in which the flag now representing ACC_SUPER had no assigned meaning, and Oracle's Java Virtual Machine implementation ignored the flag if it was set. ACC_SYNTHETIC The ACC_SYNTHETIC flag indicates that this class or interface was generated by a compiler and does not appear in source code. Table 4.1-B. Class access and property modifiers *OWPLF%ZOBNJD$PNQMJDBUFE-BNCEBKBWB
  77. 5JQT#4.͕࡞੒͢Δ$MBTTΛϑΝΠϧʹు͘ w ϑΝΫτϦϝιουHFU-BNCEB w ࣗ਎ͷΠϯελϯεΛ࡞੒͢Δ w 'VODUJPO*OUFSGBDFͷ BQQMZϝιουͷ࣮૷ w ϑΟʔϧυBSHͷ֨ೲ஋ͱɺϝιουࣗ

    ମͷҾ਺ΛΦϖϥϯυελοΫʹੵΉ w JOWPLFTUBUJDͰΦϦδφϧΫϥεͷ MBNCEBNBJO Λ࣮ߦʂ private static java.util.function.Function get$Lambda(long); descriptor: (J)Ljava/util/function/Function; flags: (0x000a) ACC_PRIVATE, ACC_STATIC Code: stack=4, locals=2, args_size=1 0: new #2 // class InvokeDynamicComplicated$$Lambda$1 3: dup 4: lload_0 5: invokespecial #19 // Method "<init>":(J)V 8: areturn public java.lang.Object apply(java.lang.Object); descriptor: (Ljava/lang/Object;)Ljava/lang/Object; flags: (0x0001) ACC_PUBLIC Code: stack=3, locals=2, args_size=2 0: aload_0 1: getfield #15 // Field arg$1:J 4: aload_1 5: checkcast #24 // class java/lang/Integer 8: invokestatic #30 // Method InvokeDynamicComplicated.lambda$main$0:(JLjava/lang/Integer;)Ljava/lang/ Double; 11: areturn RuntimeVisibleAnnotations: 0: #22() java.lang.invoke.LambdaForm$Hidden த਎Λ೷͍ͯΈΔ
  78. 5JQT#4.͕࡞੒͢Δ$MBTTΛϑΝΠϧʹు͘ w ϑΝΫτϦϝιουHFU-BNCEB w ࣗ਎ͷΠϯελϯεΛ࡞੒͢Δ w 'VODUJPO*OUFSGBDFͷ BQQMZϝιουͷ࣮૷ w ϑΟʔϧυBSHͷ֨ೲ஋ͱɺϝιουࣗ

    ମͷҾ਺ΛΦϖϥϯυελοΫʹੵΉ w JOWPLFTUBUJDͰΦϦδφϧΫϥεͷ MBNCEBNBJO *OU %PVCMFΛ࣮ߦʂ private static java.util.function.Function get$Lambda(long); descriptor: (J)Ljava/util/function/Function; flags: (0x000a) ACC_PRIVATE, ACC_STATIC Code: stack=4, locals=2, args_size=1 0: new #2 // class InvokeDynamicComplicated$$Lambda$1 3: dup 4: lload_0 5: invokespecial #19 // Method "<init>":(J)V 8: areturn public java.lang.Object apply(java.lang.Object); descriptor: (Ljava/lang/Object;)Ljava/lang/Object; flags: (0x0001) ACC_PUBLIC Code: stack=3, locals=2, args_size=2 0: aload_0 1: getfield #15 // Field arg$1:J 4: aload_1 5: checkcast #24 // class java/lang/Integer 8: invokestatic #30 // Method InvokeDynamicComplicated.lambda$main$0:(JLjava/lang/Integer;)Ljava/lang/ Double; 11: areturn RuntimeVisibleAnnotations: 0: #22() java.lang.invoke.LambdaForm$Hidden த਎Λ೷͍ͯΈΔ TQJO*OOFS$MBTT ͷॲཧͱಉ౳Ͱ͋Δ͜ͱ͕֬ೝͰ͖ͨ🙌
  79. -BNCEBͷੜ੒JOWPLFEZOBNJD͕ݺ͹ΕΔͱʜ public static CallSite metafactory(MethodHandles.Lookup caller, String invokedName, MethodType invokedType,

    MethodType samMethodType, MethodHandle implMethod, MethodType instantiatedMethodType) throws LambdaConversionException { } package invoke.dynamic; import java.util.function.Function; public class InvokeDynamicComplicated { public static void main(String[] args) { long l = 10L; Function<Integer, Double> f = (i) -> (double)i / (double)l; f.apply(1); } } @FunctionalInterface public interface Function<T, R> { R apply(T t); -BNCEB.FUBGBDUPSZKBWB 0: #23 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:( Ljava/lang/invoke/MethodHandles$Lookup; // MethodHandles.lookup() Ljava/lang/String; // apply Ljava/lang/invoke/MethodType; // (J)Ljava/util/function/Function; Ljava/lang/invoke/MethodType; // (Ljava/lang/Object;)Ljava/lang/Object; Ljava/lang/invoke/MethodHandle; // InvokeDynamicComplicated.lambda$main$0: (JLjava/lang/Integer;)Ljava/lang/Double; Ljava/lang/invoke/MethodType; // (Ljava/lang/Integer;)Ljava/lang/Double; )Ljava/lang/invoke/CallSite; #PPU4USBQ.FUIPE #4. Λϩʔυ͢Δ #4.͸-BNCEB.FUBGBDUPSZNFUBGBDUPSZΛJOWPLFTUBUJDͰ࣮ߦ͠ɺ$BMM4JUFΛฦ͢ w*OWPLF%ZOBNJD$PNQMFDBUFE-BNCEB/ΫϥεΛੜ੒͢Δ $BMM4JUFʹόϯυϧ͞Εͨ.FUIPE)BOEMFSΛJOWPLFWJSUVBMͰ࣮ߦ͢Δ w'VODUJPOJOUFSGBDFΛ࣮૷ͨ͠*OWPLF%ZOBNJD$PNQMFDBUFE-BNCEB/ΫϥεͷΠϯελϯεΛಘΔ $BMM4JUF͔Βฦ͖ͬͯͨΠϯελϯεͷBQQMZϝιουΛ࣮ߦ͠ɺ-BNCEBຊମΛJOWPLFTUBUJDͰ࣮ߦ͢Δʂʂʂ
  80. 3FGFSFODFT • Sample Code: https://github.com/ikuo-suyama/JVMDeepDive • Javaʹ͓͚Δϝιουݺग़͠ͷ࢓૊Έ • JavaͰͷinvokedynamicʹΑΔϝιουݺग़͠Λཧղ͢Δ •

    invokedynamicͷਆൿΛղ͘ ύʔτ̍ • invokedynamic ͷਆൿΛղ͘ ύʔτ̎ • The Java® Virtual Machine Speci fi cation • An Introduction to the Constant Pool in the JVM • Openjdk package java.lang.invoke