Hi Raffaello, The code snippet I posted previously was not the original test I verified on Java 17 (which was generated via asmtools to trigger verification)
Here's the pretty much the test I used: Test_1.java import java.lang.invoke.*; public class Test_1 { static MethodHandle mh; static { try { mh = MethodHandles.lookup().findStatic(Test_2.class, "testMethod", MethodType.methodType(int[].class)); } catch (NoSuchMethodException | IllegalAccessException e) { e.printStackTrace(); } } public static void main(String[] args) throws Throwable { //Test_1.mh.invoke(); } } Test_2.jasm super public class Test_2 version 52:0 { static Method "<clinit>":"()V" stack 5 locals 12 { bipush -2; istore 7; iload 7; sipush 997; if_icmplt L127; iconst_0; istore 8; L127: stack_frame_type full; locals_map int, class "[B", class "[B", class "[Ljava/lang/Class;", class "[I", class "[I", class "[I", int, bogus, bogus, float, float; iload 8; istore 8; return; } public Method "<init>":"()V" stack 1 locals 1 { aload_0; invokespecial Method java/lang/Object."<init>":"()V"; return; } static Method testMethod:"()[I" stack 6 locals 1 { getstatic Field testArray:"[I"; areturn; } } // end Class Test_2 Jdk17/bin/java -jar asmtools.jar jasm Test_2.jasm // create the .class file of Test_2 Jdk17/bin/java Test_1 java.lang.IllegalAccessException: no such method: Test_2.testMethod()int[]/invokeStatic at java.base/java.lang.invoke.MemberName.makeAccessException(MemberName.java:972) at java.base/java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:1117) at java.base/java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:3649) at java.base/java.lang.invoke.MethodHandles$Lookup.findStatic(MethodHandles.java:2588) at Test_1.<clinit>(Test_1.java:9) Caused by: java.lang.VerifyError: Inconsistent stackmap frames at branch target 15 Exception Details: Location: Test_2.<clinit>()V @15: iload Reason: Type top (current frame, locals[0]) is not assignable to integer (stack map, locals[0]) Current Frame: bci: @9 flags: { } locals: { top, top, top, top, top, top, top, integer } stack: { integer, integer } Stackmap Frame: bci: @15 flags: { } locals: { integer, '[B', '[B', '[Ljava/lang/Class;', '[I', '[I', '[I', integer, top, top, float, float } stack: { } Bytecode: 0000000: 10fe 3607 1507 1103 e5a1 0006 0336 0815 0000010: 0836 08b1 Stackmap Table: full_frame(@15,{Integer,Object[#11],Object[#11],Object[#20],Object[#5],Object[#5],Object[#5],Integer,Top,Top,Float,Float},{}) at java.base/java.lang.invoke.MethodHandleNatives.resolve(Native Method) at java.base/java.lang.invoke.MemberName$Factory.resolve(MemberName.java:1085) at java.base/java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:1114) ... 3 more -------- Test_2 was intentionally modified to throw VerifyError if initialized. As you see above, mh.inovke() was commented out in Test_1.main() but the Test_2 was still verified in the test. So it is impossible to verify Test_2 if it is not initialized, which only means Test_2 is initialized during the lookup.findstatic rather than mh.invoke(). Best Regards Cheng ----- Original Message ----- > From: "Cheng Jin" <jinch...@ca.ibm.com> > To: "core-libs-dev" <core-libs-dev@openjdk.java.net> > Sent: Thursday, March 17, 2022 5:42:57 PM > Subject: When to initialize the method's class for > MethodHandles.Lookup.findStatic()? > Hi there, > > The document of > INVALID URI REMOVED > n_java_javase_17_docs_api_java.base_java_lang_invoke_MethodHandles.Loo > kup.html-23findStatic-28java.lang.Class-2Cjava.lang.String-2Cjava.lang > .invoke.MethodType-29&d=DwIFaQ&c=jf_iaSHvJObTbx-siA1ZOg&r=X90f3XIRXAH8 > hbNam6bIUlWfF_qUAezL9ue7M7bFuPQ&m=Xt-10pHYoPWnY6dByKowR4yeLtEs7kZkKUgt > bxKUGvM&s=dPAMGMxphLLXT9N4ZdukiNvWyvRPAGkcGCBLTy_sm0c&e= > in the Java API is ambiguous in terms of when to initialize the > method's class as follows (the same description as in other OpenJDK > versions) > > If the returned method handle is invoked, the method's class will be > initialized, if it has not already been initialized. > > > It occurs to me that the method's class should be initialized when > invoking the method handle but OpenJDK actually chooses to do the > initialization in > lookup.findStatic() rather than in mh.invoke() e.g. > import java.lang.invoke.*; > > public class Test_1 { > static MethodHandle mh = MethodHandles.lookup().findStatic(Test_2.class, > "testMethod", MethodType.methodType(int.class, int.class)); <----------- > Test_2.class gets initialized and verified. > > public static void main(String[] args) throws Throwable { > Test_1.mh.invoke(); > } > } > > public class Test_2 { > static int testMethod(int value) { return (value + 1); } } > > So there should be more clear explanation what is the correct or > expected behaviour at this point and why OpenJDK doesn't comply with > the document to delay the initialization of the method's class to mh.invoke(). Hi, if by initialization you mean running the static block, then it's a bug. As far as i remember, the JVMS spec cleanly separate the Linking exceptions from the Runtime exceptions. https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-6.html#jvms-6.5.invokestatic The linking exceptions occurs when calling findStatic() while the runtime exceptions will appear at runtime when calling invokeExact()/invoke(). > > Best Regards > Cheng Jin regards, Rémi