Re: [External] : Re: Classes used in method body are loaded lazily or eagerly depending on method return type

2023-05-26 Thread Raffaello Giulietti

My bad.

In the modifications of the original code, I proposed to replace

URL classFileB = 
TestLoading.class.getResource(TestLoading.class.getSimpleName() + 
"$ChildClass.class");


with

URL classFileB = 
TestLoading.class.getResource(ChildClass.class.getSimpleName() + ".class");


However, this loads ChildClass just a few lines *before* it is removed 
from the filesystem, so later uses of the class in the same run, in 
particular during verification of method BaseClassReturner.getObject(), 
are immune to the removal.


Replacing with

URL classFileB = 
TestLoading.class.getResource(TestLoading.class.getPackageName() + 
"ChildClass.class");


will remove the class without loading it, and will later throw, as in 
the original setup.



Sorry for the noise
Raffaello



On 2023-05-26 08:10, David Holmes wrote:

On 25/05/2023 7:21 pm, Raffaello Giulietti wrote:


Yes, ChildClass.class is removed from the filesystem.


And here's, the relevant info when running with -Xlog:class+init, 
showing that verification succeeds for both TestLoading$ObjectReturner 
and TestLoading$BaseClassReturner:


loading: TestLoading$ObjectReturner...
[0.039s][info][class,init] Start class verification for: 
TestLoading$ObjectReturner
[0.039s][info][class,init] End class verification for: 
TestLoading$ObjectReturner
[0.039s][info][class,init] 500 Initializing 
'TestLoading$ObjectReturner'(no method) (0x000801001800)

loading: TestLoading$BaseClassReturner...
[0.039s][info][class,init] Start class verification for: 
TestLoading$BaseClassReturner
[0.039s][info][class,init] End class verification for: 
TestLoading$BaseClassReturner
[0.039s][info][class,init] 501 Initializing 
'TestLoading$BaseClassReturner'(no method) (0x000801001a08)


Can you enable -xlog:verification and class+load too please.

Thanks,
David
-





On 2023-05-25 04:57, David Holmes wrote:

On 25/05/2023 12:34 am, Raffaello Giulietti wrote:
As mentioned in my previous email, if you move the member class 
ChildClass out of TestLoading (out of the nest), and make it a 
top-level class like


 public class ChildClass extends TestLoading.BaseClass {
 }

and change

 URL classFileB = 
TestLoading.class.getResource(TestLoading.class.getSimpleName() + 
"$ChildClass.class");


to

 URL classFileB = 
TestLoading.class.getResource(ChildClass.class.getSimpleName() + 
".class");


rebuild everything and run, nothing is thrown.

 deleting: /ChildClass.class
 loading: TestLoading$ObjectReturner...
 loading: TestLoading$BaseClassReturner...

I can't see any substantial difference, except that the nest rooted 
at TestLoading lacks a member in the original setup and lacks 
nothing in this setup.


What's an explanation for this difference?


Are you sure it actually deletes the file? What do you see when you 
enable class+load/init and verification logging?


David
-





Greetings
Raffaello


On 2023-05-24 00:35, Remi Forax wrote:



- Original Message -

From: "David Holmes" 
To: "Raffaello Giulietti" , 
"core-libs-dev" 

Sent: Wednesday, May 24, 2023 12:23:24 AM
Subject: Re: Classes used in method body are loaded lazily or 
eagerly depending on method return type



On 24/05/2023 12:50 am, Raffaello Giulietti wrote:

I think the problem here is that you are deleting a class in a nest.

During the verification of BaseClassReturner.getObject(), access 
control

(JVMS, 5.4.4, second half) determines that the nest is broken, as
ChildClass is not present anymore.


Not sure access control gets involved at this stage of the 
verification

process. But in any case turning on logging does not show anything
related to nestmates happening between BaseClass and ChildClass. It
seems to just be the resolution of the return type during 
verification
of the method, that causes the loading of ChildClass and the 
subsequent

CNFE if it has been removed.

If you move ChildClass out of TestLoading so that it becomes a 
top-level
class extending TestLoading.BaseClass, and if you adapt the line 
that
initializes the local var classFileB to refer to the new 
location, the

code will not throw, despite ChildClass being deleted.


My simplified test shows it still throws when verifying 
BaseClassReturner.


Nestmate checking is done lazily, so if you do not call a 
method/access a field of a nested class, the VM should not trigger 
a class loading.


Moreover, if you test with Java 8 (nestmates were introduced in 
Java 11), it failed too.
That's another clue that the error is not related to nestmates 
checking.





Cheers,
David


regards,
Rémi





Greetings
Raffaello



On 2023-05-23 13:20, Сергей Цыпанов wrote:

Hello,

originally this question was asked here:
https://urldefense.com/v3/__https://stackoverflow.com/q/76260269/12473843__;!!ACWV5N9M2RV99hQ!Mb5nhj7EbuftWzF7s4GX9auUZZlyPyCUnLs64c4mkmSGJm4pw0CNgRzQR5wOY

Re: [External] : Re: Classes used in method body are loaded lazily or eagerly depending on method return type

2023-05-25 Thread David Holmes

On 25/05/2023 7:21 pm, Raffaello Giulietti wrote:


Yes, ChildClass.class is removed from the filesystem.


And here's, the relevant info when running with -Xlog:class+init, 
showing that verification succeeds for both TestLoading$ObjectReturner 
and TestLoading$BaseClassReturner:


loading: TestLoading$ObjectReturner...
[0.039s][info][class,init] Start class verification for: 
TestLoading$ObjectReturner
[0.039s][info][class,init] End class verification for: 
TestLoading$ObjectReturner
[0.039s][info][class,init] 500 Initializing 
'TestLoading$ObjectReturner'(no method) (0x000801001800)

loading: TestLoading$BaseClassReturner...
[0.039s][info][class,init] Start class verification for: 
TestLoading$BaseClassReturner
[0.039s][info][class,init] End class verification for: 
TestLoading$BaseClassReturner
[0.039s][info][class,init] 501 Initializing 
'TestLoading$BaseClassReturner'(no method) (0x000801001a08)


Can you enable -xlog:verification and class+load too please.

Thanks,
David
-





On 2023-05-25 04:57, David Holmes wrote:

On 25/05/2023 12:34 am, Raffaello Giulietti wrote:
As mentioned in my previous email, if you move the member class 
ChildClass out of TestLoading (out of the nest), and make it a 
top-level class like


 public class ChildClass extends TestLoading.BaseClass {
 }

and change

 URL classFileB = 
TestLoading.class.getResource(TestLoading.class.getSimpleName() + 
"$ChildClass.class");


to

 URL classFileB = 
TestLoading.class.getResource(ChildClass.class.getSimpleName() + 
".class");


rebuild everything and run, nothing is thrown.

 deleting: /ChildClass.class
 loading: TestLoading$ObjectReturner...
 loading: TestLoading$BaseClassReturner...

I can't see any substantial difference, except that the nest rooted 
at TestLoading lacks a member in the original setup and lacks nothing 
in this setup.


What's an explanation for this difference?


Are you sure it actually deletes the file? What do you see when you 
enable class+load/init and verification logging?


David
-





Greetings
Raffaello


On 2023-05-24 00:35, Remi Forax wrote:



- Original Message -

