RFR: 8369742: Link AOT-linked classes at JVM bootstrap

Vladimir Kozlov kvn at openjdk.org
Wed Oct 15 18:09:08 UTC 2025


On Wed, 15 Oct 2025 18:00:56 GMT, Vladimir Kozlov <kvn at openjdk.org> wrote:

>> **PROBLEM**
>> 
>> If we have an AOT-initialized class like this in java.base
>> 
>> 
>> @AOTSafeClassInitializer
>> class Foo {
>>     static Bar b = new Bar(); // AOT-cached
>>     static void doit() {
>>         b.toString(); /// invokevirtual Bar::toString()Ljava/lang/String;
>>     }
>> }
>> 
>> 
>> If `Foo.doit()` is called before `AOTLinkedClassBulkLoader::link_or_init_javabase_classe()`, it's possible for the `Bar` class to be not yet linked. The `invokevirtual` bytecode will crash because the vtable of the object `b` is not yet initialized.
>> 
>> **FIX**
>> 
>> Before we execute the first Java bytecode, unconditionally link all AOT-linked classes. This will ensure that the `Bar` class will have an initialized vtable for the above example.
>> 
>> **NOTES**
>> 
>> - The scenario in the  above example does not affect JDK 24, 25 or the current JDK mainline (26). We are lucky that in all the bytecode execution up to `AOTLinkedClassBulkLoader::link_or_init_javabase_classe()`, whenever we do a vtable/itable dispatch on an AOT-cached heap object, we happen to have already linked its class (either by explicit calls from the JVM, or as side effect of invokestatic/getstatic/putstatic/new). However, this is a potential problem that should be fixed. I have run into this problem when implementing [JDK-8368199](https://bugs.openjdk.org/browse/JDK-8368199), which changes the bytecodes that are executed in early VM bootstrap.
>> - I had to enable `CDSConfig::is_preserving_verification_constraints()` to for the static CDS archive. The reason is to avoid class loading. Please see the new comments in `AOTLinkedClassBulkLoader::link_classes_in_table()`.
>> - The change in `AdapterHandlerLibrary::create_native_wrapper` is for supporting JVMTI. The offending methods are `jdk.internal.vm.Continuation::enterSpecial` and `jdk.internal.vm.Continuation::doYield`. These are "continuation native intrinsic" methods that are usually linked much later after the ServiceThread have been started.
>
> src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp line 350:
> 
>> 348: // With AOT-linked classes, we could compile nmethods before the ServiceThread
>> 349: // has been started, so we must delay the events to be posted later.
>> 350: void AOTLinkedClassBulkLoader::add_delayed_compiled_method_load_event(nmethod* nm) {
> 
> I don't think it should be done in `AOTLinkedClassBulkLoader`.  Please move it to `nmethod.*` files

This only affects native wrappers as I understand which are generated by Shared runtime. JIT compilers are not initialized yet.  May be update comment to be clear: "With AOT-linked classes, we could compile wrappers for native methods before the ServiceThread"

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/27783#discussion_r2433513623


More information about the hotspot-dev mailing list