Skip to content

Commit ce375c5

Browse files
committed
[GR-67560] Remove unnecessary image heap partition alignment and filler object support.
PullRequest: graal/21532
2 parents ef314c4 + e6f932f commit ce375c5

File tree

8 files changed

+42
-154
lines changed

8 files changed

+42
-154
lines changed

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

Lines changed: 6 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,13 @@
2828
import java.util.List;
2929

3030
import com.oracle.svm.core.config.ConfigurationValues;
31-
import com.oracle.svm.core.image.ImageHeap;
3231
import com.oracle.svm.core.image.ImageHeapObject;
33-
import com.oracle.svm.core.image.ImageHeapPartition;
3432
import com.oracle.svm.core.util.UnsignedUtils;
3533
import com.oracle.svm.core.util.VMError;
3634

37-
import jdk.graal.compiler.core.common.NumUtil;
3835
import jdk.graal.compiler.word.Word;
3936

4037
class ChunkedImageHeapAllocator {
41-
/** A pseudo-partition for filler objects, see {@link FillerObjectDummyPartition}. */
42-
private static final ImageHeapPartition FILLERS_DUMMY_PARTITION = new FillerObjectDummyPartition();
43-
4438
abstract static class Chunk {
4539
private final long begin;
4640
private final long endOffset;
@@ -116,35 +110,6 @@ public long allocate(ImageHeapObject obj, boolean writable) {
116110
return objStart;
117111
}
118112

119-
public boolean tryAlignTop(int multiple) {
120-
long padding = computePadding(getTop(), multiple);
121-
if (padding != 0 && padding < minimumObjectSize) {
122-
/*
123-
* Cannot fit a filler object into the remaining padding space, so need to go up to
124-
* the next alignment multiple.
125-
*/
126-
padding = padding + multiple;
127-
}
128-
if (padding > getUnallocatedBytes()) {
129-
return false;
130-
}
131-
allocateFiller(padding);
132-
assert getTop() % multiple == 0;
133-
return true;
134-
}
135-
136-
private void allocateFiller(long size) {
137-
if (size != 0) {
138-
ImageHeapObject filler = imageHeap.addFillerObject(NumUtil.safeToInt(size));
139-
if (filler == null) {
140-
throw VMError.shouldNotReachHere("Failed to leave enough space for a filler object: " + size + " byte remaining");
141-
}
142-
filler.setHeapPartition(FILLERS_DUMMY_PARTITION);
143-
long location = allocate(filler, false);
144-
filler.setOffsetInPartition(location);
145-
}
146-
}
147-
148113
public List<ImageHeapObject> getObjects() {
149114
return objects;
150115
}
@@ -163,7 +128,6 @@ public long getUnallocatedBytes() {
163128
}
164129
}
165130

166-
private final ImageHeap imageHeap;
167131
private final int alignedChunkSize;
168132
private final int alignedChunkAlignment;
169133
private final int alignedChunkObjectsOffset;
@@ -176,8 +140,7 @@ public long getUnallocatedBytes() {
176140

177141
final int minimumObjectSize;
178142

179-
ChunkedImageHeapAllocator(ImageHeap imageHeap, long position) {
180-
this.imageHeap = imageHeap;
143+
ChunkedImageHeapAllocator(long position) {
181144
this.alignedChunkSize = UnsignedUtils.safeToInt(HeapParameters.getAlignedHeapChunkSize());
182145
this.alignedChunkAlignment = UnsignedUtils.safeToInt(HeapParameters.getAlignedHeapChunkAlignment());
183146
this.alignedChunkObjectsOffset = UnsignedUtils.safeToInt(AlignedHeapChunk.getObjectsStartOffset());
@@ -192,11 +155,6 @@ public long getPosition() {
192155
return (currentAlignedChunk != null) ? currentAlignedChunk.getTop() : position;
193156
}
194157

195-
public void alignBetweenChunks(int multiple) {
196-
assert currentAlignedChunk == null;
197-
allocateRaw(computePadding(position, multiple));
198-
}
199-
200158
public long allocateUnalignedChunkForObject(ImageHeapObject obj, boolean writable) {
201159
assert currentAlignedChunk == null;
202160
long objSize = obj.getSize();
@@ -220,6 +178,11 @@ public void startNewAlignedChunk() {
220178
alignedChunks.add(currentAlignedChunk);
221179
}
222180

181+
private void alignBetweenChunks(int multiple) {
182+
assert currentAlignedChunk == null;
183+
allocateRaw(computePadding(position, multiple));
184+
}
185+
223186
public long getRemainingBytesInAlignedChunk() {
224187
return currentAlignedChunk.getUnallocatedBytes();
225188
}
@@ -228,15 +191,6 @@ public long allocateObjectInAlignedChunk(ImageHeapObject obj, boolean writable)
228191
return currentAlignedChunk.allocate(obj, writable);
229192
}
230193

231-
public void alignInAlignedChunk(int multiple) {
232-
if (!currentAlignedChunk.tryAlignTop(multiple)) {
233-
startNewAlignedChunk();
234-
if (!currentAlignedChunk.tryAlignTop(multiple)) {
235-
throw VMError.shouldNotReachHere("Cannot align to " + multiple + " bytes within an aligned chunk's object area");
236-
}
237-
}
238-
}
239-
240194
public void finishAlignedChunk() {
241195
currentAlignedChunk = null;
242196
}
@@ -261,40 +215,3 @@ private static long computePadding(long offset, int alignment) {
261215
return (remainder == 0) ? 0 : (alignment - remainder);
262216
}
263217
}
264-
265-
/**
266-
* A pseudo-partition for filler objects, which does not really exist at runtime, in any statistics,
267-
* or otherwise. Necessary because like all other {@link ImageHeapObject}s, filler objects must be
268-
* assigned to a partition, the start offset of which is used to compute their absolute locations.
269-
* <p>
270-
* For filler objects in the middle of a partition (between genuine objects of that partition), it
271-
* would be acceptable to assign them to their enclosing partition. However, filler objects that are
272-
* inserted between partitions for alignment purposes are problematic because if they were assigned
273-
* to either partition, they would either be out of the partition's boundaries, or they would change
274-
* those boundaries, which would make them useless because that's exactly why they are needed there.
275-
*/
276-
final class FillerObjectDummyPartition implements ImageHeapPartition {
277-
/**
278-
* Zero so that the partition-relative offsets of filler objects are always their absolute
279-
* locations.
280-
*/
281-
@Override
282-
public long getStartOffset() {
283-
return 0;
284-
}
285-
286-
@Override
287-
public String getName() {
288-
throw VMError.shouldNotReachHereAtRuntime(); // ExcludeFromJacocoGeneratedReport
289-
}
290-
291-
@Override
292-
public long getSize() {
293-
throw VMError.shouldNotReachHereAtRuntime(); // ExcludeFromJacocoGeneratedReport
294-
}
295-
296-
@Override
297-
public boolean isFiller() {
298-
return true;
299-
}
300-
}

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

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import org.graalvm.nativeimage.ImageInfo;
3131
import org.graalvm.word.UnsignedWord;
3232

33-
import com.oracle.svm.core.SubstrateOptions;
3433
import com.oracle.svm.core.SubstrateUtil;
3534
import com.oracle.svm.core.config.ConfigurationValues;
3635
import com.oracle.svm.core.genscavenge.ChunkedImageHeapAllocator.AlignedChunk;
@@ -39,8 +38,8 @@
3938
import com.oracle.svm.core.genscavenge.remset.RememberedSet;
4039
import com.oracle.svm.core.hub.DynamicHub;
4140
import com.oracle.svm.core.image.ImageHeap;
42-
import com.oracle.svm.core.image.ImageHeapLayouter;
4341
import com.oracle.svm.core.image.ImageHeapLayoutInfo;
42+
import com.oracle.svm.core.image.ImageHeapLayouter;
4443
import com.oracle.svm.core.image.ImageHeapObject;
4544
import com.oracle.svm.core.option.SubstrateOptionsParser;
4645
import com.oracle.svm.core.util.UserError;
@@ -89,14 +88,13 @@ public class ChunkedImageHeapLayouter implements ImageHeapLayouter {
8988
/** @param startOffset Offset relative to the heap base. */
9089
@SuppressWarnings("this-escape")
9190
public ChunkedImageHeapLayouter(ImageHeapInfo heapInfo, long startOffset) {
92-
int alignment = ConfigurationValues.getObjectLayout().getAlignment();
9391
this.partitions = new ChunkedImageHeapPartition[PARTITION_COUNT];
94-
this.partitions[READ_ONLY_REGULAR] = new ChunkedImageHeapPartition("readOnly", false, false, alignment, alignment);
95-
this.partitions[READ_ONLY_RELOCATABLE] = new ChunkedImageHeapPartition("readOnlyRelocatable", false, false, alignment, alignment);
96-
this.partitions[WRITABLE_PATCHED] = new ChunkedImageHeapPartition("writablePatched", true, false, alignment, alignment);
97-
this.partitions[WRITABLE_REGULAR] = new ChunkedImageHeapPartition("writable", true, false, alignment, alignment);
98-
this.partitions[WRITABLE_HUGE] = new ChunkedImageHeapPartition("writableHuge", true, true, alignment, alignment);
99-
this.partitions[READ_ONLY_HUGE] = new ChunkedImageHeapPartition("readOnlyHuge", false, true, alignment, SubstrateOptions.getPageSize());
92+
this.partitions[READ_ONLY_REGULAR] = new ChunkedImageHeapPartition("readOnly", false, false);
93+
this.partitions[READ_ONLY_RELOCATABLE] = new ChunkedImageHeapPartition("readOnlyRelocatable", false, false);
94+
this.partitions[WRITABLE_PATCHED] = new ChunkedImageHeapPartition("writablePatched", true, false);
95+
this.partitions[WRITABLE_REGULAR] = new ChunkedImageHeapPartition("writable", true, false);
96+
this.partitions[WRITABLE_HUGE] = new ChunkedImageHeapPartition("writableHuge", true, true);
97+
this.partitions[READ_ONLY_HUGE] = new ChunkedImageHeapPartition("readOnlyHuge", false, true);
10098

10199
this.heapInfo = heapInfo;
102100
this.startOffset = startOffset;
@@ -166,16 +164,20 @@ public ImageHeapLayoutInfo layout(ImageHeap imageHeap, int pageSize, ImageHeapLa
166164

167165
ImageHeapLayoutInfo layoutInfo = doLayout(imageHeap, pageSize, control);
168166

167+
/*
168+
* In case there is a need for more alignment between partitions or between objects in a
169+
* chunk, see the version history of this file (and package) for a earlier implementation.
170+
*/
169171
for (ChunkedImageHeapPartition partition : getPartitions()) {
170-
assert partition.getStartOffset() % partition.getStartAlignment() == 0 : partition;
171-
assert (partition.getStartOffset() + partition.getSize()) % partition.getEndAlignment() == 0 : partition;
172+
assert partition.getStartOffset() % objectAlignment == 0 : partition;
173+
assert (partition.getStartOffset() + partition.getSize()) % objectAlignment == 0 : partition;
172174
}
173175
assert layoutInfo.getImageHeapSize() % pageSize == 0 : "Image heap size is not a multiple of page size";
174176
return layoutInfo;
175177
}
176178

177179
private ImageHeapLayoutInfo doLayout(ImageHeap imageHeap, int pageSize, ImageHeapLayouterControl control) {
178-
allocator = new ChunkedImageHeapAllocator(imageHeap, startOffset);
180+
allocator = new ChunkedImageHeapAllocator(startOffset);
179181
for (ChunkedImageHeapPartition partition : getPartitions()) {
180182
control.poll();
181183
partition.layout(allocator, control);
@@ -219,7 +221,9 @@ private ImageHeapLayoutInfo populateInfoObjects(int dynamicHubCount, int pageSiz
219221

220222
long writableEnd = getWritableHuge().getStartOffset() + getWritableHuge().getSize();
221223
long writableSize = writableEnd - offsetOfFirstWritableAlignedChunk;
222-
long imageHeapSize = getReadOnlyHuge().getStartOffset() + getReadOnlyHuge().getSize() - startOffset;
224+
/* Aligning the end to the page size can be required for mapping into memory. */
225+
long imageHeapEnd = NumUtil.roundUp(getReadOnlyHuge().getStartOffset() + getReadOnlyHuge().getSize(), pageSize);
226+
long imageHeapSize = imageHeapEnd - startOffset;
223227
return new ImageHeapLayoutInfo(startOffset, imageHeapSize, offsetOfFirstWritableAlignedChunk, writableSize, getReadOnlyRelocatable().getStartOffset(), getReadOnlyRelocatable().getSize(),
224228
getWritablePatched().getStartOffset(), getWritablePatched().getSize());
225229
}

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

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@ public class ChunkedImageHeapPartition implements ImageHeapPartition {
4646
private final String name;
4747
private final boolean writable;
4848
private final boolean hugeObjects;
49-
private final int startAlignment;
50-
private final int endAlignment;
5149
private final int minimumObjectSize;
5250
private final List<ImageHeapObject> objects = new ArrayList<>();
5351

@@ -57,12 +55,10 @@ public class ChunkedImageHeapPartition implements ImageHeapPartition {
5755
long startOffset = -1;
5856
long endOffset = -1;
5957

60-
ChunkedImageHeapPartition(String name, boolean writable, boolean hugeObjects, int startAlignment, int endAlignment) {
58+
ChunkedImageHeapPartition(String name, boolean writable, boolean hugeObjects) {
6159
this.name = name;
6260
this.writable = writable;
6361
this.hugeObjects = hugeObjects;
64-
this.startAlignment = startAlignment;
65-
this.endAlignment = endAlignment;
6662

6763
/* Cache to prevent frequent lookups of the object layout from ImageSingletons. */
6864
this.minimumObjectSize = ConfigurationValues.getObjectLayout().getMinImageHeapObjectSize();
@@ -82,27 +78,32 @@ void layout(ChunkedImageHeapAllocator allocator, ImageHeapLayouterControl contro
8278
}
8379

8480
private void layoutInUnalignedChunks(ChunkedImageHeapAllocator allocator, ImageHeapLayouterControl control) {
81+
if (objects.isEmpty()) {
82+
/*
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.
86+
*/
87+
startOffset = allocator.getPosition();
88+
endOffset = startOffset;
89+
return;
90+
}
91+
8592
allocator.finishAlignedChunk();
86-
allocator.alignBetweenChunks(getStartAlignment());
8793
startOffset = allocator.getPosition();
8894

8995
for (ImageHeapObject info : objects) { // No need to sort by size
9096
appendAllocatedObject(info, allocator.allocateUnalignedChunkForObject(info, isWritable()));
9197
control.poll();
9298
}
9399

94-
allocator.alignBetweenChunks(getEndAlignment());
95100
endOffset = allocator.getPosition();
96101
}
97102

98103
private void layoutInAlignedChunks(ChunkedImageHeapAllocator allocator, ImageHeapLayouterControl control) {
99104
allocator.maybeStartAlignedChunk();
100-
allocator.alignInAlignedChunk(getStartAlignment());
101105
startOffset = allocator.getPosition();
102-
103106
allocateObjectsInAlignedChunks(allocator, control);
104-
105-
allocator.alignInAlignedChunk(getEndAlignment());
106107
endOffset = allocator.getPosition();
107108
}
108109

@@ -176,14 +177,6 @@ boolean usesUnalignedObjects() {
176177
return hugeObjects;
177178
}
178179

179-
final int getStartAlignment() {
180-
return startAlignment;
181-
}
182-
183-
final int getEndAlignment() {
184-
return endAlignment;
185-
}
186-
187180
@Override
188181
public long getStartOffset() {
189182
assert startOffset >= 0 : "Start offset not yet set";
@@ -200,11 +193,6 @@ public long getSize() {
200193
return getEndOffset() - getStartOffset();
201194
}
202195

203-
@Override
204-
public boolean isFiller() {
205-
return false;
206-
}
207-
208196
@Override
209197
public String toString() {
210198
return name;

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

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -331,15 +331,12 @@ public static boolean isConsumedHeapChunkZapped(UnsignedWord header) {
331331
public long encodeHubPointerForImageHeap(ImageHeapObject obj, long hubOffsetFromHeapBase) {
332332
long header = hubOffsetFromHeapBase << numReservedExtraHubBits;
333333
assert (header & reservedHubBitsMask) == 0 : "Object header bits must be zero initially";
334-
if (obj.getPartition() instanceof ChunkedImageHeapPartition partition) {
335-
if (partition.isWritable() && HeapImpl.usesImageHeapCardMarking()) {
336-
header |= REMSET_OR_MARKED1_BIT.rawValue();
337-
}
338-
if (partition.usesUnalignedObjects()) {
339-
header |= UNALIGNED_BIT.rawValue();
340-
}
341-
} else {
342-
assert obj.getPartition() instanceof FillerObjectDummyPartition;
334+
ChunkedImageHeapPartition partition = (ChunkedImageHeapPartition) obj.getPartition();
335+
if (partition.isWritable() && HeapImpl.usesImageHeapCardMarking()) {
336+
header |= REMSET_OR_MARKED1_BIT.rawValue();
337+
}
338+
if (partition.usesUnalignedObjects()) {
339+
header |= UNALIGNED_BIT.rawValue();
343340
}
344341
if (isIdentityHashFieldOptional()) {
345342
header |= (IDHASH_STATE_IN_FIELD.rawValue() << IDHASH_STATE_SHIFT);

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/image/ImageHeapPartition.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,4 @@ public interface ImageHeapPartition {
3939
* Returns the size of the partition (i.e., the sum of all allocated objects + some overhead).
4040
*/
4141
long getSize();
42-
43-
/* Returns true if this partition is only used as a filler. */
44-
boolean isFiller();
4542
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ public Stream<DebugCodeInfo> codeInfoProvider() {
150150

151151
@Override
152152
public Stream<DebugDataInfo> dataInfoProvider() {
153-
return heap.getObjects().stream().filter(this::acceptObjectInfo).map(this::createDebugDataInfo);
153+
return heap.getObjects().stream().map(this::createDebugDataInfo);
154154
}
155155

156156
private abstract class NativeImageDebugFileInfo implements DebugFileInfo {
@@ -2658,11 +2658,6 @@ public long getSize() {
26582658
}
26592659
}
26602660

2661-
private boolean acceptObjectInfo(ObjectInfo objectInfo) {
2662-
/* This condition rejects filler partition objects. */
2663-
return !objectInfo.getPartition().isFiller();
2664-
}
2665-
26662661
private DebugDataInfo createDebugDataInfo(ObjectInfo objectInfo) {
26672662
return new NativeImageDebugDataInfo(objectInfo);
26682663
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,9 +1148,4 @@ public String getName() {
11481148
public long getSize() {
11491149
throw VMError.shouldNotReachHereAtRuntime(); // ExcludeFromJacocoGeneratedReport
11501150
}
1151-
1152-
@Override
1153-
public boolean isFiller() {
1154-
return false;
1155-
}
11561151
}

web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasmgc/image/WasmGCPartition.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,4 @@ public void add(ImageHeapObject obj) {
100100
objects.add(obj);
101101
obj.setHeapPartition(this);
102102
}
103-
104-
@Override
105-
public boolean isFiller() {
106-
return false;
107-
}
108103
}

0 commit comments

Comments
 (0)