When to initialize the method's class for MethodHandles.Lookup.findStatic()?

Raffaello Giulietti raffaello.giulietti at gmail.com
Fri Mar 18 00:34:35 UTC 2022


Cheng,

initialization is the last thing that happens because it's where user 
provided code gets executed.

This has always been this way, as long as I can remember. See the JVMS 
for the gory details.


Greetings
Raffaello


On 2022-03-18 01:21, Cheng Jin wrote:
> Hi David,
> 
> 1) for the test with mh.invoke() in main(),  the log shows:
> [0.262s][info][class,init] Start class verification for: Test_1
> [0.262s][info][class,init] End class verification for: Test_1
> [0.263s][info][class,init] 282 Initializing 'Test_1' (0x0000000800c00800)
> [0.263s][info][class,init] Start class verification for: Test_2
> [0.263s][info][class,init] End class verification for: Test_2
> [0.272s][info][class,init] 366 Initializing 'Test_2' (0x0000000800c00a08) <------
> 
> 2) for the test without  mh.invoke() in main(),  the log shows:
> [0.296s][info][class,init] Start class verification for: Test_1
> [0.296s][info][class,init] End class verification for: Test_1
> [0.297s][info][class,init] 282 Initializing 'Test_1' (0x0000000800c00800)
> [0.297s][info][class,init] Start class verification for: Test_2
> [0.297s][info][class,init] End class verification for: Test_2
> (Test_2 was verified but didn't get initialized)
> 
> The comparison above literally surprised me that the bytecode verification happened prior to the class initialization, which means
> the class got verified at first even without initialization coz I previously thought the initialization should trigger the verification rather than in the reversed order.
> 
> Could you explain a little more about why it goes in this way?
> 
> Best Regards
> Cheng
> 
> 
> -----Original Message-----
> From: core-libs-dev <core-libs-dev-retn at openjdk.java.net> On Behalf Of David Holmes
> Sent: March 17, 2022 7:46 PM
> To: Raffaello Giulietti <raffaello.giulietti at gmail.com>; core-libs-dev at openjdk.java.net
> Subject: [EXTERNAL] Re: When to initialize the method's class for MethodHandles.Lookup.findStatic()?
> 
> Run with -Xlog:class+init=info to see the classes that get initialized and in what order.
> 
> David
> 
> On 18/03/2022 5:53 am, Raffaello Giulietti wrote:
>> Hi again,
>>
>> here's code that shows that initialization doesn't happen during
>> lookup but only upon invoking the method handle. (I'm on Java 17.)
>>
>> As long as the 2nd line in main() is commented, you don't see the
>> message "Test_2 initialized", which shows that the lookup doesn't
>> initialize Test_2.
>> When you uncomment the line in main(), the message will appear.
>>
>> So, as advertised, it's the invocation of the method handle that can
>> trigger initialization, not the lookup.
>>
>>
>> HTH
>> Raffaello
>>
>> ----
>>
>> 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, int.class));
>>           } catch (NoSuchMethodException | IllegalAccessException e) {
>>               e.printStackTrace();
>>           }
>>       }
>>
>>       public static void main(String[] args) throws Throwable {
>>           System.out.println(mh);
>>           // System.out.println(Test_1.mh.invoke(0));
>>       }
>>
>> }
>>
>>
>>
>>
>> public class Test_2 {
>>
>>       static {
>>           System.out.println("Test_2 initialized");
>>       }
>>
>>       static int testMethod(int value) { return (value + 1); }
>>
>> }
>>
>>
>>
>>
>> On 2022-03-17 20:38, Raffaello Giulietti wrote:
>>> Hi,
>>>
>>> as far as I can see, the code should not even compile, as there's a
>>> static field in Test_1 which is initialized with an expression that
>>> throws checked exceptions (findStatic(..)).
>>>
>>> In addition, it seems to me that there's nothing in your code that
>>> reveals whether Test_2 has been initialized during the lookup. How
>>> can you tell?
>>>
>>> Finally, the method handle invocation in Test_1 will throw, as you
>>> don't pass any argument to a handle that expects one.
>>>
>>> Can you perhaps add more details?
>>>
>>>
>>> Greetings
>>> Raffaello
>>>
>>>
>>>
>>> On 2022-03-17 17:42, Cheng Jin wrote:
>>>> Hi there,
>>>>
>>>> The document of
>>>> INVALID URI REMOVED
>>>> _en_java_javase_17_docs_api_java.base_java_lang_invoke_MethodHandles
>>>> .Lookup.html-23findStatic-28java.lang.Class-2Cjava.lang.String-2Cjav
>>>> a.lang.invoke.MethodType-29&d=DwIDaQ&c=jf_iaSHvJObTbx-siA1ZOg&r=X90f
>>>> 3XIRXAH8hbNam6bIUlWfF_qUAezL9ue7M7bFuPQ&m=RvhguidNJ90V-HK-3Ctl-kUZE5
>>>> cIfo_nt3_r8VZ0Fcc&s=tw_ph6oUkS0eCvzITWi9zEkarss5yNeHDrAIfvd3s3g&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().
>>>>
>>>> Best Regards
>>>> Cheng Jin


More information about the core-libs-dev mailing list