From: "David Holmes" 
To: "Raffaello Giulietti" , 
"core-libs-dev" 

Sent: Wednesday, May 24, 2023 12:23:24 AM
Subject: Re: Classes used in method body are loaded lazily or 
eagerly depending on method return type



On 24/05/2023 12:50 am, Raffaello Giulietti wrote:

I think the problem here is that you are deleting a class in a nest.

During the verification of BaseClassReturner.getObject(), access 
control

(JVMS, 5.4.4, second half) determines that the nest is broken, as
ChildClass is not present anymore.


Not sure access control gets involved at this stage of the 
verification

process. But in any case turning on logging does not show anything
related to nestmates happening between BaseClass and ChildClass. It
seems to just be the resolution of the return type during verification
of the method, that causes the loading of ChildClass and the 
subsequent

CNFE if it has been removed.

If you move ChildClass out of TestLoading so that it becomes a 
top-level

class extending TestLoading.BaseClass, and if you adapt the line that
initializes the local var classFileB to refer to the new location, 
the

code will not throw, despite ChildClass being deleted.


My simplified test shows it still throws when verifying 
BaseClassReturner.


Nestmate checking is done lazily, so if you do not call a 
method/access a field of a nested class, the VM should not trigger a 
class loading.


Moreover, if you test with Java 8 (nestmates were introduced in Java 
11), it failed too.
That's another clue that the error is not related to nestmates 
checking.





Cheers,
David


regards,
Rémi





Greetings
Raffaello



On 2023-05-23 13:20, Сергей Цыпанов wrote:

Hello,

originally this question was asked here:
https://urldefense.com/v3/__https://stackoverflow.com/q/76260269/12473843__;!!ACWV5N9M2RV99hQ!Mb5nhj7EbuftWzF7s4GX9auUZZlyPyCUnLs64c4mkmSGJm4pw0CNgRzQR5wOYuApyE_kHSAnVxGyTM9PHz5StCppGw$
 ,
the code sample for reproduction will be put below or can be 
found via

the link

The issue is about eager/lazy loading of a class depending on method
return type.
If one runs the code below with Java 11-19 it will fail with
NoClassDefFoundError (this is expected as delete class file for
ChildClass):

java.lang.NoClassDefFoundError: org/example/TestLoading$ChildClass
 at java.base/java.lang.Class.forName0(Native Method)
 at java.base/java.lang.Class.forName(Class.java:390)
 at java.base/java.lang.Class.forName(Class.java:381)
 at org.example.TestLoading.loadMyClass(TestLoading.java:29)
 at org.example.TestLoading.main(TestLoading.java:23)
Caused by: java.lang.ClassNotFoundException:
org.example.TestLoading$ChildClass
 at
java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLo

Re: [External] : Re: Classes used in method body are loaded lazily or eagerly depending on method return type

2023-05-25 Thread Raffaello Giulietti



Yes, ChildClass.class is removed from the filesystem.


And here's, the relevant info when running with -Xlog:class+init, 
showing that verification succeeds for both TestLoading$ObjectReturner 
and TestLoading$BaseClassReturner:


loading: TestLoading$ObjectReturner...
[0.039s][info][class,init] Start class verification for: 
TestLoading$ObjectReturner
[0.039s][info][class,init] End class verification for: 
TestLoading$ObjectReturner
[0.039s][info][class,init] 500 Initializing 
'TestLoading$ObjectReturner'(no method) (0x000801001800)

loading: TestLoading$BaseClassReturner...
[0.039s][info][class,init] Start class verification for: 
TestLoading$BaseClassReturner
[0.039s][info][class,init] End class verification for: 
TestLoading$BaseClassReturner
[0.039s][info][class,init] 501 Initializing 
'TestLoading$BaseClassReturner'(no method) (0x000801001a08)





On 2023-05-25 04:57, David Holmes wrote:

On 25/05/2023 12:34 am, Raffaello Giulietti wrote:
As mentioned in my previous email, if you move the member class 
ChildClass out of TestLoading (out of the nest), and make it a 
top-level class like


 public class ChildClass extends TestLoading.BaseClass {
 }

and change

 URL classFileB = 
TestLoading.class.getResource(TestLoading.class.getSimpleName() + 
"$ChildClass.class");


to

 URL classFileB = 
TestLoading.class.getResource(ChildClass.class.getSimpleName() + 
".class");


rebuild everything and run, nothing is thrown.

 deleting: /ChildClass.class
 loading: TestLoading$ObjectReturner...
 loading: TestLoading$BaseClassReturner...

I can't see any substantial difference, except that the nest rooted at 
TestLoading lacks a member in the original setup and lacks nothing in 
this setup.


What's an explanation for this difference?


Are you sure it actually deletes the file? What do you see when you 
enable class+load/init and verification logging?


David
-





Greetings
Raffaello


On 2023-05-24 00:35, Remi Forax wrote:



- Original Message -

From: "David Holmes" 
To: "Raffaello Giulietti" , 
"core-libs-dev" 

Sent: Wednesday, May 24, 2023 12:23:24 AM
Subject: Re: Classes used in method body are loaded lazily or 
eagerly depending on method return type



On 24/05/2023 12:50 am, Raffaello Giulietti wrote:

I think the problem here is that you are deleting a class in a nest.

During the verification of BaseClassReturner.getObject(), access 
control

(JVMS, 5.4.4, second half) determines that the nest is broken, as
ChildClass is not present anymore.


Not sure access control gets involved at this stage of the verification
process. But in any case turning on logging does not show anything
related to nestmates happening between BaseClass and ChildClass. It
seems to just be the resolution of the return type during verification
of the method, that causes the loading of ChildClass and the subsequent
CNFE if it has been removed.

If you move ChildClass out of TestLoading so that it becomes a 
top-level

class extending TestLoading.BaseClass, and if you adapt the line that
initializes the local var classFileB to refer to the new location, the
code will not throw, despite ChildClass being deleted.


My simplified test shows it still throws when verifying 
BaseClassReturner.


Nestmate checking is done lazily, so if you do not call a 
method/access a field of a nested class, the VM should not trigger a 
class loading.


Moreover, if you test with Java 8 (nestmates were introduced in Java 
11), it failed too.

That's another clue that the error is not related to nestmates checking.




Cheers,
David


regards,
Rémi





Greetings
Raffaello



On 2023-05-23 13:20, Сергей Цыпанов wrote:

Hello,

originally this question was asked here:
https://urldefense.com/v3/__https://stackoverflow.com/q/76260269/12473843__;!!ACWV5N9M2RV99hQ!Mb5nhj7EbuftWzF7s4GX9auUZZlyPyCUnLs64c4mkmSGJm4pw0CNgRzQR5wOYuApyE_kHSAnVxGyTM9PHz5StCppGw$
 ,
the code sample for reproduction will be put below or can be found 
via

the link

The issue is about eager/lazy loading of a class depending on method
return type.
If one runs the code below with Java 11-19 it will fail with
NoClassDefFoundError (this is expected as delete class file for
ChildClass):

java.lang.NoClassDefFoundError: org/example/TestLoading$ChildClass
 at java.base/java.lang.Class.forName0(Native Method)
 at java.base/java.lang.Class.forName(Class.java:390)
 at java.base/java.lang.Class.forName(Class.java:381)
 at org.example.TestLoading.loadMyClass(TestLoading.java:29)
 at org.example.TestLoading.main(TestLoading.java:23)
