Skip to content

Commit 006a379

Browse files
committedSep 25, 2023
Force some java.lang.invoke classes to be pre-initialized at dump time

File tree

6 files changed

+82
-5
lines changed

6 files changed

+82
-5
lines changed
 

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

+61
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,67 @@ void ClassPrelinker::record_resolved_indys() {
834834
log_info(cds)("%d indies in %d classes will be resolved in final CDS image", total_indys_to_resolve, tmp_klasses.length());
835835
}
836836

837+
// Warning -- this is fragile!!!
838+
// This is a hard-coded list of classes that are safely to preinitialize at dump time. It needs
839+
// to be updated if the Java source code changes.
840+
class ForcePreinitClosure : public CLDClosure {
841+
public:
842+
void do_cld(ClassLoaderData* cld) {
843+
static const char* forced_preinit_classes[] = {
844+
"java/util/HexFormat",
845+
"jdk/internal/util/ClassFileDumper",
846+
"java/lang/reflect/ClassFileFormatVersion",
847+
"java/lang/Character$CharacterCache",
848+
"java/lang/invoke/Invokers",
849+
"java/lang/invoke/Invokers$Holder",
850+
"java/lang/invoke/MethodHandle",
851+
"java/lang/invoke/MethodHandleStatics",
852+
"java/lang/invoke/DelegatingMethodHandle",
853+
"java/lang/invoke/DelegatingMethodHandle$Holder",
854+
"java/lang/invoke/LambdaForm",
855+
"java/lang/invoke/LambdaForm$NamedFunction",
856+
"java/lang/invoke/ClassSpecializer",
857+
"java/lang/invoke/DirectMethodHandle",
858+
"java/lang/invoke/DirectMethodHandle$Holder",
859+
"java/lang/invoke/BoundMethodHandle$Specializer",
860+
"java/lang/invoke/MethodHandles$Lookup",
861+
862+
// TODO -- need to clear internTable, etc
863+
//"java/lang/invoke/MethodType",
864+
865+
// TODO -- these need to link to native code
866+
//"java/lang/invoke/BoundMethodHandle",
867+
//"java/lang/invoke/BoundMethodHandle$Holder",
868+
//"java/lang/invoke/MemberName",
869+
//"java/lang/invoke/MethodHandleNatives",
870+
nullptr
871+
};
872+
for (Klass* k = cld->klasses(); k != nullptr; k = k->next_link()) {
873+
if (k->is_instance_klass()) {
874+
for (const char** classes = forced_preinit_classes; *classes != nullptr; classes++) {
875+
const char* class_name = *classes;
876+
if (k->name()->equals(class_name)) {
877+
ResourceMark rm;
878+
log_info(cds, init)("Force initialization %s", k->external_name());
879+
SystemDictionaryShared::force_preinit(InstanceKlass::cast(k));
880+
}
881+
}
882+
}
883+
}
884+
}
885+
};
886+
887+
void ClassPrelinker::setup_forced_preinit_classes() {
888+
if (!ArchiveInvokeDynamic) {
889+
return;
890+
}
891+
892+
// Collect all loaded ClassLoaderData.
893+
ForcePreinitClosure closure;
894+
MutexLocker lock(ClassLoaderDataGraph_lock);
895+
ClassLoaderDataGraph::loaded_cld_do(&closure);
896+
}
897+
837898
// Initialize a class at dump time, if possible.
838899
void ClassPrelinker::maybe_preinit_class(InstanceKlass* ik, TRAPS) {
839900
if (ik->is_initialized()) {

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

+1
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ class ClassPrelinker : AllStatic {
113113
static void initialize();
114114
static void dispose();
115115

116+
static void setup_forced_preinit_classes();
116117
static void maybe_preinit_class(InstanceKlass* ik, TRAPS);
117118

118119
static void preresolve_class_cp_entries(JavaThread* current, InstanceKlass* ik, GrowableArray<bool>* preresolve_list);

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

+4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class DumpTimeClassInfo: public CHeapObj<mtClass> {
4242
bool _has_checked_exclusion;
4343
bool _can_be_preinited;
4444
bool _has_done_preinit_check;
45+
bool _forced_preinit;
4546

4647
class DTLoaderConstraint {
4748
Symbol* _name;
@@ -139,6 +140,7 @@ class DumpTimeClassInfo: public CHeapObj<mtClass> {
139140
_has_checked_exclusion = false;
140141
_can_be_preinited = false;
141142
_has_done_preinit_check = false;
143+
_forced_preinit = false;
142144
_id = -1;
143145
_clsfile_size = -1;
144146
_clsfile_crc32 = -1;
@@ -216,6 +218,8 @@ class DumpTimeClassInfo: public CHeapObj<mtClass> {
216218
InstanceKlass* nest_host() const { return _nest_host; }
217219
void set_nest_host(InstanceKlass* nest_host) { _nest_host = nest_host; }
218220

221+
void force_preinit() { _forced_preinit = true; }
222+
bool is_forced_preinit() const { return _forced_preinit; }
219223
bool can_be_preinited() const { return _can_be_preinited; }
220224
bool has_done_preinit_check() const { return _has_done_preinit_check; }
221225

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

+2
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,8 @@ void MetaspaceShared::link_shared_classes(bool jcmd_request, TRAPS) {
652652
LambdaFormInvokers::regenerate_holder_classes(CHECK);
653653
}
654654

655+
ClassPrelinker::setup_forced_preinit_classes();
656+
655657
// Collect all loaded ClassLoaderData.
656658
CollectCLDClosure collect_cld(THREAD);
657659
{

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

+12-4
Original file line numberDiff line numberDiff line change
@@ -1697,6 +1697,13 @@ void SystemDictionaryShared::reset_preinit_check() {
16971697
_dumptime_table->iterate_all_live_classes(iterator);
16981698
}
16991699

1700+
// Called by ClassPrelinker before we get into VM_PopulateDumpSharedSpace
1701+
void SystemDictionaryShared::force_preinit(InstanceKlass* ik) {
1702+
MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag);
1703+
DumpTimeClassInfo* info = get_info_locked(ik);
1704+
info->force_preinit();
1705+
}
1706+
17001707
bool SystemDictionaryShared::can_be_preinited(InstanceKlass* ik) {
17011708
if (!CDSConfig::is_initing_classes_at_dump_time()) {
17021709
return false;
@@ -1705,7 +1712,7 @@ bool SystemDictionaryShared::can_be_preinited(InstanceKlass* ik) {
17051712
assert_lock_strong(DumpTimeTable_lock);
17061713
DumpTimeClassInfo* info = get_info_locked(ik);
17071714
if (!info->has_done_preinit_check()) {
1708-
info->set_can_be_preinited(check_can_be_preinited(ik));
1715+
info->set_can_be_preinited(check_can_be_preinited(ik, info));
17091716
}
17101717
return info->can_be_preinited();
17111718
}
@@ -1763,7 +1770,7 @@ bool SystemDictionaryShared::has_non_default_static_fields(InstanceKlass* ik) {
17631770
return true;
17641771
}
17651772

1766-
bool SystemDictionaryShared::check_can_be_preinited(InstanceKlass* ik) {
1773+
bool SystemDictionaryShared::check_can_be_preinited(InstanceKlass* ik, DumpTimeClassInfo* info) {
17671774
ResourceMark rm;
17681775

17691776
if (!is_builtin(ik)) {
@@ -1786,8 +1793,9 @@ bool SystemDictionaryShared::check_can_be_preinited(InstanceKlass* ik) {
17861793
}
17871794
}
17881795

1789-
if (!HeapShared::is_lambda_form_klass(ik)) {
1790-
// We allow only LambdaForm classes to have <clinit> and non-default static fields
1796+
if (HeapShared::is_lambda_form_klass(ik) || info->is_forced_preinit()) {
1797+
// We allow only these to have <clinit> and non-default static fields
1798+
} else {
17911799
if (ik->class_initializer() != nullptr) {
17921800
log_info(cds, init)("cannot initialize %s (has <clinit>)", ik->external_name());
17931801
return false;

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ class SystemDictionaryShared: public SystemDictionary {
210210
static void reset_registered_lambda_proxy_class(InstanceKlass* ik);
211211
static bool is_registered_lambda_proxy_class(InstanceKlass* ik);
212212
static bool check_for_exclusion_impl(InstanceKlass* k);
213-
static bool check_can_be_preinited(InstanceKlass* ik);
213+
static bool check_can_be_preinited(InstanceKlass* ik, DumpTimeClassInfo* info);
214214
static bool has_non_default_static_fields(InstanceKlass* ik);
215215
static void remove_dumptime_info(InstanceKlass* k) NOT_CDS_RETURN;
216216
static void init_archived_hidden_classes(Handle class_loader, Array<InstanceKlass*>* classes,
@@ -256,6 +256,7 @@ class SystemDictionaryShared: public SystemDictionary {
256256
static void init_dumptime_info(InstanceKlass* k) NOT_CDS_RETURN;
257257
static void handle_class_unloading(InstanceKlass* k) NOT_CDS_RETURN;
258258

259+
static void force_preinit(InstanceKlass* ik);
259260
static bool can_be_preinited(InstanceKlass* ik);
260261
static void reset_preinit_check();
261262

0 commit comments

Comments
 (0)
Please sign in to comment.