Skip to content

Commit 8b37d48

Browse files
committed
8255493: Support for pre-generated java.lang.invoke classes in CDS dynamic archive
Reviewed-by: iklam, ccheung
1 parent 770dfc1 commit 8b37d48

File tree

11 files changed

+260
-59
lines changed

11 files changed

+260
-59
lines changed

src/hotspot/share/cds/archiveBuilder.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ void ArchiveBuilder::gather_klasses_and_symbols() {
259259
log_info(cds)(" instance classes = %5d", _num_instance_klasses);
260260
log_info(cds)(" obj array classes = %5d", _num_obj_array_klasses);
261261
log_info(cds)(" type array classes = %5d", _num_type_array_klasses);
262+
log_info(cds)(" symbols = %5d", _symbols->length());
262263

263264
if (DumpSharedSpaces) {
264265
// To ensure deterministic contents in the static archive, we need to ensure that

src/hotspot/share/cds/dynamicArchive.cpp

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "cds/archiveBuilder.hpp"
2828
#include "cds/archiveUtils.inline.hpp"
2929
#include "cds/dynamicArchive.hpp"
30+
#include "cds/lambdaFormInvokers.hpp"
3031
#include "cds/metaspaceShared.hpp"
3132
#include "classfile/classLoaderData.inline.hpp"
3233
#include "classfile/symbolTable.hpp"
@@ -344,29 +345,34 @@ void DynamicArchive::dump(const char* archive_name, TRAPS) {
344345
} else {
345346
// prevent multiple dumps.
346347
set_has_been_dumped_once();
347-
}
348-
ArchiveClassesAtExit = archive_name;
349-
if (Arguments::init_shared_archive_paths()) {
350-
dump();
351-
} else {
352-
ArchiveClassesAtExit = nullptr;
353-
THROW_MSG(vmSymbols::java_lang_RuntimeException(),
348+
ArchiveClassesAtExit = archive_name;
349+
if (Arguments::init_shared_archive_paths()) {
350+
dump(CHECK);
351+
} else {
352+
ArchiveClassesAtExit = nullptr;
353+
THROW_MSG(vmSymbols::java_lang_RuntimeException(),
354354
"Could not setup SharedDynamicArchivePath");
355-
}
356-
// prevent do dynamic dump at exit.
357-
ArchiveClassesAtExit = nullptr;
358-
if (!Arguments::init_shared_archive_paths()) {
359-
THROW_MSG(vmSymbols::java_lang_RuntimeException(),
355+
}
356+
// prevent do dynamic dump at exit.
357+
ArchiveClassesAtExit = nullptr;
358+
if (!Arguments::init_shared_archive_paths()) {
359+
THROW_MSG(vmSymbols::java_lang_RuntimeException(),
360360
"Could not restore SharedDynamicArchivePath");
361+
}
361362
}
362363
}
363364

364-
void DynamicArchive::dump() {
365+
void DynamicArchive::dump(TRAPS) {
365366
if (Arguments::GetSharedDynamicArchivePath() == NULL) {
366367
log_warning(cds, dynamic)("SharedDynamicArchivePath is not specified");
367368
return;
368369
}
369370

371+
// regenerate lambdaform holder classes
372+
log_info(cds, dynamic)("Regenerate lambdaform holder classes ...");
373+
LambdaFormInvokers::regenerate_holder_classes(CHECK);
374+
log_info(cds, dynamic)("Regenerate lambdaform holder classes ...done");
375+
370376
VM_PopulateDynamicDumpSharedSpace op;
371377
VMThread::execute(&op);
372378
}

src/hotspot/share/cds/dynamicArchive.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class DynamicArchive : AllStatic {
6161
static bool _has_been_dumped_once;
6262
public:
6363
static void dump(const char* archive_name, TRAPS);
64-
static void dump();
64+
static void dump(TRAPS);
6565
static bool has_been_dumped_once() { return _has_been_dumped_once; }
6666
static void set_has_been_dumped_once() { _has_been_dumped_once = true; }
6767
static bool is_mapped() { return FileMapInfo::dynamic_info() != NULL; }

src/hotspot/share/cds/lambdaFormInvokers.cpp

Lines changed: 92 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
*/
2424

2525
#include "precompiled.hpp"
26+
#include "cds/archiveBuilder.hpp"
2627
#include "cds/lambdaFormInvokers.hpp"
2728
#include "cds/metaspaceShared.hpp"
2829
#include "classfile/classLoadInfo.hpp"
@@ -46,23 +47,52 @@
4647
#include "runtime/handles.inline.hpp"
4748
#include "runtime/javaCalls.hpp"
4849

49-
GrowableArray<char*>* LambdaFormInvokers::_lambdaform_lines = NULL;
50+
GrowableArrayCHeap<char*, mtClassShared>* LambdaFormInvokers::_lambdaform_lines = nullptr;
51+
Array<Array<char>*>* LambdaFormInvokers::_static_archive_invokers = nullptr;
52+
53+
#define NUM_FILTER 4
54+
static const char* filter[NUM_FILTER] = {"java.lang.invoke.Invokers$Holder",
55+
"java.lang.invoke.DirectMethodHandle$Holder",
56+
"java.lang.invoke.DelegatingMethodHandle$Holder",
57+
"java.lang.invoke.LambdaForm$Holder"};
58+
59+
static bool should_be_archived(char* line) {
60+
for (int k = 0; k < NUM_FILTER; k++) {
61+
if (strstr(line, filter[k]) != nullptr) {
62+
return true;
63+
}
64+
}
65+
return false;
66+
}
67+
68+
void LambdaFormInvokers::append_filtered(char* line) {
69+
if (should_be_archived(line)) {
70+
append(line);
71+
}
72+
}
73+
#undef NUM_FILTER
5074

5175
void LambdaFormInvokers::append(char* line) {
5276
if (_lambdaform_lines == NULL) {
53-
_lambdaform_lines = new GrowableArray<char*>(100);
77+
_lambdaform_lines = new GrowableArrayCHeap<char*, mtClassShared>(150);
5478
}
5579
_lambdaform_lines->append(line);
5680
}
5781

5882
void LambdaFormInvokers::regenerate_holder_classes(TRAPS) {
59-
assert(_lambdaform_lines != NULL, "Bad List");
83+
if (_lambdaform_lines == nullptr || _lambdaform_lines->length() == 0) {
84+
log_info(cds)("Nothing to regenerate for holder classes");
85+
return;
86+
}
87+
6088
ResourceMark rm(THREAD);
6189

6290
Symbol* cds_name = vmSymbols::jdk_internal_misc_CDS();
6391
Klass* cds_klass = SystemDictionary::resolve_or_null(cds_name, THREAD);
6492
guarantee(cds_klass != NULL, "jdk/internal/misc/CDS must exist!");
93+
log_debug(cds)("Total lambdaform lines %d", _lambdaform_lines->length());
6594

95+
HandleMark hm(THREAD);
6696
int len = _lambdaform_lines->length();
6797
objArrayHandle list_lines = oopFactory::new_objArray_handle(vmClasses::String_klass(), len, CHECK);
6898
for (int i = 0; i < len; i++) {
@@ -81,9 +111,16 @@ void LambdaFormInvokers::regenerate_holder_classes(TRAPS) {
81111
JavaCalls::call_static(&result, cds_klass, method, signrs, list_lines, THREAD);
82112

83113
if (HAS_PENDING_EXCEPTION) {
84-
log_info(cds)("%s: %s", THREAD->pending_exception()->klass()->external_name(),
85-
java_lang_String::as_utf8_string(java_lang_Throwable::message(THREAD->pending_exception())));
86-
CLEAR_PENDING_EXCEPTION;
114+
if (!PENDING_EXCEPTION->is_a(vmClasses::OutOfMemoryError_klass())) {
115+
log_error(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(),
116+
java_lang_String::as_utf8_string(java_lang_Throwable::message(PENDING_EXCEPTION)));
117+
if (DumpSharedSpaces) {
118+
log_error(cds)("Failed to generate LambdaForm holder classes. Is your classlist out of date?");
119+
} else {
120+
log_error(cds)("Failed to generate LambdaForm holder classes. Was the base archive generated with an outdated classlist?");
121+
}
122+
CLEAR_PENDING_EXCEPTION;
123+
}
87124
return;
88125
}
89126

@@ -99,20 +136,10 @@ void LambdaFormInvokers::regenerate_holder_classes(TRAPS) {
99136
char *class_name = java_lang_String::as_utf8_string(h_name());
100137
int len = h_bytes->length();
101138
// make a copy of class bytes so GC will not affect us.
102-
char *buf = resource_allocate_bytes(THREAD, len);
139+
char *buf = NEW_RESOURCE_ARRAY(char, len);
103140
memcpy(buf, (char*)h_bytes->byte_at_addr(0), len);
104141
ClassFileStream st((u1*)buf, len, NULL, ClassFileStream::verify);
105-
106-
reload_class(class_name, st, THREAD);
107-
// free buf
108-
resource_free_bytes(buf, len);
109-
110-
if (HAS_PENDING_EXCEPTION) {
111-
log_info(cds)("Exception happened: %s", PENDING_EXCEPTION->klass()->name()->as_C_string());
112-
log_info(cds)("Could not create InstanceKlass for class %s", class_name);
113-
CLEAR_PENDING_EXCEPTION;
114-
return;
115-
}
142+
reload_class(class_name, st, CHECK);
116143
}
117144
}
118145

@@ -147,5 +174,51 @@ void LambdaFormInvokers::reload_class(char* name, ClassFileStream& st, TRAPS) {
147174

148175
// exclude the existing class from dump
149176
SystemDictionaryShared::set_excluded(InstanceKlass::cast(klass));
150-
log_info(cds, lambda)("Replaced class %s, old: %p new: %p", name, klass, result);
177+
SystemDictionaryShared::init_dumptime_info(result);
178+
log_debug(cds, lambda)("Replaced class %s, old: %p new: %p", name, klass, result);
179+
}
180+
181+
void LambdaFormInvokers::dump_static_archive_invokers() {
182+
if (_lambdaform_lines != nullptr && _lambdaform_lines->length() > 0) {
183+
int count = 0;
184+
int len = _lambdaform_lines->length();
185+
for (int i = 0; i < len; i++) {
186+
char* str = _lambdaform_lines->at(i);
187+
if (should_be_archived(str)) {
188+
count++;
189+
}
190+
}
191+
log_debug(cds)("Number of LF invoker lines stored: %d", count);
192+
if (count > 0) {
193+
_static_archive_invokers = ArchiveBuilder::new_ro_array<Array<char>*>(count);
194+
int index = 0;
195+
for (int i = 0; i < len; i++) {
196+
char* str = _lambdaform_lines->at(i);
197+
if (should_be_archived(str)) {
198+
size_t str_len = strlen(str) + 1; // including terminating zero
199+
Array<char>* line = ArchiveBuilder::new_ro_array<char>((int)str_len);
200+
strncpy(line->adr_at(0), str, str_len);
201+
202+
_static_archive_invokers->at_put(index, line);
203+
ArchivePtrMarker::mark_pointer(_static_archive_invokers->adr_at(index));
204+
index++;
205+
}
206+
}
207+
assert(index == count, "Should match");
208+
}
209+
}
210+
}
211+
212+
void LambdaFormInvokers::read_static_archive_invokers() {
213+
if (_static_archive_invokers != nullptr) {
214+
for (int i = 0; i < _static_archive_invokers->length(); i++) {
215+
Array<char>* line = _static_archive_invokers->at(i);
216+
char* str = line->adr_at(0);
217+
append_filtered(str);
218+
}
219+
}
220+
}
221+
222+
void LambdaFormInvokers::serialize(SerializeClosure* soc) {
223+
soc->do_ptr((void**)&_static_archive_invokers);
151224
}

src/hotspot/share/cds/lambdaFormInvokers.hpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,26 @@
2626
#define SHARE_CDS_LAMBDAFORMINVOKERS_HPP
2727
#include "memory/allStatic.hpp"
2828
#include "runtime/handles.hpp"
29+
#include "utilities/growableArray.hpp"
2930

30-
template <class T>
31-
class GrowableArray;
3231
class ClassFileStream;
32+
template <class T> class Array;
3333

3434
class LambdaFormInvokers : public AllStatic {
3535
private:
36-
static GrowableArray<char*>* _lambdaform_lines;
36+
static GrowableArrayCHeap<char*, mtClassShared>* _lambdaform_lines;
37+
// for storing LF form lines (LF_RESOLVE only) in read only table.
38+
static Array<Array<char>*>* _static_archive_invokers;
3739
static void reload_class(char* name, ClassFileStream& st, TRAPS);
3840
public:
39-
4041
static void append(char* line);
42+
static void append_filtered(char* line);
4143
static void regenerate_holder_classes(TRAPS);
42-
static GrowableArray<char*>* lambdaform_lines() {
44+
static GrowableArrayCHeap<char*, mtClassShared>* lambdaform_lines() {
4345
return _lambdaform_lines;
4446
}
47+
static void dump_static_archive_invokers();
48+
static void read_static_archive_invokers();
49+
static void serialize(SerializeClosure* soc);
4550
};
4651
#endif // SHARE_CDS_LAMBDAFORMINVOKERS_HPP

src/hotspot/share/cds/metaspaceShared.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ void MetaspaceShared::serialize(SerializeClosure* soc) {
361361

362362
CDS_JAVA_HEAP_ONLY(ClassLoaderDataShared::serialize(soc);)
363363

364+
LambdaFormInvokers::serialize(soc);
364365
soc->do_tag(666);
365366
}
366367

@@ -460,6 +461,8 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables() {
460461

461462
SystemDictionaryShared::write_to_archive();
462463

464+
// Write lambform lines into archive
465+
LambdaFormInvokers::dump_static_archive_invokers();
463466
// Write the other data to the output array.
464467
DumpRegion* ro_region = ArchiveBuilder::current()->ro_region();
465468
char* start = ro_region->top();
@@ -925,12 +928,12 @@ void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() {
925928
char* cds_end = dynamic_mapped ? dynamic_mapinfo->mapped_end() : static_mapinfo->mapped_end();
926929
set_shared_metaspace_range(cds_base, static_mapinfo->mapped_end(), cds_end);
927930
_relocation_delta = static_mapinfo->relocation_delta();
931+
_requested_base_address = static_mapinfo->requested_base_address();
928932
if (dynamic_mapped) {
929933
FileMapInfo::set_shared_path_table(dynamic_mapinfo);
930934
} else {
931935
FileMapInfo::set_shared_path_table(static_mapinfo);
932936
}
933-
_requested_base_address = static_mapinfo->requested_base_address();
934937
} else {
935938
set_shared_metaspace_range(NULL, NULL, NULL);
936939
UseSharedSpaces = false;
@@ -1444,6 +1447,12 @@ void MetaspaceShared::initialize_shared_spaces() {
14441447
dynamic_mapinfo->unmap_region(MetaspaceShared::bm);
14451448
}
14461449

1450+
// Set up LambdaFormInvokers::_lambdaform_lines for dynamic dump
1451+
if (DynamicDumpSharedSpaces) {
1452+
// Read stored LF format lines stored in static archive
1453+
LambdaFormInvokers::read_static_archive_invokers();
1454+
}
1455+
14471456
if (PrintSharedArchiveAndExit) {
14481457
// Print archive names
14491458
if (dynamic_mapinfo != nullptr) {

src/hotspot/share/classfile/systemDictionaryShared.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2205,6 +2205,19 @@ SystemDictionaryShared::find_record(RunTimeSharedDictionary* static_dict, RunTim
22052205

22062206
unsigned int hash = SystemDictionaryShared::hash_for_shared_dictionary_quick(name);
22072207
const RunTimeSharedClassInfo* record = NULL;
2208+
if (DynamicArchive::is_mapped()) {
2209+
// Those regenerated holder classes are in dynamic archive
2210+
if (name == vmSymbols::java_lang_invoke_Invokers_Holder() ||
2211+
name == vmSymbols::java_lang_invoke_DirectMethodHandle_Holder() ||
2212+
name == vmSymbols::java_lang_invoke_LambdaForm_Holder() ||
2213+
name == vmSymbols::java_lang_invoke_DelegatingMethodHandle_Holder()) {
2214+
record = dynamic_dict->lookup(name, hash, 0);
2215+
if (record != nullptr) {
2216+
return record;
2217+
}
2218+
}
2219+
}
2220+
22082221
if (!MetaspaceShared::is_shared_dynamic(name)) {
22092222
// The names of all shared classes in the static dict must also be in the
22102223
// static archive
@@ -2261,7 +2274,7 @@ class SharedDictionaryPrinter : StackObj {
22612274

22622275
void do_value(const RunTimeSharedClassInfo* record) {
22632276
ResourceMark rm;
2264-
_st->print_cr("%4d: %s %s", (_index++), record->_klass->external_name(),
2277+
_st->print_cr("%4d: %s %s", _index++, record->_klass->external_name(),
22652278
class_loader_name_for_shared(record->_klass));
22662279
}
22672280
int index() const { return _index; }
@@ -2278,7 +2291,7 @@ class SharedLambdaDictionaryPrinter : StackObj {
22782291
ResourceMark rm;
22792292
Klass* k = record->proxy_klass_head();
22802293
while (k != nullptr) {
2281-
_st->print_cr("%4d: %s %s", (++_index), k->external_name(),
2294+
_st->print_cr("%4d: %s %s", _index++, k->external_name(),
22822295
class_loader_name_for_shared(k));
22832296
k = k->next_link();
22842297
}

src/hotspot/share/classfile/vmSymbols.hpp

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -296,12 +296,6 @@
296296
template(base_name, "base") \
297297
/* Type Annotations (JDK 8 and above) */ \
298298
template(type_annotations_name, "typeAnnotations") \
299-
/* used by CDS */ \
300-
template(jdk_internal_misc_CDS, "jdk/internal/misc/CDS") \
301-
template(generateLambdaFormHolderClasses, "generateLambdaFormHolderClasses") \
302-
template(generateLambdaFormHolderClasses_signature, "([Ljava/lang/String;)[Ljava/lang/Object;") \
303-
template(dumpSharedArchive, "dumpSharedArchive") \
304-
template(dumpSharedArchive_signature, "(ZLjava/lang/String;)V") \
305299
\
306300
/* Intrinsic Annotation (JDK 9 and above) */ \
307301
template(jdk_internal_vm_annotation_DontInline_signature, "Ljdk/internal/vm/annotation/DontInline;") \
@@ -693,13 +687,22 @@
693687
/* jfr signatures */ \
694688
JFR_TEMPLATES(template) \
695689
\
696-
/* cds */ \
697-
template(jdk_internal_loader_ClassLoaders, "jdk/internal/loader/ClassLoaders") \
698-
template(java_util_concurrent_ConcurrentHashMap, "java/util/concurrent/ConcurrentHashMap") \
699-
template(java_util_ArrayList, "java/util/ArrayList") \
700-
template(toFileURL_name, "toFileURL") \
701-
template(toFileURL_signature, "(Ljava/lang/String;)Ljava/net/URL;") \
702-
template(url_void_signature, "(Ljava/net/URL;)V") \
690+
/* CDS */ \
691+
template(dumpSharedArchive, "dumpSharedArchive") \
692+
template(dumpSharedArchive_signature, "(ZLjava/lang/String;)V") \
693+
template(generateLambdaFormHolderClasses, "generateLambdaFormHolderClasses") \
694+
template(generateLambdaFormHolderClasses_signature, "([Ljava/lang/String;)[Ljava/lang/Object;") \
695+
template(java_lang_invoke_Invokers_Holder, "java/lang/invoke/Invokers$Holder") \
696+
template(java_lang_invoke_DirectMethodHandle_Holder, "java/lang/invoke/DirectMethodHandle$Holder") \
697+
template(java_lang_invoke_LambdaForm_Holder, "java/lang/invoke/LambdaForm$Holder") \
698+
template(java_lang_invoke_DelegatingMethodHandle_Holder, "java/lang/invoke/DelegatingMethodHandle$Holder") \
699+
template(jdk_internal_loader_ClassLoaders, "jdk/internal/loader/ClassLoaders") \
700+
template(jdk_internal_misc_CDS, "jdk/internal/misc/CDS") \
701+
template(java_util_concurrent_ConcurrentHashMap, "java/util/concurrent/ConcurrentHashMap") \
702+
template(java_util_ArrayList, "java/util/ArrayList") \
703+
template(toFileURL_name, "toFileURL") \
704+
template(toFileURL_signature, "(Ljava/lang/String;)Ljava/net/URL;") \
705+
template(url_void_signature, "(Ljava/net/URL;)V") \
703706
\
704707
/*end*/
705708

0 commit comments

Comments
 (0)