From df6ee202188fd5dd588447921ef926012bcf14d7 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Tue, 9 Sep 2025 12:31:38 +0200 Subject: [PATCH] Copy open type world data to the metaspace. --- .../genscavenge/metaspace/MetaspaceImpl.java | 5 +++++ .../metaspace/MetaspaceObjectAllocator.java | 5 +++++ .../core/heap/InstanceReferenceMapEncoder.java | 2 ++ .../com/oracle/svm/core/hub/DynamicHub.java | 18 +++++++++++------- .../RuntimeInstanceReferenceMapSupport.java | 7 ++----- .../oracle/svm/core/metaspace/Metaspace.java | 15 +++++++++++++++ .../oracle/svm/core/metaspace/NoMetaspace.java | 5 +++++ 7 files changed, 45 insertions(+), 12 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/metaspace/MetaspaceImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/metaspace/MetaspaceImpl.java index 5def47a9d001..8beab67775a4 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/metaspace/MetaspaceImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/metaspace/MetaspaceImpl.java @@ -111,6 +111,11 @@ public byte[] allocateByteArray(int length) { return allocator.allocateByteArray(length); } + @Override + public int[] allocateIntArray(int length) { + return allocator.allocateIntArray(length); + } + @Override public void walkObjects(ObjectVisitor visitor) { assert VMOperation.isInProgress() : "prevent other threads from manipulating the metaspace"; diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/metaspace/MetaspaceObjectAllocator.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/metaspace/MetaspaceObjectAllocator.java index 8f7ce1aafce4..e4f404a49b68 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/metaspace/MetaspaceObjectAllocator.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/metaspace/MetaspaceObjectAllocator.java @@ -73,6 +73,11 @@ public byte[] allocateByteArray(int length) { return (byte[]) allocateArrayLikeObject(hub, length); } + public int[] allocateIntArray(int length) { + DynamicHub hub = DynamicHub.fromClass(int[].class); + return (int[]) allocateArrayLikeObject(hub, length); + } + @Uninterruptible(reason = "Holds uninitialized memory.") private Object allocateArrayLikeObject(DynamicHub hub, int arrayLength) { UnsignedWord size = LayoutEncoding.getArrayAllocationSize(hub.getLayoutEncoding(), arrayLength); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/InstanceReferenceMapEncoder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/InstanceReferenceMapEncoder.java index 40c0798d1d7e..f84a827659ce 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/InstanceReferenceMapEncoder.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/InstanceReferenceMapEncoder.java @@ -35,6 +35,7 @@ import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.heap.InstanceReferenceMapDecoder.InstanceReferenceMap; import com.oracle.svm.core.snippets.KnownIntrinsics; +import com.oracle.svm.core.util.DuplicatedInNativeCode; import com.oracle.svm.core.util.VMError; import jdk.graal.compiler.core.common.NumUtil; @@ -56,6 +57,7 @@ * */ public class InstanceReferenceMapEncoder extends ReferenceMapEncoder { + @DuplicatedInNativeCode // public static final int REFERENCE_MAP_COMPRESSED_OFFSET_SHIFT = 2; public static final int MAP_HEADER_SIZE = 4; 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 f1797fd7a691..c7593d03b064 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 @@ -285,7 +285,8 @@ public final class DynamicHub implements AnnotatedElement, java.lang.reflect.Typ /** * Array containing this type's type check id information. During a type check, these slots are - * searched for a matching typeID. + * searched for a matching typeID. This array may be used by the garbage collector and therefore + * needs to live in the image heap or {@link Metaspace}. */ @UnknownObjectField(availability = AfterHostedUniverse.class)// private int[] openTypeWorldTypeCheckSlots; @@ -306,7 +307,8 @@ public final class DynamicHub implements AnnotatedElement, java.lang.reflect.Typ /** * HashTable used for interface hashing under open type world if * {@link SubstrateOptions#useInterfaceHashing()} is enabled. See TypeCheckBuilder for a general - * documentation. + * documentation. This array may be used by the garbage collector and therefore needs to live in + * the image heap or {@link Metaspace}. */ @UnknownObjectField(availability = AfterHostedUniverse.class)// private int[] openTypeWorldInterfaceHashTable; @@ -480,8 +482,8 @@ public static DynamicHub allocate(String name, DynamicHub superHub, Object inter short numClassTypes, short typeIDDepth, short numIterableInterfaceTypes, - int[] openTypeWorldTypeCheckSlots, - int[] openTypeWorldInterfaceHashTable, + int[] typeCheckSlotsHeapArray, + int[] interfaceHashTableHeapArray, int openTypeWorldInterfaceHashParam, int vTableEntries, int afterFieldsOffset, boolean valueBased) { @@ -585,16 +587,18 @@ public static DynamicHub allocate(String name, DynamicHub superHub, Object inter // GR-61330: only write if the field exists according to analysis // companion.metaType = null; - int referenceMapCompressedOffset = RuntimeInstanceReferenceMapSupport.singleton().getOrCreateReferenceMap(superHub); - // GR-57813 companion.hubMetadata = null; companion.reflectionMetadata = null; + /* Allocate memory in the metaspace and copy data from the Java heap to the metaspace. */ DynamicHub hub = Metaspace.singleton().allocateDynamicHub(vTableEntries); + int[] openTypeWorldTypeCheckSlots = Metaspace.singleton().copyToMetaspace(typeCheckSlotsHeapArray); + int[] openTypeWorldInterfaceHashTable = Metaspace.singleton().copyToMetaspace(interfaceHashTableHeapArray); + int referenceMapCompressedOffset = RuntimeInstanceReferenceMapSupport.singleton().getOrCreateReferenceMap(superHub); - DynamicHubOffsets dynamicHubOffsets = DynamicHubOffsets.singleton(); /* Write fields in defining order. */ + DynamicHubOffsets dynamicHubOffsets = DynamicHubOffsets.singleton(); writeObject(hub, dynamicHubOffsets.getNameOffset(), name); writeByte(hub, dynamicHubOffsets.getHubTypeOffset(), hubType); writeByte(hub, dynamicHubOffsets.getReferenceTypeOffset(), referenceType.getValue()); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/RuntimeInstanceReferenceMapSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/RuntimeInstanceReferenceMapSupport.java index 5486ad0244ec..236254a6ac8f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/RuntimeInstanceReferenceMapSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/RuntimeInstanceReferenceMapSupport.java @@ -106,11 +106,8 @@ private synchronized int putIfAbsent(byte[] newHeapMap) { return toCompressedOffset(existingMetaspaceMapHolder.refMap); } - /* Copy the data to the metaspace. */ - byte[] newMetaspaceMap = Metaspace.singleton().allocateByteArray(newHeapMap.length); - System.arraycopy(newHeapMap, 0, newMetaspaceMap, 0, newHeapMap.length); - - /* Store the new reference map in the hash map. */ + /* Copy the data to the metaspace and store the new reference map in the hash map. */ + byte[] newMetaspaceMap = Metaspace.singleton().copyToMetaspace(newHeapMap); ReferenceMapHolder newMetaspaceMapHolder = new ReferenceMapHolder(newMetaspaceMap); refMaps.put(newMetaspaceMapHolder, newMetaspaceMapHolder); return toCompressedOffset(newMetaspaceMapHolder.refMap); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/metaspace/Metaspace.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/metaspace/Metaspace.java index a7430a48e3af..74c188362ae6 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/metaspace/Metaspace.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/metaspace/Metaspace.java @@ -89,6 +89,21 @@ static boolean isSupported() { /** Allocates a byte array. */ byte[] allocateByteArray(int length); + /** Allocates an int array. */ + int[] allocateIntArray(int length); + + default byte[] copyToMetaspace(byte[] heapArray) { + byte[] result = Metaspace.singleton().allocateByteArray(heapArray.length); + System.arraycopy(heapArray, 0, result, 0, heapArray.length); + return result; + } + + default int[] copyToMetaspace(int[] heapArray) { + int[] result = Metaspace.singleton().allocateIntArray(heapArray.length); + System.arraycopy(heapArray, 0, result, 0, heapArray.length); + return result; + } + /** Walks all metaspace objects. May only be called at a safepoint. */ void walkObjects(ObjectVisitor visitor); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/metaspace/NoMetaspace.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/metaspace/NoMetaspace.java index 1bb518ca0556..3433bfe164e9 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/metaspace/NoMetaspace.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/metaspace/NoMetaspace.java @@ -68,6 +68,11 @@ public byte[] allocateByteArray(int length) { throw VMError.shouldNotReachHere("Must not be called if metaspace support is not available."); } + @Override + public int[] allocateIntArray(int length) { + throw VMError.shouldNotReachHere("Must not be called if metaspace support is not available."); + } + @Override public void walkObjects(ObjectVisitor visitor) { /* Nothing to do. */