The AOT assembly phase (-XX:AOTMode=create) avoids executing any code provided by the application. This is to avoid undesirable side effects being stored into the AOT cache.
The check is pretty simple -- if any code in a user class has been executed, then this class must at least be in the "is_being_initialized" state. See the following for a draft.
bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) {
assert(!ArchiveBuilder::is_active() || !ArchiveBuilder::current()->is_in_buffer_space(ik), "must be source klass");
if (!CDSConfig::is_initing_classes_at_dump_time()) {
return false;
}
if (RegeneratedClasses::is_regenerated_object(ik)) {
ik = RegeneratedClasses::get_original_object(ik);
}
if (!ik->is_initialized() && !ik->is_being_initialized()) {
return false;
}
>>>> add
DEBUG_ONLY({
if (AOTInitTestClass == nullptr && ArchiveHeapTestClass == nullptr) {
// The above flags (in debug builds only) allow user code to be executed in assembly phase,
// strictly for testing purposes. If these flags are not set, no user code will be executed
// in assembly phase.
if (ik->class_loader() != nullptr && !ik->is_hidden()) {
if (ik->is_interface() && !ik->interface_needs_clinit_execution_as_super()) {
// TODO: why are these interfaces marked as initialized??
} else {
assert(false, "cannot execute user code");
}
}
}});
<<<<<
The check is pretty simple -- if any code in a user class has been executed, then this class must at least be in the "is_being_initialized" state. See the following for a draft.
bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) {
assert(!ArchiveBuilder::is_active() || !ArchiveBuilder::current()->is_in_buffer_space(ik), "must be source klass");
if (!CDSConfig::is_initing_classes_at_dump_time()) {
return false;
}
if (RegeneratedClasses::is_regenerated_object(ik)) {
ik = RegeneratedClasses::get_original_object(ik);
}
if (!ik->is_initialized() && !ik->is_being_initialized()) {
return false;
}
>>>> add
DEBUG_ONLY({
if (AOTInitTestClass == nullptr && ArchiveHeapTestClass == nullptr) {
// The above flags (in debug builds only) allow user code to be executed in assembly phase,
// strictly for testing purposes. If these flags are not set, no user code will be executed
// in assembly phase.
if (ik->class_loader() != nullptr && !ik->is_hidden()) {
if (ik->is_interface() && !ik->interface_needs_clinit_execution_as_super()) {
// TODO: why are these interfaces marked as initialized??
} else {
assert(false, "cannot execute user code");
}
}
}});
<<<<<