Skip to content

Commit 66f59c2

Browse files
committed
8290731: Clean up CDS handling of LambdaForm Species classes
Reviewed-by: ccheung
1 parent 0dda3c1 commit 66f59c2

File tree

6 files changed

+68
-46
lines changed

6 files changed

+68
-46
lines changed

src/hotspot/share/cds/archiveBuilder.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,7 @@ void ArchiveBuilder::make_klasses_shareable() {
727727
const char* type;
728728
const char* unlinked = "";
729729
const char* hidden = "";
730+
const char* generated = "";
730731
Klass* k = klasses()->at(i);
731732
k->remove_java_mirror();
732733
if (k->is_objArray_klass()) {
@@ -771,13 +772,18 @@ void ArchiveBuilder::make_klasses_shareable() {
771772
hidden = " ** hidden";
772773
}
773774

775+
if (ik->is_generated_shared_class()) {
776+
generated = " ** generated";
777+
}
774778
MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread::current(), ik);
775779
ik->remove_unshareable_info();
776780
}
777781

778782
if (log_is_enabled(Debug, cds, class)) {
779783
ResourceMark rm;
780-
log_debug(cds, class)("klasses[%5d] = " PTR_FORMAT " %-5s %s%s%s", i, p2i(to_requested(k)), type, k->external_name(), hidden, unlinked);
784+
log_debug(cds, class)("klasses[%5d] = " PTR_FORMAT " %-5s %s%s%s%s", i,
785+
p2i(to_requested(k)), type, k->external_name(),
786+
hidden, unlinked, generated);
781787
}
782788
}
783789

src/hotspot/share/cds/lambdaFormInvokers.cpp

+29-32
Original file line numberDiff line numberDiff line change
@@ -165,46 +165,43 @@ void LambdaFormInvokers::regenerate_holder_classes(TRAPS) {
165165
assert(h_bytes != NULL, "Class bytes is NULL");
166166

167167
char *class_name = java_lang_String::as_utf8_string(h_name());
168-
int len = h_bytes->length();
169-
// make a copy of class bytes so GC will not affect us.
170-
char *buf = NEW_RESOURCE_ARRAY(char, len);
171-
memcpy(buf, (char*)h_bytes->byte_at_addr(0), len);
172-
ClassFileStream st((u1*)buf, len, NULL, ClassFileStream::verify);
173-
regenerate_class(class_name, st, CHECK);
174-
}
175-
}
176-
177-
// check if a class name is a species
178-
bool is_a_species(const char* species_name) {
179-
log_info(cds)("Checking class %s", species_name);
180-
if (strstr(species_name, "java/lang/invoke/BoundMethodHandle$Species_") != nullptr) {
181-
return true;
168+
if (strstr(class_name, "java/lang/invoke/BoundMethodHandle$Species_") != nullptr) {
169+
// The species classes are already loaded into the system dictionary
170+
// during the execution of CDS.generateLambdaFormHolderClasses(). No
171+
// need to regenerate.
172+
TempNewSymbol class_name_sym = SymbolTable::new_symbol(class_name);
173+
Klass* klass = SystemDictionary::resolve_or_null(class_name_sym, THREAD);
174+
assert(klass != NULL, "must already be loaded");
175+
if (!klass->is_shared() && klass->shared_classpath_index() < 0) {
176+
// Fake it, so that it will be included into the archive.
177+
klass->set_shared_classpath_index(0);
178+
// Set the "generated" bit, so it won't interfere with JVMTI.
179+
// See SystemDictionaryShared::find_builtin_class().
180+
klass->set_is_generated_shared_class();
181+
}
182+
} else {
183+
int len = h_bytes->length();
184+
// make a copy of class bytes so GC will not affect us.
185+
char *buf = NEW_RESOURCE_ARRAY(char, len);
186+
memcpy(buf, (char*)h_bytes->byte_at_addr(0), len);
187+
ClassFileStream st((u1*)buf, len, NULL, ClassFileStream::verify);
188+
regenerate_class(class_name, st, CHECK);
189+
}
182190
}
183-
return false;
184191
}
185192

