Skip to content

Commit 443cdd5

Browse files
committed
8368020: Remove preloading of null-restricted static fields classes
Reviewed-by: coleenp
1 parent ec61d0a commit 443cdd5

File tree

2 files changed

+42
-251
lines changed

2 files changed

+42
-251
lines changed

src/hotspot/share/oops/instanceKlass.cpp

Lines changed: 41 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -970,6 +970,44 @@ bool InstanceKlass::verify_code(TRAPS) {
970970
return Verifier::verify(this, should_verify_class(), THREAD);
971971
}
972972

973+
static void load_classes_from_loadable_descriptors_attribute(InstanceKlass *ik, TRAPS) {
974+
ResourceMark rm(THREAD);
975+
if (ik->loadable_descriptors() != nullptr && PreloadClasses) {
976+
HandleMark hm(THREAD);
977+
for (int i = 0; i < ik->loadable_descriptors()->length(); i++) {
978+
Symbol* sig = ik->constants()->symbol_at(ik->loadable_descriptors()->at(i));
979+
if (!Signature::has_envelope(sig)) continue;
980+
TempNewSymbol class_name = Signature::strip_envelope(sig);
981+
if (class_name == ik->name()) continue;
982+
log_info(class, preload)("Preloading of class %s during linking of class %s "
983+
"because of the class is listed in the LoadableDescriptors attribute",
984+
sig->as_C_string(), ik->name()->as_C_string());
985+
oop loader = ik->class_loader();
986+
Klass* klass = SystemDictionary::resolve_or_null(class_name,
987+
Handle(THREAD, loader), THREAD);
988+
if (HAS_PENDING_EXCEPTION) {
989+
CLEAR_PENDING_EXCEPTION;
990+
}
991+
if (klass != nullptr) {
992+
log_info(class, preload)("Preloading of class %s during linking of class %s "
993+
"(cause: LoadableDescriptors attribute) succeeded",
994+
class_name->as_C_string(), ik->name()->as_C_string());
995+
if (!klass->is_inline_klass()) {
996+
// Non value class are allowed by the current spec, but it could be an indication
997+
// of an issue so let's log a warning
998+
log_warning(class, preload)("Preloading of class %s during linking of class %s "
999+
"(cause: LoadableDescriptors attribute) but loaded class is not a value class",
1000+
class_name->as_C_string(), ik->name()->as_C_string());
1001+
}
1002+
} else {
1003+
log_warning(class, preload)("Preloading of class %s during linking of class %s "
1004+
"(cause: LoadableDescriptors attribute) failed",
1005+
class_name->as_C_string(), ik->name()->as_C_string());
1006+
}
1007+
}
1008+
}
1009+
}
1010+
9731011
void InstanceKlass::link_class(TRAPS) {
9741012
assert(is_loaded(), "must be loaded");
9751013
if (!is_linked()) {
@@ -1041,105 +1079,11 @@ bool InstanceKlass::link_class_impl(TRAPS) {
10411079
interk->link_class_impl(CHECK_false);
10421080
}
10431081

1044-
1045-
// If a class declares a method that uses an inline class as an argument
1046-
// type or return inline type, this inline class must be loaded during the
1047-
// linking of this class because size and properties of the inline class
1048-
// must be known in order to be able to perform inline type optimizations.
1049-
// The implementation below is an approximation of this rule, the code
1050-
// iterates over all methods of the current class (including overridden
1051-
// methods), not only the methods declared by this class. This
1052-
// approximation makes the code simpler, and doesn't change the semantic
1053-
// because classes declaring methods overridden by the current class are
1054-
// linked (and have performed their own pre-loading) before the linking
1055-
// of the current class.
1056-
1057-
1058-
// Note:
1059-
// Inline class types are loaded during
1060-
// the loading phase (see ClassFileParser::post_process_parsed_stream()).
1061-
// Inline class types used as element types for array creation
1062-
// are not pre-loaded. Their loading is triggered by either anewarray
1063-
// or multianewarray bytecodes.
1064-
1065-
// Could it be possible to do the following processing only if the
1066-
// class uses inline types?
10671082
if (EnableValhalla) {
1068-
ResourceMark rm(THREAD);
1069-
for (AllFieldStream fs(this); !fs.done(); fs.next()) {
1070-
if (fs.is_null_free_inline_type() && fs.access_flags().is_static()) {
1071-
assert(fs.access_flags().is_strict(), "null-free fields must be strict");
1072-
Symbol* sig = fs.signature();
1073-
TempNewSymbol s = Signature::strip_envelope(sig);
1074-
if (s != name()) {
1075-
log_info(class, preload)("Preloading of class %s during linking of class %s. Cause: a null-free static field is declared with this type", s->as_C_string(), name()->as_C_string());
1076-
Klass* klass = SystemDictionary::resolve_or_fail(s,
1077-
Handle(THREAD, class_loader()), true,
1078-
CHECK_false);
1079-
if (HAS_PENDING_EXCEPTION) {
1080-
log_warning(class, preload)("Preloading of class %s during linking of class %s (cause: null-free static field) failed: %s",
1081-
s->as_C_string(), name()->as_C_string(), PENDING_EXCEPTION->klass()->name()->as_C_string());
1082-
return false; // Exception is still pending
1083-
}
1084-
log_info(class, preload)("Preloading of class %s during linking of class %s (cause: null-free static field) succeeded",
1085-
s->as_C_string(), name()->as_C_string());
1086-
assert(klass != nullptr, "Sanity check");
1087-
if (klass->is_abstract()) {
1088-
THROW_MSG_(vmSymbols::java_lang_IncompatibleClassChangeError(),
1089-
err_msg("Class %s expects class %s to be concrete value class, but it is an abstract class",
1090-
name()->as_C_string(),
1091-
InstanceKlass::cast(klass)->external_name()), false);
1092-
}
1093-
if (!klass->is_inline_klass()) {
1094-
THROW_MSG_(vmSymbols::java_lang_IncompatibleClassChangeError(),
1095-
err_msg("class %s expects class %s to be a value class but it is an identity class",
1096-
name()->as_C_string(), klass->external_name()), false);
1097-
}
1098-
InlineKlass* vk = InlineKlass::cast(klass);
1099-
// the inline_type_field_klasses_array might have been loaded with CDS, so update only if not already set and check consistency
1100-
InlineLayoutInfo* li = inline_layout_info_adr(fs.index());
1101-
if (li->klass() == nullptr) {
1102-
li->set_klass(InlineKlass::cast(vk));
1103-
li->set_kind(LayoutKind::REFERENCE);
1104-
}
1105-
assert(get_inline_type_field_klass(fs.index()) == vk, "Must match");
1106-
} else {
1107-
InlineLayoutInfo* li = inline_layout_info_adr(fs.index());
1108-
if (li->klass() == nullptr) {
1109-
li->set_klass(InlineKlass::cast(this));
1110-
li->set_kind(LayoutKind::REFERENCE);
1111-
}
1112-
assert(get_inline_type_field_klass(fs.index()) == this, "Must match");
1113-
}
1114-
}
1115-
}
1116-
11171083
// Aggressively preloading all classes from the LoadableDescriptors attribute
1118-
if (loadable_descriptors() != nullptr && PreloadClasses) {
1119-
HandleMark hm(THREAD);
1120-
for (int i = 0; i < loadable_descriptors()->length(); i++) {
1121-
Symbol* sig = constants()->symbol_at(loadable_descriptors()->at(i));
1122-
if (!Signature::has_envelope(sig)) continue;
1123-
TempNewSymbol class_name = Signature::strip_envelope(sig);
1124-
if (class_name == name()) continue;
1125-
log_info(class, preload)("Preloading of class %s during linking of class %s because of the class is listed in the LoadableDescriptors attribute", sig->as_C_string(), name()->as_C_string());
1126-
oop loader = class_loader();
1127-
Klass* klass = SystemDictionary::resolve_or_null(class_name,
1128-
Handle(THREAD, loader), THREAD);
1129-
if (HAS_PENDING_EXCEPTION) {
1130-
CLEAR_PENDING_EXCEPTION;
1131-
}
1132-
if (klass != nullptr) {
1133-
log_info(class, preload)("Preloading of class %s during linking of class %s (cause: LoadableDescriptors attribute) succeeded", class_name->as_C_string(), name()->as_C_string());
1134-
if (!klass->is_inline_klass()) {
1135-
// Non value class are allowed by the current spec, but it could be an indication of an issue so let's log a warning
1136-
log_warning(class, preload)("Preloading of class %s during linking of class %s (cause: LoadableDescriptors attribute) but loaded class is not a value class", class_name->as_C_string(), name()->as_C_string());
1137-
}
1138-
} else {
1139-
log_warning(class, preload)("Preloading of class %s during linking of class %s (cause: LoadableDescriptors attribute) failed", class_name->as_C_string(), name()->as_C_string());
1140-
}
1141-
}
1142-
}
1084+
// so inline classes can be scalarized in the calling conventions computed below
1085+
load_classes_from_loadable_descriptors_attribute(this, THREAD);
1086+
assert(!HAS_PENDING_EXCEPTION, "Shouldn't have pending exceptions from call above");
11431087
}
11441088

11451089
// in case the class is linked in the process of linking its superclasses

test/hotspot/jtreg/runtime/valhalla/inlinetypes/PreloadCircularityTest.java

Lines changed: 1 addition & 154 deletions
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
@@ -296,159 +296,6 @@ void test_9() throws Exception {
296296
out.shouldContain("java.lang.IncompatibleClassChangeError: Class PreloadCircularityTest$Class9a expects class PreloadCircularityTest$Class9b to be a value class, but it is an identity class");
297297
}
298298

299-
static value class Class10a {
300-
@Strict
301-
@NullRestricted
302-
Class10b vb = new Class10b();
303-
}
304-
305-
static value class Class10b { }
306-
307-
// void test_10() throws Exception {
308-
// OutputAnalyzer out = tryLoadingClass("PreloadCircularityTest$Class10a");
309-
// out.shouldHaveExitValue(1);
310-
// out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class10b during loading of class PreloadCircularityTest$Class10a. Cause: a null-free non-static field is declared with this type");
311-
// out.shouldContain("java.lang.IncompatibleClassChangeError: class PreloadCircularityTest$Class10b is not implicitly constructible and it is used in a null restricted non-static field (not supported)");
312-
// }
313-
314-
// Testing preloading due to static fields
315-
316-
static value class Class50a {
317-
@Strict
318-
@NullRestricted
319-
static Class50a sa = new Class50a();
320-
}
321-
322-
void test_50() throws Exception {
323-
OutputAnalyzer out = tryLoadingClass("PreloadCircularityTest$Class50a");
324-
out.shouldHaveExitValue(0);
325-
out.shouldNotContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class50a");
326-
}
327-
328-
static value class Class51a {
329-
@Strict
330-
@NullRestricted
331-
static Class51b sb = new Class51b();
332-
333-
@Strict
334-
@NullRestricted
335-
static Class51c sc = new Class51c();
336-
}
337-
338-
static value class Class51b {
339-
@Strict
340-
@NullRestricted
341-
static Class51a sa = new Class51a();
342-
}
343-
344-
static value class Class51c {
345-
@Strict
346-
@NullRestricted
347-
Class51a sa = new Class51a();
348-
}
349-
350-
void test_51() throws Exception {
351-
OutputAnalyzer out = tryLoadingClass("PreloadCircularityTest$Class51a");
352-
out.shouldHaveExitValue(0);
353-
out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class51b during linking of class PreloadCircularityTest$Class51a. Cause: a null-free static field is declared with this type");
354-
out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class51b during linking of class PreloadCircularityTest$Class51a (cause: null-free static field) succeeded");
355-
out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class51c during linking of class PreloadCircularityTest$Class51a. Cause: a null-free static field is declared with this type");
356-
out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class51a during loading of class PreloadCircularityTest$Class51c. Cause: a null-free non-static field is declared with this type");
357-
out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class51a during loading of class PreloadCircularityTest$Class51c (cause: null-free non-static field) succeeded");
358-
out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class51c during linking of class PreloadCircularityTest$Class51a (cause: null-free static field) succeeded");
359-
out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class51a during linking of class PreloadCircularityTest$Class51b. Cause: a null-free static field is declared with this type");
360-
out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class51a during linking of class PreloadCircularityTest$Class51b (cause: null-free static field) succeeded");
361-
}
362-
363-
static value class Class52a {
364-
@Strict
365-
@NullRestricted
366-
static Class52b vb = new Class52b();
367-
}
368-
369-
static value class Class52b {
370-
@Strict
371-
@NullRestricted
372-
Class52c vc = new Class52c();
373-
}
374-
375-
static value class Class52c {
376-
@Strict
377-
@NullRestricted
378-
Class52b vb = new Class52b();
379-
}
380-
381-
void test_52() throws Exception {
382-
OutputAnalyzer out = tryLoadingClass("PreloadCircularityTest$Class52a");
383-
out.shouldHaveExitValue(1);
384-
out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class52b during linking of class PreloadCircularityTest$Class52a. Cause: a null-free static field is declared with this type");
385-
out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class52c during loading of class PreloadCircularityTest$Class52b. Cause: a null-free non-static field is declared with this type");
386-
out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class52b during loading of class PreloadCircularityTest$Class52c. Cause: a null-free non-static field is declared with this type");
387-
out.shouldContain("[warning][class,preload] Preloading of class PreloadCircularityTest$Class52b during loading of class PreloadCircularityTest$Class52c (cause: null-free non-static field) failed: java/lang/ClassCircularityError");
388-
out.shouldContain("[warning][class,preload] Preloading of class PreloadCircularityTest$Class52c during loading of class PreloadCircularityTest$Class52b (cause: null-free non-static field) failed: java/lang/ClassCircularityError");
389-
}
390-
391-
static value class Class53a {
392-
Class53b vb = new Class53b();
393-
394-
@Strict
395-
@NullRestricted
396-
static Class53b sb = new Class53b();
397-
}
398-
399-
static value class Class53b {
400-
@Strict
401-
@NullRestricted
402-
Class53a va = new Class53a();
403-
}
404-
405-
// In the following test, Class53a fails to optimistically load Class53b at load time, but successfully loads it at link time
406-
407-
// void test_53() throws Exception {
408-
// OutputAnalyzer out = tryLoadingClass("PreloadCircularityTest$Class53a");
409-
// out.shouldHaveExitValue(0);
410-
// out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class53b during loading of class PreloadCircularityTest$Class53a. Cause: field type in LoadableDescriptors attribute");
411-
// out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class53a during loading of class PreloadCircularityTest$Class53b. Cause: a null-free non-static field is declared with this type");
412-
// out.shouldContain("[warning][class,preload] Preloading of class PreloadCircularityTest$Class53a during loading of class PreloadCircularityTest$Class53b (cause: null-free non-static field) failed: java/lang/ClassCircularityError");
413-
// out.shouldContain("[warning][class,preload] Preloading of class PreloadCircularityTest$Class53b during loading of class PreloadCircularityTest$Class53a (cause: field type in LoadableDescriptors attribute) failed : java/lang/ClassCircularityError");
414-
// out.shouldContain("[info ][class,preload] Preloading of class PreloadCircularityTest$Class53b during linking of class PreloadCircularityTest$Class53a. Cause: a null-free static field is declared with this type");
415-
// out.shouldContain("[info ][class,preload] Preloading of class PreloadCircularityTest$Class53a during loading of class PreloadCircularityTest$Class53b. Cause: a null-free non-static field is declared with this type");
416-
// out.shouldContain("[info ][class,preload] Preloading of class PreloadCircularityTest$Class53a during loading of class PreloadCircularityTest$Class53b (cause: null-free non-static field) succeeded");
417-
// out.shouldContain("[info ][class,preload] Preloading of class PreloadCircularityTest$Class53b during linking of class PreloadCircularityTest$Class53a (cause: null-free static field) succeeded");
418-
// }
419-
420-
static value class Class54a {
421-
@Strict
422-
@NullRestricted
423-
static Class54b sb = new Class54b();
424-
}
425-
426-
static class Class54b { }
427-
428-
void test_54() throws Exception {
429-
OutputAnalyzer out = tryLoadingClass("PreloadCircularityTest$Class54a");
430-
out.shouldHaveExitValue(1);
431-
out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class54b during linking of class PreloadCircularityTest$Class54a. Cause: a null-free static field is declared with this type");
432-
out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class54b during linking of class PreloadCircularityTest$Class54a (cause: null-free static field) succeeded");
433-
out.shouldContain("java.lang.IncompatibleClassChangeError: class PreloadCircularityTest$Class54a expects class PreloadCircularityTest$Class54b to be a value class but it is an identity class");
434-
}
435-
436-
static class Class55a {
437-
@Strict
438-
@NullRestricted
439-
static Class55b sb = new Class55b();
440-
}
441-
442-
static value class Class55b { }
443-
444-
// void test_55() throws Exception {
445-
// OutputAnalyzer out = tryLoadingClass("PreloadCircularityTest$Class55a");
446-
// out.shouldHaveExitValue(1);
447-
// out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class55b during linking of class PreloadCircularityTest$Class55a. Cause: a null-free static field is declared with this type");
448-
// out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class55b during linking of class PreloadCircularityTest$Class55a (cause: null-free static field) succeeded");
449-
// out.shouldContain("java.lang.IncompatibleClassChangeError: class PreloadCircularityTest$Class55b is not implicitly constructible and it is used in a null restricted static field (not supported)");
450-
// }
451-
452299
public static class TestHelper {
453300
public static void main(String[] args) {
454301
try {

0 commit comments

Comments
 (0)