Skip to content

Commit 760ffd5

Browse files
committed
Remove excess allocations from chunked layouting
1 parent 272457e commit 760ffd5

File tree

5 files changed

+44
-58
lines changed

5 files changed

+44
-58
lines changed

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

Lines changed: 18 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,14 @@
2626

2727
import java.util.ArrayDeque;
2828
import java.util.ArrayList;
29-
import java.util.Arrays;
30-
import java.util.Comparator;
3129
import java.util.List;
32-
import java.util.Map;
3330
import java.util.NavigableMap;
3431
import java.util.Queue;
3532
import java.util.TreeMap;
3633

3734
import com.oracle.svm.core.config.ConfigurationValues;
3835
import com.oracle.svm.core.image.ImageHeapObject;
3936
import com.oracle.svm.core.image.ImageHeapPartition;
40-
import com.oracle.svm.core.meta.SubstrateObjectConstant;
4137

4238
import jdk.graal.compiler.debug.Assertions;
4339

@@ -124,63 +120,44 @@ private ImageHeapObject dequeueBestFit(NavigableMap<Long, Queue<ImageHeapObject>
124120
if (nbytes < minimumObjectSize) {
125121
return null;
126122
}
127-
Map.Entry<Long, Queue<ImageHeapObject>> entry = sortedObjects.floorEntry(nbytes);
128-
if (entry == null) {
123+
124+
/**
125+
* Find a floor entry. We are purposefully not calling {@link TreeMap#getFloorEntry(Object)}
126+
* as that method allocates a new entry object. Instead, we fetch the floor key and get the
127+
* value for the returned key.
128+
*/
129+
Long floorKey = sortedObjects.floorKey(nbytes);
130+
if (floorKey == null) {
129131
return null;
130132
}
131-
Queue<ImageHeapObject> queue = entry.getValue();
132-
ImageHeapObject info = queue.remove();
133+
Queue<ImageHeapObject> queue = sortedObjects.get(floorKey);
134+
ImageHeapObject obj = queue.remove();
133135
if (queue.isEmpty()) {
134-
sortedObjects.remove(entry.getKey());
136+
sortedObjects.remove(floorKey);
135137
}
136-
return info;
138+
return obj;
137139
}
138140

139141
private NavigableMap<Long, Queue<ImageHeapObject>> createSortedObjectsMap() {
140-
ImageHeapObject[] sorted = objects.toArray(new ImageHeapObject[0]);
141-
Arrays.sort(sorted, new SizeComparator());
142-
143142
NavigableMap<Long, Queue<ImageHeapObject>> map = new TreeMap<>();
144-
Queue<ImageHeapObject> currentQueue = null;
145-
long currentObjectsSize = -1;
146-
for (ImageHeapObject obj : sorted) {
143+
for (ImageHeapObject obj : objects) {
147144
long objSize = obj.getSize();
148-
if (objSize != currentObjectsSize) {
149-
assert objSize > currentObjectsSize && objSize >= ConfigurationValues.getObjectLayout().getMinImageHeapObjectSize() : Assertions.errorMessage(obj, objSize);
150-
currentObjectsSize = objSize;
151-
currentQueue = new ArrayDeque<>();
152-
map.put(currentObjectsSize, currentQueue);
153-
}
154-
assert currentQueue != null;
155-
currentQueue.add(obj);
145+
assert objSize >= ConfigurationValues.getObjectLayout().getMinImageHeapObjectSize() : Assertions.errorMessage(obj, objSize);
146+
Queue<ImageHeapObject> q = map.computeIfAbsent(objSize, k -> new ArrayDeque<>());
147+
q.add(obj);
156148
}
157149
return map;
158150
}
159151

160152
private void appendAllocatedObject(ImageHeapObject info, long allocationOffset) {
161153
if (firstObject == null) {
162-
firstObject = extractObject(info);
154+
firstObject = info.getWrapped();
163155
}
164156
assert info.getPartition() == this;
165157
long offsetInPartition = allocationOffset - startOffset;
166158
assert ConfigurationValues.getObjectLayout().isAligned(offsetInPartition) : "start: " + offsetInPartition + " must be aligned.";
167159
info.setOffsetInPartition(offsetInPartition);
168-
lastObject = extractObject(info);
169-
}
170-
171-
private static Object extractObject(ImageHeapObject info) {
172-
if (info.getConstant() instanceof SubstrateObjectConstant) {
173-
return info.getObject();
174-
} else {
175-
/*
176-
* The info wraps an ImageHeapObject, i.e., a build time representation of an object
177-
* that is not backed by a raw hosted object. We set the partition limit to the actual
178-
* constant. The constant reflection provider knows that this is a build time value, and
179-
* it will not wrap it in a JavaConstant when reading it. This case is not different
180-
* from normal objects referencing simulated objects.
181-
*/
182-
return info.getConstant();
183-
}
160+
lastObject = info.getWrapped();
184161
}
185162

186163
@Override
@@ -229,11 +206,4 @@ public boolean isFiller() {
229206
public String toString() {
230207
return name;
231208
}
232-
233-
private static final class SizeComparator implements Comparator<ImageHeapObject> {
234-
@Override
235-
public int compare(ImageHeapObject o1, ImageHeapObject o2) {
236-
return Long.signum(o1.getSize() - o2.getSize());
237-
}
238-
}
239209
}

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,8 @@
2424
*/
2525
package com.oracle.svm.core.image;
2626

27-
import java.util.Collection;
28-
2927
public interface ImageHeap {
30-
Collection<? extends ImageHeapObject> getObjects();
28+
Iterable<? extends ImageHeapObject> getObjects();
3129

3230
ImageHeapObject addLateToImageHeap(Object object, Object reason);
3331

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,15 @@
2424
*/
2525
package com.oracle.svm.core.image;
2626

27-
import jdk.vm.ci.meta.JavaConstant;
28-
2927
public interface ImageHeapObject {
3028
long getSize();
3129

30+
Object getWrapped();
31+
3232
Object getObject();
3333

3434
Class<?> getObjectClass();
3535

36-
JavaConstant getConstant();
37-
3836
void setHeapPartition(ImageHeapPartition value);
3937

4038
void setOffsetInPartition(long value);

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

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
import com.oracle.svm.core.util.UserError;
7777
import com.oracle.svm.core.util.VMError;
7878
import com.oracle.svm.hosted.HostedConfiguration;
79+
import com.oracle.svm.hosted.ameta.SVMHostedValueProvider;
7980
import com.oracle.svm.hosted.config.DynamicHubLayout;
8081
import com.oracle.svm.hosted.config.HybridLayout;
8182
import com.oracle.svm.hosted.imagelayer.HostedImageLayerBuildingSupport;
@@ -874,7 +875,6 @@ public Class<?> getObjectClass() {
874875
return clazz.getJavaClass();
875876
}
876877

877-
@Override
878878
public ImageHeapConstant getConstant() {
879879
return constant;
880880
}
@@ -912,6 +912,25 @@ public long getSize() {
912912
return size;
913913
}
914914

915+
/**
916+
* The image builder references heap objects via {@link ImageHeapConstant}, i.e., a build
917+
* time representation of an object that permits hosted constants which may or may not be
918+
* backed by a raw hosted object. For example the class initializer simulation will produce
919+
* simulated objects, not present in the underlying VM. The {@link ImageHeapConstant} can be
920+
* referenced directly from raw objects and the constant reflection provider knows that this
921+
* is a build time value, and it will not wrap it again in a {@link JavaConstant} when
922+
* reading it (see {@link SVMHostedValueProvider#interceptHosted(JavaConstant)}). This is
923+
* useful for example when encoding the heap partitions limits: we simply use the constant
924+
* representation regardless of whether the constant is backed by an object of the host VM
925+
* or not. This case is not different from normal objects referencing simulated objects. The
926+
* {@link NativeImageHeapWriter} will recursively unwrap the {@link ImageHeapConstant} all
927+
* the way to primitive values, so there's no risk of it leaking into the runtime.
928+
*/
929+
@Override
930+
public Object getWrapped() {
931+
return getConstant();
932+
}
933+
915934
public int getIdentityHashCode() {
916935
return identityHashCode;
917936
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
package com.oracle.svm.hosted.webimage.wasmgc.image;
2727

2828
import java.nio.ByteBuffer;
29+
import java.util.stream.StreamSupport;
2930

3031
import com.oracle.graal.pointsto.heap.ImageHeapPrimitiveArray;
3132
import com.oracle.svm.core.image.ImageHeap;
@@ -64,7 +65,7 @@ public ImageHeapPartition[] getPartitions() {
6465

6566
@Override
6667
public void assignObjectToPartition(ImageHeapObject info, boolean immutable, boolean references, boolean relocatable, boolean patched) {
67-
if (info.getConstant() instanceof ImageHeapPrimitiveArray) {
68+
if (info.getWrapped() instanceof ImageHeapPrimitiveArray) {
6869
singlePartition.add(info);
6970
} else {
7071
pseudoPartition.add(info);
@@ -76,7 +77,7 @@ public WasmGCImageHeapLayoutInfo layout(ImageHeap imageHeap, int pageSize) {
7677
layoutPseudoPartition();
7778
doLayout();
7879

79-
long totalSize = imageHeap.getObjects().stream().mapToLong(ImageHeapObject::getSize).sum();
80+
long totalSize = StreamSupport.stream(imageHeap.getObjects().spliterator(), false).mapToLong(ImageHeapObject::getSize).sum();
8081
long serializedSize = singlePartition.getStartOffset() + singlePartition.getSize() - startOffset;
8182
return new WasmGCImageHeapLayoutInfo(startOffset, serializedSize, totalSize);
8283
}

0 commit comments

Comments
 (0)