When to initialize the method's class for MethodHandles.Lookup.findStatic()?
Raffaello Giulietti
raffaello.giulietti at gmail.com
Fri Mar 18 00:20:43 UTC 2022
Hi Cheng,
I'm not sure I understand your point. By class initialization I mean
what's specified in the JVMS [1].
Are you concerned with initialization or with verification (which
precedes initialization)?
Raffaello
----
[1] https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-5.html#jvms-5.5
On 2022-03-18 00:02, Cheng Jin wrote:
> 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" <jincheng at ca.ibm.com>
>> To: "core-libs-dev" <core-libs-dev at 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
More information about the core-libs-dev
mailing list