Skip to content

Commit 41118c9

Browse files
Add reference map support for runtime allocated DynamicHubs.
1 parent 924c962 commit 41118c9

File tree

24 files changed

+450
-89
lines changed

24 files changed

+450
-89
lines changed

sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/ClassLoading.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
package org.graalvm.nativeimage.impl;
4242

4343
import org.graalvm.nativeimage.ImageInfo;
44-
import org.graalvm.nativeimage.ImageSingletons;
4544

4645
/**
4746
* Experimental API used to support runtime class loading in the context of native images.
@@ -57,7 +56,7 @@ public static boolean isSupported() {
5756
if (!ImageInfo.inImageRuntimeCode()) {
5857
return true;
5958
}
60-
return ImageSingletons.lookup(ClassLoadingSupport.class).isSupported();
59+
return ClassLoadingSupport.singleton().isSupported();
6160
}
6261

6362
/**
@@ -80,8 +79,7 @@ public static final class ArbitraryClassLoadingScope implements AutoCloseable {
8079
if (!ImageInfo.inImageRuntimeCode()) {
8180
return;
8281
}
83-
ClassLoadingSupport support = ImageSingletons.lookup(ClassLoadingSupport.class);
84-
support.startIgnoreReflectionConfigurationScope();
82+
ClassLoadingSupport.singleton().startIgnoreReflectionConfigurationScope();
8583
}
8684

8785
@Override
@@ -93,7 +91,7 @@ public void close() {
9391
if (!ImageInfo.inImageRuntimeCode()) {
9492
return;
9593
}
96-
ImageSingletons.lookup(ClassLoadingSupport.class).endIgnoreReflectionConfigurationScope();
94+
ClassLoadingSupport.singleton().endIgnoreReflectionConfigurationScope();
9795
}
9896
}
9997
}

sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/ClassLoadingSupport.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,13 @@
4040
*/
4141
package org.graalvm.nativeimage.impl;
4242

43+
import org.graalvm.nativeimage.ImageSingletons;
44+
4345
public interface ClassLoadingSupport {
46+
static ClassLoadingSupport singleton() {
47+
return ImageSingletons.lookup(ClassLoadingSupport.class);
48+
}
49+
4450
boolean isSupported();
4551

4652
boolean followReflectionConfiguration();

substratevm/mx.substratevm/mx_substratevm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1705,7 +1705,7 @@ def prevent_build_path_in_libgraal():
17051705
use_modules='image',
17061706
jar_distributions=['substratevm:SVM_JDWP_SERVER'],
17071707
build_args=libsvmjdwp_build_args + [
1708-
'--features=com.oracle.svm.jdwp.server.ServerJDWPFeature,com.oracle.svm.hosted.SymbolsFeature',
1708+
'--features=com.oracle.svm.jdwp.server.ServerJDWPFeature,com.oracle.svm.hosted.classloading.SymbolsFeature',
17091709
],
17101710
headers=False,
17111711
)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ private ImageHeapLayoutInfo doLayout(ImageHeap imageHeap, int pageSize, ImageHea
185185
control.poll();
186186
partition.layout(allocator, control);
187187
}
188-
return populateInfoObjects(imageHeap.countAndVerifyDynamicHubs(), pageSize, control);
188+
return populateInfoObjects(imageHeap.countPatchAndVerifyDynamicHubs(), pageSize, control);
189189
}
190190

