Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/hotspot/share/cds/aotClassInitializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) {
// Automatic selection for aot-inited classes
// ==========================================
//
// When CDSConfig::is_initing_classes_at_dump_time() is enabled,
// When CDSConfig::is_initing_classes_at_dump_time is enabled,
// AOTArtifactFinder::find_artifacts() finds the classes of all
// heap objects that are reachable from HeapShared::_run_time_special_subgraph,
// and mark these classes as aot-inited. This preserves the initialized
Expand Down Expand Up @@ -266,7 +266,7 @@ bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) {
}
}

if (CDSConfig::is_dumping_invokedynamic()) {
if (CDSConfig::is_dumping_method_handles()) {
// This table was created with the help of CDSHeapVerifier.
// Also, some $Holder classes are needed. E.g., Invokers.<clinit> explicitly
// initializes Invokers$Holder. Since Invokers.<clinit> won't be executed
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/cds/aotClassLinker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ bool AOTClassLinker::try_add_candidate(InstanceKlass* ik) {

if (ik->is_hidden()) {
assert(ik->shared_class_loader_type() != ClassLoader::OTHER, "must have been set");
if (!CDSConfig::is_dumping_invokedynamic()) {
if (!CDSConfig::is_dumping_method_handles()) {
return false;
}
if (HeapShared::is_lambda_proxy_klass(ik)) {
Expand Down
11 changes: 8 additions & 3 deletions src/hotspot/share/cds/archiveBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,7 @@ void ArchiveBuilder::make_klasses_shareable() {
const char* aotlinked_msg = "";
const char* inited_msg = "";
Klass* k = get_buffered_addr(klasses()->at(i));
bool inited = false;
k->remove_java_mirror();
#ifdef _LP64
if (UseCompactObjectHeaders) {
Expand All @@ -811,7 +812,7 @@ void ArchiveBuilder::make_klasses_shareable() {
InstanceKlass* ik = InstanceKlass::cast(k);
InstanceKlass* src_ik = get_source_addr(ik);
bool aotlinked = AOTClassLinker::is_candidate(src_ik);
bool inited = ik->has_aot_initialized_mirror();
inited = ik->has_aot_initialized_mirror();
ADD_COUNT(num_instance_klasses);
if (CDSConfig::is_dumping_dynamic_archive()) {
// For static dump, class loader type are already set.
Expand All @@ -834,7 +835,7 @@ void ArchiveBuilder::make_klasses_shareable() {
type = "bad";
assert(0, "shouldn't happen");
}
if (CDSConfig::is_dumping_invokedynamic()) {
if (CDSConfig::is_dumping_method_handles()) {
assert(HeapShared::is_archivable_hidden_klass(ik), "sanity");
} else {
// Legacy CDS support for lambda proxies
Expand Down Expand Up @@ -892,7 +893,11 @@ void ArchiveBuilder::make_klasses_shareable() {
aotlinked_msg = " aot-linked";
}
if (inited) {
inited_msg = " inited";
if (InstanceKlass::cast(k)->static_field_size() == 0) {
inited_msg = " inited (no static fields)";
} else {
inited_msg = " inited";
}
}

MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread::current(), ik);
Expand Down
10 changes: 7 additions & 3 deletions src/hotspot/share/cds/cdsConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ bool CDSConfig::_is_using_optimized_module_handling = true;
bool CDSConfig::_is_dumping_full_module_graph = true;
bool CDSConfig::_is_using_full_module_graph = true;
bool CDSConfig::_has_aot_linked_classes = false;
bool CDSConfig::_has_archived_invokedynamic = false;
bool CDSConfig::_old_cds_flags_used = false;
bool CDSConfig::_disable_heap_dumping = false;

Expand Down Expand Up @@ -656,8 +655,13 @@ bool CDSConfig::is_dumping_invokedynamic() {
return AOTInvokeDynamicLinking && is_dumping_aot_linked_classes() && is_dumping_heap();
}

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like it does the same check as is_initing_classes_at_dump_time() and is very similar to is_dumping_invokedynamic(). Maybe you can combine these methods to avoid duplicate code?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the CDSConfig::is_initing_classes_at_dump_time() since the conditions are the same as CDSConfig::is_dumping_method_handles(). All the calls to CDSConfig::is_initing_classes_at_dump_time() have been updated accordingly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should keep is_initing_classes_at_dump_time(), because it's used as a precondition for archiving initialized Java mirrors. Putting such code inside is_dumping_method_handles() would not make sense.

In fact, archived method handles require the ability to store initialized mirrors (for the hidden classes). So I think we should change is_dumping_method_handles() to this:

// When we can dump initialized classes mirrors, we automatically enable the archiving of MethodHandles.
// This will in turn enable the archiving of MethodTypes and hidden classes that are used in the
// implementation of MethodHandles. Note: these hidden classes need to be stored in the initialized state,
// as we don't have a mechanism to trigger their initialization on-demand.
// Archived MethodHandles are required for higher-level optimizations such as AOT resolution of invokedynamic
// and dynamic proxies.
bool CDSConfig::is_dumping_method_handles() {
  return is_initing_classes_at_dump_time();
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added back the CDSConfig::is_initing_classes_at_dump_time() function and reverted most of previous changes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The three changes in aotArtifactFinder.cpp should also be reverted.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

return is_initing_classes_at_dump_time();
}

#endif // INCLUDE_CDS_JAVA_HEAP
4 changes: 1 addition & 3 deletions src/hotspot/share/cds/cdsConfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ class CDSConfig : public AllStatic {
static bool _is_dumping_full_module_graph;
static bool _is_using_full_module_graph;
static bool _has_aot_linked_classes;
static bool _has_archived_invokedynamic;

static char* _default_archive_path;
static char* _static_archive_path;
Expand Down Expand Up @@ -126,8 +125,7 @@ class CDSConfig : public AllStatic {
static bool is_initing_classes_at_dump_time() NOT_CDS_JAVA_HEAP_RETURN_(false);

static bool is_dumping_invokedynamic() NOT_CDS_JAVA_HEAP_RETURN_(false);
static bool is_loading_invokedynamic() NOT_CDS_JAVA_HEAP_RETURN_(false);
static void set_has_archived_invokedynamic() { CDS_JAVA_HEAP_ONLY(_has_archived_invokedynamic = true); }
static bool is_dumping_method_handles() NOT_CDS_JAVA_HEAP_RETURN_(false);

// full_module_graph (requires optimized_module_handling)
static bool is_dumping_full_module_graph() { return CDS_ONLY(_is_dumping_full_module_graph) NOT_CDS(false); }
Expand Down
4 changes: 3 additions & 1 deletion src/hotspot/share/cds/cdsHeapVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ CDSHeapVerifier::CDSHeapVerifier() : _archived_objs(0), _problems(0)

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

ADD_EXCL("java/util/Collections", "EMPTY_LIST"); // E

// A dummy object used by HashSet. The value doesn't matter and it's never
// tested for equality.
ADD_EXCL("java/util/HashSet", "PRESENT"); // E
Expand All @@ -127,7 +129,7 @@ CDSHeapVerifier::CDSHeapVerifier() : _archived_objs(0), _problems(0)
ADD_EXCL("sun/invoke/util/ValueConversions", "ONE_INT", // E
"ZERO_INT"); // E

if (CDSConfig::is_dumping_invokedynamic()) {
if (CDSConfig::is_dumping_method_handles()) {
ADD_EXCL("java/lang/invoke/InvokerBytecodeGenerator", "MEMBERNAME_FACTORY", // D
"CD_Object_array", // E same as <...>ConstantUtils.CD_Object_array::CD_Object
"INVOKER_SUPER_DESC"); // E same as java.lang.constant.ConstantDescs::CD_Object
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/cds/classListParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ void ClassListParser::resolve_indy(JavaThread* current, Symbol* class_name_symbo
}

void ClassListParser::resolve_indy_impl(Symbol* class_name_symbol, TRAPS) {
if (CDSConfig::is_dumping_invokedynamic()) {
if (CDSConfig::is_dumping_method_handles()) {
// The CP entry for the invokedynamic instruction will be resolved.
// No need to do the following.
return;
Expand Down
6 changes: 0 additions & 6 deletions src/hotspot/share/cds/filemap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,6 @@ void FileMapHeader::populate(FileMapInfo *info, size_t core_region_alignment,
_use_optimized_module_handling = CDSConfig::is_using_optimized_module_handling();
_has_aot_linked_classes = CDSConfig::is_dumping_aot_linked_classes();
_has_full_module_graph = CDSConfig::is_dumping_full_module_graph();
_has_archived_invokedynamic = CDSConfig::is_dumping_invokedynamic();

// The following fields are for sanity checks for whether this archive
// will function correctly with this JVM and the bootclasspath it's
Expand Down Expand Up @@ -296,7 +295,6 @@ void FileMapHeader::print(outputStream* st) {
st->print_cr("- use_optimized_module_handling: %d", _use_optimized_module_handling);
st->print_cr("- has_full_module_graph %d", _has_full_module_graph);
st->print_cr("- has_aot_linked_classes %d", _has_aot_linked_classes);
st->print_cr("- has_archived_invokedynamic %d", _has_archived_invokedynamic);
}

bool FileMapInfo::validate_class_location() {
Expand Down Expand Up @@ -1885,10 +1883,6 @@ bool FileMapHeader::validate() {
if (!_has_full_module_graph) {
CDSConfig::stop_using_full_module_graph("archive was created without full module graph");
}

if (_has_archived_invokedynamic) {
CDSConfig::set_has_archived_invokedynamic();
}
}

return true;
Expand Down
1 change: 0 additions & 1 deletion src/hotspot/share/cds/filemap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@ class FileMapHeader: private CDSFileMapHeaderBase {
// some expensive operations.
bool _has_aot_linked_classes; // Was the CDS archive created with -XX:+AOTClassLinking
bool _has_full_module_graph; // Does this CDS archive contain the full archived module graph?
bool _has_archived_invokedynamic; // Does the archive have aot-linked invokedynamic CP entries?
HeapRootSegments _heap_root_segments; // Heap root segments info
size_t _heap_oopmap_start_pos; // The first bit in the oopmap corresponds to this position in the heap.
size_t _heap_ptrmap_start_pos; // The first bit in the ptrmap corresponds to this position in the heap.
Expand Down
8 changes: 4 additions & 4 deletions src/hotspot/share/cds/heapShared.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ bool HeapShared::is_string_concat_klass(InstanceKlass* ik) {
}

bool HeapShared::is_archivable_hidden_klass(InstanceKlass* ik) {
return CDSConfig::is_dumping_invokedynamic() &&
return CDSConfig::is_dumping_method_handles() &&
(is_lambda_form_klass(ik) || is_lambda_proxy_klass(ik) || is_string_concat_klass(ik));
}

Expand Down Expand Up @@ -779,7 +779,7 @@ void KlassSubGraphInfo::add_subgraph_object_klass(Klass* orig_k) {
if (orig_k->is_instance_klass()) {
#ifdef ASSERT
InstanceKlass* ik = InstanceKlass::cast(orig_k);
if (CDSConfig::is_dumping_invokedynamic()) {
if (CDSConfig::is_dumping_method_handles()) {
assert(ik->class_loader() == nullptr ||
HeapShared::is_lambda_proxy_klass(ik),
"we can archive only instances of boot classes or lambda proxy classes");
Expand Down Expand Up @@ -832,7 +832,7 @@ void KlassSubGraphInfo::check_allowed_klass(InstanceKlass* ik) {
}

const char* lambda_msg = "";
if (CDSConfig::is_dumping_invokedynamic()) {
if (CDSConfig::is_dumping_method_handles()) {
lambda_msg = ", or a lambda proxy class";
if (HeapShared::is_lambda_proxy_klass(ik) &&
(ik->class_loader() == nullptr ||
Expand Down Expand Up @@ -1105,7 +1105,7 @@ void HeapShared::resolve_classes_for_subgraph_of(JavaThread* current, Klass* k)
}

void HeapShared::initialize_java_lang_invoke(TRAPS) {
if (CDSConfig::is_loading_invokedynamic() || CDSConfig::is_dumping_invokedynamic()) {
if (CDSConfig::is_using_aot_linked_classes() || CDSConfig::is_dumping_method_handles()) {
resolve_or_init("java/lang/invoke/Invokers$Holder", true, CHECK);
resolve_or_init("java/lang/invoke/MethodHandle", true, CHECK);
resolve_or_init("java/lang/invoke/MethodHandleNatives", true, CHECK);
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/cds/lambdaFormInvokers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ void LambdaFormInvokers::regenerate_holder_classes(TRAPS) {
return;
}

if (CDSConfig::is_dumping_static_archive() && CDSConfig::is_dumping_invokedynamic()) {
if (CDSConfig::is_dumping_static_archive() && CDSConfig::is_dumping_method_handles()) {
// Work around JDK-8310831, as some methods in lambda form holder classes may not get generated.
log_info(cds)("Archived MethodHandles may refer to lambda form holder classes. Cannot regenerate.");
return;
Expand Down
7 changes: 5 additions & 2 deletions src/hotspot/share/cds/metaspaceShared.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ void VM_PopulateDumpSharedSpace::doit() {
DEBUG_ONLY(SystemDictionaryShared::NoClassLoadingMark nclm);

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

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

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

Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/classfile/javaClasses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5452,7 +5452,7 @@ void JavaClasses::serialize_offsets(SerializeClosure* soc) {
bool JavaClasses::is_supported_for_archiving(oop obj) {
Klass* klass = obj->klass();

if (!CDSConfig::is_dumping_invokedynamic()) {
if (!CDSConfig::is_dumping_method_handles()) {
// These are supported by CDS only when CDSConfig::is_dumping_invokedynamic() is enabled.
if (klass == vmClasses::ResolvedMethodName_klass() ||
klass == vmClasses::MemberName_klass()) {
Expand Down
4 changes: 2 additions & 2 deletions src/hotspot/share/classfile/systemDictionaryShared.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) {
if (!k->is_hidden() && k->shared_classpath_index() < 0 && is_builtin(k)) {
if (k->name()->starts_with("java/lang/invoke/BoundMethodHandle$Species_")) {
// This class is dynamically generated by the JDK
if (CDSConfig::is_dumping_aot_linked_classes()) {
if (CDSConfig::is_dumping_method_handles()) {
k->set_shared_classpath_index(0);
} else {
ResourceMark rm;
Expand Down Expand Up @@ -565,7 +565,7 @@ void SystemDictionaryShared::validate_before_archiving(InstanceKlass* k) {
guarantee(!info->is_excluded(), "Should not attempt to archive excluded class %s", name);
if (is_builtin(k)) {
if (k->is_hidden()) {
if (!CDSConfig::is_dumping_invokedynamic()) {
if (!CDSConfig::is_dumping_method_handles()) {
assert(is_registered_lambda_proxy_class(k), "unexpected hidden class %s", name);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/oops/constantPool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ void ConstantPool::klass_at_put(int class_index, Klass* k) {
template <typename Function>
void ConstantPool::iterate_archivable_resolved_references(Function function) {
objArrayOop rr = resolved_references();
if (rr != nullptr && cache() != nullptr && CDSConfig::is_dumping_invokedynamic()) {
if (rr != nullptr && cache() != nullptr && CDSConfig::is_dumping_method_handles()) {
Array<ResolvedIndyEntry>* indy_entries = cache()->resolved_indy_entries();
if (indy_entries != nullptr) {
for (int i = 0; i < indy_entries->length(); i++) {
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/oops/cpCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,7 @@ bool ConstantPoolCache::can_archive_resolved_method(ConstantPool* src_cp, Resolv
method_entry->is_resolved(Bytecodes::_invokespecial)) {
return true;
} else if (method_entry->is_resolved(Bytecodes::_invokehandle)) {
if (CDSConfig::is_dumping_invokedynamic()) {
if (CDSConfig::is_dumping_method_handles()) {
// invokehandle depends on archived MethodType and LambdaForms.
return true;
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -80,6 +80,15 @@ public static void main(String[] args) throws Exception {
.assertAbnormalExit("CDS archive has aot-linked classes." +
" It cannot be used with -Djava.security.manager=default.");

// Dumping with AOTInvokeDynamicLinking disabled
TestCommon.testDump(appJar, TestCommon.list("Hello"),
"-XX:+AOTClassLinking", "-XX:-AOTInvokeDynamicLinking");

testCase("Archived full module graph must be enabled at runtime (with -XX:-AOTInvokeDynamicLinking)");
TestCommon.run("-cp", appJar, "-Djdk.module.validation=1", "Hello")
.assertAbnormalExit("CDS archive has aot-linked classes." +
" It cannot be used when archived full module graph is not used");

// NOTE: tests for ClassFileLoadHook + AOTClassLinking is in
// ../jvmti/ClassFileLoadHookTest.java

Expand Down