Caused by: java.lang.ClassNotFoundException:
org.example.TestLoading$ChildClass
 at
java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
 at
java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
 at 
java.base/java.lang.Cla

Re: [External] : Re: Classes used in method body are loaded lazily or eagerly depending on method return type

2023-05-24 Thread David Holmes

On 25/05/2023 12:34 am, Raffaello Giulietti wrote:
As mentioned in my previous email, if you move the member class 
ChildClass out of TestLoading (out of the nest), and make it a top-level 
class like


     public class ChildClass extends TestLoading.BaseClass {
     }

and change

     URL classFileB = 
TestLoading.class.getResource(TestLoading.class.getSimpleName() + 
"$ChildClass.class");


to

     URL classFileB = 
TestLoading.class.getResource(ChildClass.class.getSimpleName() + ".class");


rebuild everything and run, nothing is thrown.

     deleting: /ChildClass.class
     loading: TestLoading$ObjectReturner...
     loading: TestLoading$BaseClassReturner...

I can't see any substantial difference, except that the nest rooted at 
TestLoading lacks a member in the original setup and lacks nothing in 
this setup.


What's an explanation for this difference?


Are you sure it actually deletes the file? What do you see when you 
enable class+load/init and verification logging?


David
-





Greetings
Raffaello


On 2023-05-24 00:35, Remi Forax wrote:



- Original Message -

From: "David Holmes" 
To: "Raffaello Giulietti" , 
"core-libs-dev" 

Sent: Wednesday, May 24, 2023 12:23:24 AM
Subject: Re: Classes used in method body are loaded lazily or eagerly 
depending on method return type



On 24/05/2023 12:50 am, Raffaello Giulietti wrote:

I think the problem here is that you are deleting a class in a nest.

During the verification of BaseClassReturner.getObject(), access 
control

(JVMS, 5.4.4, second half) determines that the nest is broken, as
ChildClass is not present anymore.


Not sure access control gets involved at this stage of the verification
process. But in any case turning on logging does not show anything
related to nestmates happening between BaseClass and ChildClass. It
seems to just be the resolution of the return type during verification
of the method, that causes the loading of ChildClass and the subsequent
CNFE if it has been removed.

If you move ChildClass out of TestLoading so that it becomes a 
top-level

class extending TestLoading.BaseClass, and if you adapt the line that
initializes the local var classFileB to refer to the new location, the
code will not throw, despite ChildClass being deleted.


My simplified test shows it still throws when verifying 
BaseClassReturner.


Nestmate checking is done lazily, so if you do not call a 
method/access a field of a nested class, the VM should not trigger a 
class loading.


Moreover, if you test with Java 8 (nestmates were introduced in Java 
11), it failed too.

That's another clue that the error is not related to nestmates checking.




Cheers,
David


regards,
Rémi





Greetings
Raffaello



On 2023-05-23 13:20, Сергей Цыпанов wrote:

Hello,

originally this question was asked here:
https://urldefense.com/v3/__https://stackoverflow.com/q/76260269/12473843__;!!ACWV5N9M2RV99hQ!Mb5nhj7EbuftWzF7s4GX9auUZZlyPyCUnLs64c4mkmSGJm4pw0CNgRzQR5wOYuApyE_kHSAnVxGyTM9PHz5StCppGw$
 ,
the code sample for reproduction will be put below or can be found via
the link

The issue is about eager/lazy loading of a class depending on method
return type.
If one runs the code below with Java 11-19 it will fail with
NoClassDefFoundError (this is expected as delete class file for
ChildClass):

java.lang.NoClassDefFoundError: org/example/TestLoading$ChildClass
 at java.base/java.lang.Class.forName0(Native Method)
 at java.base/java.lang.Class.forName(Class.java:390)
 at java.base/java.lang.Class.forName(Class.java:381)
 at org.example.TestLoading.loadMyClass(TestLoading.java:29)
 at org.example.TestLoading.main(TestLoading.java:23)
Caused by: java.lang.ClassNotFoundException:
org.example.TestLoading$ChildClass
 at
java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
 at
java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
 at 
java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)

 ... 5 more

As of Java 20 chapter 12.4.1 of JLS states:
-
A class or interface T will be initialized immediately before the
first occurrence of any one of the following:

- T is a class and an instance of T is created.
- a static method declared by T is invoked.
- a static field declared by T is assigned.
- a static field declared by T is used and the field is not a constant
variable (§4.12.4).

When a class is initialized, its superclasses are initialized (if they
have not been previously initialized), as well as any superinterfaces
(§8.1.5) that declare any default methods (§9.4.3) (if they have not
been previously initialized).
Initialization of an interface does not, of itself, cause
initialization of any of its superinterfaces.
A reference to a static field (§8.3.1.1) causes initialization of only
the class or interface that 

Re: [External] : Re: Classes used in method body are loaded lazily or eagerly depending on method return type

2023-05-24 Thread Raffaello Giulietti
As mentioned in my previous email, if you move the member class 
ChildClass out of TestLoading (out of the nest), and make it a top-level 
class like


public class ChildClass extends TestLoading.BaseClass {
}

and change

URL classFileB = 
TestLoading.class.getResource(TestLoading.class.getSimpleName() + 
"$ChildClass.class");


to

URL classFileB = 
TestLoading.class.getResource(ChildClass.class.getSimpleName() + ".class");


rebuild everything and run, nothing is thrown.

deleting: /ChildClass.class
loading: TestLoading$ObjectReturner...
loading: TestLoading$BaseClassReturner...

I can't see any substantial difference, except that the nest rooted at 
TestLoading lacks a member in the original setup and lacks nothing in 
this setup.


What's an explanation for this difference?


Greetings
Raffaello


On 2023-05-24 00:35, Remi Forax wrote:



- Original Message -

From: "David Holmes" 
To: "Raffaello Giulietti" , "core-libs-dev" 

Sent: Wednesday, May 24, 2023 12:23:24 AM
Subject: Re: Classes used in method body are loaded lazily or eagerly depending 
on method return type



On 24/05/2023 12:50 am, Raffaello Giulietti wrote:

I think the problem here is that you are deleting a class in a nest.

During the verification of BaseClassReturner.getObject(), access control
(JVMS, 5.4.4, second half) determines that the nest is broken, as
ChildClass is not present anymore.


Not sure access control gets involved at this stage of the verification
process. But in any case turning on logging does not show anything
related to nestmates happening between BaseClass and ChildClass. It
seems to just be the resolution of the return type during verification
of the method, that causes the loading of ChildClass and the subsequent
CNFE if it has been removed.


If you move ChildClass out of TestLoading so that it becomes a top-level
class extending TestLoading.BaseClass, and if you adapt the line that
initializes the local var classFileB to refer to the new location, the
code will not throw, despite ChildClass being deleted.


My simplified test shows it still throws when verifying BaseClassReturner.


Nestmate checking is done lazily, so if you do not call a method/access a field 
of a nested class, the VM should not trigger a class loading.

Moreover, if you test with Java 8 (nestmates were introduced in Java 11), it 
failed too.
That's another clue that the error is not related to nestmates checking.




Cheers,
David


regards,
Rémi





Greetings
Raffaello



On 2023-05-23 13:20, Сергей Цыпанов wrote:

