Skip to content

Commit 093d033

Browse files
committed
8374554: [lworld] Field layout assert with UseCompactObjectHeaders
Reviewed-by: coleenp
1 parent d8438ac commit 093d033

File tree

5 files changed

+295
-110
lines changed

5 files changed

+295
-110
lines changed

src/hotspot/share/classfile/fieldLayoutBuilder.cpp

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2020, 2026, 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
@@ -1064,29 +1064,17 @@ void FieldLayoutBuilder::compute_inline_class_layout() {
10641064

10651065
assert(_layout->start()->block_kind() == LayoutRawBlock::RESERVED, "Unexpected");
10661066

1067-
if (_layout->super_has_fields() && !_is_abstract_value) { // non-static field layout
1068-
if (!_has_nonstatic_fields) {
1069-
assert(_is_abstract_value, "Concrete value types have at least one field");
1070-
// Nothing to do
1071-
} else {
1072-
// decide which alignment to use, then set first allowed field offset
1073-
1074-
assert(_layout->super_alignment() >= _payload_alignment, "Incompatible alignment");
1075-
assert(_layout->super_alignment() % _payload_alignment == 0, "Incompatible alignment");
1076-
1077-
if (_payload_alignment < _layout->super_alignment()) {
1078-
int new_alignment = _payload_alignment > _layout->super_min_align_required() ? _payload_alignment : _layout->super_min_align_required();
1079-
assert(new_alignment % _payload_alignment == 0, "Must be");
1080-
assert(new_alignment % _layout->super_min_align_required() == 0, "Must be");
1081-
_payload_alignment = new_alignment;
1082-
}
1083-
_layout->set_start(_layout->first_field_block());
1084-
}
1085-
} else {
1067+
if (!_layout->super_has_fields()) {
1068+
// No inherited fields, the layout must be empty except for the RESERVED block
1069+
// PADDING is inserted if needed to ensure the correct alignment of the payload.
10861070
if (_is_abstract_value && _has_nonstatic_fields) {
1071+
// non-static fields of the abstract class must be laid out without knowning
1072+
// the alignment constraints of the fields of the sub-classes, so the worst
1073+
// case scenario is assumed, which is currently the alignment of T_LONG.
1074+
// PADDING is added if needed to ensure the payload will respect this alignment.
10871075
_payload_alignment = type2aelembytes(BasicType::T_LONG);
10881076
}
1089-
assert(_layout->start()->next_block()->block_kind() == LayoutRawBlock::EMPTY || !UseCompressedClassPointers, "Unexpected");
1077+
assert(_layout->start()->next_block()->block_kind() == LayoutRawBlock::EMPTY, "Unexpected");
10901078
LayoutRawBlock* first_empty = _layout->start()->next_block();
10911079
if (first_empty->offset() % _payload_alignment != 0) {
10921080
LayoutRawBlock* padding = new LayoutRawBlock(LayoutRawBlock::PADDING, _payload_alignment - (first_empty->offset() % _payload_alignment));
@@ -1096,6 +1084,29 @@ void FieldLayoutBuilder::compute_inline_class_layout() {
10961084
}
10971085
_layout->set_start(padding);
10981086
}
1087+
} else { // the class has inherited some fields from its super(s)
1088+
if (!_is_abstract_value) {
1089+
// This is the step where the layout of the final concrete value class' layout
1090+
// is computed. Super abstract value classes might have been too conservative
1091+
// regarding alignment constraints, but now that the full set of non-static fields is
1092+
// known, compute which alignment to use, then set first allowed field offset
1093+
1094+
assert(_has_nonstatic_fields, "Concrete value classes must have at least one field");
1095+
if (_payload_alignment == -1) { // current class declares no local nonstatic fields
1096+
_payload_alignment = _layout->super_min_align_required();
1097+
}
1098+
1099+
assert(_layout->super_alignment() >= _payload_alignment, "Incompatible alignment");
1100+
assert(_layout->super_alignment() % _payload_alignment == 0, "Incompatible alignment");
1101+
1102+
if (_payload_alignment < _layout->super_alignment()) {
1103+
int new_alignment = _payload_alignment > _layout->super_min_align_required() ? _payload_alignment : _layout->super_min_align_required();
1104+
assert(new_alignment % _payload_alignment == 0, "Must be");
1105+
assert(new_alignment % _layout->super_min_align_required() == 0, "Must be");
1106+
_payload_alignment = new_alignment;
1107+
}
1108+
_layout->set_start(_layout->first_field_block());
1109+
}
10991110
}
11001111

11011112
_layout->add(_root_group->big_primitive_fields());

test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/FieldAlignmentTest.java

Lines changed: 85 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2024, 2026, 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
@@ -22,36 +22,69 @@
2222
*/
2323

2424
/*
25-
* @test id=Oops32
25+
* @test id=32
2626
* @requires vm.bits == 32
2727
* @requires vm.flagless
2828
* @library /test/lib
2929
* @modules java.base/jdk.internal.vm.annotation
3030
* @enablePreview
3131
* @compile FieldLayoutAnalyzer.java FieldAlignmentTest.java
32-
* @run main runtime.valhalla.inlinetypes.field_layout.FieldAlignmentTest 0
32+
* @run main runtime.valhalla.inlinetypes.field_layout.FieldAlignmentTest 32
3333
*/
3434

35-
/*
36-
* @test id=CompressedOops
35+
/*
36+
* @test id=64_COOP_CCP_NCOH
37+
* @requires vm.bits == 64
38+
* @requires vm.flagless
39+
* @library /test/lib
40+
* @modules java.base/jdk.internal.vm.annotation
41+
* @enablePreview
42+
* @compile FieldLayoutAnalyzer.java FieldAlignmentTest.java
43+
* @run main runtime.valhalla.inlinetypes.field_layout.FieldAlignmentTest 64_COOP_CCP_NCOH
44+
*/
45+
46+
/*
47+
* @test id=64_NCOOP_CCP_NCOH
3748
* @requires vm.bits == 64
3849
* @requires vm.flagless
3950
* @library /test/lib
4051
* @modules java.base/jdk.internal.vm.annotation
4152
* @enablePreview
4253
* @compile FieldLayoutAnalyzer.java FieldAlignmentTest.java
43-
* @run main runtime.valhalla.inlinetypes.field_layout.FieldAlignmentTest 1
54+
* @run main runtime.valhalla.inlinetypes.field_layout.FieldAlignmentTest 64_NCOOP_CCP_NCOH
4455
*/
4556

46-
/*
47-
* @test id=NoCompressedOops
57+
/*
58+
* @test id=64_NCOOP_NCCP_NCOH
4859
* @requires vm.bits == 64
4960
* @requires vm.flagless
5061
* @library /test/lib
5162
* @modules java.base/jdk.internal.vm.annotation
5263
* @enablePreview
5364
* @compile FieldLayoutAnalyzer.java FieldAlignmentTest.java
54-
* @run main runtime.valhalla.inlinetypes.field_layout.FieldAlignmentTest 2
65+
* @run main runtime.valhalla.inlinetypes.field_layout.FieldAlignmentTest 64_NCOOP_NCCP_NCOH
66+
*/
67+
68+
/*
69+
* @test id=64_COOP_CCP_COH
70+
* @requires vm.bits == 64
71+
* @requires vm.flagless
72+
* @library /test/lib
73+
* @modules java.base/jdk.internal.vm.annotation
74+
* @enablePreview
75+
* @compile FieldLayoutAnalyzer.java FieldAlignmentTest.java
76+
* @run main runtime.valhalla.inlinetypes.field_layout.FieldAlignmentTest 64_COOP_CCP_COH
77+
*/
78+
79+
/*
80+
* @test id=64_NCOOP_CCP_COH
81+
* @requires vm.bits == 64
82+
* @requires vm.flagless
83+
* @library /test/lib
84+
* @modules java.base/jdk.internal.vm.annotation
85+
* @enablePreview
86+
* @compile FieldLayoutAnalyzer.java FieldAlignmentTest.java
87+
* @run main runtime.valhalla.inlinetypes.field_layout.FieldAlignmentTest 64_NCOOP_CCP_COH
5588
*/
5689

5790
package runtime.valhalla.inlinetypes.field_layout;
@@ -152,7 +185,10 @@ void generateTestRunner() throws Exception {
152185
jdk.test.lib.helpers.ClassFileInstaller.writeClassToDisk(className, byteCode);
153186
}
154187

155-
static ProcessBuilder exec(String compressedOopsArg, String... args) throws Exception {
188+
static ProcessBuilder exec(String compressedOopsArg,
189+
String compressedKlassPointersArg,
190+
String compactObjectHeader,
191+
String... args) throws Exception {
156192
List<String> argsList = new ArrayList<>();
157193
Collections.addAll(argsList, "--enable-preview");
158194
Collections.addAll(argsList, "-XX:+UnlockDiagnosticVMOptions");
@@ -161,6 +197,12 @@ static ProcessBuilder exec(String compressedOopsArg, String... args) throws Exce
161197
if (compressedOopsArg != null) {
162198
Collections.addAll(argsList, compressedOopsArg);
163199
}
200+
if (compressedKlassPointersArg != null) {
201+
Collections.addAll(argsList, compressedKlassPointersArg);
202+
}
203+
if (compactObjectHeader != null) {
204+
Collections.addAll(argsList, compactObjectHeader);
205+
}
164206
Collections.addAll(argsList, "-Xmx256m");
165207
Collections.addAll(argsList, "-cp", System.getProperty("java.class.path") + System.getProperty("path.separator") +".");
166208
Collections.addAll(argsList, args);
@@ -169,14 +211,40 @@ static ProcessBuilder exec(String compressedOopsArg, String... args) throws Exce
169211

170212
public static void main(String[] args) throws Exception {
171213
String compressedOopsArg;
214+
String compressedKlassPointersArg;
215+
String compactObjectHeaderArg;
172216

173217
switch(args[0]) {
174-
case "0": compressedOopsArg = null;
175-
break;
176-
case "1": compressedOopsArg = "-XX:+UseCompressedOops";
177-
break;
178-
case "2": compressedOopsArg = "-XX:-UseCompressedOops";
179-
break;
218+
case "32":
219+
compressedOopsArg = null;
220+
compressedKlassPointersArg = null;
221+
compactObjectHeaderArg = null;
222+
break;
223+
case "64_COOP_CCP_NCOH":
224+
compressedOopsArg = "-XX:+UseCompressedOops";
225+
compressedKlassPointersArg = "-XX:+UseCompressedClassPointers";
226+
compactObjectHeaderArg = "-XX:-UseCompactObjectHeaders";
227+
break;
228+
case "64_NCOOP_CCP_NCOH":
229+
compressedOopsArg = "-XX:-UseCompressedOops";
230+
compressedKlassPointersArg = "-XX:+UseCompressedClassPointers";
231+
compactObjectHeaderArg = "-XX:-UseCompactObjectHeaders";
232+
break;
233+
case "64_NCOOP_NCCP_NCOH":
234+
compressedOopsArg = "-XX:-UseCompressedOops";
235+
compressedKlassPointersArg = "-XX:-UseCompressedClassPointers";
236+
compactObjectHeaderArg = "-XX:-UseCompactObjectHeaders";
237+
break;
238+
case "64_COOP_CCP_COH":
239+
compressedOopsArg = "-XX:+UseCompressedOops";
240+
compressedKlassPointersArg = "-XX:+UseCompressedClassPointers";
241+
compactObjectHeaderArg = "-XX:+UseCompactObjectHeaders";
242+
break;
243+
case "64_NCOOP_CCP_COH":
244+
compressedOopsArg = "-XX:-UseCompressedOops";
245+
compressedKlassPointersArg = "-XX:+UseCompressedClassPointers";
246+
compactObjectHeaderArg = "-XX:+UseCompactObjectHeaders";
247+
break;
180248
default: throw new RuntimeException("Unrecognized configuration");
181249
}
182250

@@ -186,7 +254,7 @@ public static void main(String[] args) throws Exception {
186254
fat.generateTestRunner();
187255

188256
// Execute the test runner in charge of loading all test classes
189-
ProcessBuilder pb = exec(compressedOopsArg, "TestRunner");
257+
ProcessBuilder pb = exec(compressedOopsArg, compressedKlassPointersArg, compactObjectHeaderArg, "TestRunner");
190258
OutputAnalyzer out = new OutputAnalyzer(pb.start());
191259

192260
if (out.getExitValue() != 0) {

test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/FieldLayoutAnalyzer.java

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,17 @@ static BlockType parseType(String s) {
7878
}
7979
}
8080

81-
static enum LayoutKind {
82-
NON_FLAT,
83-
NULL_FREE_NON_ATOMIC_FLAT,
84-
NULL_FREE_ATOMIC_FLAT,
85-
NULLABLE_ATOMIC_FLAT;
81+
static public enum LayoutKind {
82+
NON_FLAT(false),
83+
NULL_FREE_NON_ATOMIC_FLAT(false),
84+
NULL_FREE_ATOMIC_FLAT(false),
85+
NULLABLE_ATOMIC_FLAT(true);
86+
87+
private final boolean hasNullMarker;
88+
89+
private LayoutKind(boolean hasNullMarker) {
90+
this.hasNullMarker = hasNullMarker;
91+
}
8692

8793
static LayoutKind parseLayoutKind(String s) {
8894
switch(s) {
@@ -94,6 +100,10 @@ static LayoutKind parseLayoutKind(String s) {
94100
throw new RuntimeException("Unknown layout kind: " + s);
95101
}
96102
}
103+
104+
boolean hasNullMarker() {
105+
return this.hasNullMarker;
106+
}
97107
}
98108

99109
static public record FieldBlock (int offset,
@@ -124,6 +134,7 @@ void print(PrintStream out) {
124134
}
125135

126136
boolean isFlat() { return type == BlockType.FLAT; } // Warning: always return false for inherited fields, even flat ones
137+
boolean hasNullMarker() { return layoutKind.hasNullMarker(); }
127138

128139
static FieldBlock parseField(String line) {
129140
String[] fieldLine = line.split("\\s+");
@@ -243,7 +254,7 @@ int getAlignment(LayoutKind layoutKind) {
243254
void processField(String line, boolean isStatic) {
244255
FieldBlock block = FieldBlock.parseField(line);
245256
if (isStatic) {
246-
Asserts.assertTrue(block.type != BlockType.INHERITED); // static fields cannotbe inherited
257+
Asserts.assertTrue(block.type != BlockType.INHERITED); // static fields cannot be inherited
247258
staticFields.add(block);
248259
} else {
249260
nonStaticFields.add(block);

0 commit comments

Comments
 (0)