Skip to content

Commit 4ed66aa

Browse files
[GR-60080] Add reference map support for runtime allocated DynamicHubs.
PullRequest: graal/21856
2 parents 072eb60 + f0f3938 commit 4ed66aa

File tree

27 files changed

+482
-106
lines changed

27 files changed

+482
-106
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: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,12 @@
8989
import org.graalvm.nativeimage.ImageSingletons;
9090
import org.graalvm.nativeimage.Platform;
9191
import org.graalvm.nativeimage.Platforms;
92+
import org.graalvm.nativeimage.impl.InternalPlatform.NATIVE_ONLY;
9293

9394
import com.oracle.svm.configure.ClassNameSupport;
9495
import com.oracle.svm.configure.config.SignatureUtil;
96+
import com.oracle.svm.core.AlwaysInline;
97+
import com.oracle.svm.core.BuildPhaseProvider.AfterHeapLayout;
9598
import com.oracle.svm.core.BuildPhaseProvider.AfterHostedUniverse;
9699
import com.oracle.svm.core.BuildPhaseProvider.CompileQueueFinished;
97100
import com.oracle.svm.core.NeverInline;
@@ -114,6 +117,9 @@
114117
import com.oracle.svm.core.config.ObjectLayout;
115118
import com.oracle.svm.core.configure.RuntimeConditionSet;
116119
import com.oracle.svm.core.graal.meta.DynamicHubOffsets;
120+
import com.oracle.svm.core.heap.InstanceReferenceMapDecoder.InstanceReferenceMap;
121+
import com.oracle.svm.core.heap.InstanceReferenceMapEncoder;
122+
import com.oracle.svm.core.heap.ReferenceMapIndex;
117123
import com.oracle.svm.core.heap.UnknownObjectField;
118124
import com.oracle.svm.core.heap.UnknownPrimitiveField;
119125
import com.oracle.svm.core.hub.registry.ClassRegistries;
@@ -356,12 +362,17 @@ public final class DynamicHub implements AnnotatedElement, java.lang.reflect.Typ
356362
@Substitute //
357363
private final DynamicHub componentType;
358364

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

366377
private final byte layerId;
367378

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

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

547557
// GR-57813
548558
companion.hubMetadata = null;
@@ -575,7 +585,7 @@ public static DynamicHub allocate(String name, DynamicHub superHub, Object inter
575585

576586
writeObject(hub, dynamicHubOffsets.getComponentTypeOffset(), componentHub);
577587

578-
writeInt(hub, dynamicHubOffsets.getReferenceMapIndexOffset(), referenceMapIndex);
588+
writeInt(hub, dynamicHubOffsets.getCompressedReferenceMapOffsetOffset(), compressedReferenceMapOffset);
579589
writeByte(hub, dynamicHubOffsets.getLayerIdOffset(), NumUtil.safeToByte(DynamicImageLayerInfo.CREMA_LAYER_ID));
580590

581591
// skip vtable (special treatment)
@@ -643,8 +653,7 @@ public void setClassInitializationInfo(ClassInitializationInfo classInitializati
643653
}
644654

645655
@Platforms(Platform.HOSTED_ONLY.class)
646-
public void setSharedData(int layoutEncoding, int monitorOffset, int identityHashOffset, long referenceMapIndex,
647-
boolean isInstantiated) {
656+
public void setSharedData(int layoutEncoding, int monitorOffset, int identityHashOffset, long referenceMapIndex, boolean isInstantiated) {
648657
VMError.guarantee(monitorOffset == -1 || monitorOffset == (char) monitorOffset, "Class %s has an invalid monitor field offset. Most likely, its objects are larger than supported.", name);
649658
VMError.guarantee(identityHashOffset == -1 || identityHashOffset == (char) identityHashOffset,
650659
"Class %s has an invalid identity hash code field offset. Most likely, its objects are larger than supported.", name);
@@ -653,9 +662,7 @@ public void setSharedData(int layoutEncoding, int monitorOffset, int identityHas
653662
this.monitorOffset = monitorOffset == -1 ? 0 : (char) monitorOffset;
654663
this.identityHashOffset = identityHashOffset == -1 ? 0 : (char) identityHashOffset;
655664

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-
}
665+
VMError.guarantee(NumUtil.isInt(referenceMapIndex), "Reference map index not within integer range");
659666
this.referenceMapIndex = (int) referenceMapIndex;
660667

661668
assert companion.additionalFlags == 0;
@@ -934,9 +941,28 @@ public DynamicHub getArrayHub() {
934941
return companion.arrayHub;
935942
}
936943

944+
@AlwaysInline("GC performance")
937945
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
938-
public int getReferenceMapIndex() {
939-
return referenceMapIndex;
946+
public int getCompressedReferenceMapOffset() {
947+
assert compressedReferenceMapOffset >= 0;
948+
return compressedReferenceMapOffset;
949+
}
950+
951+
/**
952+
* Initializes the {@link #compressedReferenceMapOffset} based on the
953+
* {@link #referenceMapIndex}.
954+
*/
955+
@Platforms(Platform.HOSTED_ONLY.class)
956+
public void initializeCompressedReferenceMapOffset(long currentLayerRefMapDataStart) {
957+
assert compressedReferenceMapOffset == -1;
958+
assert ReferenceMapIndex.denotesValidReferenceMap(referenceMapIndex);
959+
960+
if (Platform.includedIn(NATIVE_ONLY.class)) {
961+
this.compressedReferenceMapOffset = InstanceReferenceMapEncoder.computeCompressedReferenceMapOffset(currentLayerRefMapDataStart, referenceMapIndex);
962+
} else {
963+
/* Remove once a heap base is supported, see GR-68847. */
964+
this.compressedReferenceMapOffset = referenceMapIndex;
965+
}
940966
}
941967

942968
/**

0 commit comments

Comments
 (0)