Hello,

originally this question was asked here:
https://urldefense.com/v3/__https://stackoverflow.com/q/76260269/12473843__;!!ACWV5N9M2RV99hQ!Mb5nhj7EbuftWzF7s4GX9auUZZlyPyCUnLs64c4mkmSGJm4pw0CNgRzQR5wOYuApyE_kHSAnVxGyTM9PHz5StCppGw$
 ,
the code sample for reproduction will be put below or can be found via
the link

The issue is about eager/lazy loading of a class depending on method
return type.
If one runs the code below with Java 11-19 it will fail with
NoClassDefFoundError (this is expected as delete class file for
ChildClass):

java.lang.NoClassDefFoundError: org/example/TestLoading$ChildClass
 at java.base/java.lang.Class.forName0(Native Method)
 at java.base/java.lang.Class.forName(Class.java:390)
 at java.base/java.lang.Class.forName(Class.java:381)
 at org.example.TestLoading.loadMyClass(TestLoading.java:29)
 at org.example.TestLoading.main(TestLoading.java:23)
Caused by: java.lang.ClassNotFoundException:
org.example.TestLoading$ChildClass
 at
java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
 at
java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
 at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
 ... 5 more

As of Java 20 chapter 12.4.1 of JLS states:
-
A class or interface T will be initialized immediately before the
first occurrence of any one of the following:

- T is a class and an instance of T is created.
- a static method declared by T is invoked.
- a static field declared by T is assigned.
- a static field declared by T is used and the field is not a constant
variable (§4.12.4).

When a class is initialized, its superclasses are initialized (if they
have not been previously initialized), as well as any superinterfaces
(§8.1.5) that declare any default methods (§9.4.3) (if they have not
been previously initialized).
Initialization of an interface does not, of itself, cause
initialization of any of its superinterfaces.
A reference to a static field (§8.3.1.1) causes initialization of only
the class or interface that actually declares it, even though it might
be referred to through the name of a subclass, a subinterface, or a
class that implements an interface.
Invocation of certain reflective methods in class Clas

Re: Classes used in method body are loaded lazily or eagerly depending on method return type

2023-05-23 Thread Remi Forax



- Original Message -
> From: "David Holmes" 
> To: "Raffaello Giulietti" , "core-libs-dev" 
> 
> Sent: Wednesday, May 24, 2023 12:23:24 AM
> Subject: Re: Classes used in method body are loaded lazily or eagerly 
> depending on method return type

> On 24/05/2023 12:50 am, Raffaello Giulietti wrote:
>> I think the problem here is that you are deleting a class in a nest.
>> 
>> During the verification of BaseClassReturner.getObject(), access control
>> (JVMS, 5.4.4, second half) determines that the nest is broken, as
>> ChildClass is not present anymore.
> 
> Not sure access control gets involved at this stage of the verification
> process. But in any case turning on logging does not show anything
> related to nestmates happening between BaseClass and ChildClass. It
> seems to just be the resolution of the return type during verification
> of the method, that causes the loading of ChildClass and the subsequent
> CNFE if it has been removed.
> 
>> If you move ChildClass out of TestLoading so that it becomes a top-level
>> class extending TestLoading.BaseClass, and if you adapt the line that
>> initializes the local var classFileB to refer to the new location, the
>> code will not throw, despite ChildClass being deleted.
> 
> My simplified test shows it still throws when verifying BaseClassReturner.

Nestmate checking is done lazily, so if you do not call a method/access a field 
of a nested class, the VM should not trigger a class loading.

Moreover, if you test with Java 8 (nestmates were introduced in Java 11), it 
failed too.
That's another clue that the error is not related to nestmates checking.

> 
> 
> Cheers,
> David

regards,
Rémi

> 
>> 
>> Greetings
>> Raffaello
>> 
>> 
>> 
>> On 2023-05-23 13:20, Сергей Цыпанов wrote:
>>> Hello,
>>>
>>> originally this question was asked here:
>>> https://stackoverflow.com/q/76260269/12473843,
>>> the code sample for reproduction will be put below or can be found via
>>> the link
>>>
>>> The issue is about eager/lazy loading of a class depending on method
>>> return type.
>>> If one runs the code below with Java 11-19 it will fail with
>>> NoClassDefFoundError (this is expected as delete class file for
>>> ChildClass):
>>>
>>> java.lang.NoClassDefFoundError: org/example/TestLoading$ChildClass
>>> at java.base/java.lang.Class.forName0(Native Method)
>>> at java.base/java.lang.Class.forName(Class.java:390)
>>> at java.base/java.lang.Class.forName(Class.java:381)
>>> at org.example.TestLoading.loadMyClass(TestLoading.java:29)
>>> at org.example.TestLoading.main(TestLoading.java:23)
>>> Caused by: java.lang.ClassNotFoundException:
>>> org.example.TestLoading$ChildClass
>>> at
>>> java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
>>> at
>>> java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
>>> at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
>>> ... 5 more
>>>
>>> As of Java 20 chapter 12.4.1 of JLS states:
>>> -
>>> A class or interface T will be initialized immediately before the
>>> first occurrence of any one of the following:
>>>
>>> - T is a class and an instance of T is created.
>>> - a static method declared by T is invoked.
>>> - a static field declared by T is assigned.
>>> - a static field declared by T is used and the field is not a constant
>>> variable (§4.12.4).
>>>
>>> When a class is initialized, its superclasses are initialized (if they
>>> have not been previously initialized), as well as any superinterfaces
>>> (§8.1.5) that declare any default methods (§9.4.3) (if they have not
>>> been previously initialized).
>>> Initialization of an interface does not, of itself, cause
>>> initialization of any of its superinterfaces.
>>> A reference to a static field (§8.3.1.1) causes initialization of only
>>> the class or interface that actually declares it, even though it might
>>> be referred to through the name of a subclass, a subinterface, or a
>>> class that implements an interface.
>>> Invocation of certain reflective methods in class Class and in package
>>> java.lang.reflect also causes class or interface initialization.
>>> A class or interface will not be initialized under any other
>>&g

Re: Classes used in method body are loaded lazily or eagerly depending on method return type

2023-05-23 Thread Remi Forax
- Original Message -
> From: "Сергей Цыпанов" 
> To: "core-libs-dev" 
> Sent: Tuesday, May 23, 2023 1:20:44 PM
> Subject: Classes used in method body are loaded lazily or eagerly depending 
> on method return type

> Hello,

Hello,

> 
> originally this question was asked here:
> https://stackoverflow.com/q/76260269/12473843,
> the code sample for reproduction will be put below or can be found via the 
> link
> 
> The issue is about eager/lazy loading of a class depending on method return
> type.

It also depends on the content of the methods.
If you modify the code to return null, the NoClassDefFoundError disappears

 public static class ObjectReturner {
   public Object getObject() {
 return null;
   }
 }
 
 public static class BaseClassReturner {
public BaseClass getObject() {
  return null;
}
 }

which means that the NoClassDefFoundError comes from the bytecode verifier.

In your original ObjectReturner, the bytecode verifier needs to check if 
ChildClass is an Object and there is a shortcircuit for that, so ChildClass 
does not need to be loaded.
But in BaseClassReturner, the bytecode verifier needs to check if ChildClass is 
a BaseClass, so it has to load ChildClass to know if the superclass is 
BaseClass.

