Resolving super interface in different contexts depending on the child class

Aleksandr Popov a.popov.tmb at gmail.com
Fri Feb 23 16:32:49 UTC 2024


Hi! In the following test case I've investigated how Hotspot loads classes
into the loaders.
And found out that the inheritance chain could affect the result.

//--------------------------------------------------------------------------
public class SimpleTest {
    public static int compare(ScheduledFutureTask o1, ScheduledFutureTask
o2) {
        return o1.compareTo(o2);
    }

    public static void main(String[] args) {
        ScheduledFutureTask instances0 = new ScheduledFutureTask();
        ScheduledFutureTask instances1 = new ScheduledFutureTask();
        compare(instances0, instances1);
    }
}

final class ScheduledFutureTask implements ScheduledFuture<Void> {
...
    @Override
    public int compareTo(Delayed o) {
        if (this == o) {
            return 0;
        }
    }
}
//--------------------------------------------------------------------------


   - If *ScheduledFutureTask* class implements
   *java.util.concurrent.ScheduledFuture *interface,

which implements *java.util.concurrent.Delayed* interface: *[application
class -> core class -> core class],*
then the *Delayed *interface would be loaded into the boot class loader,
since it's resolved in the context of the core class.

I've added some logs to track class resolving:
# parse interfaces of class ScheduledFutureTask, [APP] loader
# parse interfaces of class java/util/concurrent/ScheduledFuture, [BOOT]
loader
# parse interfaces of class java/util/concurrent/Delayed, [BOOT] loader
# Adding java/util/concurrent/Delayed to dictionary [BOOT]


   - If we replace core class in the chain with an application one:
*[application
   class -> application class -> core class], *

then the *Delayed *interface would be loaded into both class loaders, since
it would be resolved in the context of the application class:

# parse interfaces of class ScheduledFutureTask, [application class loader]
# parse interfaces of class Interface1, [application class loader]
# parse interfaces of class java/util/concurrent/Delayed, [boot class
loader]
# Adding java/util/concurrent/Delayed to dictionary [boot class loader]
# Adding java/util/concurrent/Delayed to dictionary [application class
loader]


   - Theoretically, this difference could affect the result of the
   has_unloaded_classes_in_signature() call

for the ScheduledFutureTask::compareTo method.

final class ScheduledFutureTask implements ScheduledFuture<Void> {
...
    @Override
    public int compareTo(Delayed o) {
        if (this == o) {
            return 0;
        }
    }
}

Because in the first case (application class -> core class -> core class)
we have unloaded *java/util/concurrent/Delayed*
interface in the context of the accessing class, which was loaded into the
application class loader.

So my question is: why is it correct to have class loaded into different
class loaders depending on the inheritance chain?
Or maybe it's intentionally resolved somewhere in the code?

Note that SystemDictionary::check_signature_loaders doesn't add loader
constraints to the interface, since the caller and callee loaders are the
same in this case: both application loaders.
Thank you!
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/hotspot-dev/attachments/20240223/1de8a552/attachment-0001.htm>


More information about the hotspot-dev mailing list