191191
private ImageHeapLayoutInfo populateInfoObjects(int dynamicHubCount, int pageSize, ImageHeapLayouterControl control) {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/DynamicHubOffsets.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public class DynamicHubOffsets {
8181
private int componentTypeOffset = UNINITIALIZED;
8282

8383
@UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) //
84-
private int referenceMapIndexOffset = UNINITIALIZED;
84+
private int compressedReferenceMapOffsetOffset = UNINITIALIZED;
8585
@UnknownPrimitiveField(availability = BuildPhaseProvider.ReadyForCompilation.class) //
8686
private int layerIdOffset = UNINITIALIZED;
8787

@@ -185,8 +185,8 @@ public int getComponentTypeOffset() {
185185
return componentTypeOffset;
186186
}
187187

188-
public int getReferenceMapIndexOffset() {
189-
return referenceMapIndexOffset;
188+
public int getCompressedReferenceMapOffsetOffset() {
189+
return compressedReferenceMapOffsetOffset;
190190
}
191191

192192
public int getLayerIdOffset() {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/InstanceReferenceMapDecoder.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
package com.oracle.svm.core.heap;
2626

2727
import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE;
28+
import static com.oracle.svm.core.heap.InstanceReferenceMapEncoder.COMPRESSED_REFERENCE_MAP_OFFSET_SHIFT;
2829

2930
import org.graalvm.word.Pointer;
3031
import org.graalvm.word.UnsignedWord;
@@ -36,6 +37,7 @@
3637
import com.oracle.svm.core.c.NonmovableArray;
3738
import com.oracle.svm.core.config.ConfigurationValues;
3839
import com.oracle.svm.core.graal.jdk.SubstrateObjectCloneSnippets;
40+
import com.oracle.svm.core.snippets.KnownIntrinsics;
3941
import com.oracle.svm.core.util.DuplicatedInNativeCode;
4042
import com.oracle.svm.core.util.NonmovableByteArrayReader;
4143

@@ -83,6 +85,13 @@ public static InstanceReferenceMap getReferenceMap(NonmovableArray<Byte> referen
8385
return (InstanceReferenceMap) NonmovableByteArrayReader.pointerTo(referenceMapEncoding, referenceMapIndex);
8486
}
8587

88+
@AlwaysInline("GC performance")
89+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
90+
public static InstanceReferenceMap getReferenceMap(long compressedReferenceMapOffset) {
91+
long uncompressedOffset = (compressedReferenceMapOffset << COMPRESSED_REFERENCE_MAP_OFFSET_SHIFT);
92+
return (InstanceReferenceMap) KnownIntrinsics.heapBase().add(Word.unsigned(uncompressedOffset));
93+
}
94+
8695
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
8796
public static boolean isEmpty(InstanceReferenceMap referenceMap) {
8897
return ((Pointer) referenceMap).readInt(0) == 0;

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/InstanceReferenceMapEncoder.java

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,17 @@
2828
import java.util.Map;
2929
import java.util.Map.Entry;
3030

31+
import org.graalvm.nativeimage.Platform;
32+
import org.graalvm.nativeimage.Platforms;
33+
import org.graalvm.word.Pointer;
34+
3135
import com.oracle.svm.core.config.ConfigurationValues;
36+
import com.oracle.svm.core.heap.InstanceReferenceMapDecoder.InstanceReferenceMap;
37+
import com.oracle.svm.core.snippets.KnownIntrinsics;
38+
import com.oracle.svm.core.util.VMError;
39+
40+
import jdk.graal.compiler.core.common.NumUtil;
41+
import jdk.graal.compiler.core.common.util.UnsafeArrayTypeWriter;
3242

3343
/**
3444
* Encodes the reference map of Java instances. Features such as derived pointers and mixing
@@ -46,9 +56,37 @@
4656
* </ul>
4757
*/
4858
public class InstanceReferenceMapEncoder extends ReferenceMapEncoder {
59+
public static final int COMPRESSED_REFERENCE_MAP_OFFSET_SHIFT = 2;
60+
4961
public static final int MAP_HEADER_SIZE = 4;
5062
public static final int MAP_ENTRY_SIZE = 8;
5163

64+
@Platforms(Platform.HOSTED_ONLY.class)
65+
public static int computeCompressedReferenceMapOffset(long currentLayerRefMapDataStart, int referenceMapIndex) {
66+
long uncompressedOffset = currentLayerRefMapDataStart + referenceMapIndex;
67+
return computeCompressedReferenceMapOffset(uncompressedOffset);
68+
}
69+
70+
public static int computeCompressedReferenceMapOffset(InstanceReferenceMap refMap) {
71+
long uncompressedOffset = ((Pointer) refMap).subtract(KnownIntrinsics.heapBase()).rawValue();
72+
return computeCompressedReferenceMapOffset(uncompressedOffset);
73+
}
74+
75+
/**
76+
* Computes a compressed, heap-base relative offset that points to the start of an
77+
* {@link InstanceReferenceMap}. Due to the compression, all {@link InstanceReferenceMap}s must
78+
* be within the first 16 GB of the address space.
79+
*
80+
* @param uncompressedOffset heap-base relative offset of an {@link InstanceReferenceMap}.
81+
*/
82+
private static int computeCompressedReferenceMapOffset(long uncompressedOffset) {
83+
long compressedOffset = uncompressedOffset >>> COMPRESSED_REFERENCE_MAP_OFFSET_SHIFT;
84+
assert uncompressedOffset == (compressedOffset << COMPRESSED_REFERENCE_MAP_OFFSET_SHIFT) : "wrong alignment";
85+
86+
VMError.guarantee(NumUtil.isUInt(compressedOffset), "Compressed reference map offset is not within unsigned integer range");
87+
return (int) compressedOffset;
88+
}
89+
5290
@Override
5391
protected void encodeAll(List<Entry<Input, Long>> sortedEntries) {
5492
/*
@@ -60,11 +98,11 @@ protected void encodeAll(List<Entry<Input, Long>> sortedEntries) {
6098

6199
for (Map.Entry<ReferenceMapEncoder.Input, Long> entry : sortedEntries) {
62100
ReferenceMapEncoder.Input map = entry.getKey();
63-
encodings.put(map, encode(map.getOffsets()));
101+
encodings.put(map, encode(writeBuffer, map.getOffsets()));
64102
}
65103
}
66104

67-
private long encode(ReferenceMapEncoder.OffsetIterator offsets) {
105+
public static long encode(UnsafeArrayTypeWriter writeBuffer, ReferenceMapEncoder.OffsetIterator offsets) {
68106
long startIndex = writeBuffer.getBytesWritten();
69107
// make room for the number of entries that we need to patch at the end
70108
writeBuffer.putS4(-1);
@@ -88,7 +126,7 @@ private long encode(ReferenceMapEncoder.OffsetIterator offsets) {
88126
assert nextOffset >= nextAdjacentOffset : "values must be strictly increasing";
89127
if (adjacentReferences > 0) {
90128
// The end of a run. Encode the *previous* run.
91-
encodeRun(offset, adjacentReferences);
129+
encodeRun(writeBuffer, offset, adjacentReferences);
92130
entries++;
93131
}
94132
// Beginning of the next gap+run pair.
@@ -100,7 +138,7 @@ private long encode(ReferenceMapEncoder.OffsetIterator offsets) {
100138
} while (offsets.hasNext());
101139

102140
if (adjacentReferences > 0) {
103-
encodeRun(offset, adjacentReferences);
141+
encodeRun(writeBuffer, offset, adjacentReferences);
104142
entries++;
105143
}
106144
}
@@ -109,7 +147,7 @@ private long encode(ReferenceMapEncoder.OffsetIterator offsets) {
109147
return startIndex;
110148
}
111149

112-
private void encodeRun(int offset, int refsCount) {
150+
private static void encodeRun(UnsafeArrayTypeWriter writeBuffer, int offset, int refsCount) {
113151
assert offset >= 0 && refsCount >= 0;
114152
writeBuffer.putS4(offset);
115153
writeBuffer.putS4(refsCount);

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/ClassForNameSupport.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
import com.oracle.svm.core.util.ImageHeapMap;
6464
import com.oracle.svm.core.util.VMError;
6565

66+
import jdk.graal.compiler.api.replacements.Fold;
6667
import jdk.graal.compiler.options.Option;
6768

6869
@AutomaticallyRegisteredImageSingleton
@@ -169,6 +170,7 @@ public ClassForNameSupport(Map<String, Boolean> previousLayerClasses, Set<String
169170
this.previousLayerUnsafe = previousLayerUnsafe;
170171
}
171172

173+
@Fold
172174
public static boolean respectClassLoader() {
173175
return Options.ClassForNameRespectsClassLoader.getValue();
174176
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@
9292

9393
import com.oracle.svm.configure.ClassNameSupport;
9494
import com.oracle.svm.configure.config.SignatureUtil;
95+
import com.oracle.svm.core.AlwaysInline;
96+
import com.oracle.svm.core.BuildPhaseProvider.AfterHeapLayout;
9597
import com.oracle.svm.core.BuildPhaseProvider.AfterHostedUniverse;
9698
import com.oracle.svm.core.BuildPhaseProvider.CompileQueueFinished;
9799
import com.oracle.svm.core.NeverInline;
@@ -114,6 +116,9 @@
114116
import com.oracle.svm.core.config.ObjectLayout;
115117
import com.oracle.svm.core.configure.RuntimeConditionSet;
116118
import com.oracle.svm.core.graal.meta.DynamicHubOffsets;
119+
import com.oracle.svm.core.heap.InstanceReferenceMapDecoder.InstanceReferenceMap;
120+
import com.oracle.svm.core.heap.InstanceReferenceMapEncoder;
121+
import com.oracle.svm.core.heap.ReferenceMapIndex;
117122
import com.oracle.svm.core.heap.UnknownObjectField;
118123
import com.oracle.svm.core.heap.UnknownPrimitiveField;
119124
import com.oracle.svm.core.hub.registry.ClassRegistries;
@@ -356,12 +361,17 @@ public final class DynamicHub implements AnnotatedElement, java.lang.reflect.Typ
356361
@Substitute //
357362
private final DynamicHub componentType;
358363

364+
/** Index into the current layer's instance reference map {@code byte[]}. */
365+
@Platforms(Platform.HOSTED_ONLY.class) //
366+
private int referenceMapIndex;
367+
359368
/**
360-
* Reference map information for this hub. The byte[] array encoding data is available via
361-
* {@link DynamicHubSupport#getReferenceMapEncoding()}.
369+
* A compressed offset, relative to the heap base, that points to the
370+
* {@link InstanceReferenceMap} for this hub (see
371+
* {@link DynamicHubSupport#getInstanceReferenceMap}).
362372
*/
363-
@UnknownPrimitiveField(availability = AfterHostedUniverse.class)//
364-
private int referenceMapIndex;
373+
@UnknownPrimitiveField(availability = AfterHeapLayout.class)//
374+
private int compressedReferenceMapOffset = -1;
365375

366376
private final byte layerId;
367377

@@ -541,8 +551,7 @@ public static DynamicHub allocate(String name, DynamicHub superHub, Object inter
541551
// GR-61330: only write if the field exists according to analysis
542552
// companion.metaType = null;
543553

544-
// GR-60080: Proper referenceMap needed.
545-
int referenceMapIndex = DynamicHub.fromClass(Object.class).referenceMapIndex;
554+
int compressedReferenceMapOffset = RuntimeInstanceReferenceMapSupport.singleton().getOrCreateReferenceMap(superHub);
546555

547556
// GR-57813
548557
companion.hubMetadata = null;
@@ -575,7 +584,7 @@ public static DynamicHub allocate(String name, DynamicHub superHub, Object inter
575584

576585
writeObject(hub, dynamicHubOffsets.getComponentTypeOffset(), componentHub);
577586

578-
writeInt(hub, dynamicHubOffsets.getReferenceMapIndexOffset(), referenceMapIndex);
587+
writeInt(hub, dynamicHubOffsets.getCompressedReferenceMapOffsetOffset(), compressedReferenceMapOffset);
579588
writeByte(hub, dynamicHubOffsets.getLayerIdOffset(), NumUtil.safeToByte(DynamicImageLayerInfo.CREMA_LAYER_ID));
580589

581590
// skip vtable (special treatment)
@@ -643,8 +652,7 @@ public void setClassInitializationInfo(ClassInitializationInfo classInitializati
643652
}
644653

645654
@Platforms(Platform.HOSTED_ONLY.class)
646-
public void setSharedData(int layoutEncoding, int monitorOffset, int identityHashOffset, long referenceMapIndex,
647-
boolean isInstantiated) {
655+
public void setSharedData(int layoutEncoding, int monitorOffset, int identityHashOffset, long referenceMapIndex, boolean isInstantiated) {
648656
VMError.guarantee(monitorOffset == -1 || monitorOffset == (char) monitorOffset, "Class %s has an invalid monitor field offset. Most likely, its objects are larger than supported.", name);
649657
VMError.guarantee(identityHashOffset == -1 || identityHashOffset == (char) identityHashOffset,
650658
"Class %s has an invalid identity hash code field offset. Most likely, its objects are larger than supported.", name);
@@ -653,9 +661,7 @@ public void setSharedData(int layoutEncoding, int monitorOffset, int identityHas
653661
this.monitorOffset = monitorOffset == -1 ? 0 : (char) monitorOffset;
654662
this.identityHashOffset = identityHashOffset == -1 ? 0 : (char) identityHashOffset;
655663

656-
if ((int) referenceMapIndex != referenceMapIndex) {
657-
throw VMError.shouldNotReachHere("Reference map index not within integer range, need to switch field from int to long");
658-
}
664+
VMError.guarantee(NumUtil.isInt(referenceMapIndex), "Reference map index not within integer range");
659665
this.referenceMapIndex = (int) referenceMapIndex;
660666

661667
assert companion.additionalFlags == 0;
@@ -934,9 +940,23 @@ public DynamicHub getArrayHub() {
934940
return companion.arrayHub;
935941
}
936942

943+
@AlwaysInline("GC performance")
937944
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
938-
public int getReferenceMapIndex() {
939-
return referenceMapIndex;
945+
public int getCompressedReferenceMapOffset() {
946+
assert compressedReferenceMapOffset >= 0;
947+
return compressedReferenceMapOffset;
948+
}
949+
950+
/**
951+
* Initializes the {@link #compressedReferenceMapOffset} based on the
952+
* {@link #referenceMapIndex}.
953+
*/
954+
@Platforms(Platform.HOSTED_ONLY.class)
955+
public void initializeCompressedReferenceMapOffset(long currentLayerRefMapDataStart) {
956+
assert compressedReferenceMapOffset == -1;
957+
assert ReferenceMapIndex.denotesValidReferenceMap(referenceMapIndex);
958+
959+
this.compressedReferenceMapOffset = InstanceReferenceMapEncoder.computeCompressedReferenceMapOffset(currentLayerRefMapDataStart, referenceMapIndex);
940960
}
941961

942962
/**

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHubSupport.java

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,15 @@
3636
import com.oracle.svm.core.Uninterruptible;
3737
import com.oracle.svm.core.c.NonmovableArray;
3838
import com.oracle.svm.core.c.NonmovableArrays;
39-
import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton;
4039
import com.oracle.svm.core.heap.InstanceReferenceMapDecoder;
4140
import com.oracle.svm.core.heap.InstanceReferenceMapDecoder.InstanceReferenceMap;
4241
import com.oracle.svm.core.heap.UnknownObjectField;
4342
import com.oracle.svm.core.heap.UnknownPrimitiveField;
44-
import com.oracle.svm.core.imagelayer.DynamicImageLayerInfo;
4543
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags;
4644
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonSupport;
4745
import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton;
4846
import com.oracle.svm.core.layeredimagesingleton.UnsavedSingleton;
4947

50-
@AutomaticallyRegisteredImageSingleton
5148
public final class DynamicHubSupport implements MultiLayeredImageSingleton, UnsavedSingleton {
5249

5350
@UnknownPrimitiveField(availability = AfterHostedUniverse.class) private int maxTypeId;
@@ -58,22 +55,10 @@ public static DynamicHubSupport currentLayer() {
5855
return LayeredImageSingletonSupport.singleton().lookup(DynamicHubSupport.class, false, true);
5956
}
6057

61-
@AlwaysInline("Performance")
62-
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
63-
public static DynamicHubSupport forLayer(int layerId) {
64-
return MultiLayeredImageSingleton.getForLayer(DynamicHubSupport.class, layerId);
65-
}
66-
58+
@AlwaysInline("GC performance")
6759
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
6860
public static InstanceReferenceMap getInstanceReferenceMap(DynamicHub hub) {
69-
int layerId = hub.getLayerId();
70-
if (RuntimeClassLoading.isSupported() && layerId == DynamicImageLayerInfo.CREMA_LAYER_ID) {
71-
/* Assume that the reference map is in the base layer until GR-60080 is implemented. */
72-
layerId = 0;
73-
}
74-
75-
NonmovableArray<Byte> referenceMapEncoding = forLayer(layerId).getReferenceMapEncoding();
76-
return InstanceReferenceMapDecoder.getReferenceMap(referenceMapEncoding, hub.getReferenceMapIndex());
61+
return InstanceReferenceMapDecoder.getReferenceMap(hub.getCompressedReferenceMapOffset());
7762
}
7863

7964
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
@@ -101,9 +86,9 @@ public void setReferenceMapEncoding(NonmovableArray<Byte> referenceMapEncoding)
10186
this.referenceMapEncoding = NonmovableArrays.getHostedArray(referenceMapEncoding);
10287
}
10388

104-
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
105-
public NonmovableArray<Byte> getReferenceMapEncoding() {
106-
return NonmovableArrays.fromImageHeap(referenceMapEncoding);
89+
@Platforms(Platform.HOSTED_ONLY.class)
90+
public byte[] getReferenceMapEncoding() {
91+
return referenceMapEncoding;
10792
}
10893

10994
@Override

0 commit comments

Comments
 (0)