From 023f9eca3af54ed5f9be6a65bd71546691fde8c5 Mon Sep 17 00:00:00 2001 From: Vojin Jovanovic Date: Fri, 28 Mar 2025 16:31:50 +0100 Subject: [PATCH] Report user errors for huge relocatable objects in heap --- .../genscavenge/ChunkedImageHeapLayouter.java | 33 +++++++++++++++---- .../SerialAndEpsilonGCOptions.java | 12 +------ 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java index 8a4ab3313d45..c78bb1314e4d 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ChunkedImageHeapLayouter.java @@ -27,6 +27,7 @@ import java.nio.ByteBuffer; import java.util.List; +import org.graalvm.nativeimage.ImageInfo; import org.graalvm.word.UnsignedWord; import com.oracle.svm.core.SubstrateOptions; @@ -41,6 +42,8 @@ import com.oracle.svm.core.image.ImageHeapLayoutInfo; import com.oracle.svm.core.image.ImageHeapLayouter; import com.oracle.svm.core.image.ImageHeapObject; +import com.oracle.svm.core.option.SubstrateOptionsParser; +import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; import jdk.graal.compiler.core.common.NumUtil; @@ -75,6 +78,8 @@ public class ChunkedImageHeapLayouter implements ImageHeapLayouter { private static final int READ_ONLY_HUGE = WRITABLE_HUGE + 1; private static final int PARTITION_COUNT = READ_ONLY_HUGE + 1; + private static final String ALIGNED_HEAP_CHUNK_OPTION = SubstrateOptionsParser.commandArgument(SerialAndEpsilonGCOptions.AlignedHeapChunkSize, "<2^n>"); + private final ChunkedImageHeapPartition[] partitions; private final ImageHeapInfo heapInfo; private final long startOffset; @@ -120,15 +125,21 @@ private ChunkedImageHeapPartition choosePartition(ImageHeapObject info, boolean if (patched) { return getWritablePatched(); } else if (immutable) { - if (hasRelocatables) { - VMError.guarantee(info.getSize() < hugeObjectThreshold, "Objects with relocatable pointers cannot be huge objects"); - return getReadOnlyRelocatable(); - } if (info.getSize() >= hugeObjectThreshold) { - VMError.guarantee(info.getObjectClass() != DynamicHub.class, "Class metadata (dynamic hubs) cannot be huge objects"); + if (hasRelocatables) { + if (info.getObjectClass() == DynamicHub.class) { + throw reportHugeObjectError(info, "Class metadata (dynamic hubs) cannot be huge objects: the dynamic hub %s", info.getObject().toString()); + } + throw reportHugeObjectError(info, "Objects in image heap with relocatable pointers cannot be huge objects. Detected an object of type %s", + info.getObject().getClass().getTypeName()); + } return getReadOnlyHuge(); } - return getReadOnlyRegular(); + if (hasRelocatables) { + return getReadOnlyRelocatable(); + } else { + return getReadOnlyRegular(); + } } else { assert info.getObjectClass() != DynamicHub.class : "Class metadata (dynamic hubs) cannot be writable"; if (info.getSize() >= hugeObjectThreshold) { @@ -138,6 +149,16 @@ private ChunkedImageHeapPartition choosePartition(ImageHeapObject info, boolean } } + private Error reportHugeObjectError(ImageHeapObject info, String objectTypeMsg, String objectText) { + String msg = String.format(objectTypeMsg + " with size %d B and the limit is %d B. Use '%s' to increase GC chunk size to be larger than the object.", + objectText, info.getSize(), hugeObjectThreshold, ALIGNED_HEAP_CHUNK_OPTION); + if (ImageInfo.inImageBuildtimeCode()) { + throw UserError.abort(msg); + } else { + throw VMError.shouldNotReachHere(msg); + } + } + @Override public ImageHeapLayoutInfo layout(ImageHeap imageHeap, int pageSize) { int objectAlignment = ConfigurationValues.getObjectLayout().getAlignment(); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialAndEpsilonGCOptions.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialAndEpsilonGCOptions.java index f9e2f9aa9982..417f10071ceb 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialAndEpsilonGCOptions.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/SerialAndEpsilonGCOptions.java @@ -24,16 +24,12 @@ */ package com.oracle.svm.core.genscavenge; -import org.graalvm.collections.EconomicMap; - import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.option.NotifyGCRuntimeOptionKey; import com.oracle.svm.core.option.RuntimeOptionKey; import com.oracle.svm.core.util.UserError; - import jdk.graal.compiler.options.Option; -import jdk.graal.compiler.options.OptionKey; import jdk.graal.compiler.options.OptionType; /** Common options that can be specified for both the serial and the epsilon GC. */ @@ -45,13 +41,7 @@ public final class SerialAndEpsilonGCOptions { public static final RuntimeOptionKey MaximumYoungGenerationSizePercent = new NotifyGCRuntimeOptionKey<>(10, SerialAndEpsilonGCOptions::validateSerialOrEpsilonRuntimeOption); @Option(help = "The size of an aligned chunk. Serial and epsilon GC only.", type = OptionType.Expert) // - public static final HostedOptionKey AlignedHeapChunkSize = new HostedOptionKey<>(512 * 1024L, SerialAndEpsilonGCOptions::validateSerialOrEpsilonHostedOption) { - @Override - protected void onValueUpdate(EconomicMap, Object> values, Long oldValue, Long newValue) { - int multiple = 4096; - UserError.guarantee(newValue > 0 && newValue % multiple == 0, "%s value must be a multiple of %d.", getName(), multiple); - } - }; + public static final HostedOptionKey AlignedHeapChunkSize = new HostedOptionKey<>(512 * 1024L, SerialAndEpsilonGCOptions::validateSerialOrEpsilonHostedOption); /* * This should be a fraction of the size of an aligned chunk, else large small arrays will not