Another way to see that it's the verifier that triggers the class loading is to 
use the option "-noverify"
  java -noverify TestLoading

should works !

regards,
Rémi


> If one runs the code below with Java 11-19 it will fail with
> NoClassDefFoundError (this is expected as delete class file for ChildClass):
> 
> java.lang.NoClassDefFoundError: org/example/TestLoading$ChildClass
>   at java.base/java.lang.Class.forName0(Native Method)
>   at java.base/java.lang.Class.forName(Class.java:390)
>   at java.base/java.lang.Class.forName(Class.java:381)
>   at org.example.TestLoading.loadMyClass(TestLoading.java:29)
>   at org.example.TestLoading.main(TestLoading.java:23)
> Caused by: java.lang.ClassNotFoundException: 
> org.example.TestLoading$ChildClass
>   at
>   
> java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
>   at
>   
> java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
>   at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
>   ... 5 more
> 
> As of Java 20 chapter 12.4.1 of JLS states:
> -
> A class or interface T will be initialized immediately before the first
> occurrence of any one of the following:
> 
> - T is a class and an instance of T is created.
> - a static method declared by T is invoked.
> - a static field declared by T is assigned.
> - a static field declared by T is used and the field is not a constant 
> variable
> (§4.12.4).
> 
> When a class is initialized, its superclasses are initialized (if they have 
> not
> been previously initialized), as well as any superinterfaces (§8.1.5) that
> declare any default methods (§9.4.3) (if they have not been previously
> initialized).
> Initialization of an interface does not, of itself, cause initialization of 
> any
> of its superinterfaces.
> A reference to a static field (§8.3.1.1) causes initialization of only the 
> class
> or interface that actually declares it, even though it might be referred to
> through the name of a subclass, a subinterface, or a class that implements an
> interface.
> Invocation of certain reflective methods in class Class and in package
> java.lang.reflect also causes class or interface initialization.
> A class or interface will not be initialized under any other circumstance.
> -
> With the code snippet we see that calling
> Class.forName(ObjectReturner.class.getName()) succeeds and
> Class.forName(BaseClassReturner.class.getName()) fails even though both 
> declare
> returning an instance of ChildClass.
> This failure is unexpected as in the code below we don't fulfill any 
> requirement
> for class loading as of JLS 12.4.1, but the JVM still tries to load the class.
> 
> I suspect it might be related to class file validation and/or security, 
> because
> when we run the code with -Xlog:class+init there's a reference to LinkageError
> in loading log:
> 
> loading: org.example.TestLoading$BaseClassReturner...
> [0.277s][info][class,init] Start class verification for:
> org.example.TestLoading$BaseClassReturner
> [0.277s][info][class,init] 771 Initializing
> 'java/lang/ReflectiveOperationException'(no method) (0x00084028)
> [0.277s][info][class,init] 772 Initializing
> 'java/lang/ClassNotFoundException'(no me

Re: Classes used in method body are loaded lazily or eagerly depending on method return type

2023-05-23 Thread David Holmes

On 24/05/2023 12:50 am, Raffaello Giulietti wrote:

I think the problem here is that you are deleting a class in a nest.

During the verification of BaseClassReturner.getObject(), access control 
(JVMS, 5.4.4, second half) determines that the nest is broken, as 
ChildClass is not present anymore.


Not sure access control gets involved at this stage of the verification 
process. But in any case turning on logging does not show anything 
related to nestmates happening between BaseClass and ChildClass. It 
seems to just be the resolution of the return type during verification 
of the method, that causes the loading of ChildClass and the subsequent 
CNFE if it has been removed.


If you move ChildClass out of TestLoading so that it becomes a top-level 
class extending TestLoading.BaseClass, and if you adapt the line that 
initializes the local var classFileB to refer to the new location, the 
code will not throw, despite ChildClass being deleted.


My simplified test shows it still throws when verifying BaseClassReturner.


Cheers,
David



Greetings
Raffaello



On 2023-05-23 13:20, Сергей Цыпанов wrote:

Hello,

originally this question was asked here: 
https://stackoverflow.com/q/76260269/12473843,
the code sample for reproduction will be put below or can be found via 
the link


The issue is about eager/lazy loading of a class depending on method 
return type.
If one runs the code below with Java 11-19 it will fail with 
NoClassDefFoundError (this is expected as delete class file for 
ChildClass):


java.lang.NoClassDefFoundError: org/example/TestLoading$ChildClass
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:390)
at java.base/java.lang.Class.forName(Class.java:381)
at org.example.TestLoading.loadMyClass(TestLoading.java:29)
at org.example.TestLoading.main(TestLoading.java:23)
Caused by: java.lang.ClassNotFoundException: 
org.example.TestLoading$ChildClass
at 
java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at 
java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)

at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 5 more

As of Java 20 chapter 12.4.1 of JLS states:
-
A class or interface T will be initialized immediately before the 
first occurrence of any one of the following:


- T is a class and an instance of T is created.
- a static method declared by T is invoked.
- a static field declared by T is assigned.
- a static field declared by T is used and the field is not a constant 
variable (§4.12.4).


When a class is initialized, its superclasses are initialized (if they 
have not been previously initialized), as well as any superinterfaces 
(§8.1.5) that declare any default methods (§9.4.3) (if they have not 
been previously initialized).
Initialization of an interface does not, of itself, cause 
initialization of any of its superinterfaces.
A reference to a static field (§8.3.1.1) causes initialization of only 
the class or interface that actually declares it, even though it might 
be referred to through the name of a subclass, a subinterface, or a 
class that implements an interface.
Invocation of certain reflective methods in class Class and in package 
java.lang.reflect also causes class or interface initialization.
A class or interface will not be initialized under any other 
circumstance.

-
With the code snippet we see that calling 
Class.forName(ObjectReturner.class.getName()) succeeds and 
Class.forName(BaseClassReturner.class.getName()) fails even though 
both declare returning an instance of ChildClass.
This failure is unexpected as in the code below we don't fulfill any 
requirement for class loading as of JLS 12.4.1, but the JVM still 
tries to load the class.


I suspect it might be related to class file validation and/or 
security, because when we run the code with -Xlog:class+init there's a 
reference to LinkageError in loading log:


loading: org.example.TestLoading$BaseClassReturner...
[0.277s][info][class,init] Start class verification for: 
org.example.TestLoading$BaseClassReturner
[0.277s][info][class,init] 771 Initializing 
'java/lang/ReflectiveOperationException'(no method) (0x00084028)
[0.277s][info][class,init] 772 Initializing 
'java/lang/ClassNotFoundException'(no method) (0x00084288)
[0.277s][info][class,init] 773 Initializing 
'java/lang/LinkageError'(no method) 
(0x000844f8)  <
[0.277s][info][class,init] 774 Initializing 
'java/lang/NoClassDefFoundError'(no method) (0x00084758)
[0.277s][info][class,init] Verification for 
org.example.TestLoading$BaseClassReturner has exception pending 
'java.lang.NoClassDefFoundError org/example/TestLoading$ChildClass'
[0.277s][info][class,init] End class verification for: 

Re: Classes used in method body are loaded lazily or eagerly depending on method return type

2023-05-23 Thread David Holmes

On 24/05/2023 5:04 am, Сергей Цыпанов wrote:

Hi,


Verification can require classes to be loaded to perform the
verification - see JVMS 4.10 for all the details.


sorry, I still don't get it completely. Here's the byte code for 
ObjectReturner.getObject():

// access flags 0x1
public getObject()Ljava/lang/Object;
  L0
   LINENUMBER 43 L0
   NEW org/example/TestLoading$ChildClass
   DUP
   INVOKESPECIAL org/example/TestLoading$ChildClass. ()V
   ARETURN
  L1
   LOCALVARIABLE this Lorg/example/TestLoading$ObjectReturner; L0 L1 0
   MAXSTACK = 2
   MAXLOCALS = 1

and this one is for BaseClassReturner.getObject():

// access flags 0x1
public getObject()Lorg/example/TestLoading$BaseClass;
  L0
   LINENUMBER 49 L0
   NEW org/example/TestLoading$ChildClass
   DUP
   INVOKESPECIAL org/example/TestLoading$ChildClass. ()V
   ARETURN
  L1
   LOCALVARIABLE this Lorg/example/TestLoading$BaseClassReturner; L0 L1 0
   MAXSTACK = 2
   MAXLOCALS = 1

Apart from type of 'this' the only difference is return type, so I've 
referenced JVMS 4.10 in the part where return type is described.

There we have clause for areturn:

"An areturn instruction is type safe iff the enclosing method has a declared return 
type, ReturnType, that is a reference type, and one can validly pop a type matching 
ReturnType off the incoming operand stack."

and for return type:

"If the method returns a reference type, only an areturn instruction may be used, 
and the type of the returned value must be assignment compatible with the return 
descriptor of the method (§4.3.3)"

I guess the second one is a clue for to check whether returned value can be 
assigned to return type the VM should look into inheritance tree. Please 
correct me if idea is wrong.


For the Object case the type-checking is always obviously trivially 
correct so it doesn't need to load the actual return type. So the seems 
a reasonable conclusion.


If you take your test code and only have the BaseClassReturner and only 
load it then you see in the logging:


loading: TestLoading$BaseClassReturner...
[0.067s][info][class,init  ] Start class verification for: 
TestLoading$BaseClassReturner
[0.067s][info][verification] Verifying class 
TestLoading$BaseClassReturner with new format
[0.067s][info][verification] Verifying method 
TestLoading$BaseClassReturner.()V
[0.067s][info][verification] Verifying method 
TestLoading$BaseClassReturner.getObject()LTestLoading$BaseClass;
[0.068s][info][class,load  ] TestLoading$BaseClass source: 
file:/scratch/users/daholme/tests/
[0.068s][info][class,load  ] TestLoading$ChildClass source: 
file:/scratch/users/daholme/tests/
[0.068s][info][class,init  ] End class verification for: 
TestLoading$BaseClassReturner
[0.068s][info][verification] End class verification for: 
TestLoading$BaseClassReturner


So you can see the ChildClass being loaded.

David
-




Regards,
Sergey



Hi,

On 23/05/2023 9:20 pm, Сергей Цыпанов wrote:


Hello,

originally this question was asked here: 
https://stackoverflow.com/q/76260269/12473843,
the code sample for reproduction will be put below or can be found via the link

The issue is about eager/lazy loading of a class depending on method return 
type.
If one runs the code below with Java 11-19 it will fail with 
NoClassDefFoundError (this is expected as delete class file for ChildClass):

java.lang.NoClassDefFoundError: org/example/TestLoading$ChildClass
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:390)
at java.base/java.lang.Class.forName(Class.java:381)
at org.example.TestLoading.loadMyClass(TestLoading.java:29)
at org.example.TestLoading.main(TestLoading.java:23)
Caused by: java.lang.ClassNotFoundException: org.example.TestLoading$ChildClass
at 
java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at 
java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 5 more

As of Java 20 chapter 12.4.1 of JLS states:
-
A class or interface T will be initialized immediately before the first 
occurrence of any one of the following:

- T is a class and an instance of T is created.
- a static method declared by T is invoked.
- a static field declared by T is assigned.
- a static field declared by T is used and the field is not a constant variable 
(§4.12.4).

When a class is initialized, its superclasses are initialized (if they have not 
been previously initialized), as well as any superinterfaces (§8.1.5) that 
declare any default methods (§9.4.3) (if they have not been previously 
initialized).
Initialization of an interface does not, of itself, cause initialization of any 
of its superinterfaces.
A reference to a static field (§8.3.1.1) causes initialization of only the 
class 

Re: Classes used in method body are loaded lazily or eagerly depending on method return type

2023-05-23 Thread Сергей Цыпанов
Hi,

> Verification can require classes to be loaded to perform the
> verification - see JVMS 4.10 for all the details.

sorry, I still don't get it completely. Here's the byte code for 
ObjectReturner.getObject():

// access flags 0x1
public getObject()Ljava/lang/Object;
 L0
  LINENUMBER 43 L0
  NEW org/example/TestLoading$ChildClass
  DUP
  INVOKESPECIAL org/example/TestLoading$ChildClass. ()V
  ARETURN
 L1
  LOCALVARIABLE this Lorg/example/TestLoading$ObjectReturner; L0 L1 0
  MAXSTACK = 2
  MAXLOCALS = 1

and this one is for BaseClassReturner.getObject():

// access flags 0x1
public getObject()Lorg/example/TestLoading$BaseClass;
 L0
  LINENUMBER 49 L0
  NEW org/example/TestLoading$ChildClass
  DUP
  INVOKESPECIAL org/example/TestLoading$ChildClass. ()V
  ARETURN
 L1
  LOCALVARIABLE this Lorg/example/TestLoading$BaseClassReturner; L0 L1 0
  MAXSTACK = 2
  MAXLOCALS = 1

Apart from type of 'this' the only difference is return type, so I've 
referenced JVMS 4.10 in the part where return type is described.

There we have clause for areturn:

"An areturn instruction is type safe iff the enclosing method has a declared 
return type, ReturnType, that is a reference type, and one can validly pop a 
type matching ReturnType off the incoming operand stack."

and for return type:

"If the method returns a reference type, only an areturn instruction may be 
used, and the type of the returned value must be assignment compatible with the 
return descriptor of the method (§4.3.3)"

I guess the second one is a clue for to check whether returned value can be 
assigned to return type the VM should look into inheritance tree. Please 
correct me if idea is wrong.

Regards,
Sergey