186-
void LambdaFormInvokers::regenerate_class(char* name, ClassFileStream& st, TRAPS) {
187-
Symbol* class_name = SymbolTable::new_symbol((const char*)name);
188-
// the class must exist
189-
Klass* klass = SystemDictionary::resolve_or_null(class_name, THREAD);
190-
if (klass == NULL) {
191-
log_info(cds)("Class %s not present, skip", name);
192-
return;
193-
}
194-
// the species is shared in base archive, skip it.
195-
if (klass->is_regenerated() && is_a_species(name)) {
196-
log_info(cds)("Skip regenerating for shared %s", name);
197-
return;
198-
}
199-
193+
void LambdaFormInvokers::regenerate_class(char* class_name, ClassFileStream& st, TRAPS) {
194+
TempNewSymbol class_name_sym = SymbolTable::new_symbol(class_name);
195+
Klass* klass = SystemDictionary::resolve_or_null(class_name_sym, THREAD);
196+
assert(klass != NULL, "must exist");
200197
assert(klass->is_instance_klass(), "Should be");
201198

202199
ClassLoaderData* cld = ClassLoaderData::the_null_class_loader_data();
203200
Handle protection_domain;
204201
ClassLoadInfo cl_info(protection_domain);
205202

206203
InstanceKlass* result = KlassFactory::create_from_stream(&st,
207-
class_name,
204+
class_name_sym,
208205
cld,
209206
cl_info,
210207
CHECK);
@@ -220,11 +217,11 @@ void LambdaFormInvokers::regenerate_class(char* name, ClassFileStream& st, TRAPS
220217
MetaspaceShared::try_link_class(THREAD, result);
221218
assert(!HAS_PENDING_EXCEPTION, "Invariant");
222219

223-
result->set_regenerated(); // mark for regenerated
220+
result->set_is_generated_shared_class();
224221
SystemDictionaryShared::set_excluded(InstanceKlass::cast(klass)); // exclude the existing class from dump
225222
SystemDictionaryShared::init_dumptime_info(result);
226223
log_info(cds, lambda)("Regenerated class %s, old: " INTPTR_FORMAT " new: " INTPTR_FORMAT,
227-
name, p2i(klass), p2i(result));
224+
class_name, p2i(klass), p2i(result));
228225
}
229226

230227
void LambdaFormInvokers::dump_static_archive_invokers() {

src/hotspot/share/classfile/systemDictionaryShared.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -1341,7 +1341,8 @@ SystemDictionaryShared::find_record(RunTimeSharedDictionary* static_dict, RunTim
13411341
unsigned int hash = SystemDictionaryShared::hash_for_shared_dictionary_quick(name);
13421342
const RunTimeClassInfo* record = NULL;
13431343
if (DynamicArchive::is_mapped()) {
1344-
// Those regenerated holder classes are in dynamic archive
1344+
// Use the regenerated holder classes in the dynamic archive as they
1345+
// have more methods than those in the base archive.
13451346
if (name == vmSymbols::java_lang_invoke_Invokers_Holder() ||
13461347
name == vmSymbols::java_lang_invoke_DirectMethodHandle_Holder() ||
13471348
name == vmSymbols::java_lang_invoke_LambdaForm_Holder() ||
@@ -1373,9 +1374,9 @@ InstanceKlass* SystemDictionaryShared::find_builtin_class(Symbol* name) {
13731374
if (record != NULL) {
13741375
assert(!record->_klass->is_hidden(), "hidden class cannot be looked up by name");
13751376
assert(check_alignment(record->_klass), "Address not aligned");
1376-
// We did not save the classfile data of the regenerated LambdaForm invoker classes,
1377+
// We did not save the classfile data of the generated LambdaForm invoker classes,
13771378
// so we cannot support CLFH for such classes.
1378-
if (record->_klass->is_regenerated() && JvmtiExport::should_post_class_file_load_hook()) {
1379+
if (record->_klass->is_generated_shared_class() && JvmtiExport::should_post_class_file_load_hook()) {
13791380
return NULL;
13801381
}
13811382
return record->_klass;

src/hotspot/share/oops/klass.hpp

+9-7
Original file line numberDiff line numberDiff line change
@@ -173,14 +173,16 @@ class Klass : public Metadata {
173173
jshort _shared_class_path_index;
174174

175175
#if INCLUDE_CDS
176-
// Flags of the current shared class.
176+
// Various attributes for shared classes. Should be zero for a non-shared class.
177177
u2 _shared_class_flags;
178-
enum {
178+
enum CDSSharedClassFlags {
179179
_archived_lambda_proxy_is_available = 1 << 1,
180180
_has_value_based_class_annotation = 1 << 2,
181181
_verified_at_dump_time = 1 << 3,
182182
_has_archived_enum_objs = 1 << 4,
183-
_regenerated = 1 << 5
183+
// This class was not loaded from a classfile in the module image
184+
// or classpath.
185+
_is_generated_shared_class = 1 << 5
184186
};
185187
#endif
186188

@@ -352,11 +354,11 @@ class Klass : public Metadata {
352354
NOT_CDS(return false;)
353355
}
354356

355-
void set_regenerated() {
356-
CDS_ONLY(_shared_class_flags |= _regenerated;)
357+
void set_is_generated_shared_class() {
358+
CDS_ONLY(_shared_class_flags |= _is_generated_shared_class;)
357359
}
358-
bool is_regenerated() const {
359-
CDS_ONLY(return (_shared_class_flags & _regenerated) != 0;)
360+
bool is_generated_shared_class() const {
361+
CDS_ONLY(return (_shared_class_flags & _is_generated_shared_class) != 0;)
360362
NOT_CDS(return false;)
361363
}
362364

test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/CDSLambdaInvoker.java

+7-1
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,15 @@
2828

2929
public class CDSLambdaInvoker {
3030
public static void main(String args[]) throws Throwable {
31+
// The following calls trigger the generation of new Species classes
32+
// that are not included in the base archive (or the default modules image).
33+
// - java.lang.invoke.BoundMethodHandle$Species_F
34+
// - java.lang.invoke.BoundMethodHandle$Species_FL
35+
// - java.lang.invoke.BoundMethodHandle$Species_J
36+
// - java.lang.invoke.BoundMethodHandle$Species_JL
3137
invoke(MethodHandles.identity(double.class), 1.0);
3238
invoke(MethodHandles.identity(long.class), 1);
33-
invoke(MethodHandles.identity(int.class), 1);
39+
invoke(MethodHandles.identity(int.class), 1); // Note: Species_IL is in default modules image.
3440
invoke(MethodHandles.identity(float.class), 1.0f);
3541

3642
MethodHandles.Lookup lookup = MethodHandles.lookup();

test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestLambdaInvokers.java

+12-2
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,18 @@ public class TestLambdaInvokers extends DynamicArchiveTestBase {
4242
private static void doTest(String topArchiveName) throws Exception {
4343
dump(topArchiveName,
4444
"-Xlog:cds",
45+
"-Xlog:cds+class=debug",
4546
"-Xlog:cds+dynamic=debug",
4647
"-cp",
4748
jarFile,
4849
mainClass)
4950
.assertNormalExit(output -> {
50-
output.shouldContain("Skip regenerating for shared");
51+
// This should be not be generated from the dynamic dump, as it should be included
52+
// by the base archive.
53+
output.shouldNotMatch("cds,class.*=.*java.lang.invoke.BoundMethodHandle.Species_IL");
54+
55+
// This should be generated from the dynamic dump
56+
output.shouldMatch("cds,class.*=.*java.lang.invoke.BoundMethodHandle.Species_JL");
5157
});
5258
run(topArchiveName,
5359
"-Xlog:cds",
@@ -57,7 +63,11 @@ private static void doTest(String topArchiveName) throws Exception {
5763
jarFile,
5864
mainClass)
5965
.assertNormalExit(output -> {
60-
// java.lang.invoke.BoundMethodHandle$Species_JL is generated from CDSLambdaInvoker
66+
// java.lang.invoke.BoundMethodHandle$Species_IL is loaded from base archive
67+
output.shouldContain("java.lang.invoke.BoundMethodHandle$Species_IL source: shared objects file");
68+
69+
// java.lang.invoke.BoundMethodHandle$Species_JL is generated from CDSLambdaInvoker and
70+
// stored in the dynamic archive
6171
output.shouldContain("java.lang.invoke.BoundMethodHandle$Species_JL source: shared objects file (top)");
6272
});
6373
}

0 commit comments

Comments
 (0)