Skip to content

Commit c4b516d

Browse files
calvinccheungiklam
andcommittedMar 3, 2025
8348322: AOT cache creation crashes with "All cached hidden classes must be aot-linkable" when AOTInvokeDynamicLinking is disabled
Co-authored-by: Ioi Lam <iklam@openjdk.org> Reviewed-by: iklam, matsaave
1 parent e470f47 commit c4b516d

17 files changed

+48
-34
lines changed
 

‎src/hotspot/share/cds/aotClassInitializer.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) {
107107
// Automatic selection for aot-inited classes
108108
// ==========================================
109109
//
110-
// When CDSConfig::is_initing_classes_at_dump_time() is enabled,
110+
// When CDSConfig::is_initing_classes_at_dump_time is enabled,
111111
// AOTArtifactFinder::find_artifacts() finds the classes of all
112112
// heap objects that are reachable from HeapShared::_run_time_special_subgraph,
113113
// and mark these classes as aot-inited. This preserves the initialized
@@ -266,7 +266,7 @@ bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) {
266266
}
267267
}
268268

269-
if (CDSConfig::is_dumping_invokedynamic()) {
269+
if (CDSConfig::is_dumping_method_handles()) {
270270
// This table was created with the help of CDSHeapVerifier.
271271
// Also, some $Holder classes are needed. E.g., Invokers.<clinit> explicitly
272272
// initializes Invokers$Holder. Since Invokers.<clinit> won't be executed

‎src/hotspot/share/cds/aotClassLinker.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ bool AOTClassLinker::try_add_candidate(InstanceKlass* ik) {
142142

143143
if (ik->is_hidden()) {
144144
assert(ik->shared_class_loader_type() != ClassLoader::OTHER, "must have been set");
145-
if (!CDSConfig::is_dumping_invokedynamic()) {
145+
if (!CDSConfig::is_dumping_method_handles()) {
146146
return false;
147147
}
148148
if (HeapShared::is_lambda_proxy_klass(ik)) {

‎src/hotspot/share/cds/archiveBuilder.cpp

+8-3
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,7 @@ void ArchiveBuilder::make_klasses_shareable() {
786786
const char* aotlinked_msg = "";
787787
const char* inited_msg = "";
788788
Klass* k = get_buffered_addr(klasses()->at(i));
789+
bool inited = false;
789790
k->remove_java_mirror();
790791
#ifdef _LP64
791792
if (UseCompactObjectHeaders) {
@@ -810,7 +811,7 @@ void ArchiveBuilder::make_klasses_shareable() {
810811
InstanceKlass* ik = InstanceKlass::cast(k);
811812
InstanceKlass* src_ik = get_source_addr(ik);
812813
bool aotlinked = AOTClassLinker::is_candidate(src_ik);
813-
bool inited = ik->has_aot_initialized_mirror();
814+
inited = ik->has_aot_initialized_mirror();
814815
ADD_COUNT(num_instance_klasses);
815816
if (CDSConfig::is_dumping_dynamic_archive()) {
816817
// For static dump, class loader type are already set.
@@ -833,7 +834,7 @@ void ArchiveBuilder::make_klasses_shareable() {
833834
type = "bad";
834835
assert(0, "shouldn't happen");
835836
}
836-
if (CDSConfig::is_dumping_invokedynamic()) {
837+
if (CDSConfig::is_dumping_method_handles()) {
837838
assert(HeapShared::is_archivable_hidden_klass(ik), "sanity");
838839
} else {
839840
// Legacy CDS support for lambda proxies
@@ -891,7 +892,11 @@ void ArchiveBuilder::make_klasses_shareable() {
891892
aotlinked_msg = " aot-linked";
892893
}
893894
if (inited) {
894-
inited_msg = " inited";
895+
if (InstanceKlass::cast(k)->static_field_size() == 0) {
896+
inited_msg = " inited (no static fields)";
897+
} else {
898+
inited_msg = " inited";
899+
}
895900
}
896901

897902
MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread::current(), ik);

‎src/hotspot/share/cds/cdsConfig.cpp

+7-3
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ bool CDSConfig::_is_using_optimized_module_handling = true;
4747
bool CDSConfig::_is_dumping_full_module_graph = true;
4848
bool CDSConfig::_is_using_full_module_graph = true;
4949
bool CDSConfig::_has_aot_linked_classes = false;
50-
bool CDSConfig::_has_archived_invokedynamic = false;
5150
bool CDSConfig::_old_cds_flags_used = false;
5251
bool CDSConfig::_new_aot_flags_used = false;
5352
bool CDSConfig::_disable_heap_dumping = false;
@@ -738,8 +737,13 @@ bool CDSConfig::is_dumping_invokedynamic() {
738737
return AOTInvokeDynamicLinking && is_dumping_aot_linked_classes() && is_dumping_heap();
739738
}
740739

741-
bool CDSConfig::is_loading_invokedynamic() {
742-
return UseSharedSpaces && is_using_full_module_graph() && _has_archived_invokedynamic;
740+
// When we are dumping aot-linked classes and we are able to write archived heap objects, we automatically
741+
// enable the archiving of MethodHandles. This will in turn enable the archiving of MethodTypes and hidden
742+
// classes that are used in the implementation of MethodHandles.
743+
// Archived MethodHandles are required for higher-level optimizations such as AOT resolution of invokedynamic
744+
// and dynamic proxies.
745+
bool CDSConfig::is_dumping_method_handles() {
746+
return is_initing_classes_at_dump_time();
743747
}
744748

745749
#endif // INCLUDE_CDS_JAVA_HEAP

‎src/hotspot/share/cds/cdsConfig.hpp

+1-3
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ class CDSConfig : public AllStatic {
4141
static bool _is_dumping_full_module_graph;
4242
static bool _is_using_full_module_graph;
4343
static bool _has_aot_linked_classes;
44-
static bool _has_archived_invokedynamic;
4544

4645
static char* _default_archive_path;
4746
static char* _static_archive_path;
@@ -160,8 +159,7 @@ class CDSConfig : public AllStatic {
160159
static bool is_initing_classes_at_dump_time() NOT_CDS_JAVA_HEAP_RETURN_(false);
161160

162161
static bool is_dumping_invokedynamic() NOT_CDS_JAVA_HEAP_RETURN_(false);
163-
static bool is_loading_invokedynamic() NOT_CDS_JAVA_HEAP_RETURN_(false);
164-
static void set_has_archived_invokedynamic() { CDS_JAVA_HEAP_ONLY(_has_archived_invokedynamic = true); }
162+
static bool is_dumping_method_handles() NOT_CDS_JAVA_HEAP_RETURN_(false);
165163

166164
// full_module_graph (requires optimized_module_handling)
167165
static bool is_dumping_full_module_graph() { return CDS_ONLY(_is_dumping_full_module_graph) NOT_CDS(false); }

‎src/hotspot/share/cds/cdsHeapVerifier.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ CDSHeapVerifier::CDSHeapVerifier() : _archived_objs(0), _problems(0)
106106

107107
ADD_EXCL("java/lang/System", "bootLayer"); // A
108108

109+
ADD_EXCL("java/util/Collections", "EMPTY_LIST"); // E
110+
109111
// A dummy object used by HashSet. The value doesn't matter and it's never
110112
// tested for equality.
111113
ADD_EXCL("java/util/HashSet", "PRESENT"); // E
@@ -127,7 +129,7 @@ CDSHeapVerifier::CDSHeapVerifier() : _archived_objs(0), _problems(0)
127129
ADD_EXCL("sun/invoke/util/ValueConversions", "ONE_INT", // E
128130
"ZERO_INT"); // E
129131

130-
if (CDSConfig::is_dumping_invokedynamic()) {
132+
if (CDSConfig::is_dumping_method_handles()) {
131133
ADD_EXCL("java/lang/invoke/InvokerBytecodeGenerator", "MEMBERNAME_FACTORY", // D
132134
"CD_Object_array", // E same as <...>ConstantUtils.CD_Object_array::CD_Object
133135
"INVOKER_SUPER_DESC"); // E same as java.lang.constant.ConstantDescs::CD_Object

‎src/hotspot/share/cds/classListParser.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,7 @@ void ClassListParser::resolve_indy(JavaThread* current, Symbol* class_name_symbo
627627
}
628628

629629
void ClassListParser::resolve_indy_impl(Symbol* class_name_symbol, TRAPS) {
630-
if (CDSConfig::is_dumping_invokedynamic()) {
630+
if (CDSConfig::is_dumping_method_handles()) {
631631
// The CP entry for the invokedynamic instruction will be resolved.
632632
// No need to do the following.
633633
return;

‎src/hotspot/share/cds/filemap.cpp

-6
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,6 @@ void FileMapHeader::populate(FileMapInfo *info, size_t core_region_alignment,
234234
_use_optimized_module_handling = CDSConfig::is_using_optimized_module_handling();
235235
_has_aot_linked_classes = CDSConfig::is_dumping_aot_linked_classes();
236236
_has_full_module_graph = CDSConfig::is_dumping_full_module_graph();
237-
_has_archived_invokedynamic = CDSConfig::is_dumping_invokedynamic();
238237

239238
// The following fields are for sanity checks for whether this archive
240239
// will function correctly with this JVM and the bootclasspath it's
@@ -309,7 +308,6 @@ void FileMapHeader::print(outputStream* st) {
309308
st->print_cr("- use_optimized_module_handling: %d", _use_optimized_module_handling);
310309
st->print_cr("- has_full_module_graph %d", _has_full_module_graph);
311310
st->print_cr("- has_aot_linked_classes %d", _has_aot_linked_classes);
312-
st->print_cr("- has_archived_invokedynamic %d", _has_archived_invokedynamic);
313311
}
314312

315313
bool FileMapInfo::validate_class_location() {
@@ -1950,10 +1948,6 @@ bool FileMapHeader::validate() {
19501948
if (!_has_full_module_graph) {
19511949
CDSConfig::stop_using_full_module_graph("archive was created without full module graph");
19521950
}
1953-
1954-
if (_has_archived_invokedynamic) {
1955-
CDSConfig::set_has_archived_invokedynamic();
1956-
}
19571951
}
19581952

19591953
return true;

‎src/hotspot/share/cds/filemap.hpp

-1
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,6 @@ class FileMapHeader: private CDSFileMapHeaderBase {
140140
// some expensive operations.
141141
bool _has_aot_linked_classes; // Was the CDS archive created with -XX:+AOTClassLinking
142142
bool _has_full_module_graph; // Does this CDS archive contain the full archived module graph?
143-
bool _has_archived_invokedynamic; // Does the archive have aot-linked invokedynamic CP entries?
144143
HeapRootSegments _heap_root_segments; // Heap root segments info
145144
size_t _heap_oopmap_start_pos; // The first bit in the oopmap corresponds to this position in the heap.
146145
size_t _heap_ptrmap_start_pos; // The first bit in the ptrmap corresponds to this position in the heap.

‎src/hotspot/share/cds/heapShared.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ bool HeapShared::is_string_concat_klass(InstanceKlass* ik) {
492492
}
493493

494494
bool HeapShared::is_archivable_hidden_klass(InstanceKlass* ik) {
495-
return CDSConfig::is_dumping_invokedynamic() &&
495+
return CDSConfig::is_dumping_method_handles() &&
496496
(is_lambda_form_klass(ik) || is_lambda_proxy_klass(ik) || is_string_concat_klass(ik));
497497
}
498498

@@ -782,7 +782,7 @@ void KlassSubGraphInfo::add_subgraph_object_klass(Klass* orig_k) {
782782
if (orig_k->is_instance_klass()) {
783783
#ifdef ASSERT
784784
InstanceKlass* ik = InstanceKlass::cast(orig_k);
785-
if (CDSConfig::is_dumping_invokedynamic()) {
785+
if (CDSConfig::is_dumping_method_handles()) {
786786
assert(ik->class_loader() == nullptr ||
787787
HeapShared::is_lambda_proxy_klass(ik),
788788
"we can archive only instances of boot classes or lambda proxy classes");
@@ -835,7 +835,7 @@ void KlassSubGraphInfo::check_allowed_klass(InstanceKlass* ik) {
835835
}
836836

837837
const char* lambda_msg = "";
838-
if (CDSConfig::is_dumping_invokedynamic()) {
838+
if (CDSConfig::is_dumping_method_handles()) {
839839
lambda_msg = ", or a lambda proxy class";
840840
if (HeapShared::is_lambda_proxy_klass(ik) &&
841841
(ik->class_loader() == nullptr ||
@@ -1108,7 +1108,7 @@ void HeapShared::resolve_classes_for_subgraph_of(JavaThread* current, Klass* k)
11081108
}
11091109

11101110
void HeapShared::initialize_java_lang_invoke(TRAPS) {
1111-
if (CDSConfig::is_loading_invokedynamic() || CDSConfig::is_dumping_invokedynamic()) {
1111+
if (CDSConfig::is_using_aot_linked_classes() || CDSConfig::is_dumping_method_handles()) {
11121112
resolve_or_init("java/lang/invoke/Invokers$Holder", true, CHECK);
11131113
resolve_or_init("java/lang/invoke/MethodHandle", true, CHECK);
11141114
resolve_or_init("java/lang/invoke/MethodHandleNatives", true, CHECK);

‎src/hotspot/share/cds/lambdaFormInvokers.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ void LambdaFormInvokers::regenerate_holder_classes(TRAPS) {
9595
return;
9696
}
9797

98-
if (CDSConfig::is_dumping_static_archive() && CDSConfig::is_dumping_invokedynamic()) {
98+
if (CDSConfig::is_dumping_static_archive() && CDSConfig::is_dumping_method_handles()) {
9999
// Work around JDK-8310831, as some methods in lambda form holder classes may not get generated.
100100
log_info(cds)("Archived MethodHandles may refer to lambda form holder classes. Cannot regenerate.");
101101
return;

‎src/hotspot/share/cds/metaspaceShared.cpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -636,7 +636,7 @@ void VM_PopulateDumpSharedSpace::doit() {
636636
DEBUG_ONLY(SystemDictionaryShared::NoClassLoadingMark nclm);
637637

638638
_pending_method_handle_intrinsics = new (mtClassShared) GrowableArray<Method*>(256, mtClassShared);
639-
if (CDSConfig::is_dumping_aot_linked_classes()) {
639+
if (CDSConfig::is_dumping_method_handles()) {
640640
// When dumping AOT-linked classes, some classes may have direct references to a method handle
641641
// intrinsic. The easiest thing is to save all of them into the AOT cache.
642642
SystemDictionary::get_all_method_handle_intrinsics(_pending_method_handle_intrinsics);
@@ -985,7 +985,7 @@ void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS
985985
HeapShared::reset_archived_object_states(CHECK);
986986
}
987987

988-
if (CDSConfig::is_dumping_invokedynamic()) {
988+
if (CDSConfig::is_dumping_method_handles()) {
989989
// This assert means that the MethodType and MethodTypeForm tables won't be
990990
// updated concurrently when we are saving their contents into a side table.
991991
assert(CDSConfig::allow_only_single_java_thread(), "Required");
@@ -995,12 +995,15 @@ void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS
995995
vmSymbols::createArchivedObjects(),
996996
vmSymbols::void_method_signature(),
997997
CHECK);
998+
}
998999

1000+
if (CDSConfig::is_initing_classes_at_dump_time()) {
9991001
// java.lang.Class::reflectionFactory cannot be archived yet. We set this field
10001002
// to null, and it will be initialized again at runtime.
10011003
log_debug(cds)("Resetting Class::reflectionFactory");
10021004
TempNewSymbol method_name = SymbolTable::new_symbol("resetArchivedStates");
10031005
Symbol* method_sig = vmSymbols::void_method_signature();
1006+
JavaValue result(T_VOID);
10041007
JavaCalls::call_static(&result, vmClasses::Class_klass(),
10051008
method_name, method_sig, CHECK);
10061009

‎src/hotspot/share/classfile/javaClasses.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -5452,7 +5452,7 @@ void JavaClasses::serialize_offsets(SerializeClosure* soc) {
54525452
bool JavaClasses::is_supported_for_archiving(oop obj) {
54535453
Klass* klass = obj->klass();
54545454

5455-
if (!CDSConfig::is_dumping_invokedynamic()) {
5455+
if (!CDSConfig::is_dumping_method_handles()) {
54565456
// These are supported by CDS only when CDSConfig::is_dumping_invokedynamic() is enabled.
54575457
if (klass == vmClasses::ResolvedMethodName_klass() ||
54585458
klass == vmClasses::MemberName_klass()) {

‎src/hotspot/share/classfile/systemDictionaryShared.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) {
295295
if (!k->is_hidden() && k->shared_classpath_index() < 0 && is_builtin(k)) {
296296
if (k->name()->starts_with("java/lang/invoke/BoundMethodHandle$Species_")) {
297297
// This class is dynamically generated by the JDK
298-
if (CDSConfig::is_dumping_aot_linked_classes()) {
298+
if (CDSConfig::is_dumping_method_handles()) {
299299
k->set_shared_classpath_index(0);
300300
} else {
301301
ResourceMark rm;
@@ -587,7 +587,7 @@ void SystemDictionaryShared::validate_before_archiving(InstanceKlass* k) {
587587
guarantee(!info->is_excluded(), "Should not attempt to archive excluded class %s", name);
588588
if (is_builtin(k)) {
589589
if (k->is_hidden()) {
590-
if (!CDSConfig::is_dumping_invokedynamic()) {
590+
if (!CDSConfig::is_dumping_method_handles()) {
591591
assert(is_registered_lambda_proxy_class(k), "unexpected hidden class %s", name);
592592
}
593593
}

‎src/hotspot/share/oops/constantPool.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ void ConstantPool::klass_at_put(int class_index, Klass* k) {
288288
template <typename Function>
289289
void ConstantPool::iterate_archivable_resolved_references(Function function) {
290290
objArrayOop rr = resolved_references();
291-
if (rr != nullptr && cache() != nullptr && CDSConfig::is_dumping_invokedynamic()) {
291+
if (rr != nullptr && cache() != nullptr && CDSConfig::is_dumping_method_handles()) {
292292
Array<ResolvedIndyEntry>* indy_entries = cache()->resolved_indy_entries();
293293
if (indy_entries != nullptr) {
294294
for (int i = 0; i < indy_entries->length(); i++) {

‎src/hotspot/share/oops/cpCache.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,7 @@ bool ConstantPoolCache::can_archive_resolved_method(ConstantPool* src_cp, Resolv
572572
method_entry->is_resolved(Bytecodes::_invokespecial)) {
573573
return true;
574574
} else if (method_entry->is_resolved(Bytecodes::_invokehandle)) {
575-
if (CDSConfig::is_dumping_invokedynamic()) {
575+
if (CDSConfig::is_dumping_method_handles()) {
576576
// invokehandle depends on archived MethodType and LambdaForms.
577577
return true;
578578
} else {

‎test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AOTClassLinkingVMOptions.java

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -80,6 +80,15 @@ public static void main(String[] args) throws Exception {
8080
.assertAbnormalExit("CDS archive has aot-linked classes." +
8181
" It cannot be used with -Djava.security.manager=default.");
8282

83+
// Dumping with AOTInvokeDynamicLinking disabled
84+
TestCommon.testDump(appJar, TestCommon.list("Hello"),
85+
"-XX:+AOTClassLinking", "-XX:-AOTInvokeDynamicLinking");
86+
87+
testCase("Archived full module graph must be enabled at runtime (with -XX:-AOTInvokeDynamicLinking)");
88+
TestCommon.run("-cp", appJar, "-Djdk.module.validation=1", "Hello")
89+
.assertAbnormalExit("CDS archive has aot-linked classes." +
90+
" It cannot be used when archived full module graph is not used");
91+
8392
// NOTE: tests for ClassFileLoadHook + AOTClassLinking is in
8493
// ../jvmti/ClassFileLoadHookTest.java
8594

0 commit comments

Comments
 (0)
Please sign in to comment.