> Hi,
> 
> On 23/05/2023 9:20 pm, Сергей Цыпанов wrote:
> 
>> Hello,
>>
>> originally this question was asked here: 
>> https://stackoverflow.com/q/76260269/12473843,
>> the code sample for reproduction will be put below or can be found via the 
>> link
>>
>> The issue is about eager/lazy loading of a class depending on method return 
>> type.
>> If one runs the code below with Java 11-19 it will fail with 
>> NoClassDefFoundError (this is expected as delete class file for ChildClass):
>>
>> java.lang.NoClassDefFoundError: org/example/TestLoading$ChildClass
>> at java.base/java.lang.Class.forName0(Native Method)
>> at java.base/java.lang.Class.forName(Class.java:390)
>> at java.base/java.lang.Class.forName(Class.java:381)
>> at org.example.TestLoading.loadMyClass(TestLoading.java:29)
>> at org.example.TestLoading.main(TestLoading.java:23)
>> Caused by: java.lang.ClassNotFoundException: 
>> org.example.TestLoading$ChildClass
>> at 
>> java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
>> at 
>> java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
>> at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
>> ... 5 more
>>
>> As of Java 20 chapter 12.4.1 of JLS states:
>> -
>> A class or interface T will be initialized immediately before the first 
>> occurrence of any one of the following:
>>
>> - T is a class and an instance of T is created.
>> - a static method declared by T is invoked.
>> - a static field declared by T is assigned.
>> - a static field declared by T is used and the field is not a constant 
>> variable (§4.12.4).
>>
>> When a class is initialized, its superclasses are initialized (if they have 
>> not been previously initialized), as well as any superinterfaces (§8.1.5) 
>> that declare any default methods (§9.4.3) (if they have not been previously 
>> initialized).
>> Initialization of an interface does not, of itself, cause initialization of 
>> any of its superinterfaces.
>> A reference to a static field (§8.3.1.1) causes initialization of only the 
>> class or interface that actually declares it, even though it might be 
>> referred to through the name of a subclass, a subinterface, or a class that 
>> implements an interface.
>> Invocation of certain reflective methods in class Class and in package 
>> java.lang.reflect also causes class or interface initialization.
>> A class or interface will not be initialized under any other circumstance.
>> -
>> With the code snippet we see that calling 
>> Class.forName(ObjectReturner.class.getName()) succeeds and 
>> Class.forName(BaseClassReturner.class.getName()) fails even though both 
>> declare returning an instance of ChildClass.
>> This failure is unexpected as in the code below we don't fulfill any 
>> requirement for class loading as of JLS 12.4.1, but the JVM still tries to 
>> load the class.
>>
>> I suspect it might be related to class file validation and/or security, 
>> because when we run the code with -Xlog:class+init there's a reference to 
>> LinkageError in loading log:
>>
>> loading: org.example.TestLoading$BaseClassReturner...
>> [0.277s][info][class,init] Start class 

Re: Classes used in method body are loaded lazily or eagerly depending on method return type

2023-05-23 Thread Raffaello Giulietti

I think the problem here is that you are deleting a class in a nest.

During the verification of BaseClassReturner.getObject(), access control 
(JVMS, 5.4.4, second half) determines that the nest is broken, as 
ChildClass is not present anymore.


If you move ChildClass out of TestLoading so that it becomes a top-level 
class extending TestLoading.BaseClass, and if you adapt the line that 
initializes the local var classFileB to refer to the new location, the 
code will not throw, despite ChildClass being deleted.



Greetings
Raffaello



On 2023-05-23 13:20, Сергей Цыпанов wrote:

Hello,

originally this question was asked here: 
https://stackoverflow.com/q/76260269/12473843,
the code sample for reproduction will be put below or can be found via the link

The issue is about eager/lazy loading of a class depending on method return 
type.
If one runs the code below with Java 11-19 it will fail with 
NoClassDefFoundError (this is expected as delete class file for ChildClass):

java.lang.NoClassDefFoundError: org/example/TestLoading$ChildClass
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:390)
at java.base/java.lang.Class.forName(Class.java:381)
at org.example.TestLoading.loadMyClass(TestLoading.java:29)
at org.example.TestLoading.main(TestLoading.java:23)
Caused by: java.lang.ClassNotFoundException: org.example.TestLoading$ChildClass
at 
java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at 
java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 5 more

As of Java 20 chapter 12.4.1 of JLS states:
-
A class or interface T will be initialized immediately before the first 
occurrence of any one of the following:

- T is a class and an instance of T is created.
- a static method declared by T is invoked.
- a static field declared by T is assigned.
- a static field declared by T is used and the field is not a constant variable 
(§4.12.4).

When a class is initialized, its superclasses are initialized (if they have not 
been previously initialized), as well as any superinterfaces (§8.1.5) that 
declare any default methods (§9.4.3) (if they have not been previously 
initialized).
Initialization of an interface does not, of itself, cause initialization of any 
of its superinterfaces.
A reference to a static field (§8.3.1.1) causes initialization of only the 
class or interface that actually declares it, even though it might be referred 
to through the name of a subclass, a subinterface, or a class that implements 
an interface.
Invocation of certain reflective methods in class Class and in package 
java.lang.reflect also causes class or interface initialization.
A class or interface will not be initialized under any other circumstance.
-
With the code snippet we see that calling 
Class.forName(ObjectReturner.class.getName()) succeeds and 
Class.forName(BaseClassReturner.class.getName()) fails even though both declare 
returning an instance of ChildClass.
This failure is unexpected as in the code below we don't fulfill any 
requirement for class loading as of JLS 12.4.1, but the JVM still tries to load 
the class.

I suspect it might be related to class file validation and/or security, because 
when we run the code with -Xlog:class+init there's a reference to LinkageError 
in loading log:

loading: org.example.TestLoading$BaseClassReturner...
[0.277s][info][class,init] Start class verification for: 
org.example.TestLoading$BaseClassReturner
[0.277s][info][class,init] 771 Initializing 
'java/lang/ReflectiveOperationException'(no method) (0x00084028)
[0.277s][info][class,init] 772 Initializing 
'java/lang/ClassNotFoundException'(no method) (0x00084288)
[0.277s][info][class,init] 773 Initializing 'java/lang/LinkageError'(no method) 
(0x000844f8)  <
[0.277s][info][class,init] 774 Initializing 'java/lang/NoClassDefFoundError'(no 
method) (0x00084758)
[0.277s][info][class,init] Verification for 
org.example.TestLoading$BaseClassReturner has exception pending 
'java.lang.NoClassDefFoundError org/example/TestLoading$ChildClass'
[0.277s][info][class,init] End class verification for: 
org.example.TestLoading$BaseClassReturner


So I've got three questions about this:
- Does class loading depend on method's return type?
- Which part of JLS/JVM spec describes eager class loading in this case?
- Could one point out the particular piece of the VM code responsible for class 
loading in this case?

Regards,
Sergey Tsypanov

Code snippet for reproduction:

public class TestLoading {

