From c8981cddd34397664245ac3a86e0395997913254 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Wed, 5 Mar 2025 14:44:44 +0100 Subject: [PATCH 1/3] Refactor identity hashcode access. --- .../genscavenge/CompactingOldGeneration.java | 6 +- .../genscavenge/GreyToBlackObjRefVisitor.java | 3 +- .../svm/core/genscavenge/HeapVerifier.java | 7 +- .../core/genscavenge/ObjectHeaderImpl.java | 36 +++- .../ReferenceObjectProcessing.java | 8 +- .../RuntimeCodeCacheReachabilityAnalyzer.java | 3 +- .../oracle/svm/core/genscavenge/Space.java | 4 +- .../svm/core/genscavenge/YoungGeneration.java | 4 +- .../compacting/PlanningVisitor.java | 5 +- .../genscavenge/graal/BarrierSnippets.java | 7 +- .../remset/CardTableBasedRememberedSet.java | 4 +- .../oracle/svm/core/config/ObjectLayout.java | 49 ++++- .../jdk/SubstrateObjectCloneSnippets.java | 2 +- .../meta/SubstrateBasicLoweringProvider.java | 67 ++++-- .../oracle/svm/core/heap/ObjectHeader.java | 48 +---- .../com/oracle/svm/core/hub/DynamicHub.java | 5 +- .../oracle/svm/core/hub/LayoutEncoding.java | 2 +- .../IdentityHashCodeSupport.java | 192 ++++++++++++++++-- .../SubstrateIdentityHashCodeSnippets.java | 5 +- .../svm/hosted/HostedConfiguration.java | 11 +- .../image/NativeImageDebugInfoProvider.java | 9 +- .../svm/hosted/image/NativeImageHeap.java | 5 +- .../hosted/image/NativeImageHeapWriter.java | 29 ++- .../svm/hosted/meta/HostedInstanceClass.java | 11 +- .../truffle/api/SubstrateTruffleRuntime.java | 2 +- 25 files changed, 377 insertions(+), 147 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/CompactingOldGeneration.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/CompactingOldGeneration.java index d925a91b27df..8fe97748cd6e 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/CompactingOldGeneration.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/CompactingOldGeneration.java @@ -48,6 +48,7 @@ import com.oracle.svm.core.genscavenge.remset.BrickTable; import com.oracle.svm.core.genscavenge.remset.RememberedSet; import com.oracle.svm.core.graal.RuntimeCompilation; +import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.ObjectHeader; import com.oracle.svm.core.heap.ObjectVisitor; import com.oracle.svm.core.log.Log; @@ -179,7 +180,8 @@ public Object promoteAlignedObject(Object original, AlignedHeapChunk.AlignedHead return space.copyAlignedObject(original, originalSpace); } assert originalSpace == space; - Word header = ObjectHeader.readHeaderFromObject(original); + ObjectHeader oh = Heap.getHeap().getObjectHeader(); + Word header = oh.readHeaderFromObject(original); if (ObjectHeaderImpl.isMarkedHeader(header)) { return original; } @@ -193,7 +195,7 @@ public Object promoteAlignedObject(Object original, AlignedHeapChunk.AlignedHead * object's size. The easiest way to handle this is to copy the object. */ result = space.copyAlignedObject(original, originalSpace); - assert !ObjectHeaderImpl.hasIdentityHashFromAddressInline(ObjectHeader.readHeaderFromObject(result)); + assert !ObjectHeaderImpl.hasIdentityHashFromAddressInline(oh.readHeaderFromObject(result)); } ObjectHeaderImpl.setMarked(result); markStack.push(result); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GreyToBlackObjRefVisitor.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GreyToBlackObjRefVisitor.java index 3b9de4873812..4ea88ba6194a 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GreyToBlackObjRefVisitor.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GreyToBlackObjRefVisitor.java @@ -31,7 +31,6 @@ import com.oracle.svm.core.AlwaysInline; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.genscavenge.remset.RememberedSet; -import com.oracle.svm.core.heap.ObjectHeader; import com.oracle.svm.core.heap.ObjectReferenceVisitor; import com.oracle.svm.core.heap.ReferenceAccess; import com.oracle.svm.core.hub.LayoutEncoding; @@ -91,7 +90,7 @@ public boolean visitObjectReferenceInline(Pointer objRef, int innerOffset, boole // This is the most expensive check as it accesses the heap fairly randomly, which results // in a lot of cache misses. ObjectHeaderImpl ohi = ObjectHeaderImpl.getObjectHeaderImpl(); - Word header = ObjectHeader.readHeaderFromPointer(p); + Word header = ohi.readHeaderFromPointer(p); if (GCImpl.getGCImpl().isCompleteCollection() || !RememberedSet.get().hasRememberedSet(header)) { if (ObjectHeaderImpl.isForwardedHeader(header)) { diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java index 0d1e7cbae8c9..ac96a9616a33 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapVerifier.java @@ -35,6 +35,7 @@ import com.oracle.svm.core.genscavenge.AlignedHeapChunk.AlignedHeader; import com.oracle.svm.core.genscavenge.UnalignedHeapChunk.UnalignedHeader; import com.oracle.svm.core.genscavenge.remset.RememberedSet; +import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.ObjectHeader; import com.oracle.svm.core.heap.ObjectReferenceVisitor; import com.oracle.svm.core.heap.ObjectVisitor; @@ -241,7 +242,8 @@ private static boolean verifyObject(Object obj, AlignedHeader aChunk, UnalignedH return false; } - Word header = ObjectHeader.readHeaderFromPointer(ptr); + ObjectHeader oh = Heap.getHeap().getObjectHeader(); + Word header = oh.readHeaderFromPointer(ptr); if (ObjectHeaderImpl.isProducedHeapChunkZapped(header) || ObjectHeaderImpl.isConsumedHeapChunkZapped(header)) { Log.log().string("Object ").zhex(ptr).string(" has a zapped header: ").zhex(header).newline(); return false; @@ -352,7 +354,8 @@ private static boolean verifyReference(Object parentObject, Pointer reference, P return false; } - Word header = ObjectHeader.readHeaderFromPointer(referencedObject); + ObjectHeader oh = Heap.getHeap().getObjectHeader(); + Word header = oh.readHeaderFromPointer(referencedObject); if (!ObjectHeaderImpl.getObjectHeaderImpl().isEncodedObjectHeader(header)) { Log.log().string("Object reference at ").zhex(reference).string(" does not point to a Java object or the object header of the Java object is invalid: ").zhex(referencedObject) .string(". "); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ObjectHeaderImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ObjectHeaderImpl.java index 62107ccdd20b..b0098eab13c7 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ObjectHeaderImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ObjectHeaderImpl.java @@ -156,6 +156,24 @@ protected void initializeObjectHeader(Pointer objectPointer, Word encodedHub, bo } } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + @Override + public Word readHeaderFromPointer(Pointer objectPointer) { + if (getReferenceSize() == Integer.BYTES) { + return Word.unsigned(objectPointer.readInt(getHubOffset())); + } + return objectPointer.readWord(getHubOffset()); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + @Override + public Word readHeaderFromObject(Object o) { + if (getReferenceSize() == Integer.BYTES) { + return Word.unsigned(ObjectAccess.readInt(o, getHubOffset())); + } + return ObjectAccess.readWord(o, getHubOffset()); + } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @Override public boolean hasOptionalIdentityHashField(Word header) { @@ -337,7 +355,8 @@ public static boolean isAlignedHeader(UnsignedWord header) { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static boolean isUnalignedObject(Object obj) { - UnsignedWord header = readHeaderFromObject(obj); + ObjectHeader oh = Heap.getHeap().getObjectHeader(); + UnsignedWord header = oh.readHeaderFromObject(obj); return isUnalignedHeader(header); } @@ -348,7 +367,8 @@ public static boolean isUnalignedHeader(UnsignedWord header) { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static void setRememberedSetBit(Object o) { - UnsignedWord oldHeader = readHeaderFromObject(o); + ObjectHeader oh = Heap.getHeap().getObjectHeader(); + UnsignedWord oldHeader = oh.readHeaderFromObject(o); assert oldHeader.and(FORWARDED_OR_MARKED2_BIT).equal(0); UnsignedWord newHeader = oldHeader.or(REMSET_OR_MARKED1_BIT); writeHeaderToObject(o, newHeader); @@ -364,7 +384,8 @@ public static void setMarked(Object o) { if (!SerialGCOptions.useCompactingOldGen()) { // not guarantee(): always folds, prevent call throw VMError.shouldNotReachHere("Only for compacting GC."); } - UnsignedWord header = readHeaderFromObject(o); + ObjectHeader oh = Heap.getHeap().getObjectHeader(); + UnsignedWord header = oh.readHeaderFromObject(o); assert header.and(FORWARDED_OR_MARKED2_BIT).equal(0) : "forwarded or already marked"; /* * The remembered bit is already set if the object was in the old generation before, or @@ -375,14 +396,16 @@ public static void setMarked(Object o) { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static void unsetMarkedAndKeepRememberedSetBit(Object o) { - UnsignedWord header = readHeaderFromObject(o); + ObjectHeader oh = Heap.getHeap().getObjectHeader(); + UnsignedWord header = oh.readHeaderFromObject(o); assert isMarkedHeader(header); writeHeaderToObject(o, header.and(FORWARDED_OR_MARKED2_BIT.not())); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static boolean isMarked(Object o) { - return isMarkedHeader(readHeaderFromObject(o)); + ObjectHeader oh = Heap.getHeap().getObjectHeader(); + return isMarkedHeader(oh.readHeaderFromObject(o)); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @@ -395,7 +418,8 @@ public static boolean isMarkedHeader(UnsignedWord header) { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) static boolean isPointerToForwardedObject(Pointer p) { - Word header = readHeaderFromPointer(p); + ObjectHeader oh = Heap.getHeap().getObjectHeader(); + Word header = oh.readHeaderFromPointer(p); return isForwardedHeader(header); } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ReferenceObjectProcessing.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ReferenceObjectProcessing.java index bb103917e1e8..9d61e0684eda 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ReferenceObjectProcessing.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ReferenceObjectProcessing.java @@ -31,7 +31,6 @@ import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; -import jdk.graal.compiler.word.Word; import org.graalvm.word.Pointer; import org.graalvm.word.UnsignedWord; @@ -47,6 +46,8 @@ import com.oracle.svm.core.thread.VMOperation; import com.oracle.svm.core.util.UnsignedUtils; +import jdk.graal.compiler.word.Word; + /** Discovers and handles {@link Reference} objects during garbage collection. */ final class ReferenceObjectProcessing { /** Head of the linked list of discovered references that need to be revisited. */ @@ -230,7 +231,7 @@ private static boolean processRememberedRef(Reference dr) { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) private static boolean maybeUpdateForwardedReference(Reference dr, Pointer referentAddr) { ObjectHeaderImpl ohi = ObjectHeaderImpl.getObjectHeaderImpl(); - UnsignedWord header = ObjectHeader.readHeaderFromPointer(referentAddr); + UnsignedWord header = ohi.readHeaderFromPointer(referentAddr); if (ObjectHeaderImpl.isForwardedHeader(header)) { Object forwardedObj = ohi.getForwardedObject(referentAddr); ReferenceInternals.setReferent(dr, forwardedObj); @@ -261,7 +262,8 @@ static void updateForwardedRefs() { Pointer refPointer = ReferenceInternals.getReferentPointer(current); if (!maybeUpdateForwardedReference(current, refPointer)) { - UnsignedWord header = ObjectHeader.readHeaderFromPointer(refPointer); + ObjectHeader oh = Heap.getHeap().getObjectHeader(); + UnsignedWord header = oh.readHeaderFromPointer(refPointer); if (!ObjectHeaderImpl.isMarkedHeader(header)) { ReferenceInternals.setReferent(current, null); } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/RuntimeCodeCacheReachabilityAnalyzer.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/RuntimeCodeCacheReachabilityAnalyzer.java index 60680663bbcf..59c853d01f63 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/RuntimeCodeCacheReachabilityAnalyzer.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/RuntimeCodeCacheReachabilityAnalyzer.java @@ -28,7 +28,6 @@ import org.graalvm.nativeimage.Platforms; import org.graalvm.word.Pointer; -import com.oracle.svm.core.heap.ObjectHeader; import com.oracle.svm.core.heap.ObjectReferenceVisitor; import com.oracle.svm.core.heap.ReferenceAccess; import com.oracle.svm.core.heap.RuntimeCodeCacheCleaner; @@ -71,7 +70,7 @@ public static boolean isReachable(Pointer ptrToObj) { } ObjectHeaderImpl ohi = ObjectHeaderImpl.getObjectHeaderImpl(); - Word header = ObjectHeader.readHeaderFromPointer(ptrToObj); + Word header = ohi.readHeaderFromPointer(ptrToObj); if (ObjectHeaderImpl.isForwardedHeader(header)) { return true; } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/Space.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/Space.java index 679701947b59..f5a09898fa25 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/Space.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/Space.java @@ -40,6 +40,7 @@ import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.genscavenge.GCImpl.ChunkReleaser; import com.oracle.svm.core.genscavenge.remset.RememberedSet; +import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.ObjectHeader; import com.oracle.svm.core.heap.ObjectVisitor; import com.oracle.svm.core.hub.LayoutEncoding; @@ -416,7 +417,8 @@ private Object copyAlignedObject(Object originalObj) { UnsignedWord copySize = originalSize; boolean addIdentityHashField = false; if (ConfigurationValues.getObjectLayout().isIdentityHashFieldOptional()) { - Word header = ObjectHeader.readHeaderFromObject(originalObj); + ObjectHeader oh = Heap.getHeap().getObjectHeader(); + Word header = oh.readHeaderFromObject(originalObj); if (probability(SLOW_PATH_PROBABILITY, ObjectHeaderImpl.hasIdentityHashFromAddressInline(header))) { addIdentityHashField = true; copySize = LayoutEncoding.getSizeFromObjectInlineInGC(originalObj, true); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/YoungGeneration.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/YoungGeneration.java index 7115e06f2ca7..36f73fb7774d 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/YoungGeneration.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/YoungGeneration.java @@ -33,6 +33,7 @@ import com.oracle.svm.core.AlwaysInline; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.genscavenge.GCImpl.ChunkReleaser; +import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.ObjectHeader; import com.oracle.svm.core.heap.ObjectVisitor; import com.oracle.svm.core.log.Log; @@ -262,7 +263,8 @@ public boolean contains(Object object) { return HeapChunk.getSpace(HeapChunk.getEnclosingHeapChunk(object)).isYoungSpace(); } // Only objects in the young generation have no remembered set - UnsignedWord header = ObjectHeader.readHeaderFromObject(object); + ObjectHeader oh = Heap.getHeap().getObjectHeader(); + UnsignedWord header = oh.readHeaderFromObject(object); boolean young = !ObjectHeaderImpl.hasRememberedSet(header); assert young == HeapChunk.getSpace(HeapChunk.getEnclosingHeapChunk(object)).isYoungSpace(); return young; diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/compacting/PlanningVisitor.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/compacting/PlanningVisitor.java index 5d3c0ff28f8b..500559b54547 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/compacting/PlanningVisitor.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/compacting/PlanningVisitor.java @@ -35,6 +35,8 @@ import com.oracle.svm.core.genscavenge.ObjectHeaderImpl; import com.oracle.svm.core.genscavenge.Space; import com.oracle.svm.core.genscavenge.remset.BrickTable; +import com.oracle.svm.core.heap.Heap; +import com.oracle.svm.core.heap.ObjectHeader; import com.oracle.svm.core.hub.LayoutEncoding; import jdk.graal.compiler.word.Word; @@ -77,7 +79,8 @@ public boolean visitChunk(AlignedHeapChunk.AlignedHeader chunk) { Pointer p = objSeq; while (p.belowThan(initialTop)) { - Word header = ObjectHeaderImpl.readHeaderFromPointer(p); + ObjectHeader oh = Heap.getHeap().getObjectHeader(); + Word header = oh.readHeaderFromPointer(p); UnsignedWord objSize; if (ObjectHeaderImpl.isForwardedHeader(header)) { diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/BarrierSnippets.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/BarrierSnippets.java index 081da1cb7a80..bdb9b0b047e3 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/BarrierSnippets.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/BarrierSnippets.java @@ -38,6 +38,7 @@ import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider; import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; import com.oracle.svm.core.graal.snippets.SubstrateTemplates; +import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.ObjectHeader; import com.oracle.svm.core.heap.StoredContinuation; import com.oracle.svm.core.snippets.SnippetRuntime; @@ -98,7 +99,8 @@ public static void registerForeignCalls(SubstrateForeignCallsProvider provider) @SubstrateForeignCallTarget(stubCallingConvention = false, fullyUninterruptible = true) @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static void postWriteBarrierStub(Object object) { - UnsignedWord objectHeader = ObjectHeader.readHeaderFromObject(object); + ObjectHeader oh = Heap.getHeap().getObjectHeader(); + UnsignedWord objectHeader = oh.readHeaderFromObject(object); if (ObjectHeaderImpl.isUnalignedHeader(objectHeader)) { RememberedSet.get().dirtyCardForUnalignedObject(object, false); } else { @@ -112,7 +114,8 @@ public static void postWriteBarrierStub(Object object) { @Snippet public static void postWriteBarrierSnippet(Object object, @ConstantParameter boolean shouldOutline, @ConstantParameter boolean alwaysAlignedChunk, @ConstantParameter boolean verifyOnly) { Object fixedObject = FixedValueAnchorNode.getObject(object); - UnsignedWord objectHeader = ObjectHeader.readHeaderFromObject(fixedObject); + ObjectHeader oh = Heap.getHeap().getObjectHeader(); + UnsignedWord objectHeader = oh.readHeaderFromObject(fixedObject); if (SerialGCOptions.VerifyWriteBarriers.getValue() && alwaysAlignedChunk) { /* diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/CardTableBasedRememberedSet.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/CardTableBasedRememberedSet.java index 0de6eef284fe..e29df2228c55 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/CardTableBasedRememberedSet.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/CardTableBasedRememberedSet.java @@ -43,6 +43,7 @@ import com.oracle.svm.core.genscavenge.UnalignedHeapChunk.UnalignedHeader; import com.oracle.svm.core.genscavenge.graal.ForcedSerialPostWriteBarrier; import com.oracle.svm.core.genscavenge.graal.SubstrateCardTableBarrierSet; +import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.ObjectHeader; import com.oracle.svm.core.heap.PodReferenceMapDecoder; import com.oracle.svm.core.heap.UninterruptibleObjectVisitor; @@ -172,7 +173,8 @@ public void dirtyCardIfNecessary(Object holderObject, Object object) { return; } - UnsignedWord objectHeader = ObjectHeader.readHeaderFromObject(holderObject); + ObjectHeader oh = Heap.getHeap().getObjectHeader(); + UnsignedWord objectHeader = oh.readHeaderFromObject(holderObject); if (hasRememberedSet(objectHeader)) { if (ObjectHeaderImpl.isAlignedObject(holderObject)) { AlignedChunkRememberedSet.dirtyCardForObject(holderObject, false); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/config/ObjectLayout.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/config/ObjectLayout.java index 326e5c5381cf..e3c1b99ad306 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/config/ObjectLayout.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/config/ObjectLayout.java @@ -68,7 +68,7 @@ * object needs the field, the object is resized during garbage collection to accommodate the * field. * - * + * * See this classes instantiation sites (such as {@code HostedConfiguration#createObjectLayout}) for * more details on the exact object layout for a given configuration. */ @@ -78,32 +78,41 @@ public final class ObjectLayout { private final int referenceSize; private final int objectAlignment; private final int alignmentMask; + private final int hubSize; private final int hubOffset; private final int firstFieldOffset; private final int arrayLengthOffset; private final int arrayBaseOffset; private final int objectHeaderIdentityHashOffset; private final int identityHashMode; + private final int identityHashNumBits; + private final int identityHashShift; - public ObjectLayout(SubstrateTargetDescription target, int referenceSize, int objectAlignment, int hubOffset, int firstFieldOffset, int arrayLengthOffset, int arrayBaseOffset, - int headerIdentityHashOffset, IdentityHashMode identityHashMode) { + public ObjectLayout(SubstrateTargetDescription target, int referenceSize, int objectAlignment, int hubSize, int hubOffset, int firstFieldOffset, int arrayLengthOffset, int arrayBaseOffset, + int headerIdentityHashOffset, IdentityHashMode identityHashMode, int identityHashNumBits, int identityHashShift) { assert CodeUtil.isPowerOf2(referenceSize) : referenceSize; assert CodeUtil.isPowerOf2(objectAlignment) : objectAlignment; assert arrayLengthOffset % Integer.BYTES == 0; assert hubOffset < firstFieldOffset && hubOffset < arrayLengthOffset : hubOffset; - assert (identityHashMode != IdentityHashMode.OPTIONAL && headerIdentityHashOffset > 0 && headerIdentityHashOffset < arrayLengthOffset && headerIdentityHashOffset % Integer.BYTES == 0) || + assert hubSize == Integer.BYTES || hubSize == Long.BYTES; + assert (identityHashMode != IdentityHashMode.OPTIONAL && headerIdentityHashOffset >= 0 && headerIdentityHashOffset < arrayLengthOffset && headerIdentityHashOffset % Integer.BYTES == 0) || (identityHashMode == IdentityHashMode.OPTIONAL && headerIdentityHashOffset == -1); + assert identityHashNumBits > 0 && identityHashNumBits <= Integer.SIZE; + assert identityHashShift >= 0 && identityHashShift < Long.SIZE; this.target = target; this.referenceSize = referenceSize; this.objectAlignment = objectAlignment; this.alignmentMask = objectAlignment - 1; + this.hubSize = hubSize; this.hubOffset = hubOffset; this.firstFieldOffset = firstFieldOffset; this.arrayLengthOffset = arrayLengthOffset; this.arrayBaseOffset = arrayBaseOffset; this.objectHeaderIdentityHashOffset = headerIdentityHashOffset; this.identityHashMode = identityHashMode.value; + this.identityHashNumBits = identityHashNumBits; + this.identityHashShift = identityHashShift; if (ImageLayerBuildingSupport.buildingImageLayer()) { int[] currentValues = { @@ -111,12 +120,15 @@ public ObjectLayout(SubstrateTargetDescription target, int referenceSize, int ob this.referenceSize, this.objectAlignment, this.alignmentMask, + this.hubSize, this.hubOffset, this.firstFieldOffset, this.arrayLengthOffset, this.arrayBaseOffset, this.objectHeaderIdentityHashOffset, this.identityHashMode, + this.identityHashNumBits, + this.identityHashShift, }; var numFields = Arrays.stream(ObjectLayout.class.getDeclaredFields()).filter(Predicate.not(Field::isSynthetic)).count(); VMError.guarantee(numFields - 1 == currentValues.length, "Missing fields"); @@ -182,16 +194,15 @@ public int getHubOffset() { return hubOffset; } + public int getHubSize() { + return hubSize; + } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public int getFirstFieldOffset() { return firstFieldOffset; } - /* - * A sequence of fooOffset() and fooNextOffset() methods that give the layout of array fields: - * length, [hashcode], element .... - */ - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public int getArrayLengthOffset() { return arrayLengthOffset; @@ -219,13 +230,29 @@ public boolean isIdentityHashFieldOptional() { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public int getObjectHeaderIdentityHashOffset() { if (GraalDirectives.inIntrinsic()) { - ReplacementsUtil.dynamicAssert(objectHeaderIdentityHashOffset > 0, "must check before calling"); + ReplacementsUtil.dynamicAssert(objectHeaderIdentityHashOffset >= 0, "must check before calling"); } else { - assert objectHeaderIdentityHashOffset > 0 : "must check before calling"; + assert objectHeaderIdentityHashOffset >= 0 : "must check before calling"; } return objectHeaderIdentityHashOffset; } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public int getIdentityHashCodeNumBits() { + return identityHashNumBits; + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public int getIdentityHashCodeShift() { + return identityHashShift; + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public long getIdentityHashCodeMask() { + long mask = (1L << identityHashNumBits) - 1L; + return mask << identityHashShift; + } + public int getArrayBaseOffset(JavaKind kind) { return NumUtil.roundUp(arrayBaseOffset, sizeInBytes(kind)); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/jdk/SubstrateObjectCloneSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/jdk/SubstrateObjectCloneSnippets.java index bccc8c8efecb..41fa4efb8ec5 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/jdk/SubstrateObjectCloneSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/jdk/SubstrateObjectCloneSnippets.java @@ -182,7 +182,7 @@ private static Object doClone(Object original) throws CloneNotSupportedException BarrieredAccess.writeObject(result, monitorOffset, null); } - /* Reset identity hashcode if it is potentially outside the object header. */ + /* Reset identity hashcode if it is outside the object header. */ if (ConfigurationValues.getObjectLayout().isIdentityHashFieldAtTypeSpecificOffset()) { int offset = LayoutEncoding.getIdentityHashOffset(result); ObjectAccess.writeInt(result, offset, 0); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java index 2b90c7c45471..c2dc32657b08 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java @@ -24,6 +24,7 @@ */ package com.oracle.svm.core.graal.meta; +import java.nio.ByteOrder; import java.util.HashMap; import java.util.Map; @@ -43,6 +44,7 @@ import com.oracle.svm.core.graal.nodes.SubstrateNarrowOopStamp; import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; import com.oracle.svm.core.heap.Heap; +import com.oracle.svm.core.heap.ObjectHeader; import com.oracle.svm.core.heap.ReferenceAccess; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.identityhashcode.IdentityHashCodeSupport; @@ -55,6 +57,7 @@ import jdk.graal.compiler.core.common.spi.ForeignCallsProvider; import jdk.graal.compiler.core.common.spi.MetaAccessExtensionProvider; import jdk.graal.compiler.core.common.type.AbstractObjectStamp; +import jdk.graal.compiler.core.common.type.IntegerStamp; import jdk.graal.compiler.core.common.type.ObjectStamp; import jdk.graal.compiler.core.common.type.Stamp; import jdk.graal.compiler.core.common.type.StampFactory; @@ -74,7 +77,9 @@ import jdk.graal.compiler.nodes.calc.AddNode; import jdk.graal.compiler.nodes.calc.AndNode; import jdk.graal.compiler.nodes.calc.LeftShiftNode; +import jdk.graal.compiler.nodes.calc.NarrowNode; import jdk.graal.compiler.nodes.calc.UnsignedRightShiftNode; +import jdk.graal.compiler.nodes.calc.ZeroExtendNode; import jdk.graal.compiler.nodes.extended.LoadHubNode; import jdk.graal.compiler.nodes.extended.LoadMethodNode; import jdk.graal.compiler.nodes.memory.FloatingReadNode; @@ -248,33 +253,59 @@ protected ValueNode createReadHub(StructuredGraph graph, ValueNode object, Lower GraalError.guarantee(!object.isConstant() || object.asJavaConstant().isNull(), "Object should either not be a constant or the null constant %s", object); - ObjectLayout objectLayout = getObjectLayout(); - Stamp headerBitsStamp = StampFactory.forUnsignedInteger(8 * objectLayout.getReferenceSize()); - ConstantNode headerOffset = ConstantNode.forIntegerKind(target.wordJavaKind, objectLayout.getHubOffset(), graph); - AddressNode headerAddress = graph.unique(new OffsetAddressNode(object, headerOffset)); - ValueNode headerBits = graph.unique(new FloatingReadNode(headerAddress, NamedLocationIdentity.FINAL_LOCATION, null, headerBitsStamp, null, BarrierType.NONE)); - ValueNode hubBits; - int reservedBitsMask = Heap.getHeap().getObjectHeader().getReservedBitsMask(); - if (reservedBitsMask != 0) { - // get rid of the reserved header bits and extract the actual pointer to the hub - assert CodeUtil.isPowerOf2(reservedBitsMask + 1) : "only the lowest bits may be set"; - int numReservedBits = CodeUtil.log2(reservedBitsMask + 1); + ObjectLayout ol = getObjectLayout(); + ObjectHeader oh = Heap.getHeap().getObjectHeader(); + int referenceSize = ol.getReferenceSize(); + + int hubOffset = ol.getHubOffset(); + int bytesToRead = ol.getHubSize(); + long reservedHeaderBitsMask = oh.getReservedBitsMask(); + if (hubOffset > 0 && hubOffset + ol.getHubSize() <= Long.BYTES && target.arch.getByteOrder() == ByteOrder.LITTLE_ENDIAN) { + /* Prepare to emit a 64-bit read at offset 0 (reduces the code size). */ + hubOffset = 0; + bytesToRead = Long.BYTES; + reservedHeaderBitsMask = (reservedHeaderBitsMask << Integer.SIZE) | ((1L << Integer.SIZE) - 1); + } + + /* Read the raw hub data from the correct part of the object header. */ + IntegerStamp readStamp = StampFactory.forUnsignedInteger(bytesToRead * Byte.SIZE); + ConstantNode hubOffsetNode = ConstantNode.forIntegerKind(target.wordJavaKind, hubOffset, graph); + AddressNode hubAddressNode = graph.unique(new OffsetAddressNode(object, hubOffsetNode)); + ValueNode rawHubData = graph.unique(new FloatingReadNode(hubAddressNode, NamedLocationIdentity.FINAL_LOCATION, null, readStamp, null, BarrierType.NONE)); + + if (reservedHeaderBitsMask != 0L) { + /* Get rid of the reserved header bits and extract the actual hub bits. */ + assert CodeUtil.isPowerOf2(reservedHeaderBitsMask + 1) : "only the lowest bits may be set"; + int numReservedBits = CodeUtil.log2(reservedHeaderBitsMask + 1); int compressionShift = ReferenceAccess.singleton().getCompressionShift(); - int numAlignmentBits = CodeUtil.log2(objectLayout.getAlignment()); + int numAlignmentBits = CodeUtil.log2(ol.getAlignment()); assert compressionShift <= numAlignmentBits : "compression discards bits"; + if (numReservedBits == numAlignmentBits && compressionShift == 0) { - hubBits = graph.unique(new AndNode(headerBits, ConstantNode.forIntegerStamp(headerBitsStamp, ~reservedBitsMask, graph))); + /* AND with a constant is slightly smaller than 2 shifts. */ + rawHubData = graph.unique(new AndNode(rawHubData, ConstantNode.forIntegerStamp(readStamp, ~reservedHeaderBitsMask, graph))); } else { - hubBits = graph.unique(new UnsignedRightShiftNode(headerBits, ConstantNode.forInt(numReservedBits, graph))); + rawHubData = graph.unique(new UnsignedRightShiftNode(rawHubData, ConstantNode.forInt(numReservedBits, graph))); if (compressionShift != numAlignmentBits) { int shift = numAlignmentBits - compressionShift; - hubBits = graph.unique(new LeftShiftNode(hubBits, ConstantNode.forInt(shift, graph))); + rawHubData = graph.unique(new LeftShiftNode(rawHubData, ConstantNode.forInt(shift, graph))); } } - } else { - hubBits = headerBits; + + if (bytesToRead > referenceSize) { + /* + * More bytes than necessary were read earlier. Now that we are done with extracting + * the hub bits, we can discard the most-significant bits (must all be 0). + */ + rawHubData = graph.unique(new NarrowNode(rawHubData, referenceSize * Byte.SIZE)); + } + } else if (bytesToRead < referenceSize) { + /* Zero extend the hub bits to the full reference size if needed. */ + rawHubData = graph.unique(new ZeroExtendNode(rawHubData, referenceSize * Byte.SIZE)); } - FloatingWordCastNode hubRef = graph.unique(new FloatingWordCastNode(hubStamp, hubBits)); + + /* Uncompress the hub pointer bits to a DynamicHub object. */ + FloatingWordCastNode hubRef = graph.unique(new FloatingWordCastNode(hubStamp, rawHubData)); return maybeUncompress(hubRef); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ObjectHeader.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ObjectHeader.java index 563df4597918..6c0e6f8db238 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ObjectHeader.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ObjectHeader.java @@ -38,7 +38,6 @@ import jdk.graal.compiler.api.replacements.Fold; import jdk.graal.compiler.nodes.NamedLocationIdentity; -import jdk.graal.compiler.word.ObjectAccess; import jdk.graal.compiler.word.Word; import jdk.graal.compiler.word.WordOperationPlugin; @@ -82,22 +81,10 @@ public static DynamicHub readDynamicHubFromObject(Object o) { } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public static Word readHeaderFromPointer(Pointer objectPointer) { - if (getReferenceSize() == Integer.BYTES) { - return Word.unsigned(objectPointer.readInt(getHubOffset())); - } else { - return objectPointer.readWord(getHubOffset()); - } - } + public abstract Word readHeaderFromPointer(Pointer objectPointer); @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public static Word readHeaderFromObject(Object o) { - if (getReferenceSize() == Integer.BYTES) { - return Word.unsigned(ObjectAccess.readInt(o, getHubOffset())); - } else { - return ObjectAccess.readWord(o, getHubOffset()); - } - } + public abstract Word readHeaderFromObject(Object o); @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public DynamicHub readDynamicHubFromPointer(Pointer ptr) { @@ -124,15 +111,6 @@ public final void initializeHeaderOfNewObjectInit(Pointer ptr, Word header, bool initializeObjectHeader(ptr, header, isArrayLike, InitLocationMemWriter.INSTANCE); } - /** - * Initializes the header of a newly allocated object located anywhere in memory (i.e. writing - * to {@link LocationIdentity#ANY_LOCATION}) - */ - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public final void initializeHeaderOfNewObjectAny(Pointer ptr, Word header, boolean isArrayLike) { - initializeObjectHeader(ptr, header, isArrayLike, AnyLocationMemWriter.INSTANCE); - } - /** * Initializes the header of a newly allocated object located off the heap (i.e. writing to * {@link NamedLocationIdentity#OFF_HEAP_LOCATION}) @@ -207,28 +185,6 @@ protected interface MemWriter { void writeLong(Pointer ptr, int offset, long val); } - private static final class AnyLocationMemWriter implements MemWriter { - private static final AnyLocationMemWriter INSTANCE = new AnyLocationMemWriter(); - - @Override - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public void writeWord(Pointer ptr, int offset, Word word) { - ptr.writeWord(offset, word, LocationIdentity.ANY_LOCATION); - } - - @Override - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public void writeInt(Pointer ptr, int offset, int val) { - ptr.writeInt(offset, val, LocationIdentity.ANY_LOCATION); - } - - @Override - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public void writeLong(Pointer ptr, int offset, long val) { - ptr.writeLong(offset, val, LocationIdentity.ANY_LOCATION); - } - } - private static final class OffHeapLocationMemWriter implements MemWriter { private static final OffHeapLocationMemWriter INSTANCE = new OffHeapLocationMemWriter(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java index 5cbe762dc94a..8729b22ae035 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java @@ -573,11 +573,12 @@ public void setClassInitializationInfo(ClassInitializationInfo classInitializati public void setSharedData(int layoutEncoding, int monitorOffset, int identityHashOffset, long referenceMapIndex, boolean isInstantiated) { VMError.guarantee(monitorOffset == (char) monitorOffset, "Class %s has an invalid monitor field offset. Most likely, its objects are larger than supported.", name); - VMError.guarantee(identityHashOffset == (char) identityHashOffset, "Class %s has an invalid identity hash code field offset. Most likely, its objects are larger than supported.", name); + VMError.guarantee(identityHashOffset == -1 || identityHashOffset == (char) identityHashOffset, + "Class %s has an invalid identity hash code field offset. Most likely, its objects are larger than supported.", name); this.layoutEncoding = layoutEncoding; this.monitorOffset = (char) monitorOffset; - this.identityHashOffset = (char) identityHashOffset; + this.identityHashOffset = identityHashOffset == -1 ? 0 : (char) identityHashOffset; if ((int) referenceMapIndex != referenceMapIndex) { throw VMError.shouldNotReachHere("Reference map index not within integer range, need to switch field from int to long"); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/LayoutEncoding.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/LayoutEncoding.java index a39a8b09a2f7..8e310acac334 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/LayoutEncoding.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/LayoutEncoding.java @@ -375,7 +375,7 @@ private static UnsignedWord getSizeFromObjectInline(Object obj, boolean withOpti @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) private static boolean hasOptionalIdentityHashField(Object obj) { ObjectHeader oh = Heap.getHeap().getObjectHeader(); - Word header = ObjectHeader.readHeaderFromPointer(Word.objectToUntrackedPointer(obj)); + Word header = oh.readHeaderFromPointer(Word.objectToUntrackedPointer(obj)); return oh.hasOptionalIdentityHashField(header); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/identityhashcode/IdentityHashCodeSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/identityhashcode/IdentityHashCodeSupport.java index 10bfbc1f320d..84dcb48c55d9 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/identityhashcode/IdentityHashCodeSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/identityhashcode/IdentityHashCodeSupport.java @@ -24,9 +24,15 @@ */ package com.oracle.svm.core.identityhashcode; +import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE; + +import java.nio.ByteBuffer; import java.util.SplittableRandom; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; import org.graalvm.word.LocationIdentity; +import org.graalvm.word.Pointer; import org.graalvm.word.SignedWord; import com.oracle.svm.core.Uninterruptible; @@ -38,12 +44,13 @@ import com.oracle.svm.core.snippets.SubstrateForeignCallTarget; import com.oracle.svm.core.threadlocal.FastThreadLocalFactory; import com.oracle.svm.core.threadlocal.FastThreadLocalObject; -import com.oracle.svm.core.util.VMError; +import jdk.graal.compiler.api.directives.GraalDirectives; import jdk.graal.compiler.nodes.NamedLocationIdentity; import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.phases.util.Providers; import jdk.graal.compiler.replacements.IdentityHashCodeSnippets; +import jdk.graal.compiler.replacements.ReplacementsUtil; import jdk.graal.compiler.word.ObjectAccess; import jdk.graal.compiler.word.Word; import jdk.internal.misc.Unsafe; @@ -72,23 +79,11 @@ public static IdentityHashCodeSnippets.Templates createSnippetTemplates(OptionVa return SubstrateIdentityHashCodeSnippets.createTemplates(options, providers); } - @SubstrateForeignCallTarget(stubCallingConvention = false) - public static int generateIdentityHashCode(Object obj) { - ObjectLayout ol = ConfigurationValues.getObjectLayout(); - VMError.guarantee(!ol.isIdentityHashFieldOptional(), "Optional hash is handled in snippet"); - - int newHashCode = generateRandomHashCode(); - int offset = LayoutEncoding.getIdentityHashOffset(obj); - if (!Unsafe.getUnsafe().compareAndSetInt(obj, offset, 0, newHashCode)) { - newHashCode = ObjectAccess.readInt(obj, offset, IDENTITY_HASHCODE_LOCATION); - } - VMError.guarantee(newHashCode != 0, "Missing identity hash code"); - return newHashCode; - } - @SubstrateForeignCallTarget(stubCallingConvention = false) @Uninterruptible(reason = "Prevent a GC interfering with the object's identity hash state.") public static int computeAbsentIdentityHashCode(Object obj) { + assert ConfigurationValues.getObjectLayout().isIdentityHashFieldOptional(); + /* * This code must not be inlined into the snippet because it could be used in an * interruptible method: the individual reads and writes of the object header and hash salt @@ -99,14 +94,13 @@ public static int computeAbsentIdentityHashCode(Object obj) { */ ObjectHeader oh = Heap.getHeap().getObjectHeader(); Word objPtr = Word.objectToUntrackedPointer(obj); - Word header = ObjectHeader.readHeaderFromPointer(objPtr); + Word header = oh.readHeaderFromPointer(objPtr); if (oh.hasOptionalIdentityHashField(header)) { /* * Between the snippet and execution of this method, another thread could have set the * header bit and a GC could have triggered and added the field. */ - int offset = LayoutEncoding.getIdentityHashOffset(obj); - return ObjectAccess.readInt(obj, offset, IdentityHashCodeSupport.IDENTITY_HASHCODE_LOCATION); + return readIdentityHashCodeFromField(obj); } if (!oh.hasIdentityHashFromAddress(header)) { oh.setIdentityHashFromAddress(objPtr, header); @@ -153,4 +147,166 @@ public static int generateRandomHashCode() { return hashCode; } + + /** + * Reads the identity hashcode from the identity hashcode field. Returns zero if the object + * doesn't have an identity hashcode yet. Note that this method must not be called for objects + * that do not have an identity hashcode field (e.g., objects where the identity hashcode is + * computed from the address). + */ + @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) + public static int readIdentityHashCodeFromField(Object obj) { + assertHasIdentityHashField(obj); + + ObjectLayout ol = ConfigurationValues.getObjectLayout(); + int numBits = ol.getIdentityHashCodeNumBits(); + int shift = ol.getIdentityHashCodeShift(); + int offset = LayoutEncoding.getIdentityHashOffset(obj); + + int totalBits = numBits + shift; + if (totalBits <= Integer.SIZE) { + int value = ObjectAccess.readInt(obj, offset, IdentityHashCodeSupport.IDENTITY_HASHCODE_LOCATION); + return extractIdentityHashCode(value, numBits, shift); + } + + long value = ObjectAccess.readLong(obj, offset, IdentityHashCodeSupport.IDENTITY_HASHCODE_LOCATION); + return extractIdentityHashCode(value, numBits, shift); + } + + @SubstrateForeignCallTarget(stubCallingConvention = false) + public static int generateIdentityHashCode(Object obj) { + ObjectLayout ol = ConfigurationValues.getObjectLayout(); + assert !ol.isIdentityHashFieldOptional(); + + int numBits = ol.getIdentityHashCodeNumBits(); + int shift = ol.getIdentityHashCodeShift(); + int offset = LayoutEncoding.getIdentityHashOffset(obj); + + int newHash = generateRandomHashCode(); + int totalBits = numBits + shift; + if (numBits == Integer.SIZE && shift == 0) { + /* There is a dedicated int field for the identity hashcode. */ + if (!Unsafe.getUnsafe().compareAndSetInt(obj, offset, 0, newHash)) { + return ObjectAccess.readInt(obj, offset, IDENTITY_HASHCODE_LOCATION); + } + } else if (totalBits <= Integer.SIZE) { + int existingValue; + int newValue; + do { + existingValue = Unsafe.getUnsafe().getIntVolatile(obj, offset); + int existingHash = extractIdentityHashCode(existingValue, numBits, shift); + if (existingHash != 0) { + return existingHash; + } + newValue = encodeIdentityHashCode(existingValue, newHash, shift); + } while (!Unsafe.getUnsafe().compareAndSetInt(obj, offset, existingValue, newValue)); + } else { + assert totalBits <= Long.SIZE; + long existingValue; + long newValue; + do { + existingValue = Unsafe.getUnsafe().getLongVolatile(obj, offset); + int existingHash = extractIdentityHashCode(existingValue, numBits, shift); + if (existingHash != 0) { + return existingHash; + } + newValue = encodeIdentityHashCode(existingValue, newHash, shift); + } while (!Unsafe.getUnsafe().compareAndSetLong(obj, offset, existingValue, newValue)); + } + + assert readIdentityHashCodeFromField(obj) == newHash; + return newHash; + } + + /** This method may only be called after the hub pointer was already written. */ + public static void writeIdentityHashCodeToAuxImage(Pointer hashCodePtr, int value) { + ObjectLayout ol = ConfigurationValues.getObjectLayout(); + int numBits = ol.getIdentityHashCodeNumBits(); + int shift = ol.getIdentityHashCodeShift(); + long mask = ol.getIdentityHashCodeMask(); + + int totalBits = numBits + shift; + if (totalBits <= Integer.SIZE) { + int oldValue = hashCodePtr.readInt(0); + assertIdentityHashCodeZero(oldValue, mask); + hashCodePtr.writeInt(0, encodeIdentityHashCode(oldValue, value, shift)); + } else { + assert totalBits <= Long.SIZE; + long oldValue = hashCodePtr.readLong(0); + assertIdentityHashCodeZero(oldValue, mask); + hashCodePtr.writeLong(0, encodeIdentityHashCode(oldValue, value, shift)); + } + } + + /** This method may only be called after the object header was already written. */ + @Platforms(Platform.HOSTED_ONLY.class) + public static void writeIdentityHashCodeToImageHeap(ByteBuffer buffer, int hashCodePos, int value) { + ObjectLayout ol = ConfigurationValues.getObjectLayout(); + int numBits = ol.getIdentityHashCodeNumBits(); + int shift = ol.getIdentityHashCodeShift(); + long mask = ol.getIdentityHashCodeMask(); + + int totalBits = numBits + shift; + if (totalBits <= Integer.SIZE) { + int oldValue = buffer.getInt(hashCodePos); + assertIdentityHashCodeZero(oldValue, mask); + buffer.putInt(hashCodePos, encodeIdentityHashCode(oldValue, value, shift)); + } else { + assert totalBits <= Long.SIZE; + long oldValue = buffer.getLong(hashCodePos); + assertIdentityHashCodeZero(oldValue, mask); + buffer.putLong(hashCodePos, encodeIdentityHashCode(oldValue, value, shift)); + } + } + + @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) + private static int extractIdentityHashCode(int value, int numBits, int shift) { + int left = Integer.SIZE - numBits - shift; + int right = Integer.SIZE - numBits; + return (value << left) >>> right; + } + + @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) + private static int extractIdentityHashCode(long value, int numBits, int shift) { + int left = Long.SIZE - numBits - shift; + int right = Long.SIZE - numBits; + return (int) ((value << left) >>> right); + } + + private static int encodeIdentityHashCode(int existingValue, int newHash, int shift) { + return existingValue | (newHash << shift); + } + + private static long encodeIdentityHashCode(long existingValue, long newHash, int shift) { + return existingValue | (newHash << shift); + } + + private static void assertIdentityHashCodeZero(int oldValue, long mask) { + assert (oldValue & mask) == 0 : "hashcode bits must be 0"; + } + + private static void assertIdentityHashCodeZero(long oldValue, long mask) { + assert (oldValue & mask) == 0L : "hashcode bits must be 0"; + } + + @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) + private static void assertHasIdentityHashField(Object obj) { + if (GraalDirectives.inIntrinsic()) { + ReplacementsUtil.dynamicAssert(hasIdentityHashField(obj), "must have an identity hashcode field"); + } else { + assert hasIdentityHashField(obj) : "must have an identity hashcode field"; + } + } + + /** + * Note that the result of this method is prone to race conditions. All races that can happen + * don't matter for the current caller though (we only want to identify objects that definitely + * don't have an identity hash code field). + */ + @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) + private static boolean hasIdentityHashField(Object obj) { + ObjectLayout ol = ConfigurationValues.getObjectLayout(); + ObjectHeader oh = Heap.getHeap().getObjectHeader(); + return !ol.isIdentityHashFieldOptional() || oh.hasOptionalIdentityHashField(oh.readHeaderFromObject(obj)); + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/identityhashcode/SubstrateIdentityHashCodeSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/identityhashcode/SubstrateIdentityHashCodeSnippets.java index 30bfe2a88180..27d5d9801807 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/identityhashcode/SubstrateIdentityHashCodeSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/identityhashcode/SubstrateIdentityHashCodeSnippets.java @@ -65,7 +65,7 @@ protected int computeIdentityHashCode(Object obj) { if (ol.isIdentityHashFieldOptional()) { int identityHashCode; ObjectHeader oh = Heap.getHeap().getObjectHeader(); - Word header = ObjectHeader.readHeaderFromObject(obj); + Word header = oh.readHeaderFromObject(obj); if (probability(LIKELY_PROBABILITY, oh.hasOptionalIdentityHashField(header))) { int offset = LayoutEncoding.getIdentityHashOffset(obj); identityHashCode = ObjectAccess.readInt(obj, offset, IdentityHashCodeSupport.IDENTITY_HASHCODE_LOCATION); @@ -75,8 +75,7 @@ protected int computeIdentityHashCode(Object obj) { return identityHashCode; } - int offset = LayoutEncoding.getIdentityHashOffset(obj); - int identityHashCode = ObjectAccess.readInt(obj, offset, IdentityHashCodeSupport.IDENTITY_HASHCODE_LOCATION); + int identityHashCode = IdentityHashCodeSupport.readIdentityHashCodeFromField(obj); if (probability(SLOW_PATH_PROBABILITY, identityHashCode == 0)) { identityHashCode = foreignCall(GENERATE_IDENTITY_HASH_CODE, obj); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java index 20c86542b765..d375f4dd4139 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java @@ -148,8 +148,10 @@ public static ObjectLayout createObjectLayout(JavaKind referenceKind, IdentityHa int intSize = target.arch.getPlatformKind(JavaKind.Int).getSizeInBytes(); int objectAlignment = 8; + int hubSize = referenceSize; + int hubOffset = 0; - int headerSize = hubOffset + referenceSize; + int headerSize = hubOffset + hubSize; int extraArrayHeaderSize = 0; int headerIdentityHashOffset = headerSize; @@ -168,7 +170,12 @@ public static ObjectLayout createObjectLayout(JavaKind referenceKind, IdentityHa int arrayLengthOffset = headerSize + extraArrayHeaderSize; int arrayBaseOffset = arrayLengthOffset + intSize; - return new ObjectLayout(target, referenceSize, objectAlignment, hubOffset, firstFieldOffset, arrayLengthOffset, arrayBaseOffset, headerIdentityHashOffset, identityHashMode); + /* There is a dedicated 32-bit field that stores the 31-bit identity hashcode. */ + int identityHashNumBits = Integer.SIZE; + int identityHashShift = 0; + + return new ObjectLayout(target, referenceSize, objectAlignment, hubSize, hubOffset, firstFieldOffset, arrayLengthOffset, arrayBaseOffset, + headerIdentityHashOffset, identityHashMode, identityHashNumBits, identityHashShift); } public static void initializeDynamicHubLayout(HostedMetaAccess hMeta) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java index df2da36ba893..31bee600dc46 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java @@ -443,11 +443,12 @@ private Stream computeHeaderTypeInfo() { int hubOffset = ol.getHubOffset(); NativeImageHeaderTypeInfo objHeader = new NativeImageHeaderTypeInfo("_objhdr", ol.getFirstFieldOffset()); - objHeader.addField("hub", hubType, hubOffset, referenceSize); - if (ol.isIdentityHashFieldInObjectHeader()) { - int idHashSize = ol.sizeInBytes(JavaKind.Int); - objHeader.addField("idHash", javaKindToHostedType.get(JavaKind.Int), ol.getObjectHeaderIdentityHashOffset(), idHashSize); + if (hubOffset > 0) { + assert hubOffset == Integer.BYTES || hubOffset == Long.BYTES; + JavaKind kind = hubOffset == Integer.BYTES ? JavaKind.Int : JavaKind.Long; + objHeader.addField("reserved", javaKindToHostedType.get(kind), 0, hubOffset); } + objHeader.addField("hub", hubType, hubOffset, referenceSize); infos.add(objHeader); return infos.stream(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java index 42927c72a992..df622c337e61 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java @@ -117,6 +117,7 @@ public final class NativeImageHeap implements ImageHeap { private final ImageHeapLayouter heapLayouter; private final int minInstanceSize; private final int minArraySize; + private final int fillerArrayBaseOffset; private final boolean layeredBuild = ImageLayerBuildingSupport.buildingImageLayer(); /** @@ -162,6 +163,7 @@ public NativeImageHeap(AnalysisUniverse aUniverse, HostedUniverse hUniverse, Hos this.minInstanceSize = objectLayout.getMinImageHeapInstanceSize(); this.minArraySize = objectLayout.getMinImageHeapArraySize(); + this.fillerArrayBaseOffset = objectLayout.getArrayBaseOffset(JavaKind.Int); assert assertFillerObjectSizes(); dynamicHubLayout = DynamicHubLayout.singleton(); @@ -440,7 +442,8 @@ public int countAndVerifyDynamicHubs() { public ObjectInfo addFillerObject(int size) { if (size >= minArraySize) { int elementSize = objectLayout.getArrayIndexScale(JavaKind.Int); - int arrayLength = (size - minArraySize) / elementSize; + assert fillerArrayBaseOffset % elementSize == 0; + int arrayLength = (size - fillerArrayBaseOffset) / elementSize; assert objectLayout.getArraySize(JavaKind.Int, arrayLength, true) == size; return addLateToImageHeap(new int[arrayLength], HeapInclusionReason.FillerObject); } else if (size >= minInstanceSize) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java index 20a6a08e5cb5..16307138a77b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java @@ -51,6 +51,7 @@ import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.ObjectHeader; import com.oracle.svm.core.hub.DynamicHub; +import com.oracle.svm.core.identityhashcode.IdentityHashCodeSupport; import com.oracle.svm.core.image.ImageHeapLayoutInfo; import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; import com.oracle.svm.core.meta.MethodPointer; @@ -272,7 +273,7 @@ private void writeConstant(RelocatableBuffer buffer, int index, JavaKind kind, O write(buffer, index, con, info); } - private void writeObjectHeader(RelocatableBuffer buffer, int index, ObjectInfo obj) { + private void writeHubPointer(RelocatableBuffer buffer, int index, ObjectInfo obj) { mustBeReferenceAligned(index); DynamicHub hub = obj.getClazz().getHub(); @@ -281,14 +282,22 @@ private void writeObjectHeader(RelocatableBuffer buffer, int index, ObjectInfo o assert hubInfo != null : "Unknown object " + hub + " found. Static field or an object referenced from a static field changed during native image generation?"; ObjectHeader objectHeader = Heap.getHeap().getObjectHeader(); + int hubSize = heap.objectLayout.getHubSize(); if (NativeImageHeap.useHeapBase()) { long targetOffset = hubInfo.getOffset(); - long headerBits = objectHeader.encodeAsImageHeapObjectHeader(obj, targetOffset); - writeReferenceValue(buffer, index, headerBits); + long encoding = objectHeader.encodeAsImageHeapObjectHeader(obj, targetOffset); + + if (hubSize == Long.BYTES) { + buffer.getByteBuffer().putLong(index, encoding); + } else { + assert hubSize == Integer.BYTES; + buffer.getByteBuffer().putInt(index, NumUtil.safeToUInt(encoding)); + } } else { + assert hubSize == referenceSize(); // The address of the DynamicHub target will be added by the link editor. - long headerBits = objectHeader.encodeAsImageHeapObjectHeader(obj, 0L); - addDirectRelocationWithAddend(buffer, index, hub, headerBits); + long encoding = objectHeader.encodeAsImageHeapObjectHeader(obj, 0L); + addDirectRelocationWithAddend(buffer, index, hub, encoding); } } @@ -371,7 +380,7 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { DynamicHubLayout dynamicHubLayout = heap.dynamicHubLayout; assert objectLayout.isAligned(getIndexInBuffer(info, 0)); - writeObjectHeader(buffer, getIndexInBuffer(info, objectLayout.getHubOffset()), info); + writeHubPointer(buffer, getIndexInBuffer(info, objectLayout.getHubOffset()), info); ByteBuffer bufferBytes = buffer.getByteBuffer(); HostedClass clazz = info.getClazz(); @@ -443,7 +452,6 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { idHashOffset = hybridLayout.getIdentityHashOffset(length); instanceFields = instanceFields.filter(field -> !field.equals(hybridArrayField)); } else { - idHashOffset = instanceClazz.getIdentityHashOffset(); } @@ -459,9 +467,8 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { }); /* Write the identity hashcode */ - assert idHashOffset > 0; - bufferBytes.putInt(getIndexInBuffer(info, idHashOffset), info.getIdentityHashCode()); - + assert idHashOffset >= 0; + IdentityHashCodeSupport.writeIdentityHashCodeToImageHeap(bufferBytes, getIndexInBuffer(info, idHashOffset), info.getIdentityHashCode()); } else if (clazz.isArray()) { JavaKind kind = clazz.getComponentType().getStorageKind(); @@ -469,7 +476,7 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { int length = heap.hConstantReflection.readArrayLength(constant); bufferBytes.putInt(getIndexInBuffer(info, objectLayout.getArrayLengthOffset()), length); - bufferBytes.putInt(getIndexInBuffer(info, objectLayout.getArrayIdentityHashOffset(kind, length)), info.getIdentityHashCode()); + IdentityHashCodeSupport.writeIdentityHashCodeToImageHeap(bufferBytes, getIndexInBuffer(info, objectLayout.getArrayIdentityHashOffset(kind, length)), info.getIdentityHashCode()); if (clazz.getComponentType().isPrimitive()) { ImageHeapPrimitiveArray imageHeapArray = (ImageHeapPrimitiveArray) constant; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedInstanceClass.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedInstanceClass.java index 5f892ad3f623..532bfbdec857 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedInstanceClass.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedInstanceClass.java @@ -40,7 +40,7 @@ public class HostedInstanceClass extends HostedClass { protected int instanceSize; protected boolean monitorFieldNeeded = false; protected int monitorFieldOffset = 0; - protected int identityHashOffset = 0; + protected int identityHashOffset = -1; public HostedInstanceClass(HostedUniverse universe, AnalysisType wrapped, JavaKind kind, JavaKind storageKind, HostedClass superClass, HostedInterface[] interfaces) { super(universe, wrapped, kind, storageKind, superClass, interfaces); @@ -126,9 +126,10 @@ public int getMonitorFieldOffset() { return monitorFieldOffset; } - public void setMonitorFieldOffset(int monitorFieldOffset) { + public void setMonitorFieldOffset(int offset) { assert this.monitorFieldOffset == 0 : "setting monitor field offset twice"; - this.monitorFieldOffset = monitorFieldOffset; + assert offset > 0; + this.monitorFieldOffset = offset; } public int getIdentityHashOffset() { @@ -136,8 +137,8 @@ public int getIdentityHashOffset() { } public void setIdentityHashOffset(int offset) { - assert this.identityHashOffset == 0 : "setting identity hashcode field offset more than once"; - assert offset > 0; + assert this.identityHashOffset == -1 : "setting identity hashcode field offset more than once"; + assert offset >= 0; this.identityHashOffset = offset; } diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateTruffleRuntime.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateTruffleRuntime.java index 0d805eac3774..518b9ae6e73b 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateTruffleRuntime.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateTruffleRuntime.java @@ -463,7 +463,7 @@ protected int[] getFieldOffsets(Class type, boolean includePrimitive, boolean boolean referenceInstanceClass = dh.isReferenceInstanceClass(); int monitorOffset = dh.getMonitorOffset(); InteriorObjRefWalker.walkInstanceReferenceOffsets(dh, (offset) -> { - if (offset == monitorOffset) { + if (monitorOffset != 0 && offset == monitorOffset) { // Object monitor is not a proper field. } else if (referenceInstanceClass && ReferenceInternals.isAnyReferenceFieldOffset(offset)) { // Reference class field offsets must not be exposed. From cd1f98313b77e2e210261376d00142c9a2a58a80 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Thu, 13 Mar 2025 16:48:13 +0100 Subject: [PATCH 2/3] Renamings. --- .../objectfile/debugentry/DebugInfoBase.java | 22 +++++----- .../debuginfo/DebugInfoProvider.java | 2 +- .../elf/dwarf/DwarfInfoSectionImpl.java | 20 ++++----- .../oracle/svm/core/genscavenge/HeapImpl.java | 2 +- .../core/genscavenge/ObjectHeaderImpl.java | 42 +++++++++---------- .../meta/SubstrateBasicLoweringProvider.java | 16 +++---- .../oracle/svm/core/heap/ObjectHeader.java | 8 +++- .../image/NativeImageDebugInfoFeature.java | 8 ++-- .../NativeImageDebugInfoProviderBase.java | 8 ++-- .../hosted/image/NativeImageHeapWriter.java | 4 +- 10 files changed, 68 insertions(+), 64 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java index 47a68ad22445..bcf34306b834 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java @@ -171,11 +171,11 @@ public abstract class DebugInfoBase { /** * Bit mask used for tagging oops. */ - private int reservedBitsMask; + private int reservedHubBitsMask; /** * Number of low order bits used for tagging oops. */ - private int numReservedBits; + private int numReservedHubBits; /** * Number of bytes used to store an oop reference. */ @@ -211,8 +211,8 @@ public abstract class DebugInfoBase { public DebugInfoBase(ByteOrder byteOrder) { this.byteOrder = byteOrder; this.useHeapBase = true; - this.reservedBitsMask = 0; - this.numReservedBits = 0; + this.reservedHubBitsMask = 0; + this.numReservedHubBits = 0; this.compressionShift = 0; this.referenceSize = 0; this.pointerSize = 0; @@ -250,12 +250,12 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { /* * Save count of low order tag bits that may appear in references. */ - reservedBitsMask = debugInfoProvider.reservedBitsMask(); + reservedHubBitsMask = debugInfoProvider.reservedHubBitsMask(); /* Mask must be contiguous from bit 0. */ - assert ((reservedBitsMask + 1) & reservedBitsMask) == 0; + assert ((reservedHubBitsMask + 1) & reservedHubBitsMask) == 0; - numReservedBits = Integer.bitCount(reservedBitsMask); + numReservedHubBits = Integer.bitCount(reservedHubBitsMask); /* Save amount we need to shift references by when loading from an object field. */ compressionShift = debugInfoProvider.compressionShift(); @@ -705,12 +705,12 @@ public boolean useHeapBase() { return useHeapBase; } - public int reservedBitsMask() { - return reservedBitsMask; + public int reservedHubBitsMask() { + return reservedHubBitsMask; } - public int numReservedBits() { - return numReservedBits; + public int numReservedHubBits() { + return numReservedHubBits; } public int compressionShift() { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debuginfo/DebugInfoProvider.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debuginfo/DebugInfoProvider.java index e8488c87b4f0..691a3d480a37 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debuginfo/DebugInfoProvider.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debuginfo/DebugInfoProvider.java @@ -52,7 +52,7 @@ public interface DebugInfoProvider { /** * Mask selecting low order bits used for tagging oops. */ - int reservedBitsMask(); + int reservedHubBitsMask(); /** * Number of bytes used to store an oop reference. diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java index 7d32cd69d837..37264869eca7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java @@ -2132,8 +2132,8 @@ public int writeCompressedOopConversionExpression(boolean isHub, byte[] buffer, */ boolean useHeapBase = dwarfSections.useHeapBase(); - int reservedBitsMask = dwarfSections.reservedBitsMask(); - int numReservedBits = dwarfSections.numReservedBits(); + int reservedHubBitsMask = dwarfSections.reservedHubBitsMask(); + int numReservedHubBits = dwarfSections.numReservedHubBits(); int compressionShift = dwarfSections.compressionShift(); int numAlignmentBits = dwarfSections.numAlignmentBits(); @@ -2143,12 +2143,12 @@ public int writeCompressedOopConversionExpression(boolean isHub, byte[] buffer, * The required expression will be one of these paths: * * push object address ................................ (1 byte) ..... [offset] ............ - * IF reservedBitsMask != 0 ................................................................ - * . push reservedBitsMask ............................ (1 byte) ..... [offset, mask] ...... + * IF reservedHubBitsMask != 0 ............................................................. + * . push reservedHubBitsMask.......................... (1 byte) ..... [offset, mask] ...... * . NOT .............................................. (1 byte) ..... [offset, ~mask] ..... * . AND .............................................. (1 byte) ..... [offset] ............ - * . IF numReservedBits == numAlignmentBits && compressionShift == 0 ....................... - * ... push numReservedBits ........................... (1 byte) ..... [offset, right shift] + * . IF numReservedHubBits == numAlignmentBits && compressionShift == 0 .................... + * ... push numReservedHubBits ........................ (1 byte) ..... [offset, right shift] * ... LSHR ........................................... (1 byte) ..... [offset] ............ * ... IF compressionShift != numAlignmentBits ............................................. * ..... push numAlignmentBits - compressionShift ..... (1 byte) ..... [offset, left shift] @@ -2176,13 +2176,13 @@ public int writeCompressedOopConversionExpression(boolean isHub, byte[] buffer, pos = writeULEB(0, buffer, pos); int exprStart = pos; pos = writeExprOpcode(DwarfExpressionOpcode.DW_OP_push_object_address, buffer, pos); - if (isHub && reservedBitsMask != 0) { - if (numReservedBits == numAlignmentBits && compressionShift == 0) { - pos = writeExprOpcodeLiteral(reservedBitsMask, buffer, pos); + if (isHub && reservedHubBitsMask != 0) { + if (numReservedHubBits == numAlignmentBits && compressionShift == 0) { + pos = writeExprOpcodeLiteral(reservedHubBitsMask, buffer, pos); pos = writeExprOpcode(DwarfExpressionOpcode.DW_OP_not, buffer, pos); pos = writeExprOpcode(DwarfExpressionOpcode.DW_OP_and, buffer, pos); } else { - pos = writeExprOpcodeLiteral(numReservedBits, buffer, pos); + pos = writeExprOpcodeLiteral(numReservedHubBits, buffer, pos); pos = writeExprOpcode(DwarfExpressionOpcode.DW_OP_shr, buffer, pos); if (compressionShift != numAlignmentBits) { pos = writeExprOpcodeLiteral(numAlignmentBits - compressionShift, buffer, pos); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java index 1c11c59817e1..cda37ba72456 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java @@ -867,7 +867,7 @@ public int maxInvocationCount() { @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLevel, int invocationCount) { log.string("Heap settings and statistics:").indent(true); - log.string("Reserved object header bits: 0b").number(Heap.getHeap().getObjectHeader().getReservedBitsMask(), 2, false).newline(); + log.string("Reserved hub pointer bits: 0b").number(Heap.getHeap().getObjectHeader().getReservedHubBitsMask(), 2, false).newline(); log.string("Aligned chunk size: ").unsigned(HeapParameters.getAlignedHeapChunkSize()).newline(); log.string("Large array threshold: ").unsigned(HeapParameters.getLargeArrayThreshold()).newline(); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ObjectHeaderImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ObjectHeaderImpl.java index b0098eab13c7..4fa041336fd6 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ObjectHeaderImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ObjectHeaderImpl.java @@ -79,26 +79,26 @@ public final class ObjectHeaderImpl extends ObjectHeader { private static final UnsignedWord IDHASH_STATE_IN_FIELD = Word.unsigned(0b10); private final int numAlignmentBits; - private final int numReservedBits; - private final int numReservedExtraBits; + private final int numReservedHubBits; + private final int numReservedExtraHubBits; - private final int reservedBitsMask; + private final int reservedHubBitsMask; @Platforms(Platform.HOSTED_ONLY.class) ObjectHeaderImpl() { numAlignmentBits = CodeUtil.log2(ConfigurationValues.getObjectLayout().getAlignment()); - int numMinimumReservedBits = 3; - VMError.guarantee(numMinimumReservedBits <= numAlignmentBits, "Minimum set of reserved bits must be provided by object alignment"); + int numMinReservedHubBits = 3; + VMError.guarantee(numMinReservedHubBits <= numAlignmentBits, "Minimum set of reserved bits must be provided by object alignment"); if (isIdentityHashFieldOptional()) { VMError.guarantee(ReferenceAccess.singleton().haveCompressedReferences(), "Ensures hubs (at the start of the image heap) remain addressable"); - numReservedBits = numMinimumReservedBits + 2; - VMError.guarantee(numReservedBits <= numAlignmentBits || hasShift(), + numReservedHubBits = numMinReservedHubBits + 2; + VMError.guarantee(numReservedHubBits <= numAlignmentBits || hasShift(), "With no shift, forwarding references are stored directly in the header (with 64-bit, must be) and we cannot use non-alignment header bits"); } else { - numReservedBits = numMinimumReservedBits; + numReservedHubBits = numMinReservedHubBits; } - numReservedExtraBits = numReservedBits - numAlignmentBits; - reservedBitsMask = (1 << numReservedBits) - 1; + numReservedExtraHubBits = numReservedHubBits - numAlignmentBits; + reservedHubBitsMask = (1 << numReservedHubBits) - 1; } @Fold @@ -109,15 +109,15 @@ public static ObjectHeaderImpl getObjectHeaderImpl() { } @Override - public int getReservedBitsMask() { - return reservedBitsMask; + public int getReservedHubBitsMask() { + return reservedHubBitsMask; } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @Override public Pointer extractPotentialDynamicHubFromHeader(Word header) { if (ReferenceAccess.singleton().haveCompressedReferences()) { - UnsignedWord hubBits = header.unsignedShiftRight(numReservedBits); + UnsignedWord hubBits = header.unsignedShiftRight(numReservedHubBits); UnsignedWord baseRelativeBits = hubBits.shiftLeft(numAlignmentBits); return KnownIntrinsics.heapBase().add(baseRelativeBits); } else { @@ -277,7 +277,7 @@ public Word encodeAsObjectHeader(DynamicHub hub, boolean rememberedSet, boolean Word result = Word.objectToUntrackedPointer(hub); if (SubstrateOptions.SpawnIsolates.getValue()) { result = result.subtract(KnownIntrinsics.heapBase()); - result = result.shiftLeft(numReservedExtraBits); + result = result.shiftLeft(numReservedExtraHubBits); } if (rememberedSet) { result = result.or(REMSET_OR_MARKED1_BIT); @@ -291,7 +291,7 @@ public Word encodeAsObjectHeader(DynamicHub hub, boolean rememberedSet, boolean /** Clear the object header bits from a header. */ @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) UnsignedWord clearBits(UnsignedWord header) { - UnsignedWord mask = Word.unsigned(reservedBitsMask); + UnsignedWord mask = Word.unsigned(reservedHubBitsMask); return header.and(mask.not()); } @@ -314,9 +314,9 @@ public static boolean isConsumedHeapChunkZapped(UnsignedWord header) { } @Override - public long encodeAsImageHeapObjectHeader(ImageHeapObject obj, long hubOffsetFromHeapBase) { - long header = hubOffsetFromHeapBase << numReservedExtraBits; - assert (header & reservedBitsMask) == 0 : "Object header bits must be zero initially"; + public long encodeHubPointerForImageHeap(ImageHeapObject obj, long hubOffsetFromHeapBase) { + long header = hubOffsetFromHeapBase << numReservedExtraHubBits; + assert (header & reservedHubBitsMask) == 0 : "Object header bits must be zero initially"; if (obj.getPartition() instanceof ChunkedImageHeapPartition partition) { if (partition.isWritable() && HeapImpl.usesImageHeapCardMarking()) { header |= REMSET_OR_MARKED1_BIT.rawValue(); @@ -336,8 +336,8 @@ public long encodeAsImageHeapObjectHeader(ImageHeapObject obj, long hubOffsetFro @Override public void verifyDynamicHubOffsetInImageHeap(long offsetFromHeapBase) { long referenceSizeMask = getReferenceSize() == Integer.BYTES ? 0xFFFF_FFFFL : -1L; - long encoded = (offsetFromHeapBase << numReservedExtraBits) & referenceSizeMask; - boolean shiftLosesInformation = (encoded >>> numReservedExtraBits != offsetFromHeapBase); + long encoded = (offsetFromHeapBase << numReservedExtraHubBits) & referenceSizeMask; + boolean shiftLosesInformation = (encoded >>> numReservedExtraHubBits != offsetFromHeapBase); if (shiftLosesInformation) { throw VMError.shouldNotReachHere("Hub is too far from heap base for encoding in object header: " + offsetFromHeapBase); } @@ -487,7 +487,7 @@ private UnsignedWord getForwardHeader(Object copy) { private UnsignedWord getHeaderBitsFromHeader(UnsignedWord header) { assert !isProducedHeapChunkZapped(header) : "Produced chunk zap value"; assert !isConsumedHeapChunkZapped(header) : "Consumed chunk zap value"; - return header.and(reservedBitsMask); + return header.and(reservedHubBitsMask); } @Fold diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java index c2dc32657b08..2835cbd30d05 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java @@ -259,12 +259,12 @@ protected ValueNode createReadHub(StructuredGraph graph, ValueNode object, Lower int hubOffset = ol.getHubOffset(); int bytesToRead = ol.getHubSize(); - long reservedHeaderBitsMask = oh.getReservedBitsMask(); + long reservedHubBitsMask = oh.getReservedHubBitsMask(); if (hubOffset > 0 && hubOffset + ol.getHubSize() <= Long.BYTES && target.arch.getByteOrder() == ByteOrder.LITTLE_ENDIAN) { /* Prepare to emit a 64-bit read at offset 0 (reduces the code size). */ hubOffset = 0; bytesToRead = Long.BYTES; - reservedHeaderBitsMask = (reservedHeaderBitsMask << Integer.SIZE) | ((1L << Integer.SIZE) - 1); + reservedHubBitsMask = (reservedHubBitsMask << Integer.SIZE) | ((1L << Integer.SIZE) - 1); } /* Read the raw hub data from the correct part of the object header. */ @@ -273,19 +273,19 @@ protected ValueNode createReadHub(StructuredGraph graph, ValueNode object, Lower AddressNode hubAddressNode = graph.unique(new OffsetAddressNode(object, hubOffsetNode)); ValueNode rawHubData = graph.unique(new FloatingReadNode(hubAddressNode, NamedLocationIdentity.FINAL_LOCATION, null, readStamp, null, BarrierType.NONE)); - if (reservedHeaderBitsMask != 0L) { + if (reservedHubBitsMask != 0L) { /* Get rid of the reserved header bits and extract the actual hub bits. */ - assert CodeUtil.isPowerOf2(reservedHeaderBitsMask + 1) : "only the lowest bits may be set"; - int numReservedBits = CodeUtil.log2(reservedHeaderBitsMask + 1); + assert CodeUtil.isPowerOf2(reservedHubBitsMask + 1) : "only the lowest bits may be set"; + int numReservedHubBits = CodeUtil.log2(reservedHubBitsMask + 1); int compressionShift = ReferenceAccess.singleton().getCompressionShift(); int numAlignmentBits = CodeUtil.log2(ol.getAlignment()); assert compressionShift <= numAlignmentBits : "compression discards bits"; - if (numReservedBits == numAlignmentBits && compressionShift == 0) { + if (numReservedHubBits == numAlignmentBits && compressionShift == 0) { /* AND with a constant is slightly smaller than 2 shifts. */ - rawHubData = graph.unique(new AndNode(rawHubData, ConstantNode.forIntegerStamp(readStamp, ~reservedHeaderBitsMask, graph))); + rawHubData = graph.unique(new AndNode(rawHubData, ConstantNode.forIntegerStamp(readStamp, ~reservedHubBitsMask, graph))); } else { - rawHubData = graph.unique(new UnsignedRightShiftNode(rawHubData, ConstantNode.forInt(numReservedBits, graph))); + rawHubData = graph.unique(new UnsignedRightShiftNode(rawHubData, ConstantNode.forInt(numReservedHubBits, graph))); if (compressionShift != numAlignmentBits) { int shift = numAlignmentBits - compressionShift; rawHubData = graph.unique(new LeftShiftNode(rawHubData, ConstantNode.forInt(shift, graph))); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ObjectHeader.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ObjectHeader.java index 6c0e6f8db238..5a7a72291a41 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ObjectHeader.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ObjectHeader.java @@ -60,9 +60,13 @@ protected ObjectHeader() { /** * Returns a mask where all reserved bits are set. */ - public abstract int getReservedBitsMask(); + public abstract int getReservedHubBitsMask(); - public abstract long encodeAsImageHeapObjectHeader(ImageHeapObject obj, long hubOffsetFromHeapBase); + /** + * Returns an encoded hub pointer that can be used when writing the object header of an image + * heap object. Note that the returned value is not necessarily the full object header. + */ + public abstract long encodeHubPointerForImageHeap(ImageHeapObject obj, long hubOffsetFromHeapBase); public abstract Word encodeAsTLABObjectHeader(DynamicHub hub); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoFeature.java index 818cb347bde3..50c6c3bf9a1b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoFeature.java @@ -30,8 +30,6 @@ import java.util.function.Function; import java.util.function.Supplier; -import com.oracle.svm.core.ReservedRegisters; -import jdk.graal.compiler.word.Word; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.word.PointerBase; @@ -42,6 +40,7 @@ import com.oracle.objectfile.BasicProgbitsSectionImpl; import com.oracle.objectfile.debuginfo.DebugInfoProvider; import com.oracle.objectfile.io.AssemblyBuffer; +import com.oracle.svm.core.ReservedRegisters; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.UniqueShortNameProvider; import com.oracle.svm.core.UniqueShortNameProviderDefaultImpl; @@ -63,6 +62,7 @@ import jdk.graal.compiler.core.common.CompressEncoding; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.printer.GraalDebugHandlersFactory; +import jdk.graal.compiler.word.Word; @AutomaticallyRegisteredFeature @SuppressWarnings("unused") @@ -120,12 +120,12 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { CompressEncoding compressEncoding = ImageSingletons.lookup(CompressEncoding.class); CGlobalData compressionShift = CGlobalDataFactory.createWord(Word.signed(compressEncoding.getShift()), "__svm_compression_shift"); CGlobalData useHeapBase = CGlobalDataFactory.createWord(Word.unsigned(compressEncoding.hasBase() ? 1 : 0), "__svm_use_heap_base"); - CGlobalData reservedBitsMask = CGlobalDataFactory.createWord(Word.unsigned(Heap.getHeap().getObjectHeader().getReservedBitsMask()), "__svm_reserved_bits_mask"); + CGlobalData reservedHubBitsMask = CGlobalDataFactory.createWord(Word.unsigned(Heap.getHeap().getObjectHeader().getReservedHubBitsMask()), "__svm_reserved_bits_mask"); CGlobalData objectAlignment = CGlobalDataFactory.createWord(Word.unsigned(ConfigurationValues.getObjectLayout().getAlignment()), "__svm_object_alignment"); CGlobalData heapBaseRegnum = CGlobalDataFactory.createWord(Word.unsigned(ReservedRegisters.singleton().getHeapBaseRegister().number), "__svm_heap_base_regnum"); CGlobalDataFeature.singleton().registerWithGlobalHiddenSymbol(compressionShift); CGlobalDataFeature.singleton().registerWithGlobalHiddenSymbol(useHeapBase); - CGlobalDataFeature.singleton().registerWithGlobalHiddenSymbol(reservedBitsMask); + CGlobalDataFeature.singleton().registerWithGlobalHiddenSymbol(reservedHubBitsMask); CGlobalDataFeature.singleton().registerWithGlobalHiddenSymbol(objectAlignment); CGlobalDataFeature.singleton().registerWithGlobalHiddenSymbol(heapBaseRegnum); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProviderBase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProviderBase.java index d2375d23f730..ea2984aaa3a7 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProviderBase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProviderBase.java @@ -87,7 +87,7 @@ public abstract class NativeImageDebugInfoProviderBase { protected final int objectAlignment; protected final int primitiveStartOffset; protected final int referenceStartOffset; - protected final int reservedBitsMask; + protected final int reservedHubBitsMask; protected final HostedType hubType; protected final HostedType wordBaseType; @@ -105,7 +105,7 @@ public NativeImageDebugInfoProviderBase(NativeImageCodeCache codeCache, NativeIm ObjectHeader objectHeader = Heap.getHeap().getObjectHeader(); NativeImageHeap.ObjectInfo primitiveFields = heap.getObjectInfo(StaticFieldsSupport.getCurrentLayerStaticPrimitiveFields()); NativeImageHeap.ObjectInfo objectFields = heap.getObjectInfo(StaticFieldsSupport.getCurrentLayerStaticObjectFields()); - this.reservedBitsMask = objectHeader.getReservedBitsMask(); + this.reservedHubBitsMask = objectHeader.getReservedHubBitsMask(); if (SubstrateOptions.SpawnIsolates.getValue()) { CompressEncoding compressEncoding = ImageSingletons.lookup(CompressEncoding.class); this.useHeapBase = compressEncoding.hasBase(); @@ -385,8 +385,8 @@ public int objectAlignment() { return objectAlignment; } - public int reservedBitsMask() { - return reservedBitsMask; + public int reservedHubBitsMask() { + return reservedHubBitsMask; } public int compiledCodeMax() { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java index 16307138a77b..572541f7eb09 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java @@ -285,7 +285,7 @@ private void writeHubPointer(RelocatableBuffer buffer, int index, ObjectInfo obj int hubSize = heap.objectLayout.getHubSize(); if (NativeImageHeap.useHeapBase()) { long targetOffset = hubInfo.getOffset(); - long encoding = objectHeader.encodeAsImageHeapObjectHeader(obj, targetOffset); + long encoding = objectHeader.encodeHubPointerForImageHeap(obj, targetOffset); if (hubSize == Long.BYTES) { buffer.getByteBuffer().putLong(index, encoding); @@ -296,7 +296,7 @@ private void writeHubPointer(RelocatableBuffer buffer, int index, ObjectInfo obj } else { assert hubSize == referenceSize(); // The address of the DynamicHub target will be added by the link editor. - long encoding = objectHeader.encodeAsImageHeapObjectHeader(obj, 0L); + long encoding = objectHeader.encodeHubPointerForImageHeap(obj, 0L); addDirectRelocationWithAddend(buffer, index, hub, encoding); } } From a0b4e3dbc1a494b81b90eeaf15e9d2ed8c668606 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Wed, 26 Mar 2025 10:08:21 +0100 Subject: [PATCH 3/3] Review feedback. --- .../core/genscavenge/ObjectHeaderImpl.java | 18 +++------ .../remset/CardTableBasedRememberedSet.java | 3 +- .../meta/SubstrateBasicLoweringProvider.java | 2 +- .../com/oracle/svm/core/hub/DynamicHub.java | 4 +- .../IdentityHashCodeSupport.java | 38 +++++-------------- .../svm/hosted/image/NativeImageHeap.java | 2 +- .../hosted/image/NativeImageHeapWriter.java | 29 ++++++++------ .../svm/hosted/meta/HostedInstanceClass.java | 6 +-- .../svm/hosted/meta/UniverseBuilder.java | 2 +- 9 files changed, 42 insertions(+), 62 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ObjectHeaderImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ObjectHeaderImpl.java index 4fa041336fd6..fce5811d1c98 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ObjectHeaderImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ObjectHeaderImpl.java @@ -355,8 +355,7 @@ public static boolean isAlignedHeader(UnsignedWord header) { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static boolean isUnalignedObject(Object obj) { - ObjectHeader oh = Heap.getHeap().getObjectHeader(); - UnsignedWord header = oh.readHeaderFromObject(obj); + UnsignedWord header = getObjectHeaderImpl().readHeaderFromObject(obj); return isUnalignedHeader(header); } @@ -367,8 +366,7 @@ public static boolean isUnalignedHeader(UnsignedWord header) { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static void setRememberedSetBit(Object o) { - ObjectHeader oh = Heap.getHeap().getObjectHeader(); - UnsignedWord oldHeader = oh.readHeaderFromObject(o); + UnsignedWord oldHeader = getObjectHeaderImpl().readHeaderFromObject(o); assert oldHeader.and(FORWARDED_OR_MARKED2_BIT).equal(0); UnsignedWord newHeader = oldHeader.or(REMSET_OR_MARKED1_BIT); writeHeaderToObject(o, newHeader); @@ -384,8 +382,7 @@ public static void setMarked(Object o) { if (!SerialGCOptions.useCompactingOldGen()) { // not guarantee(): always folds, prevent call throw VMError.shouldNotReachHere("Only for compacting GC."); } - ObjectHeader oh = Heap.getHeap().getObjectHeader(); - UnsignedWord header = oh.readHeaderFromObject(o); + UnsignedWord header = getObjectHeaderImpl().readHeaderFromObject(o); assert header.and(FORWARDED_OR_MARKED2_BIT).equal(0) : "forwarded or already marked"; /* * The remembered bit is already set if the object was in the old generation before, or @@ -396,16 +393,14 @@ public static void setMarked(Object o) { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static void unsetMarkedAndKeepRememberedSetBit(Object o) { - ObjectHeader oh = Heap.getHeap().getObjectHeader(); - UnsignedWord header = oh.readHeaderFromObject(o); + UnsignedWord header = getObjectHeaderImpl().readHeaderFromObject(o); assert isMarkedHeader(header); writeHeaderToObject(o, header.and(FORWARDED_OR_MARKED2_BIT.not())); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static boolean isMarked(Object o) { - ObjectHeader oh = Heap.getHeap().getObjectHeader(); - return isMarkedHeader(oh.readHeaderFromObject(o)); + return isMarkedHeader(getObjectHeaderImpl().readHeaderFromObject(o)); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @@ -418,8 +413,7 @@ public static boolean isMarkedHeader(UnsignedWord header) { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) static boolean isPointerToForwardedObject(Pointer p) { - ObjectHeader oh = Heap.getHeap().getObjectHeader(); - Word header = oh.readHeaderFromPointer(p); + Word header = getObjectHeaderImpl().readHeaderFromPointer(p); return isForwardedHeader(header); } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/CardTableBasedRememberedSet.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/CardTableBasedRememberedSet.java index e29df2228c55..372fa5661a75 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/CardTableBasedRememberedSet.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/CardTableBasedRememberedSet.java @@ -188,7 +188,8 @@ public void dirtyCardIfNecessary(Object holderObject, Object object) { @Override @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) public void dirtyAllReferencesIfNecessary(Object obj) { - Word header = ObjectHeader.readHeaderFromObject(obj); + ObjectHeader oh = Heap.getHeap().getObjectHeader(); + Word header = oh.readHeaderFromObject(obj); if (RememberedSet.get().hasRememberedSet(header) && mayContainReferences(obj)) { ForcedSerialPostWriteBarrier.force(OffsetAddressNode.address(obj, 0), false); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java index 2835cbd30d05..64c6828eb715 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java @@ -260,7 +260,7 @@ protected ValueNode createReadHub(StructuredGraph graph, ValueNode object, Lower int hubOffset = ol.getHubOffset(); int bytesToRead = ol.getHubSize(); long reservedHubBitsMask = oh.getReservedHubBitsMask(); - if (hubOffset > 0 && hubOffset + ol.getHubSize() <= Long.BYTES && target.arch.getByteOrder() == ByteOrder.LITTLE_ENDIAN) { + if (hubOffset == Integer.BYTES && hubOffset + ol.getHubSize() == Long.BYTES && target.arch.getByteOrder() == ByteOrder.LITTLE_ENDIAN) { /* Prepare to emit a 64-bit read at offset 0 (reduces the code size). */ hubOffset = 0; bytesToRead = Long.BYTES; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java index 8729b22ae035..68d87ec69778 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java @@ -572,12 +572,12 @@ public void setClassInitializationInfo(ClassInitializationInfo classInitializati @Platforms(Platform.HOSTED_ONLY.class) public void setSharedData(int layoutEncoding, int monitorOffset, int identityHashOffset, long referenceMapIndex, boolean isInstantiated) { - VMError.guarantee(monitorOffset == (char) monitorOffset, "Class %s has an invalid monitor field offset. Most likely, its objects are larger than supported.", name); + VMError.guarantee(monitorOffset == -1 || monitorOffset == (char) monitorOffset, "Class %s has an invalid monitor field offset. Most likely, its objects are larger than supported.", name); VMError.guarantee(identityHashOffset == -1 || identityHashOffset == (char) identityHashOffset, "Class %s has an invalid identity hash code field offset. Most likely, its objects are larger than supported.", name); this.layoutEncoding = layoutEncoding; - this.monitorOffset = (char) monitorOffset; + this.monitorOffset = monitorOffset == -1 ? 0 : (char) monitorOffset; this.identityHashOffset = identityHashOffset == -1 ? 0 : (char) identityHashOffset; if ((int) referenceMapIndex != referenceMapIndex) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/identityhashcode/IdentityHashCodeSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/identityhashcode/IdentityHashCodeSupport.java index 84dcb48c55d9..e1e171974e05 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/identityhashcode/IdentityHashCodeSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/identityhashcode/IdentityHashCodeSupport.java @@ -26,11 +26,8 @@ import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE; -import java.nio.ByteBuffer; import java.util.SplittableRandom; -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; import org.graalvm.word.LocationIdentity; import org.graalvm.word.Pointer; import org.graalvm.word.SignedWord; @@ -44,6 +41,7 @@ import com.oracle.svm.core.snippets.SubstrateForeignCallTarget; import com.oracle.svm.core.threadlocal.FastThreadLocalFactory; import com.oracle.svm.core.threadlocal.FastThreadLocalObject; +import com.oracle.svm.core.util.VMError; import jdk.graal.compiler.api.directives.GraalDirectives; import jdk.graal.compiler.nodes.NamedLocationIdentity; @@ -175,6 +173,9 @@ public static int readIdentityHashCodeFromField(Object obj) { @SubstrateForeignCallTarget(stubCallingConvention = false) public static int generateIdentityHashCode(Object obj) { + /* The guarantee makes the code a bit smaller as obj is non-null afterward. */ + VMError.guarantee(obj != null); + ObjectLayout ol = ConfigurationValues.getObjectLayout(); assert !ol.isIdentityHashFieldOptional(); @@ -193,7 +194,7 @@ public static int generateIdentityHashCode(Object obj) { int existingValue; int newValue; do { - existingValue = Unsafe.getUnsafe().getIntVolatile(obj, offset); + existingValue = Unsafe.getUnsafe().getIntOpaque(obj, offset); int existingHash = extractIdentityHashCode(existingValue, numBits, shift); if (existingHash != 0) { return existingHash; @@ -205,7 +206,7 @@ public static int generateIdentityHashCode(Object obj) { long existingValue; long newValue; do { - existingValue = Unsafe.getUnsafe().getLongVolatile(obj, offset); + existingValue = Unsafe.getUnsafe().getLongOpaque(obj, offset); int existingHash = extractIdentityHashCode(existingValue, numBits, shift); if (existingHash != 0) { return existingHash; @@ -219,7 +220,7 @@ public static int generateIdentityHashCode(Object obj) { } /** This method may only be called after the hub pointer was already written. */ - public static void writeIdentityHashCodeToAuxImage(Pointer hashCodePtr, int value) { + public static void writeIdentityHashCodeToImageHeap(Pointer hashCodePtr, int value) { ObjectLayout ol = ConfigurationValues.getObjectLayout(); int numBits = ol.getIdentityHashCodeNumBits(); int shift = ol.getIdentityHashCodeShift(); @@ -238,27 +239,6 @@ public static void writeIdentityHashCodeToAuxImage(Pointer hashCodePtr, int valu } } - /** This method may only be called after the object header was already written. */ - @Platforms(Platform.HOSTED_ONLY.class) - public static void writeIdentityHashCodeToImageHeap(ByteBuffer buffer, int hashCodePos, int value) { - ObjectLayout ol = ConfigurationValues.getObjectLayout(); - int numBits = ol.getIdentityHashCodeNumBits(); - int shift = ol.getIdentityHashCodeShift(); - long mask = ol.getIdentityHashCodeMask(); - - int totalBits = numBits + shift; - if (totalBits <= Integer.SIZE) { - int oldValue = buffer.getInt(hashCodePos); - assertIdentityHashCodeZero(oldValue, mask); - buffer.putInt(hashCodePos, encodeIdentityHashCode(oldValue, value, shift)); - } else { - assert totalBits <= Long.SIZE; - long oldValue = buffer.getLong(hashCodePos); - assertIdentityHashCodeZero(oldValue, mask); - buffer.putLong(hashCodePos, encodeIdentityHashCode(oldValue, value, shift)); - } - } - @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) private static int extractIdentityHashCode(int value, int numBits, int shift) { int left = Integer.SIZE - numBits - shift; @@ -300,8 +280,8 @@ private static void assertHasIdentityHashField(Object obj) { /** * Note that the result of this method is prone to race conditions. All races that can happen - * don't matter for the current caller though (we only want to identify objects that definitely - * don't have an identity hash code field). + * don't matter for the current callers though (we only want to know if the given object + * definitely has an identity hash code field - once it has one, it won't be taken away). */ @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) private static boolean hasIdentityHashField(Object obj) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java index df622c337e61..afbbe67dea80 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java @@ -502,7 +502,7 @@ private void addObjectToImageHeap(final JavaConstant constant, boolean immutable if (type.isInstanceClass()) { final HostedInstanceClass clazz = (HostedInstanceClass) type; // If the type has a monitor field, it has a reference field that is written. - if (clazz.getMonitorFieldOffset() != 0) { + if (clazz.getMonitorFieldOffset() >= 0) { written = true; references = true; // also not immutable: users of registerAsImmutable() must take precautions diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java index 572541f7eb09..c55f091309ad 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java @@ -55,6 +55,7 @@ import com.oracle.svm.core.image.ImageHeapLayoutInfo; import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; import com.oracle.svm.core.meta.MethodPointer; +import com.oracle.svm.core.util.HostedByteBufferPointer; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.DeadlockWatchdog; import com.oracle.svm.hosted.code.CEntryPointLiteralFeature; @@ -286,13 +287,7 @@ private void writeHubPointer(RelocatableBuffer buffer, int index, ObjectInfo obj if (NativeImageHeap.useHeapBase()) { long targetOffset = hubInfo.getOffset(); long encoding = objectHeader.encodeHubPointerForImageHeap(obj, targetOffset); - - if (hubSize == Long.BYTES) { - buffer.getByteBuffer().putLong(index, encoding); - } else { - assert hubSize == Integer.BYTES; - buffer.getByteBuffer().putInt(index, NumUtil.safeToUInt(encoding)); - } + writeValue(buffer, index, encoding, hubSize); } else { assert hubSize == referenceSize(); // The address of the DynamicHub target will be added by the link editor. @@ -361,12 +356,16 @@ private static void writePrimitive(RelocatableBuffer buffer, int index, JavaCons } private void writeReferenceValue(RelocatableBuffer buffer, int index, long value) { - if (referenceSize() == Long.BYTES) { + writeValue(buffer, index, value, referenceSize()); + } + + private static void writeValue(RelocatableBuffer buffer, int index, long value, int size) { + if (size == Long.BYTES) { buffer.getByteBuffer().putLong(index, value); - } else if (referenceSize() == Integer.BYTES) { + } else if (size == Integer.BYTES) { buffer.getByteBuffer().putInt(index, NumUtil.safeToUInt(value)); } else { - throw shouldNotReachHere("Unsupported reference size: " + referenceSize()); + throw shouldNotReachHere("Unsupported value size: " + size); } } @@ -468,7 +467,8 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { /* Write the identity hashcode */ assert idHashOffset >= 0; - IdentityHashCodeSupport.writeIdentityHashCodeToImageHeap(bufferBytes, getIndexInBuffer(info, idHashOffset), info.getIdentityHashCode()); + HostedByteBufferPointer identityHashPtr = new HostedByteBufferPointer(bufferBytes, getIndexInBuffer(info, idHashOffset)); + IdentityHashCodeSupport.writeIdentityHashCodeToImageHeap(identityHashPtr, info.getIdentityHashCode()); } else if (clazz.isArray()) { JavaKind kind = clazz.getComponentType().getStorageKind(); @@ -476,7 +476,8 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { int length = heap.hConstantReflection.readArrayLength(constant); bufferBytes.putInt(getIndexInBuffer(info, objectLayout.getArrayLengthOffset()), length); - IdentityHashCodeSupport.writeIdentityHashCodeToImageHeap(bufferBytes, getIndexInBuffer(info, objectLayout.getArrayIdentityHashOffset(kind, length)), info.getIdentityHashCode()); + HostedByteBufferPointer identityHashPtr = getHashCodePtr(info, bufferBytes, objectLayout, kind, length); + IdentityHashCodeSupport.writeIdentityHashCodeToImageHeap(identityHashPtr, info.getIdentityHashCode()); if (clazz.getComponentType().isPrimitive()) { ImageHeapPrimitiveArray imageHeapArray = (ImageHeapPrimitiveArray) constant; @@ -492,6 +493,10 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { } } + private HostedByteBufferPointer getHashCodePtr(ObjectInfo info, ByteBuffer bufferBytes, ObjectLayout objectLayout, JavaKind kind, int length) { + return new HostedByteBufferPointer(bufferBytes, getIndexInBuffer(info, objectLayout.getArrayIdentityHashOffset(kind, length))); + } + private int getIndexInBuffer(ObjectInfo objInfo, long offset) { long index = objInfo.getOffset() + offset - heapLayout.getStartOffset(); return NumUtil.safeToInt(index); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedInstanceClass.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedInstanceClass.java index 532bfbdec857..d3462aea281f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedInstanceClass.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedInstanceClass.java @@ -39,7 +39,7 @@ public class HostedInstanceClass extends HostedClass { protected int afterFieldsOffset; protected int instanceSize; protected boolean monitorFieldNeeded = false; - protected int monitorFieldOffset = 0; + protected int monitorFieldOffset = -1; protected int identityHashOffset = -1; public HostedInstanceClass(HostedUniverse universe, AnalysisType wrapped, JavaKind kind, JavaKind storageKind, HostedClass superClass, HostedInterface[] interfaces) { @@ -127,8 +127,8 @@ public int getMonitorFieldOffset() { } public void setMonitorFieldOffset(int offset) { - assert this.monitorFieldOffset == 0 : "setting monitor field offset twice"; - assert offset > 0; + assert this.monitorFieldOffset == -1 : "setting monitor field offset twice"; + assert offset >= 0; this.monitorFieldOffset = offset; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java index 3a5c8fdbedd3..eb84bf298f13 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java @@ -989,7 +989,7 @@ private static ReferenceMapEncoder.Input createReferenceMap(HostedType type) { * If the instance type has a monitor field, add it to the reference map. */ final int monitorOffset = instanceClass.getMonitorFieldOffset(); - if (monitorOffset != 0) { + if (monitorOffset >= 0) { referenceMap.markReferenceAtOffset(monitorOffset, true); } }