Skip to content

Commit 4a74b8f

Browse files
[GR-71216] [GR-71222] Cleanups, refactorings, and fixes for the layouting and walking of the image heap.
PullRequest: graal/22551
2 parents 50d5293 + 5aba5ed commit 4a74b8f

File tree

11 files changed

+276
-242
lines changed

11 files changed

+276
-242
lines changed

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java

Lines changed: 69 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -50,40 +50,36 @@
5050

5151
public class ChunkedImageHeapLayouter implements ImageHeapLayouter {
5252
/** A partition holding read-only objects. */
53-
private static final int READ_ONLY_REGULAR = 0;
53+
private static final int ALIGNED_READ_ONLY_REGULAR = 0;
5454
/**
55-
* A pseudo-partition used during image building to consolidate objects that contain relocatable
56-
* references.
55+
* A partition holding all read-only objects that contain relocatable references.
5756
* <p>
5857
* Collecting the relocations together means the dynamic linker has to operate on less of the
5958
* image heap during image startup, and it means that less of the image heap has to be
6059
* copied-on-write if the image heap is relocated in a new process.
6160
* <p>
62-
* A relocated reference is read-only once relocated, e.g., at runtime.
61+
* A relocated reference is read-only once relocated, i.e., at runtime.
6362
*/
64-
private static final int READ_ONLY_RELOCATABLE = READ_ONLY_REGULAR + 1;
63+
private static final int ALIGNED_READ_ONLY_RELOCATABLE = ALIGNED_READ_ONLY_REGULAR + 1;
6564
/**
6665
* A partition holding objects which must be patched at execution startup by our initialization
6766
* code. This is currently only used within layered images.
6867
*/
69-
private static final int WRITABLE_PATCHED = READ_ONLY_RELOCATABLE + 1;
68+
private static final int ALIGNED_WRITABLE_PATCHED = ALIGNED_READ_ONLY_RELOCATABLE + 1;
7069
/** A partition holding writable objects. */
71-
private static final int WRITABLE_REGULAR = WRITABLE_PATCHED + 1;
72-
/** A partition holding very large writable objects with or without references. */
73-
private static final int WRITABLE_HUGE = WRITABLE_REGULAR + 1;
74-
/**
75-
* A partition holding very large read-only objects with or without references, but never with
76-
* relocatable references.
77-
*/
78-
private static final int READ_ONLY_HUGE = WRITABLE_HUGE + 1;
79-
private static final int PARTITION_COUNT = READ_ONLY_HUGE + 1;
70+
private static final int ALIGNED_WRITABLE_REGULAR = ALIGNED_WRITABLE_PATCHED + 1;
71+
/** A partition holding very large writable objects. */
72+
private static final int UNALIGNED_WRITABLE = ALIGNED_WRITABLE_REGULAR + 1;
73+
/** A partition holding very large read-only objects, but never with relocatable references. */
74+
private static final int UNALIGNED_READ_ONLY = UNALIGNED_WRITABLE + 1;
75+
private static final int PARTITION_COUNT = UNALIGNED_READ_ONLY + 1;
8076

8177
private static final String ALIGNED_HEAP_CHUNK_OPTION = SubstrateOptionsParser.commandArgument(SerialAndEpsilonGCOptions.AlignedHeapChunkSize, "<2^n>");
8278

8379
private final ChunkedImageHeapPartition[] partitions;
8480
private final ImageHeapInfo heapInfo;
8581
private final long startOffset;
86-
private final long hugeObjectThreshold;
82+
private final long unalignedObjectSizeThreshold;
8783
private ChunkedImageHeapAllocator allocator;
8884

8985
/** @param startOffset Offset relative to the heap base. */
@@ -92,19 +88,18 @@ public ChunkedImageHeapLayouter(ImageHeapInfo heapInfo, long startOffset) {
9288
assert startOffset % Heap.getHeap().getImageHeapAlignment() == 0 : "the start of each image heap must be aligned";
9389

9490
this.partitions = new ChunkedImageHeapPartition[PARTITION_COUNT];
95-
this.partitions[READ_ONLY_REGULAR] = new ChunkedImageHeapPartition("readOnly", false, false);
96-
this.partitions[READ_ONLY_RELOCATABLE] = new ChunkedImageHeapPartition("readOnlyRelocatable", false, false);
97-
this.partitions[WRITABLE_PATCHED] = new ChunkedImageHeapPartition("writablePatched", true, false);
98-
this.partitions[WRITABLE_REGULAR] = new ChunkedImageHeapPartition("writable", true, false);
99-
this.partitions[WRITABLE_HUGE] = new ChunkedImageHeapPartition("writableHuge", true, true);
100-
this.partitions[READ_ONLY_HUGE] = new ChunkedImageHeapPartition("readOnlyHuge", false, true);
91+
this.partitions[ALIGNED_READ_ONLY_REGULAR] = new ChunkedImageHeapPartition("alignedReadOnlyRegular", false, false);
92+
this.partitions[ALIGNED_READ_ONLY_RELOCATABLE] = new ChunkedImageHeapPartition("alignedReadOnlyRelocatable", false, false);
93+
this.partitions[ALIGNED_WRITABLE_PATCHED] = new ChunkedImageHeapPartition("alignedWritablePatched", true, false);
94+
this.partitions[ALIGNED_WRITABLE_REGULAR] = new ChunkedImageHeapPartition("alignedWritableRegular", true, false);
95+
this.partitions[UNALIGNED_WRITABLE] = new ChunkedImageHeapPartition("unalignedWritable", true, true);
96+
this.partitions[UNALIGNED_READ_ONLY] = new ChunkedImageHeapPartition("unalignedReadOnly", false, true);
10197

10298
this.heapInfo = heapInfo;
10399
this.startOffset = startOffset;
104100

105101
UnsignedWord alignedHeaderSize = RememberedSet.get().getHeaderSizeOfAlignedChunk();
106-
UnsignedWord hugeThreshold = HeapParameters.getAlignedHeapChunkSize().subtract(alignedHeaderSize);
107-
this.hugeObjectThreshold = hugeThreshold.rawValue();
102+
this.unalignedObjectSizeThreshold = HeapParameters.getAlignedHeapChunkSize().subtract(alignedHeaderSize).rawValue();
108103
}
109104

110105
@Override
@@ -124,35 +119,35 @@ private ChunkedImageHeapPartition choosePartition(ImageHeapObject info, boolean
124119
throw VMError.shouldNotReachHere("Object cannot contain both relocatables and patched constants: " + info.getObject());
125120
}
126121
if (patched) {
127-
return getWritablePatched();
122+
return getAlignedWritablePatched();
128123
} else if (immutable) {
129-
if (info.getSize() >= hugeObjectThreshold) {
124+
if (info.getSize() >= unalignedObjectSizeThreshold) {
130125
if (hasRelocatables) {
131126
if (info.getObjectClass() == DynamicHub.class) {
132-
throw reportHugeObjectError(info, "Class metadata (dynamic hubs) cannot be huge objects: the dynamic hub %s", info.getObject().toString());
127+
throw reportObjectTooLargeForAlignedChunkError(info, "Class metadata (dynamic hubs) cannot be in unaligned heap chunks: the dynamic hub %s", info.getObject().toString());
133128
}
134-
throw reportHugeObjectError(info, "Objects in image heap with relocatable pointers cannot be huge objects. Detected an object of type %s",
129+
throw reportObjectTooLargeForAlignedChunkError(info, "Objects in image heap with relocatable pointers cannot be in unaligned heap chunks. Detected an object of type %s",
135130
info.getObject().getClass().getTypeName());
136131
}
137-
return getReadOnlyHuge();
132+
return getUnalignedReadOnly();
138133
}
139134
if (hasRelocatables) {
140-
return getReadOnlyRelocatable();
135+
return getAlignedReadOnlyRelocatable();
141136
} else {
142-
return getReadOnlyRegular();
137+
return getAlignedReadOnlyRegular();
143138
}
144139
} else {
145140
assert info.getObjectClass() != DynamicHub.class : "Class metadata (dynamic hubs) cannot be writable";
146-
if (info.getSize() >= hugeObjectThreshold) {
147-
return getWritableHuge();
141+
if (info.getSize() >= unalignedObjectSizeThreshold) {
142+
return getUnalignedWritable();
148143
}
149-
return getWritableRegular();
144+
return getAlignedWritableRegular();
150145
}
151146
}
152147

153-
private Error reportHugeObjectError(ImageHeapObject info, String objectTypeMsg, String objectText) {
148+
private Error reportObjectTooLargeForAlignedChunkError(ImageHeapObject info, String objectTypeMsg, String objectText) {
154149
String msg = String.format(objectTypeMsg + " with size %d B and the limit is %d B. Use '%s' to increase GC chunk size to be larger than the object.",
155-
objectText, info.getSize(), hugeObjectThreshold, ALIGNED_HEAP_CHUNK_OPTION);
150+
objectText, info.getSize(), unalignedObjectSizeThreshold, ALIGNED_HEAP_CHUNK_OPTION);
156151
if (ImageInfo.inImageBuildtimeCode()) {
157152
throw UserError.abort(msg);
158153
} else {
@@ -214,20 +209,37 @@ private ImageHeapLayoutInfo populateInfoObjects(int dynamicHubCount, int pageSiz
214209
}
215210
control.poll();
216211

217-
heapInfo.initialize(getReadOnlyRegular().firstObject, getReadOnlyRegular().lastObject, getReadOnlyRelocatable().firstObject, getReadOnlyRelocatable().lastObject,
218-
getWritablePatched().firstObject, getWritablePatched().lastObject,
219-
getWritableRegular().firstObject, getWritableRegular().lastObject, getWritableHuge().firstObject, getWritableHuge().lastObject,
220-
getReadOnlyHuge().firstObject, getReadOnlyHuge().lastObject, offsetOfFirstWritableAlignedChunk, offsetOfFirstWritableUnalignedChunk, offsetOfLastWritableUnalignedChunk,
212+
Object firstAlignedReadOnlyObject = firstNonNullValue(getAlignedReadOnlyRegular().firstObject, getAlignedReadOnlyRelocatable().firstObject);
213+
Object lastAlignedReadOnlyObject = firstNonNullValue(getAlignedReadOnlyRelocatable().lastObject, getAlignedReadOnlyRegular().lastObject);
214+
Object firstAlignedWritableObject = firstNonNullValue(getAlignedWritablePatched().firstObject, getAlignedWritableRegular().firstObject);
215+
Object lastAlignedWritableObject = firstNonNullValue(getAlignedWritableRegular().lastObject, getAlignedWritablePatched().lastObject);
216+
217+
heapInfo.initialize(firstAlignedReadOnlyObject, lastAlignedReadOnlyObject,
218+
getAlignedReadOnlyRelocatable().firstObject, getAlignedReadOnlyRelocatable().lastObject,
219+
firstAlignedWritableObject, lastAlignedWritableObject,
220+
getAlignedWritablePatched().firstObject, getAlignedWritablePatched().lastObject,
221+
getUnalignedWritable().firstObject, getUnalignedWritable().lastObject,
222+
getUnalignedReadOnly().firstObject, getUnalignedReadOnly().lastObject,
223+
offsetOfFirstWritableAlignedChunk, offsetOfFirstWritableUnalignedChunk, offsetOfLastWritableUnalignedChunk,
221224
dynamicHubCount);
222225

223226
control.poll();
224227

225-
long writableEnd = getWritableHuge().getStartOffset() + getWritableHuge().getSize();
228+
long writableEnd = getUnalignedWritable().getStartOffset() + getUnalignedWritable().getSize();
226229
long writableSize = writableEnd - offsetOfFirstWritableAlignedChunk;
227-
/* Aligning the end to the page size can be required for mapping into memory. */
228-
long imageHeapEnd = NumUtil.roundUp(getReadOnlyHuge().getStartOffset() + getReadOnlyHuge().getSize(), pageSize);
229-
return new ImageHeapLayoutInfo(startOffset, imageHeapEnd, offsetOfFirstWritableAlignedChunk, writableSize, getReadOnlyRelocatable().getStartOffset(), getReadOnlyRelocatable().getSize(),
230-
getWritablePatched().getStartOffset(), getWritablePatched().getSize());
230+
long imageHeapEnd = NumUtil.roundUp(getUnalignedReadOnly().getStartOffset() + getUnalignedReadOnly().getSize(), pageSize);
231+
return new ImageHeapLayoutInfo(startOffset, imageHeapEnd, offsetOfFirstWritableAlignedChunk, writableSize,
232+
getAlignedReadOnlyRelocatable().getStartOffset(), getAlignedReadOnlyRelocatable().getSize(),
233+
getAlignedWritablePatched().getStartOffset(), getAlignedWritablePatched().getSize());
234+
}
235+
236+
private static Object firstNonNullValue(Object... objects) {
237+
for (Object o : objects) {
238+
if (o != null) {
239+
return o;
240+
}
241+
}
242+
return null;
231243
}
232244

233245
@Override
@@ -266,27 +278,27 @@ private static void writeHeader(ImageHeapChunkWriter writer, Chunk previous, Chu
266278
}
267279
}
268280

269-
private ChunkedImageHeapPartition getReadOnlyRegular() {
270-
return partitions[READ_ONLY_REGULAR];
281+
private ChunkedImageHeapPartition getAlignedReadOnlyRegular() {
282+
return partitions[ALIGNED_READ_ONLY_REGULAR];
271283
}
272284

273-
private ChunkedImageHeapPartition getReadOnlyRelocatable() {
274-
return partitions[READ_ONLY_RELOCATABLE];
285+
private ChunkedImageHeapPartition getAlignedReadOnlyRelocatable() {
286+
return partitions[ALIGNED_READ_ONLY_RELOCATABLE];
275287
}
276288

277-
private ChunkedImageHeapPartition getWritablePatched() {
278-
return partitions[WRITABLE_PATCHED];
289+
private ChunkedImageHeapPartition getAlignedWritablePatched() {
290+
return partitions[ALIGNED_WRITABLE_PATCHED];
279291
}
280292

281-
private ChunkedImageHeapPartition getWritableRegular() {
282-
return partitions[WRITABLE_REGULAR];
293+
private ChunkedImageHeapPartition getAlignedWritableRegular() {
294+
return partitions[ALIGNED_WRITABLE_REGULAR];
283295
}
284296

285-
private ChunkedImageHeapPartition getWritableHuge() {
286-
return partitions[WRITABLE_HUGE];
297+
private ChunkedImageHeapPartition getUnalignedWritable() {
298+
return partitions[UNALIGNED_WRITABLE];
287299
}
288300

289-
private ChunkedImageHeapPartition getReadOnlyHuge() {
290-
return partitions[READ_ONLY_HUGE];
301+
private ChunkedImageHeapPartition getUnalignedReadOnly() {
302+
return partitions[UNALIGNED_READ_ONLY];
291303
}
292304
}

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapPartition.java

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
public class ChunkedImageHeapPartition implements ImageHeapPartition {
4646
private final String name;
4747
private final boolean writable;
48-
private final boolean hugeObjects;
48+
private final boolean unalignedChunks;
4949
private final int minimumObjectSize;
5050
private final List<ImageHeapObject> objects = new ArrayList<>();
5151

@@ -55,10 +55,10 @@ public class ChunkedImageHeapPartition implements ImageHeapPartition {
5555
long startOffset = -1;
5656
long endOffset = -1;
5757

58-
ChunkedImageHeapPartition(String name, boolean writable, boolean hugeObjects) {
58+
ChunkedImageHeapPartition(String name, boolean writable, boolean unalignedChunks) {
5959
this.name = name;
6060
this.writable = writable;
61-
this.hugeObjects = hugeObjects;
61+
this.unalignedChunks = unalignedChunks;
6262

6363
/* Cache to prevent frequent lookups of the object layout from ImageSingletons. */
6464
this.minimumObjectSize = ConfigurationValues.getObjectLayout().getMinImageHeapObjectSize();
@@ -70,25 +70,26 @@ void assign(ImageHeapObject obj) {
7070
}
7171

7272
void layout(ChunkedImageHeapAllocator allocator, ImageHeapLayouterControl control) {
73-
if (hugeObjects) {
74-
layoutInUnalignedChunks(allocator, control);
75-
} else {
76-
layoutInAlignedChunks(allocator, control);
77-
}
78-
}
79-
80-
private void layoutInUnalignedChunks(ChunkedImageHeapAllocator allocator, ImageHeapLayouterControl control) {
8173
if (objects.isEmpty()) {
8274
/*
83-
* Without objects, don't force finishing the current chunk and therefore committing
84-
* space for the rest of it. Another partition might be able to continue filling it, or,
85-
* if no more objects follow, we don't need to dedicate space in the image at all.
75+
* Without objects, there is no need to start a new chunk, or to force finishing the
76+
* current chunk and therefore committing space for the rest of it. Another partition
77+
* might be able to continue filling it, or, if no more objects follow, we don't need to
78+
* dedicate space in the image at all.
8679
*/
8780
startOffset = allocator.getPosition();
8881
endOffset = startOffset;
8982
return;
9083
}
9184

85+
if (unalignedChunks) {
86+
layoutInUnalignedChunks(allocator, control);
87+
} else {
88+
layoutInAlignedChunks(allocator, control);
89+
}
90+
}
91+
92+
private void layoutInUnalignedChunks(ChunkedImageHeapAllocator allocator, ImageHeapLayouterControl control) {
9293
allocator.finishAlignedChunk();
9394
startOffset = allocator.getPosition();
9495

@@ -108,7 +109,7 @@ private void layoutInAlignedChunks(ChunkedImageHeapAllocator allocator, ImageHea
108109
}
109110

110111
private void allocateObjectsInAlignedChunks(ChunkedImageHeapAllocator allocator, ImageHeapLayouterControl control) {
111-
NavigableMap<Long, Queue<ImageHeapObject>> sortedObjects = createSortedObjectsMap();
112+
TreeMap<Long, Queue<ImageHeapObject>> sortedObjects = createSortedObjectsMap();
112113
while (!sortedObjects.isEmpty()) {
113114
ImageHeapObject info = dequeueBestFit(sortedObjects, allocator.getRemainingBytesInAlignedChunk());
114115
if (info == null) {
@@ -120,16 +121,16 @@ private void allocateObjectsInAlignedChunks(ChunkedImageHeapAllocator allocator,
120121
}
121122
}
122123

124+
/**
125+
* Find a floor entry. We intentionally do not call {@link TreeMap#getFloorEntry} because that
126+
* method allocates a new entry object. Instead, we fetch the floor key and get the value for
127+
* the returned key.
128+
*/
123129
private ImageHeapObject dequeueBestFit(NavigableMap<Long, Queue<ImageHeapObject>> sortedObjects, long nbytes) {
124130
if (nbytes < minimumObjectSize) {
125131
return null;
126132
}
127133

128-
/**
129-
* Find a floor entry. We are purposefully not calling {@link TreeMap#getFloorEntry(Object)}
130-
* as that method allocates a new entry object. Instead, we fetch the floor key and get the
131-
* value for the returned key.
132-
*/
133134
Long floorKey = sortedObjects.floorKey(nbytes);
134135
if (floorKey == null) {
135136
return null;
@@ -142,8 +143,8 @@ private ImageHeapObject dequeueBestFit(NavigableMap<Long, Queue<ImageHeapObject>
142143
return obj;
143144
}
144145

145-
private NavigableMap<Long, Queue<ImageHeapObject>> createSortedObjectsMap() {
146-
NavigableMap<Long, Queue<ImageHeapObject>> map = new TreeMap<>();
146+
private TreeMap<Long, Queue<ImageHeapObject>> createSortedObjectsMap() {
147+
TreeMap<Long, Queue<ImageHeapObject>> map = new TreeMap<>();
147148
for (ImageHeapObject obj : objects) {
148149
long objSize = obj.getSize();
149150
assert objSize >= ConfigurationValues.getObjectLayout().getMinImageHeapObjectSize() : Assertions.errorMessage(obj, objSize);
@@ -174,8 +175,8 @@ public boolean isWritable() {
174175
return writable;
175176
}
176177

177-
boolean usesUnalignedObjects() {
178-
return hugeObjects;
178+
boolean usesUnalignedChunks() {
179+
return unalignedChunks;
179180
}
180181

181182
@Override

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -962,8 +962,8 @@ private void blackenImageHeapRoots(ImageHeapInfo imageHeapInfo) {
962962
@AlwaysInline("GC Performance")
963963
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
964964
static void walkImageHeapRoots(ImageHeapInfo imageHeapInfo, ObjectVisitor visitor) {
965-
ImageHeapWalker.walkPartitionInline(imageHeapInfo.firstWritableRegularObject, imageHeapInfo.lastWritableRegularObject, visitor, true);
966-
ImageHeapWalker.walkPartitionInline(imageHeapInfo.firstWritableHugeObject, imageHeapInfo.lastWritableHugeObject, visitor, false);
965+
ImageHeapWalker.walkPartitionInline(imageHeapInfo.firstAlignedWritableObject, imageHeapInfo.lastAlignedWritableObject, visitor, true);
966+
ImageHeapWalker.walkPartitionInline(imageHeapInfo.firstUnalignedWritableObject, imageHeapInfo.lastUnalignedWritableObject, visitor, false);
967967
}
968968

969969
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)

0 commit comments

Comments
 (0)