   public static void main(String[] args) throws Exception {
 Class.forName(BaseClass.class.getName());

Re: Classes used in method body are loaded lazily or eagerly depending on method return type

2023-05-23 Thread David Holmes

Hi,

On 23/05/2023 9:20 pm, Сергей Цыпанов wrote:

Hello,

originally this question was asked here: 
https://stackoverflow.com/q/76260269/12473843,
the code sample for reproduction will be put below or can be found via the link

The issue is about eager/lazy loading of a class depending on method return 
type.
If one runs the code below with Java 11-19 it will fail with 
NoClassDefFoundError (this is expected as delete class file for ChildClass):

java.lang.NoClassDefFoundError: org/example/TestLoading$ChildClass
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:390)
at java.base/java.lang.Class.forName(Class.java:381)
at org.example.TestLoading.loadMyClass(TestLoading.java:29)
at org.example.TestLoading.main(TestLoading.java:23)
Caused by: java.lang.ClassNotFoundException: org.example.TestLoading$ChildClass
at 
java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at 
java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 5 more

As of Java 20 chapter 12.4.1 of JLS states:
-
A class or interface T will be initialized immediately before the first 
occurrence of any one of the following:

- T is a class and an instance of T is created.
- a static method declared by T is invoked.
- a static field declared by T is assigned.
- a static field declared by T is used and the field is not a constant variable 
(§4.12.4).

When a class is initialized, its superclasses are initialized (if they have not 
been previously initialized), as well as any superinterfaces (§8.1.5) that 
declare any default methods (§9.4.3) (if they have not been previously 
initialized).
Initialization of an interface does not, of itself, cause initialization of any 
of its superinterfaces.
A reference to a static field (§8.3.1.1) causes initialization of only the 
class or interface that actually declares it, even though it might be referred 
to through the name of a subclass, a subinterface, or a class that implements 
an interface.
Invocation of certain reflective methods in class Class and in package 
java.lang.reflect also causes class or interface initialization.
A class or interface will not be initialized under any other circumstance.
-
With the code snippet we see that calling 
Class.forName(ObjectReturner.class.getName()) succeeds and 
Class.forName(BaseClassReturner.class.getName()) fails even though both declare 
returning an instance of ChildClass.
This failure is unexpected as in the code below we don't fulfill any 
requirement for class loading as of JLS 12.4.1, but the JVM still tries to load 
the class.

I suspect it might be related to class file validation and/or security, because 
when we run the code with -Xlog:class+init there's a reference to LinkageError 
in loading log:

loading: org.example.TestLoading$BaseClassReturner...
[0.277s][info][class,init] Start class verification for: 
org.example.TestLoading$BaseClassReturner
[0.277s][info][class,init] 771 Initializing 
'java/lang/ReflectiveOperationException'(no method) (0x00084028)
[0.277s][info][class,init] 772 Initializing 
'java/lang/ClassNotFoundException'(no method) (0x00084288)
[0.277s][info][class,init] 773 Initializing 'java/lang/LinkageError'(no method) 
(0x000844f8)  <
[0.277s][info][class,init] 774 Initializing 'java/lang/NoClassDefFoundError'(no 
method) (0x00084758)
[0.277s][info][class,init] Verification for 
org.example.TestLoading$BaseClassReturner has exception pending 
'java.lang.NoClassDefFoundError org/example/TestLoading$ChildClass'
[0.277s][info][class,init] End class verification for: 
org.example.TestLoading$BaseClassReturner


So I've got three questions about this:
- Does class loading depend on method's return type?
- Which part of JLS/JVM spec describes eager class loading in this case?
- Could one point out the particular piece of the VM code responsible for class 
loading in this case?


Verification can require classes to be loaded to perform the 
verification - see JVMS 4.10 for all the details.


Note you seem to be confusing class loading with class initialization 
above. The rules for initialization are very precise; the rules for 
loading are far more lax.


Cheers,
David
-


Regards,
Sergey Tsypanov

Code snippet for reproduction:

public class TestLoading {

   public static void main(String[] args) throws Exception {
 Class.forName(BaseClass.class.getName());
 URL classFileB = TestLoading.class.getResource(TestLoading.class.getSimpleName() + 
"$ChildClass.class");
 if (classFileB != null) {
   if (!"file".equals(classFileB.getProtocol())) {
 throw new UnsupportedOperat

Classes used in method body are loaded lazily or eagerly depending on method return type

2023-05-23 Thread Сергей Цыпанов
Hello,

originally this question was asked here: 
https://stackoverflow.com/q/76260269/12473843,
the code sample for reproduction will be put below or can be found via the link

The issue is about eager/lazy loading of a class depending on method return 
type.
If one runs the code below with Java 11-19 it will fail with 
NoClassDefFoundError (this is expected as delete class file for ChildClass):

java.lang.NoClassDefFoundError: org/example/TestLoading$ChildClass
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:390)
at java.base/java.lang.Class.forName(Class.java:381)
at org.example.TestLoading.loadMyClass(TestLoading.java:29)
at org.example.TestLoading.main(TestLoading.java:23)
Caused by: java.lang.ClassNotFoundException: org.example.TestLoading$ChildClass
at 
java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at 
java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 5 more

As of Java 20 chapter 12.4.1 of JLS states:
-
A class or interface T will be initialized immediately before the first 
occurrence of any one of the following:

- T is a class and an instance of T is created.
- a static method declared by T is invoked.
- a static field declared by T is assigned.
- a static field declared by T is used and the field is not a constant variable 
(§4.12.4).

When a class is initialized, its superclasses are initialized (if they have not 
been previously initialized), as well as any superinterfaces (§8.1.5) that 
declare any default methods (§9.4.3) (if they have not been previously 
initialized).
Initialization of an interface does not, of itself, cause initialization of any 
of its superinterfaces.
A reference to a static field (§8.3.1.1) causes initialization of only the 
class or interface that actually declares it, even though it might be referred 
to through the name of a subclass, a subinterface, or a class that implements 
an interface.
Invocation of certain reflective methods in class Class and in package 
java.lang.reflect also causes class or interface initialization.
A class or interface will not be initialized under any other circumstance.
-
With the code snippet we see that calling 
Class.forName(ObjectReturner.class.getName()) succeeds and 
Class.forName(BaseClassReturner.class.getName()) fails even though both declare 
returning an instance of ChildClass.
This failure is unexpected as in the code below we don't fulfill any 
requirement for class loading as of JLS 12.4.1, but the JVM still tries to load 
the class.

I suspect it might be related to class file validation and/or security, because 
when we run the code with -Xlog:class+init there's a reference to LinkageError 
in loading log:

loading: org.example.TestLoading$BaseClassReturner...
[0.277s][info][class,init] Start class verification for: 
org.example.TestLoading$BaseClassReturner
[0.277s][info][class,init] 771 Initializing 
'java/lang/ReflectiveOperationException'(no method) (0x00084028)
[0.277s][info][class,init] 772 Initializing 
'java/lang/ClassNotFoundException'(no method) (0x00084288)
[0.277s][info][class,init] 773 Initializing 'java/lang/LinkageError'(no method) 
(0x000844f8)  <
[0.277s][info][class,init] 774 Initializing 'java/lang/NoClassDefFoundError'(no 
method) (0x00084758)
[0.277s][info][class,init] Verification for 
org.example.TestLoading$BaseClassReturner has exception pending 
'java.lang.NoClassDefFoundError org/example/TestLoading$ChildClass'
[0.277s][info][class,init] End class verification for: 
org.example.TestLoading$BaseClassReturner


So I've got three questions about this:
- Does class loading depend on method's return type?
- Which part of JLS/JVM spec describes eager class loading in this case?
- Could one point out the particular piece of the VM code responsible for class 
loading in this case?

Regards,
Sergey Tsypanov

Code snippet for reproduction:

public class TestLoading {

  public static void main(String[] args) throws Exception {
Class.forName(BaseClass.class.getName());
URL classFileB = 
TestLoading.class.getResource(TestLoading.class.getSimpleName() + 
"$ChildClass.class");
if (classFileB != null) {
  if (!"file".equals(classFileB.getProtocol())) {
throw new UnsupportedOperationException();
  }
  Path path = new File(classFileB.getPath()).toPath();
  System.out.println("deleting: " + path);
  Files.delete(path);
}

loadMyClass(ObjectReturner.class.getName());
loadMyClass(BaseClassReturner.class.getName());
  }

  private static void loadMyClass(String name) {
System.out.println("loading: " + name +