From 2aa101310ae62324c11880af9bcf3f5b49b483e7 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Tue, 8 Apr 2025 13:33:21 +0200 Subject: [PATCH] Fix heap dumping issues. --- .../compiler/libgraal/LibGraalSupportImpl.java | 6 +++--- .../jdk/graal/compiler/core/GraalCompiler.java | 2 +- .../src/jdk/graal/compiler/phases/BasePhase.java | 8 ++++---- .../compiler/serviceprovider/GraalServices.java | 5 ++--- .../src/org/graalvm/nativeimage/VMRuntime.java | 5 +---- .../com/oracle/svm/core/VMInspectionOptions.java | 16 ++++++++-------- .../svm/core/heap/dump/HeapDumpSupportImpl.java | 7 ++++++- .../graal/substitutions/GraalSubstitutions.java | 10 +++++++--- .../oracle/svm/hosted/heap/HeapDumpFeature.java | 13 ++++++------- 9 files changed, 38 insertions(+), 34 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/LibGraalSupportImpl.java b/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/LibGraalSupportImpl.java index 1acc94f8a7ee..d29d836e7159 100644 --- a/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/LibGraalSupportImpl.java +++ b/compiler/src/jdk.graal.compiler.libgraal/src/jdk/graal/compiler/libgraal/LibGraalSupportImpl.java @@ -35,7 +35,6 @@ import java.util.Map; import java.util.function.Supplier; -import jdk.graal.compiler.options.OptionValues; import org.graalvm.collections.EconomicMap; import org.graalvm.collections.EconomicSet; import org.graalvm.collections.MapCursor; @@ -49,13 +48,14 @@ import org.graalvm.nativeimage.RuntimeOptions; import org.graalvm.nativeimage.StackValue; import org.graalvm.nativeimage.VMRuntime; -import org.graalvm.nativeimage.libgraal.hosted.LibGraalLoader; import org.graalvm.nativeimage.libgraal.LibGraalRuntime; import org.graalvm.nativeimage.libgraal.hosted.GlobalData; +import org.graalvm.nativeimage.libgraal.hosted.LibGraalLoader; import jdk.graal.compiler.core.common.LibGraalSupport; import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.libgraal.truffle.HSTruffleCompilerRuntime; +import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.graal.compiler.word.Word; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; @@ -162,7 +162,7 @@ public void processReferences() { } @Override - public void dumpHeap(String outputFile, boolean live) throws IOException { + public void dumpHeap(String outputFile, boolean live) throws IOException, UnsupportedOperationException { VMRuntime.dumpHeap(outputFile, live); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/GraalCompiler.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/GraalCompiler.java index 8538ba97901b..8cd5852c6b29 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/GraalCompiler.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/GraalCompiler.java @@ -175,7 +175,7 @@ private static void checkForHeapDump(Request re try { final String path = debug.getDumpPath(".compilation.hprof", false); GraalServices.dumpHeap(path, false); - } catch (IOException e) { + } catch (IOException | UnsupportedOperationException e) { e.printStackTrace(System.out); } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/BasePhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/BasePhase.java index 852e595ecd24..e8352f5e8d53 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/BasePhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/BasePhase.java @@ -34,11 +34,9 @@ import java.util.Optional; import java.util.regex.Pattern; -import jdk.graal.compiler.core.GraalCompilerOptions; -import jdk.graal.compiler.debug.GraphFilter; -import jdk.graal.compiler.serviceprovider.GraalServices; import org.graalvm.collections.EconomicMap; +import jdk.graal.compiler.core.GraalCompilerOptions; import jdk.graal.compiler.core.common.util.CompilationAlarm; import jdk.graal.compiler.debug.CounterKey; import jdk.graal.compiler.debug.DebugCloseable; @@ -46,6 +44,7 @@ import jdk.graal.compiler.debug.DebugContext.CompilerPhaseScope; import jdk.graal.compiler.debug.DebugOptions; import jdk.graal.compiler.debug.GraalError; +import jdk.graal.compiler.debug.GraphFilter; import jdk.graal.compiler.debug.MemUseTrackerKey; import jdk.graal.compiler.debug.TTY; import jdk.graal.compiler.debug.TimerKey; @@ -65,6 +64,7 @@ import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.phases.contract.NodeCostUtil; import jdk.graal.compiler.phases.contract.PhaseSizeContract; +import jdk.graal.compiler.serviceprovider.GraalServices; import jdk.vm.ci.meta.SpeculationLog; /** @@ -506,7 +506,7 @@ public final void apply(final StructuredGraph graph, final C context, final bool try { final String path = debug.getDumpPath("_" + getName() + ".hprof", false); GraalServices.dumpHeap(path, false); - } catch (IOException e) { + } catch (IOException | UnsupportedOperationException e) { e.printStackTrace(System.out); } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/serviceprovider/GraalServices.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/serviceprovider/GraalServices.java index 9c0f04a5b0f1..b5501023da55 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/serviceprovider/GraalServices.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/serviceprovider/GraalServices.java @@ -41,10 +41,9 @@ import jdk.graal.compiler.core.ArchitectureSpecific; import jdk.graal.compiler.core.common.LibGraalSupport; import jdk.graal.compiler.core.common.NativeImageSupport; -import jdk.vm.ci.code.Architecture; - import jdk.graal.compiler.debug.GraalError; import jdk.internal.misc.VM; +import jdk.vm.ci.code.Architecture; import jdk.vm.ci.meta.EncodedSpeculationReason; import jdk.vm.ci.meta.SpeculationLog.SpeculationReason; import jdk.vm.ci.runtime.JVMCI; @@ -498,7 +497,7 @@ public static List getInputArguments() { * @throws IOException if an IO error occurred dyring dumping * @throws UnsupportedOperationException if this operation is not supported. */ - public static void dumpHeap(String outputFile, boolean live) throws IOException { + public static void dumpHeap(String outputFile, boolean live) throws IOException, UnsupportedOperationException { LibGraalSupport libgraal = LibGraalSupport.INSTANCE; if (libgraal != null) { libgraal.dumpHeap(outputFile, live); diff --git a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/VMRuntime.java b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/VMRuntime.java index 983207c0dbcc..9c36c0387577 100644 --- a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/VMRuntime.java +++ b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/VMRuntime.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -86,9 +86,6 @@ public static void shutdown() { * @since 20.1 */ public static void dumpHeap(String outputFile, boolean live) throws IOException { - if (!ImageSingletons.contains(HeapDumpSupport.class)) { - throw new UnsupportedOperationException(); - } ImageSingletons.lookup(HeapDumpSupport.class).dumpHeap(outputFile, live); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/VMInspectionOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/VMInspectionOptions.java index 114c811bafa1..6b7263118918 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/VMInspectionOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/VMInspectionOptions.java @@ -78,10 +78,6 @@ public final class VMInspectionOptions { ", '" + MONITORING_JCMD_NAME + "' (experimental)" + ", or '" + MONITORING_ALL_NAME + "' (deprecated behavior: defaults to '" + MONITORING_ALL_NAME + "' if no argument is provided)"; - static { - assert MONITORING_ALL_VALUES.stream().allMatch(v -> MONITORING_DEFAULT_NAME.equals(v) || MONITORING_ALLOWED_VALUES_TEXT.contains(v)) : "A value is missing in the user-facing help text"; - } - @APIOption(name = ENABLE_MONITORING_OPTION, defaultValue = MONITORING_DEFAULT_NAME) // @Option(help = "Enable monitoring features that allow the VM to be inspected at run time. Comma-separated list can contain " + MONITORING_ALLOWED_VALUES_TEXT + ". " + "For example: '--" + ENABLE_MONITORING_OPTION + "=" + MONITORING_HEAPDUMP_NAME + "," + MONITORING_JFR_NAME + "'.", type = OptionType.User) // @@ -92,6 +88,10 @@ public final class VMInspectionOptions { @Option(help = "Dumps all runtime compiled methods on SIGUSR2.", type = OptionType.User) // public static final HostedOptionKey DumpRuntimeCompilationOnSignal = new HostedOptionKey<>(false, VMInspectionOptions::notSupportedOnWindows); + static { + assert MONITORING_ALL_VALUES.stream().allMatch(v -> MONITORING_DEFAULT_NAME.equals(v) || MONITORING_ALLOWED_VALUES_TEXT.contains(v)) : "A value is missing in the user-facing help text"; + } + @Platforms(Platform.HOSTED_ONLY.class) private static void notSupportedOnWindows(HostedOptionKey optionKey) { if (Platform.includedIn(WINDOWS.class) && optionKey.getValue()) { @@ -136,8 +136,9 @@ private static String getDefaultMonitoringCommandArgument() { } @Fold - public static String getHeapDumpCommandArgument() { - return SubstrateOptionsParser.commandArgument(EnableMonitoringFeatures, MONITORING_HEAPDUMP_NAME); + public static String getHeapDumpNotSupportedMessage() { + return "Unable to dump heap. Heap dumping is only supported on Linux and MacOS for native binaries built with '" + + SubstrateOptionsParser.commandArgument(EnableMonitoringFeatures, MONITORING_HEAPDUMP_NAME) + "'."; } private static Set getEnabledMonitoringFeatures() { @@ -167,8 +168,7 @@ public static boolean dumpImageHeap() { System.out.println("Heap dump created at '" + absoluteHeapDumpPath + "'."); return true; } else { - System.out.println("Unable to dump heap. Heap dumping is only supported on Linux and MacOS for native executables built with '" + - VMInspectionOptions.getHeapDumpCommandArgument() + "'."); + System.out.println(VMInspectionOptions.getHeapDumpNotSupportedMessage()); return false; } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/dump/HeapDumpSupportImpl.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/dump/HeapDumpSupportImpl.java index b4f26a9ff46d..b9c9e76a1b56 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/dump/HeapDumpSupportImpl.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/dump/HeapDumpSupportImpl.java @@ -28,7 +28,6 @@ import java.io.IOException; -import jdk.graal.compiler.word.Word; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.StackValue; @@ -39,6 +38,7 @@ import org.graalvm.word.Pointer; import com.oracle.svm.core.UnmanagedMemoryUtil; +import com.oracle.svm.core.VMInspectionOptions; import com.oracle.svm.core.heap.GCCause; import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.RestrictHeapAccess; @@ -55,6 +55,7 @@ import com.oracle.svm.core.util.TimeUtils; import jdk.graal.compiler.api.replacements.Fold; +import jdk.graal.compiler.word.Word; public class HeapDumpSupportImpl extends HeapDumping { private final HeapDumpWriter writer; @@ -133,6 +134,10 @@ private void dumpHeapOnOutOfMemoryError0() { @Override public void dumpHeap(String filename, boolean gcBefore, boolean overwrite) throws IOException { + if (!RawFileOperationSupport.isPresent()) { + throw new UnsupportedOperationException(VMInspectionOptions.getHeapDumpNotSupportedMessage()); + } + FileCreationMode creationMode = overwrite ? FileCreationMode.CREATE_OR_REPLACE : FileCreationMode.CREATE; RawFileDescriptor fd = getFileSupport().create(filename, creationMode, RawFileOperationSupport.FileAccessMode.READ_WRITE); if (!getFileSupport().isValid(fd)) { diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/substitutions/GraalSubstitutions.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/substitutions/GraalSubstitutions.java index 5a9a74435a26..d04bd54ce9d2 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/substitutions/GraalSubstitutions.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/substitutions/GraalSubstitutions.java @@ -34,8 +34,6 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import com.oracle.svm.core.Isolates; -import jdk.graal.compiler.graph.Edges; import org.graalvm.collections.EconomicMap; import org.graalvm.collections.EconomicSet; import org.graalvm.collections.Equivalence; @@ -44,7 +42,9 @@ import org.graalvm.nativeimage.VMRuntime; import org.graalvm.nativeimage.hosted.FieldValueTransformer; +import com.oracle.svm.core.Isolates; import com.oracle.svm.core.SubstrateTargetDescription; +import com.oracle.svm.core.VMInspectionOptions; import com.oracle.svm.core.annotate.Alias; import com.oracle.svm.core.annotate.Inject; import com.oracle.svm.core.annotate.InjectAccessors; @@ -74,6 +74,7 @@ import jdk.graal.compiler.debug.MetricKey; import jdk.graal.compiler.debug.TTY; import jdk.graal.compiler.debug.TimeSource; +import jdk.graal.compiler.graph.Edges; import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.lir.gen.ArithmeticLIRGeneratorTool; import jdk.graal.compiler.lir.phases.LIRPhase; @@ -232,7 +233,10 @@ final class Target_jdk_graal_compiler_serviceprovider_GraalServices { * {@code jdk.graal.compiler.management.JMXServiceProvider}. */ @Substitute - public static void dumpHeap(String outputFile, boolean live) throws IOException { + public static void dumpHeap(String outputFile, boolean live) throws IOException, UnsupportedOperationException { + if (!VMInspectionOptions.hasHeapDumpSupport()) { + throw new UnsupportedOperationException(VMInspectionOptions.getHeapDumpNotSupportedMessage()); + } VMRuntime.dumpHeap(outputFile, live); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/HeapDumpFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/HeapDumpFeature.java index 02e3e51a8637..10b8ffcee61f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/HeapDumpFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/HeapDumpFeature.java @@ -32,7 +32,6 @@ import org.graalvm.collections.EconomicMap; import org.graalvm.collections.MapCursor; import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.nativeimage.impl.HeapDumpSupport; @@ -69,18 +68,18 @@ public class HeapDumpFeature implements InternalFeature { @Override public boolean isInConfiguration(IsInConfigurationAccess access) { /* - * Include the feature unconditionally (all platforms except Windows - even unknown - * platforms). The code and all its data are only present in the final image if the heap - * dumping infrastructure is actually called by any code (e.g., VMRuntime.dumpHeap(...) or - * --enable-monitoring=heapdump). + * Include the feature unconditionally (all platforms, even unknown platforms). The static + * analysis ensures that the code and all its data are only present in the final image if + * the heap dumping infrastructure is actually called by any code (e.g., + * VMRuntime.dumpHeap(...) or --enable-monitoring=heapdump). */ - return !Platform.includedIn(Platform.WINDOWS.class); + return true; } @Override public void duringSetup(DuringSetupAccess access) { HeapDumpMetadata metadata = new HeapDumpMetadata(); - HeapDumping heapDumpSupport = new HeapDumpSupportImpl(metadata); + HeapDumpSupportImpl heapDumpSupport = new HeapDumpSupportImpl(metadata); ImageSingletons.add(HeapDumpSupport.class, heapDumpSupport); ImageSingletons.add(HeapDumping.class, heapDumpSupport);