From 75ab50b30062a0b53354e5ee1bb8e4e47623bcbc Mon Sep 17 00:00:00 2001 From: Yudi Zheng Date: Thu, 27 Jul 2023 16:57:32 +0200 Subject: [PATCH 01/78] respect maximum eden size in AggressiveShrinkCollectionPolicy. --- .../AggressiveShrinkCollectionPolicy.java | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AggressiveShrinkCollectionPolicy.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AggressiveShrinkCollectionPolicy.java index a7132140e4b0..5c006955e4e9 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AggressiveShrinkCollectionPolicy.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/AggressiveShrinkCollectionPolicy.java @@ -29,7 +29,7 @@ import org.graalvm.word.WordFactory; import com.oracle.svm.core.heap.GCCause; -import com.oracle.svm.core.option.HostedOptionKey; +import com.oracle.svm.core.option.RuntimeOptionKey; import com.oracle.svm.core.util.UnsignedUtils; /** @@ -41,14 +41,16 @@ class AggressiveShrinkCollectionPolicy extends AdaptiveCollectionPolicy { public static final class Options { @Option(help = "Ratio of used bytes to total allocated bytes for eden space. Setting it to a smaller value " + "will trade more triggered hinted GCs for less resident set size.") // - public static final HostedOptionKey UsedEdenProportionThreshold = new HostedOptionKey<>(0.75D); + public static final RuntimeOptionKey UsedEdenProportionThreshold = new RuntimeOptionKey<>(0.75D); @Option(help = "Soft upper limit for used eden size. The hinted GC will be performed if the used eden size " + "exceeds this value.") // - public static final HostedOptionKey ExpectedEdenSize = new HostedOptionKey<>(32 * 1024 * 1024); + public static final RuntimeOptionKey ExpectedEdenSize = new RuntimeOptionKey<>(32L * 1024L * 1024L); } - protected static final UnsignedWord INITIAL_HEAP_SIZE = WordFactory.unsigned(64 * 1024 * 1024); - protected static final UnsignedWord FULL_GC_BONUS = WordFactory.unsigned(2 * 1024 * 1024); + protected static final UnsignedWord INITIAL_HEAP_SIZE = WordFactory.unsigned(64L * 1024L * 1024L); + protected static final UnsignedWord FULL_GC_BONUS = WordFactory.unsigned(2L * 1024L * 1024L); + + protected static final UnsignedWord MAXIMUM_HEAP_SIZE = WordFactory.unsigned(16L * 1024L * 1024L * 1024L); private UnsignedWord sizeBefore = WordFactory.zero(); private GCCause lastGCCause = null; @@ -73,7 +75,7 @@ public boolean shouldCollectOnRequest(GCCause cause, boolean fullGC) { // memory usage point. edenUsedBytes = edenUsedBytes.add(FULL_GC_BONUS); } - return edenUsedBytes.aboveOrEqual(Options.ExpectedEdenSize.getValue()) || + return edenUsedBytes.aboveOrEqual(WordFactory.unsigned(Options.ExpectedEdenSize.getValue())) || (UnsignedUtils.toDouble(edenUsedBytes) / UnsignedUtils.toDouble(edenSize) >= Options.UsedEdenProportionThreshold.getValue()); } return super.shouldCollectOnRequest(cause, fullGC); @@ -84,6 +86,15 @@ protected UnsignedWord getInitialHeapSize() { return INITIAL_HEAP_SIZE; } + @Override + public UnsignedWord getMaximumHeapSize() { + UnsignedWord initialSetup = super.getMaximumHeapSize(); + if (initialSetup.aboveThan(MAXIMUM_HEAP_SIZE)) { + return MAXIMUM_HEAP_SIZE; + } + return initialSetup; + } + @Override public void onCollectionBegin(boolean completeCollection, long requestingNanoTime) { sizeBefore = GCImpl.getChunkBytes(); @@ -125,7 +136,10 @@ protected void computeEdenSpaceSize(boolean completeCollection, GCCause cause) { } else { UnsignedWord sizeAfter = GCImpl.getChunkBytes(); if (sizeBefore.notEqual(0) && sizeBefore.belowThan(sizeAfter.multiply(2))) { - edenSize = alignUp(edenSize.multiply(2)); + UnsignedWord newEdenSize = UnsignedUtils.min(getMaximumEdenSize(), alignUp(edenSize.multiply(2))); + if (edenSize.belowThan(newEdenSize)) { + edenSize = newEdenSize; + } } else { super.computeEdenSpaceSize(completeCollection, cause); } From 8b3a0516b351f23c425a23c1dd06aa4cc9c5f652 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Mon, 16 Oct 2023 17:26:40 +0200 Subject: [PATCH 02/78] Improve OutOfMemoryError messages. (cherry picked from commit b7c0558d04f192df68f2beaba1cb8d9131f3ebbe) --- .../src/com/oracle/svm/core/heap/OutOfMemoryUtil.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/OutOfMemoryUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/OutOfMemoryUtil.java index 86fb9c99d2d3..579c8e015d8e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/OutOfMemoryUtil.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/OutOfMemoryUtil.java @@ -30,8 +30,13 @@ import com.oracle.svm.core.log.Log; import com.oracle.svm.core.util.VMError; +/** + * This class must be used for {@link OutOfMemoryError}s that are thrown because the VM is out of + * Java heap memory. Other {@link OutOfMemoryError}s (e.g., when we run out of native memory) can be + * thrown directly. + */ public class OutOfMemoryUtil { - private static final OutOfMemoryError OUT_OF_MEMORY_ERROR = new OutOfMemoryError("Garbage-collected heap size exceeded."); + private static final OutOfMemoryError OUT_OF_MEMORY_ERROR = new OutOfMemoryError("Garbage-collected heap size exceeded. Consider increasing the maximum Java heap size, for example with '-Xmx'."); @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Can't allocate when out of memory.") public static OutOfMemoryError heapSizeExceeded() { From 2532d1970764143207a45de8878bb7d9bdf44e5c Mon Sep 17 00:00:00 2001 From: Michal Karm Babacek Date: Thu, 26 Oct 2023 11:59:01 +0200 Subject: [PATCH 03/78] Fixes issue-7652 for epsilon gc (cherry picked from commit c36bf4354b9b47d7ad26fd39b8360498ac8283a7) --- .../src/com/oracle/svm/core/genscavenge/HeapImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 f41076dd6ed1..3ff72c4c8549 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 @@ -689,7 +689,7 @@ public long getThreadAllocatedMemory(IsolateThread thread) { @Override @Uninterruptible(reason = "Ensure that no GC can occur between modification of the object and this call.", callerMustBe = true) public void dirtyAllReferencesOf(Object obj) { - if (obj != null) { + if (SubstrateOptions.useRememberedSet() && obj != null) { ForcedSerialPostWriteBarrier.force(OffsetAddressNode.address(obj, 0), false); } } From c8fb366c16f6ee4264854b0e207a5aed5296a1b5 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Wed, 6 Dec 2023 14:40:45 +0100 Subject: [PATCH 04/78] Remove broken method VMError.shouldNotReachHereAtRuntime(). --- .../src/com/oracle/svm/core/util/VMError.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/VMError.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/VMError.java index 10335e80140b..bbee4ee3dae2 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/VMError.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/VMError.java @@ -64,9 +64,6 @@ public static final class HostedError extends Error { } - public static final String msgShouldNotReachHere = "should not reach here"; - public static final String msgShouldNotReachHereAtRuntime = msgShouldNotReachHere + ": this code is expected to be unreachable at runtime"; - public static RuntimeException shouldNotReachHere() { throw new HostedError("should not reach here"); } @@ -83,13 +80,6 @@ public static RuntimeException shouldNotReachHere(String msg, Throwable cause) { throw new HostedError(msg, cause); } - /** - * A hardcoded list of options (if, switch) did not handle the case actually provided. - */ - public static RuntimeException shouldNotReachHereAtRuntime() { - throw new HostedError(msgShouldNotReachHereAtRuntime); - } - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static void guarantee(boolean condition) { if (!condition) { From 634e1d78301237ddad70085cc6a44f442d8310fc Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Tue, 12 Dec 2023 07:53:35 +0000 Subject: [PATCH 05/78] update to jvmci-23.0-b26 --- common.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common.json b/common.json index 38f6d23a3c5d..7629e2a07944 100644 --- a/common.json +++ b/common.json @@ -14,9 +14,9 @@ "labsjdk-ce-17": {"name": "labsjdk", "version": "ce-17.0.9+9-jvmci-23.0-b22", "platformspecific": true }, "labsjdk-ce-17Debug": {"name": "labsjdk", "version": "ce-17.0.9+9-jvmci-23.0-b22-debug", "platformspecific": true }, "labsjdk-ce-17-llvm": {"name": "labsjdk", "version": "ce-17.0.9+9-jvmci-23.0-b22-sulong", "platformspecific": true }, - "labsjdk-ee-17": {"name": "labsjdk", "version": "ee-17.0.10+9-jvmci-23.0-b25", "platformspecific": true }, - "labsjdk-ee-17Debug": {"name": "labsjdk", "version": "ee-17.0.10+9-jvmci-23.0-b25-debug", "platformspecific": true }, - "labsjdk-ee-17-llvm": {"name": "labsjdk", "version": "ee-17.0.10+9-jvmci-23.0-b25-sulong", "platformspecific": true }, + "labsjdk-ee-17": {"name": "labsjdk", "version": "ee-17.0.10+10-jvmci-23.0-b26", "platformspecific": true }, + "labsjdk-ee-17Debug": {"name": "labsjdk", "version": "ee-17.0.10+10-jvmci-23.0-b26-debug", "platformspecific": true }, + "labsjdk-ee-17-llvm": {"name": "labsjdk", "version": "ee-17.0.10+10-jvmci-23.0-b26-sulong", "platformspecific": true }, "oraclejdk19": {"name": "jpg-jdk", "version": "19", "build_id": "26", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, "labsjdk-ce-19": {"name": "labsjdk", "version": "ce-19.0.1+10-jvmci-23.0-b04", "platformspecific": true }, From 394f15dc75443bc6965f892f87a9698d18188419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C3=B6=20Barany?= Date: Mon, 18 Dec 2023 11:30:27 +0100 Subject: [PATCH 06/78] Fix intrinsic frame states --- .../meta/HotSpotGraphBuilderPlugins.java | 11 +++++----- .../graphbuilderconf/GraphBuilderContext.java | 20 +++++++++++++------ .../StandardGraphBuilderPlugins.java | 10 +++++++++- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java index 82805b18fc98..94cea781e5fe 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java @@ -540,7 +540,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec ValueNode valueLength = b.add(new ArrayLengthNode(value)); ValueNode limit = b.add(new SubNode(valueLength, length)); helper.intrinsicRangeCheck(srcBegin, Condition.GT, limit); - ValueNode newArray = b.add(new NewArrayNode(b.getMetaAccess().lookupJavaType(Byte.TYPE), b.add(new LeftShiftNode(length, ConstantNode.forInt(1))), false)); + ValueNode newArray = new NewArrayNode(b.getMetaAccess().lookupJavaType(Byte.TYPE), b.add(new LeftShiftNode(length, ConstantNode.forInt(1))), false); b.addPush(JavaKind.Object, newArray); // The stateAfter should include the value pushed, so push it first and then // perform the call that fills in the array. @@ -963,7 +963,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec int byteArrayBaseOffset = metaAccess.getArrayBaseOffset(JavaKind.Byte); ComputeObjectAddressNode srcAddress = b.add(new ComputeObjectAddressNode(src, ConstantNode.forInt(byteArrayBaseOffset))); ComputeObjectAddressNode dstAddress = b.add(new ComputeObjectAddressNode(dst, ConstantNode.forInt(byteArrayBaseOffset))); - ForeignCallNode call = b.add(new ForeignCallNode(BASE64_DECODE_BLOCK, srcAddress, sp, sl, dstAddress, dp, isURL, isMime)); + ForeignCallNode call = new ForeignCallNode(BASE64_DECODE_BLOCK, srcAddress, sp, sl, dstAddress, dp, isURL, isMime); b.addPush(JavaKind.Int, call); return true; } @@ -976,7 +976,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec int byteArrayBaseOffset = metaAccess.getArrayBaseOffset(JavaKind.Byte); ComputeObjectAddressNode srcAddress = b.add(new ComputeObjectAddressNode(src, ConstantNode.forInt(byteArrayBaseOffset))); ComputeObjectAddressNode dstAddress = b.add(new ComputeObjectAddressNode(dst, ConstantNode.forInt(byteArrayBaseOffset))); - ForeignCallNode call = b.add(new ForeignCallNode(BASE64_DECODE_BLOCK, srcAddress, sp, sl, dstAddress, dp, isURL)); + ForeignCallNode call = new ForeignCallNode(BASE64_DECODE_BLOCK, srcAddress, sp, sl, dstAddress, dp, isURL); b.addPush(JavaKind.Int, call); return true; } @@ -1075,7 +1075,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec ValueNode stateStart = helper.arrayStart(stateNotNull, JavaKind.Int); ValueNode resultStart = helper.arrayStart(resultNotNull, JavaKind.Byte); - ForeignCallNode call = b.add(new ForeignCallNode(CHACHA20Block, stateStart, resultStart)); + ForeignCallNode call = new ForeignCallNode(CHACHA20Block, stateStart, resultStart); b.addPush(JavaKind.Int, call); } return true; @@ -1160,10 +1160,11 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec ValueNode instanceSize = b.add(AndNode.create(layoutHelper, ConstantNode.forInt(~(Long.BYTES - 1)), NodeView.DEFAULT)); b.add(new IfNode(isArray, arrayLengthNode, instanceBranch, BranchProbabilityData.unknown())); - MergeNode merge = b.add(new MergeNode()); + MergeNode merge = b.append(new MergeNode()); merge.addForwardEnd(arrayBranch); merge.addForwardEnd(instanceBranch); b.addPush(JavaKind.Long, SignExtendNode.create(new ValuePhiNode(StampFactory.positiveInt(), merge, new ValueNode[]{arraySizeMasked, instanceSize}), 64, NodeView.DEFAULT)); + b.setStateAfter(merge); } return true; } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java index 0dc66c98eddb..b97df48e8533 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java @@ -112,7 +112,10 @@ default ValueNode[] popArguments(int argSize) { /** * Adds a node and all its inputs to the graph. If the node is in the graph, returns * immediately. If the node is a {@link StateSplit} with a null - * {@linkplain StateSplit#stateAfter() frame state} , the frame state is initialized. + * {@linkplain StateSplit#stateAfter() frame state} , the frame state is initialized. A + * {@link StateSplit} that will be pushed to the stack using + * {@link #addPush(JavaKind, ValueNode)} should not be added using this method, + * otherwise its frame state will be initialized with an incorrect stack effect. * * @param value the value to add to the graph. The {@code value.getJavaKind()} kind is used when * type checking this operation. @@ -123,7 +126,7 @@ default T add(T value) { assert !(value instanceof StateSplit) || ((StateSplit) value).stateAfter() != null; return value; } - return GraphBuilderContextUtil.setStateAfterIfNecessary(this, append(value)); + return setStateAfterIfNecessary(this, append(value)); } default ValueNode addNonNullCast(ValueNode value) { @@ -141,7 +144,9 @@ default ValueNode addNonNullCast(ValueNode value) { /** * Adds a node with a non-void kind to the graph, pushes it to the stack. If the returned node * is a {@link StateSplit} with a null {@linkplain StateSplit#stateAfter() frame state}, the - * frame state is initialized. + * frame state is initialized. A {@link StateSplit} added using this method should not + * be added using {@link #add(ValueNode)} beforehand, otherwise its frame state will be + * initialized with an incorrect stack effect. * * @param kind the kind to use when type checking this operation * @param value the value to add to the graph and push to the stack @@ -150,7 +155,7 @@ default ValueNode addNonNullCast(ValueNode value) { default T addPush(JavaKind kind, T value) { T equivalentValue = value.graph() != null ? value : append(value); push(kind, equivalentValue); - return GraphBuilderContextUtil.setStateAfterIfNecessary(this, equivalentValue); + return setStateAfterIfNecessary(this, equivalentValue); } /** @@ -515,15 +520,18 @@ default void replacePluginWithException(GeneratedInvocationPlugin plugin, Resolv PluginReplacementWithExceptionNode.ReplacementWithExceptionFunction replacementFunction) { throw GraalError.unimplemented(); // ExcludeFromJacocoGeneratedReport } -} -class GraphBuilderContextUtil { static T setStateAfterIfNecessary(GraphBuilderContext b, T value) { if (value instanceof StateSplit) { StateSplit stateSplit = (StateSplit) value; + FrameState oldState = stateSplit.stateAfter(); if (stateSplit.stateAfter() == null && (stateSplit.hasSideEffect() || stateSplit instanceof AbstractMergeNode)) { b.setStateAfter(stateSplit); } + FrameState newState = stateSplit.stateAfter(); + GraalError.guarantee(oldState == null || oldState.equals(newState), + "graph builder changed existing state on %s from %s to %s, this indicates multiple calls to add() or addPush() for one node", + stateSplit, oldState, newState); } return value; } diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java index 5439cafd59e1..f9e9db445898 100644 --- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java +++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java @@ -2317,8 +2317,16 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode len, ValueNode z, ValueNode zlen) { try (InvocationPluginHelper helper = new InvocationPluginHelper(b, targetMethod)) { - b.add(new BigIntegerSquareToLenNode(helper.arrayStart(x, JavaKind.Int), len, helper.arrayStart(z, JavaKind.Int), zlen)); + /* + * The intrinsified method takes the z array as a parameter, performs + * side-effects on its contents, then returns the same reference to z. Our + * intrinsic only performs the side-effects, we set z as the result directly. + * The stateAfter for the intrinsic should include this value on the stack, so + * push it first and only compute the state afterwards. + */ + BigIntegerSquareToLenNode squareToLen = b.append(new BigIntegerSquareToLenNode(helper.arrayStart(x, JavaKind.Int), len, helper.arrayStart(z, JavaKind.Int), zlen)); b.push(JavaKind.Object, z); + b.setStateAfter(squareToLen); return true; } } From a79ef82ba9443cf4de50f3fe868604fe4994afa3 Mon Sep 17 00:00:00 2001 From: Raphael Mosaner Date: Mon, 18 Dec 2023 18:46:38 +0100 Subject: [PATCH 07/78] [GR-49481] Remove explicit null check exceptions from genCheckCast and genInstanceof. (cherry picked from commit 020b17fe9492d371d89c97c58e4b861d3659cc97) --- .../src/org/graalvm/compiler/java/BytecodeParser.java | 4 ++-- .../nodes/graphbuilderconf/GraphBuilderContext.java | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/compiler/src/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java b/compiler/src/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java index 6c7b972246eb..e3984e817e49 100644 --- a/compiler/src/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java +++ b/compiler/src/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java @@ -4406,7 +4406,7 @@ protected void genCheckCast(ResolvedJavaType resolvedType, ValueNode objectIn) { if (profile.getNullSeen().isFalse()) { SpeculationLog.Speculation speculation = mayUseTypeProfile(); if (speculation != null) { - object = nullCheckedValue(object); + object = addNonNullCast(object, InvalidateReprofile); ResolvedJavaType singleType = profile.asSingleType(); if (singleType != null && checkedType.getType().isAssignableFrom(singleType)) { LogicNode typeCheck = append(createInstanceOf(TypeReference.createExactTrusted(singleType), object, profile)); @@ -4469,7 +4469,7 @@ protected void genInstanceOf(ResolvedJavaType resolvedType, ValueNode objectIn) LogicNode instanceOfNode = null; if (profile != null) { if (profile.getNullSeen().isFalse()) { - object = nullCheckedValue(object); + object = addNonNullCast(object, InvalidateReprofile); boolean createGuard = true; ResolvedJavaType singleType = profile.asSingleType(); if (singleType != null) { diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java index 0dc66c98eddb..878815ff766f 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java @@ -127,12 +127,16 @@ default T add(T value) { } default ValueNode addNonNullCast(ValueNode value) { + return addNonNullCast(value, DeoptimizationAction.None); + } + + default ValueNode addNonNullCast(ValueNode value, DeoptimizationAction action) { AbstractPointerStamp valueStamp = (AbstractPointerStamp) value.stamp(NodeView.DEFAULT); if (valueStamp.nonNull()) { return value; } else { LogicNode isNull = add(IsNullNode.create(value)); - FixedGuardNode fixedGuard = add(new FixedGuardNode(isNull, DeoptimizationReason.NullCheckException, DeoptimizationAction.None, true)); + FixedGuardNode fixedGuard = add(new FixedGuardNode(isNull, DeoptimizationReason.NullCheckException, action, true)); Stamp newStamp = valueStamp.improveWith(StampFactory.objectNonNull()); return add(PiNode.create(value, newStamp, fixedGuard)); } From 247b7a9a756d2698405905b42647d47ddbf33f58 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Wed, 20 Dec 2023 14:54:35 +0000 Subject: [PATCH 08/78] update to jvmci-23.0-b27 --- common.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common.json b/common.json index 7629e2a07944..d465866f7885 100644 --- a/common.json +++ b/common.json @@ -14,9 +14,9 @@ "labsjdk-ce-17": {"name": "labsjdk", "version": "ce-17.0.9+9-jvmci-23.0-b22", "platformspecific": true }, "labsjdk-ce-17Debug": {"name": "labsjdk", "version": "ce-17.0.9+9-jvmci-23.0-b22-debug", "platformspecific": true }, "labsjdk-ce-17-llvm": {"name": "labsjdk", "version": "ce-17.0.9+9-jvmci-23.0-b22-sulong", "platformspecific": true }, - "labsjdk-ee-17": {"name": "labsjdk", "version": "ee-17.0.10+10-jvmci-23.0-b26", "platformspecific": true }, - "labsjdk-ee-17Debug": {"name": "labsjdk", "version": "ee-17.0.10+10-jvmci-23.0-b26-debug", "platformspecific": true }, - "labsjdk-ee-17-llvm": {"name": "labsjdk", "version": "ee-17.0.10+10-jvmci-23.0-b26-sulong", "platformspecific": true }, + "labsjdk-ee-17": {"name": "labsjdk", "version": "ee-17.0.10+11-jvmci-23.0-b27", "platformspecific": true }, + "labsjdk-ee-17Debug": {"name": "labsjdk", "version": "ee-17.0.10+11-jvmci-23.0-b27-debug", "platformspecific": true }, + "labsjdk-ee-17-llvm": {"name": "labsjdk", "version": "ee-17.0.10+11-jvmci-23.0-b27-sulong", "platformspecific": true }, "oraclejdk19": {"name": "jpg-jdk", "version": "19", "build_id": "26", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, "labsjdk-ce-19": {"name": "labsjdk", "version": "ce-19.0.1+10-jvmci-23.0-b04", "platformspecific": true }, From 25e54162c01319e68253c89193bc036dd6c0b6c9 Mon Sep 17 00:00:00 2001 From: Tom Shull Date: Tue, 20 Jun 2023 10:01:58 +0200 Subject: [PATCH 09/78] Speedup method verification. --- .../graal/llvm/LLVMNativeImageCodeCache.java | 6 ++--- .../oracle/svm/core/code/CodeInfoEncoder.java | 4 +-- .../hosted/image/LIRNativeImageCodeCache.java | 2 +- .../hosted/image/NativeImageCodeCache.java | 25 ++++++++++++++----- 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMNativeImageCodeCache.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMNativeImageCodeCache.java index d152e278bd8d..e4e50e6840a1 100644 --- a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMNativeImageCodeCache.java +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMNativeImageCodeCache.java @@ -145,7 +145,7 @@ public void layoutMethods(DebugContext debug, BigBang bb, ForkJoinPool threadPoo compileBitcodeBatches(executor, debug, numBatches); } try (StopTimer t = TimerCollection.createTimerAndStart("(postlink)")) { - linkCompiledBatches(executor, debug, numBatches); + linkCompiledBatches(debug, threadPool, executor, numBatches); } } } @@ -216,7 +216,7 @@ private void compileBitcodeBatches(BatchExecutor executor, DebugContext debug, i }); } - private void linkCompiledBatches(BatchExecutor executor, DebugContext debug, int numBatches) { + private void linkCompiledBatches(DebugContext debug, ForkJoinPool threadPool, BatchExecutor executor, int numBatches) { List compiledBatches = IntStream.range(0, numBatches).mapToObj(this::getBatchCompiledFilename).collect(Collectors.toList()); nativeLink(debug, getLinkedFilename(), compiledBatches); @@ -240,7 +240,7 @@ private void linkCompiledBatches(BatchExecutor executor, DebugContext debug, int llvmCleanupStackMaps(debug, getLinkedFilename()); codeAreaSize = textSectionInfo.getCodeSize(); - buildRuntimeMetadata(new MethodPointer(getFirstCompilation().getLeft()), WordFactory.signed(codeAreaSize)); + buildRuntimeMetadata(threadPool, new MethodPointer(getFirstCompilation().getLeft()), WordFactory.signed(codeAreaSize)); } private void llvmOptimize(DebugContext debug, String outputPath, String inputPath) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoEncoder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoEncoder.java index bde7d510f25d..2b59e58c23c4 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoEncoder.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoEncoder.java @@ -470,9 +470,9 @@ public boolean verifyFrameInfo(CodeInfo info) { class CodeInfoVerifier { static void verifyMethod(SharedMethod method, CompilationResult compilation, int compilationOffset, int compilationSize, CodeInfo info) { + CodeInfoQueryResult queryResult = new CodeInfoQueryResult(); for (int relativeIP = 0; relativeIP < compilationSize; relativeIP++) { int totalIP = relativeIP + compilationOffset; - CodeInfoQueryResult queryResult = new CodeInfoQueryResult(); CodeInfoAccess.lookupCodeInfo(info, totalIP, queryResult); assert queryResult.isEntryPoint() == method.isEntryPoint(); assert queryResult.hasCalleeSavedRegisters() == method.hasCalleeSavedRegisters(); @@ -486,7 +486,6 @@ static void verifyMethod(SharedMethod method, CompilationResult compilation, int int offset = CodeInfoEncoder.getEntryOffset(infopoint); if (offset >= 0) { assert offset < compilationSize; - CodeInfoQueryResult queryResult = new CodeInfoQueryResult(); CodeInfoAccess.lookupCodeInfo(info, offset + compilationOffset, queryResult); CollectingObjectReferenceVisitor visitor = new CollectingObjectReferenceVisitor(); @@ -506,7 +505,6 @@ static void verifyMethod(SharedMethod method, CompilationResult compilation, int int offset = handler.pcOffset; assert offset >= 0 && offset < compilationSize; - CodeInfoQueryResult queryResult = new CodeInfoQueryResult(); CodeInfoAccess.lookupCodeInfo(info, offset + compilationOffset, queryResult); long actual = queryResult.getExceptionOffset(); long expected = handler.handlerPos - handler.pcOffset; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java index a8a9f3519364..42ae894f2f12 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java @@ -218,7 +218,7 @@ public void layoutMethods(DebugContext debug, BigBang bb, ForkJoinPool threadPoo assert verifyMethodLayout(); - buildRuntimeMetadata(new MethodPointer(getFirstCompilation().getLeft()), WordFactory.unsigned(totalSize)); + buildRuntimeMetadata(threadPool, new MethodPointer(getFirstCompilation().getLeft()), WordFactory.unsigned(totalSize)); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java index f11b8a8d5ddb..262403324d9a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java @@ -63,6 +63,7 @@ import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.graal.pointsto.util.CompletionExecutor; import com.oracle.objectfile.ObjectFile; import com.oracle.svm.common.meta.MultiMethod; import com.oracle.svm.core.SubstrateOptions; @@ -247,7 +248,7 @@ public int getAlignedConstantsSize() { return ConfigurationValues.getObjectLayout().alignUp(getConstantsSize()); } - public void buildRuntimeMetadata(CFunctionPointer firstMethod, UnsignedWord codeSize) { + public void buildRuntimeMetadata(ForkJoinPool threadPool, CFunctionPointer firstMethod, UnsignedWord codeSize) { // Build run-time metadata. HostedFrameInfoCustomization frameInfoCustomization = new HostedFrameInfoCustomization(); CodeInfoEncoder.Encoders encoders = new CodeInfoEncoder.Encoders(); @@ -403,7 +404,7 @@ public void buildRuntimeMetadata(CFunctionPointer firstMethod, UnsignedWord code verifyDeoptEntries(imageCodeInfo); } - assert verifyMethods(codeInfoEncoder, imageCodeInfo); + assert verifyMethods(hUniverse, threadPool, codeInfoEncoder, imageCodeInfo); } protected HostedImageCodeInfo installCodeInfo(CFunctionPointer firstMethod, UnsignedWord codeSize, CodeInfoEncoder codeInfoEncoder, ReflectionMetadataEncoder reflectionMetadataEncoder) { @@ -545,10 +546,22 @@ private static boolean error(HostedMethod method, long encodedBci, String msg) { return true; } - protected boolean verifyMethods(CodeInfoEncoder codeInfoEncoder, CodeInfo codeInfo) { - for (Pair pair : getOrderedCompilations()) { - HostedMethod method = pair.getLeft(); - CodeInfoEncoder.verifyMethod(method, pair.getRight(), method.getCodeAddressOffset(), codeSizeFor(method), codeInfo); + protected boolean verifyMethods(HostedUniverse hUniverse, ForkJoinPool threadPool, CodeInfoEncoder codeInfoEncoder, CodeInfo codeInfo) { + /* + * Run method verification in parallel to reduce computation time. + */ + BigBang bb = hUniverse.getBigBang(); + CompletionExecutor executor = new CompletionExecutor(bb, threadPool, bb.getHeartbeatCallback()); + try { + executor.init(); + executor.start(); + for (Pair pair : getOrderedCompilations()) { + HostedMethod method = pair.getLeft(); + executor.execute(ignore -> CodeInfoEncoder.verifyMethod(method, pair.getRight(), method.getCodeAddressOffset(), codeSizeFor(method), codeInfo)); + } + executor.complete(); + } catch (InterruptedException e) { + throw VMError.shouldNotReachHere("Failed to verify methods"); } codeInfoEncoder.verifyFrameInfo(codeInfo); return true; From 6e2ed2cc46a2dd0f673ffbfa9acae6947f8cae30 Mon Sep 17 00:00:00 2001 From: Marouane El Hallaoui Date: Fri, 29 Dec 2023 11:38:59 +0100 Subject: [PATCH 10/78] GR-50540 : release GraalVM 23.0.3 --- compiler/mx.compiler/suite.py | 2 +- espresso/mx.espresso/suite.py | 2 +- regex/mx.regex/suite.py | 2 +- sdk/mx.sdk/suite.py | 2 +- substratevm/mx.substratevm/suite.py | 2 +- tools/mx.tools/suite.py | 2 +- truffle/mx.truffle/suite.py | 2 +- vm/mx.vm/suite.py | 8 ++++---- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/mx.compiler/suite.py b/compiler/mx.compiler/suite.py index d1ab5453108e..587aef5006aa 100644 --- a/compiler/mx.compiler/suite.py +++ b/compiler/mx.compiler/suite.py @@ -5,7 +5,7 @@ "groupId" : "org.graalvm.compiler", "version" : "23.0.3", - "release" : False, + "release" : True, "url" : "http://www.graalvm.org/", "developer" : { "name" : "GraalVM Development", diff --git a/espresso/mx.espresso/suite.py b/espresso/mx.espresso/suite.py index ffee0da99309..0a56eecc632c 100644 --- a/espresso/mx.espresso/suite.py +++ b/espresso/mx.espresso/suite.py @@ -24,7 +24,7 @@ "mxversion": "6.17.0", "name": "espresso", "version" : "23.0.3", - "release" : False, + "release" : True, "groupId" : "org.graalvm.espresso", "url" : "https://www.graalvm.org/reference-manual/java-on-truffle/", "developer" : { diff --git a/regex/mx.regex/suite.py b/regex/mx.regex/suite.py index eb6708ef73fb..93d7452f25ba 100644 --- a/regex/mx.regex/suite.py +++ b/regex/mx.regex/suite.py @@ -44,7 +44,7 @@ "name" : "regex", "version" : "23.0.3", - "release" : False, + "release" : True, "groupId" : "org.graalvm.regex", "url" : "http://www.graalvm.org/", "developer" : { diff --git a/sdk/mx.sdk/suite.py b/sdk/mx.sdk/suite.py index e439a961b539..8a7f94f27d0d 100644 --- a/sdk/mx.sdk/suite.py +++ b/sdk/mx.sdk/suite.py @@ -42,7 +42,7 @@ "mxversion": "6.17.0", "name" : "sdk", "version" : "23.0.3", - "release" : False, + "release" : True, "sourceinprojectwhitelist" : [], "url" : "https://github.com/oracle/graal", "groupId" : "org.graalvm.sdk", diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index 23def5c140a9..9e49c16f1a29 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -3,7 +3,7 @@ "mxversion": "6.17.0", "name": "substratevm", "version" : "23.0.3", - "release" : False, + "release" : True, "url" : "https://github.com/oracle/graal/tree/master/substratevm", "groupId" : "org.graalvm.nativeimage", diff --git a/tools/mx.tools/suite.py b/tools/mx.tools/suite.py index ccf357c06f19..bbd1657ea49c 100644 --- a/tools/mx.tools/suite.py +++ b/tools/mx.tools/suite.py @@ -27,7 +27,7 @@ "groupId" : "org.graalvm.tools", "version" : "23.0.3", - "release" : False, + "release" : True, "url" : "http://openjdk.java.net/projects/graal", "developer" : { "name" : "GraalVM Development", diff --git a/truffle/mx.truffle/suite.py b/truffle/mx.truffle/suite.py index a575c55cd011..aaf8fcec614d 100644 --- a/truffle/mx.truffle/suite.py +++ b/truffle/mx.truffle/suite.py @@ -42,7 +42,7 @@ "mxversion": "6.17.0", "name" : "truffle", "version" : "23.0.3", - "release" : False, + "release" : True, "groupId" : "org.graalvm.truffle", "sourceinprojectwhitelist" : [], "url" : "http://openjdk.java.net/projects/graal", diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index dc74d2d52784..3373ab7ecac1 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -2,7 +2,7 @@ "name": "vm", "version" : "23.0.3", "mxversion": "6.17.0", - "release" : False, + "release" : True, "groupId" : "org.graalvm", "url" : "http://www.graalvm.org/", @@ -39,7 +39,7 @@ "name": "graal-nodejs", "subdir": True, "dynamic": True, - "version": "99c8a2c475732c770e7e05ae0823d49648cc7ebb", + "version": "68a2a2a1f218492240360135a03642cc5070cfef", "urls" : [ {"url" : "https://github.com/graalvm/graaljs.git", "kind" : "git"}, {"url": "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind": "binary"}, @@ -49,7 +49,7 @@ "name": "graal-js", "subdir": True, "dynamic": True, - "version": "99c8a2c475732c770e7e05ae0823d49648cc7ebb", + "version": "68a2a2a1f218492240360135a03642cc5070cfef", "urls": [ {"url": "https://github.com/graalvm/graaljs.git", "kind" : "git"}, {"url": "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind": "binary"}, @@ -75,7 +75,7 @@ }, { "name": "graalpython", - "version": "249facdaa87860239cb454df7732d6e810224f9e", + "version": "060d5709cf1fa5598b62ef56f2550cb8d4de4cf6", "dynamic": True, "urls": [ {"url": "https://github.com/graalvm/graalpython.git", "kind": "git"}, From ad9a4ab14339fe893887004ca63f19d494cc0d08 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Tue, 19 Dec 2023 14:29:14 +0100 Subject: [PATCH 11/78] Remove Heap.allowPageSizeMismatch(). --- .../com/oracle/svm/core/genscavenge/HeapImpl.java | 12 +++--------- .../svm/core/graal/snippets/CEntryPointSnippets.java | 4 +--- .../src/com/oracle/svm/core/heap/Heap.java | 9 --------- 3 files changed, 4 insertions(+), 21 deletions(-) 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 3ff72c4c8549..1eb336a4a267 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 @@ -42,17 +42,16 @@ import org.graalvm.word.UnsignedWord; import com.oracle.svm.core.MemoryWalker; +import com.oracle.svm.core.NeverInline; import com.oracle.svm.core.SubstrateDiagnostics; import com.oracle.svm.core.SubstrateDiagnostics.DiagnosticThunk; import com.oracle.svm.core.SubstrateDiagnostics.DiagnosticThunkRegistry; import com.oracle.svm.core.SubstrateDiagnostics.ErrorContext; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateUtil; -import com.oracle.svm.core.NeverInline; -import com.oracle.svm.core.heap.RestrictHeapAccess; +import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; -import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.genscavenge.AlignedHeapChunk.AlignedHeader; import com.oracle.svm.core.genscavenge.ThreadLocalAllocation.Descriptor; @@ -69,6 +68,7 @@ import com.oracle.svm.core.heap.ReferenceHandler; import com.oracle.svm.core.heap.ReferenceHandlerThread; import com.oracle.svm.core.heap.ReferenceInternals; +import com.oracle.svm.core.heap.RestrictHeapAccess; import com.oracle.svm.core.heap.RuntimeCodeInfoGCSupport; import com.oracle.svm.core.jdk.UninterruptibleUtils.AtomicReference; import com.oracle.svm.core.locks.VMCondition; @@ -444,12 +444,6 @@ public int getImageHeapNullRegionSize() { return 0; } - @Fold - @Override - public boolean allowPageSizeMismatch() { - return true; - } - @Override public boolean walkImageHeapObjects(ObjectVisitor visitor) { VMOperation.guaranteeInProgressAtSafepoint("Must only be called at a safepoint"); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java index af7327cec9f5..a822eb27ff36 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java @@ -89,7 +89,6 @@ import com.oracle.svm.core.graal.nodes.CEntryPointLeaveNode; import com.oracle.svm.core.graal.nodes.CEntryPointUtilityNode; import com.oracle.svm.core.graal.nodes.WriteCurrentVMThreadNode; -import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.PhysicalMemory; import com.oracle.svm.core.heap.ReferenceHandler; import com.oracle.svm.core.heap.ReferenceHandlerThread; @@ -214,8 +213,7 @@ private static int createIsolate(CEntryPointCreateIsolateParameters parameters, UnsignedWord runtimePageSize = VirtualMemoryProvider.get().getGranularity(); UnsignedWord imagePageSize = WordFactory.unsigned(SubstrateOptions.getPageSize()); - boolean validPageSize = runtimePageSize.equal(imagePageSize) || - (Heap.getHeap().allowPageSizeMismatch() && UnsignedUtils.isAMultiple(imagePageSize, runtimePageSize)); + boolean validPageSize = UnsignedUtils.isAMultiple(imagePageSize, runtimePageSize); if (!validPageSize) { return CEntryPointErrors.PAGE_SIZE_CHECK_FAILED; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java index 42e28322d963..4902b9c13dd5 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java @@ -37,7 +37,6 @@ import org.graalvm.word.Pointer; import org.graalvm.word.UnsignedWord; -import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.hub.PredefinedClassesSupport; @@ -168,14 +167,6 @@ public List> getLoadedClasses() { @Fold public abstract int getImageHeapNullRegionSize(); - /** - * Returns whether the runtime page size doesn't have to match the page size set at image - * creation ({@link SubstrateOptions#getPageSize()}). If there is a mismatch, then the page size - * set at image creation must be a multiple of the runtime page size. - */ - @Fold - public abstract boolean allowPageSizeMismatch(); - /** * Returns true if the given object is located in the image heap. */ From e7efdb3300b3c9925c713f6805f248ad2d1fa9fe Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Fri, 5 Jan 2024 12:16:57 +0100 Subject: [PATCH 12/78] Provide a method to set the physical memory size. --- .../src/com/oracle/svm/core/heap/PhysicalMemory.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/PhysicalMemory.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/PhysicalMemory.java index d9516fe2b2d3..02849154089b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/PhysicalMemory.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/PhysicalMemory.java @@ -24,6 +24,7 @@ */ package com.oracle.svm.core.heap; +import com.oracle.svm.core.Uninterruptible; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; @@ -58,10 +59,17 @@ default boolean hasSize() { private static final UnsignedWord UNSET_SENTINEL = UnsignedUtils.MAX_VALUE; private static UnsignedWord cachedSize = UNSET_SENTINEL; + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static boolean isInitialized() { return cachedSize != UNSET_SENTINEL; } + @Uninterruptible(reason = "May only be called during early startup.") + public static void setSize(UnsignedWord value) { + VMError.guarantee(!isInitialized(), "PhysicalMemorySize must not be initialized yet."); + cachedSize = value; + } + /** * Returns the size of physical memory in bytes, querying it from the OS if it has not been * initialized yet. From 0bf3cb9cc7ff7617989459f0120daec844a37850 Mon Sep 17 00:00:00 2001 From: Anas El korchi Date: Fri, 12 Jan 2024 10:37:23 +0100 Subject: [PATCH 13/78] New dev cycle GraalVM 23.0.4 --- compiler/mx.compiler/suite.py | 4 ++-- espresso/mx.espresso/suite.py | 4 ++-- regex/mx.regex/suite.py | 4 ++-- sdk/mx.sdk/suite.py | 4 ++-- substratevm/mx.substratevm/suite.py | 4 ++-- tools/mx.tools/suite.py | 4 ++-- truffle/external_repos/simplelanguage/pom.xml | 2 +- truffle/external_repos/simplelanguage/sl | 2 +- truffle/external_repos/simpletool/pom.xml | 2 +- truffle/mx.truffle/suite.py | 4 ++-- vm/mx.vm/suite.py | 10 +++++----- wasm/mx.wasm/suite.py | 2 +- 12 files changed, 23 insertions(+), 23 deletions(-) diff --git a/compiler/mx.compiler/suite.py b/compiler/mx.compiler/suite.py index 587aef5006aa..5372ff7872b1 100644 --- a/compiler/mx.compiler/suite.py +++ b/compiler/mx.compiler/suite.py @@ -4,8 +4,8 @@ "sourceinprojectwhitelist" : [], "groupId" : "org.graalvm.compiler", - "version" : "23.0.3", - "release" : True, + "version" : "23.0.4", + "release" : False, "url" : "http://www.graalvm.org/", "developer" : { "name" : "GraalVM Development", diff --git a/espresso/mx.espresso/suite.py b/espresso/mx.espresso/suite.py index 0a56eecc632c..f1408521b7a0 100644 --- a/espresso/mx.espresso/suite.py +++ b/espresso/mx.espresso/suite.py @@ -23,8 +23,8 @@ suite = { "mxversion": "6.17.0", "name": "espresso", - "version" : "23.0.3", - "release" : True, + "version" : "23.0.4", + "release" : False, "groupId" : "org.graalvm.espresso", "url" : "https://www.graalvm.org/reference-manual/java-on-truffle/", "developer" : { diff --git a/regex/mx.regex/suite.py b/regex/mx.regex/suite.py index 93d7452f25ba..5ddf3fd01b0b 100644 --- a/regex/mx.regex/suite.py +++ b/regex/mx.regex/suite.py @@ -43,8 +43,8 @@ "name" : "regex", - "version" : "23.0.3", - "release" : True, + "version" : "23.0.4", + "release" : False, "groupId" : "org.graalvm.regex", "url" : "http://www.graalvm.org/", "developer" : { diff --git a/sdk/mx.sdk/suite.py b/sdk/mx.sdk/suite.py index 8a7f94f27d0d..0afe2abc071c 100644 --- a/sdk/mx.sdk/suite.py +++ b/sdk/mx.sdk/suite.py @@ -41,8 +41,8 @@ suite = { "mxversion": "6.17.0", "name" : "sdk", - "version" : "23.0.3", - "release" : True, + "version" : "23.0.4", + "release" : False, "sourceinprojectwhitelist" : [], "url" : "https://github.com/oracle/graal", "groupId" : "org.graalvm.sdk", diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index 9e49c16f1a29..e29ed9216255 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -2,8 +2,8 @@ suite = { "mxversion": "6.17.0", "name": "substratevm", - "version" : "23.0.3", - "release" : True, + "version" : "23.0.4", + "release" : False, "url" : "https://github.com/oracle/graal/tree/master/substratevm", "groupId" : "org.graalvm.nativeimage", diff --git a/tools/mx.tools/suite.py b/tools/mx.tools/suite.py index bbd1657ea49c..81172a2726f0 100644 --- a/tools/mx.tools/suite.py +++ b/tools/mx.tools/suite.py @@ -26,8 +26,8 @@ "defaultLicense" : "GPLv2-CPE", "groupId" : "org.graalvm.tools", - "version" : "23.0.3", - "release" : True, + "version" : "23.0.4", + "release" : False, "url" : "http://openjdk.java.net/projects/graal", "developer" : { "name" : "GraalVM Development", diff --git a/truffle/external_repos/simplelanguage/pom.xml b/truffle/external_repos/simplelanguage/pom.xml index 00435368d5de..6166ead68ea8 100644 --- a/truffle/external_repos/simplelanguage/pom.xml +++ b/truffle/external_repos/simplelanguage/pom.xml @@ -48,7 +48,7 @@ UTF-8 jdt_apt - 23.0.3-dev + 23.0.4-dev 11 11 diff --git a/truffle/external_repos/simplelanguage/sl b/truffle/external_repos/simplelanguage/sl index c9f8cb3fab34..2bdbbe4c12c8 100755 --- a/truffle/external_repos/simplelanguage/sl +++ b/truffle/external_repos/simplelanguage/sl @@ -41,7 +41,7 @@ # # If you update this number make sure the graalvm.version value in ./pom.xml matches -VERSION="23.0.3-dev" +VERSION="23.0.4-dev" MAIN_CLASS="com.oracle.truffle.sl.launcher.SLMain" SCRIPT_HOME="$(cd "$(dirname "$0")" && pwd -P)" diff --git a/truffle/external_repos/simpletool/pom.xml b/truffle/external_repos/simpletool/pom.xml index c62e71a20acc..26ac37d09317 100644 --- a/truffle/external_repos/simpletool/pom.xml +++ b/truffle/external_repos/simpletool/pom.xml @@ -49,7 +49,7 @@ UTF-8 1.8 1.8 - 23.0.3-dev + 23.0.4-dev diff --git a/truffle/mx.truffle/suite.py b/truffle/mx.truffle/suite.py index aaf8fcec614d..1f816e8e86e6 100644 --- a/truffle/mx.truffle/suite.py +++ b/truffle/mx.truffle/suite.py @@ -41,8 +41,8 @@ suite = { "mxversion": "6.17.0", "name" : "truffle", - "version" : "23.0.3", - "release" : True, + "version" : "23.0.4", + "release" : False, "groupId" : "org.graalvm.truffle", "sourceinprojectwhitelist" : [], "url" : "http://openjdk.java.net/projects/graal", diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index 3373ab7ecac1..b8b34ec7d447 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -1,8 +1,8 @@ suite = { "name": "vm", - "version" : "23.0.3", + "version" : "23.0.4", "mxversion": "6.17.0", - "release" : True, + "release" : False, "groupId" : "org.graalvm", "url" : "http://www.graalvm.org/", @@ -39,7 +39,7 @@ "name": "graal-nodejs", "subdir": True, "dynamic": True, - "version": "68a2a2a1f218492240360135a03642cc5070cfef", + "version": "0eb794c0d3286f72a158b512d67d5fb6788e2ea1", "urls" : [ {"url" : "https://github.com/graalvm/graaljs.git", "kind" : "git"}, {"url": "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind": "binary"}, @@ -49,7 +49,7 @@ "name": "graal-js", "subdir": True, "dynamic": True, - "version": "68a2a2a1f218492240360135a03642cc5070cfef", + "version": "0eb794c0d3286f72a158b512d67d5fb6788e2ea1", "urls": [ {"url": "https://github.com/graalvm/graaljs.git", "kind" : "git"}, {"url": "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind": "binary"}, @@ -75,7 +75,7 @@ }, { "name": "graalpython", - "version": "060d5709cf1fa5598b62ef56f2550cb8d4de4cf6", + "version": "7c785269a7e8fe70066cab0108412894f6203126", "dynamic": True, "urls": [ {"url": "https://github.com/graalvm/graalpython.git", "kind": "git"}, diff --git a/wasm/mx.wasm/suite.py b/wasm/mx.wasm/suite.py index 4e0383341c91..5314ab8ecb65 100644 --- a/wasm/mx.wasm/suite.py +++ b/wasm/mx.wasm/suite.py @@ -42,7 +42,7 @@ "mxversion": "6.17.0", "name" : "wasm", "groupId" : "org.graalvm.wasm", - "version" : "23.0.3", + "version" : "23.0.4", "versionConflictResolution" : "latest", "url" : "http://graalvm.org/", "developer" : { From 29d8bf02c16c1a1a9cb7a13c59fc6e5614fabd80 Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Thu, 9 Nov 2023 14:32:14 +0100 Subject: [PATCH 14/78] Use unsigned monitor and identity hash offsets and guarantee (not assert) that they are valid. (cherry picked from commit c54e861be840391b4db7bd2fa11059a1ffdc7311) --- .../src/com/oracle/svm/core/hub/DynamicHub.java | 11 +++++++---- .../oracle/svm/hosted/meta/HostedInstanceClass.java | 6 +++--- .../com/oracle/svm/hosted/meta/UniverseBuilder.java | 2 +- 3 files changed, 11 insertions(+), 8 deletions(-) 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 e015eea7ea4e..1ec07a04d2a8 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 @@ -190,9 +190,9 @@ public final class DynamicHub implements AnnotatedElement, java.lang.reflect.Typ * by an instance of this class. If 0, then instances of this class are locked using a side * table. */ - private short monitorOffset; + private char monitorOffset; - private short optionalIdentityHashOffset; + private char optionalIdentityHashOffset; /** * Bit-set for various boolean flags, to reduce size of instances. It is important that this @@ -435,11 +435,14 @@ public void setData(int layoutEncoding, int typeID, int monitorOffset, int optio } else { assert optionalIdentityHashOffset == -1; } + VMError.guarantee(monitorOffset == (char) monitorOffset, "Class %s has an invalid monitor field offset. Most likely, its objects are larger than supported.", name); + VMError.guarantee(optionalIdentityHashOffset == (char) optionalIdentityHashOffset, "Class %s has an invalid identity hash code field offset. Most likely, its objects are larger than supported.", name); this.layoutEncoding = layoutEncoding; this.typeID = typeID; - this.monitorOffset = NumUtil.safeToShort(monitorOffset); - this.optionalIdentityHashOffset = NumUtil.safeToShort(optionalIdentityHashOffset); + this.monitorOffset = (char)monitorOffset; + this.optionalIdentityHashOffset = (char)optionalIdentityHashOffset; + this.typeCheckStart = typeCheckStart; this.typeCheckRange = typeCheckRange; this.typeCheckSlot = typeCheckSlot; 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 7ecc8c2664fa..b7507550ecd1 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 @@ -37,7 +37,7 @@ public class HostedInstanceClass extends HostedClass { protected int instanceSize; protected boolean monitorFieldNeeded = false; protected int monitorFieldOffset = 0; - protected int optionalIdentityHashOffset = -1; + protected int optionalIdentityHashOffset = 0; public HostedInstanceClass(HostedUniverse universe, AnalysisType wrapped, JavaKind kind, JavaKind storageKind, HostedClass superClass, HostedInterface[] interfaces) { super(universe, wrapped, kind, storageKind, superClass, interfaces); @@ -120,8 +120,8 @@ public int getOptionalIdentityHashOffset() { } public void setOptionalIdentityHashOffset(int offset) { - assert this.optionalIdentityHashOffset == -1 : "setting identity hashcode field offset more than once"; - assert offset >= 0; + assert this.optionalIdentityHashOffset == 0 : "setting identity hashcode field offset more than once"; + assert offset > 0; this.optionalIdentityHashOffset = 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 9069ca65dd67..7320cb831c74 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 @@ -1021,7 +1021,7 @@ private void buildHubs() { int layoutHelper; boolean canInstantiateAsInstance = false; int monitorOffset = 0; - int optionalIdHashOffset = -1; + int optionalIdHashOffset = 0; if (type.isInstanceClass()) { HostedInstanceClass instanceClass = (HostedInstanceClass) type; if (instanceClass.isAbstract()) { From 4b5165b1f27203691803eff819941dca3705085f Mon Sep 17 00:00:00 2001 From: Raphael Mosaner Date: Wed, 27 Sep 2023 15:33:59 +0200 Subject: [PATCH 15/78] [GR-48705] Fix stamp inversion for ZeroExtend and SignExtend operations. (cherry picked from commit ca8f6344a9c612e4b61399372c99629675dc1935) --- .../core/common/type/ArithmeticOpTable.java | 11 +- .../core/common/type/IntegerStamp.java | 58 ++++++--- .../nodes/test/StampInverterTest.java | 110 ++++++++++++++++++ 3 files changed, 159 insertions(+), 20 deletions(-) create mode 100644 compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampInverterTest.java diff --git a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticOpTable.java b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticOpTable.java index 735e0f887d7f..71670f49419e 100644 --- a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticOpTable.java +++ b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticOpTable.java @@ -985,7 +985,16 @@ public IntegerConvertOp unwrap() { } /** - * Computes the stamp of the input for the given output stamp. + * Computes the stamp of the input for the given output stamp. This method returns + * {@code null} if a stamp cannot be inverted for an operation (i.e., {@link Narrow}). When + * inverting non-exact stamps, i.e. {@code 0xx0xxxx}, the inversion keeps all available + * information. If the stamp to invert contains contradictions regarding the post condition + * of the operation, an empty stamp is returned. An example for a contradiction would be a + * {@code SignExtend} with both {@code 0} and {@code 1} in the extension. + * + * @return {@code null} - if stamp inversion is not supported
+ * empty stamp - if the output stamp contains contradictions
+ * inverted output stamp - otherwise
*/ public abstract Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp); } diff --git a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java index db304041b0ca..67c67d9906b3 100644 --- a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java +++ b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java @@ -1976,24 +1976,27 @@ public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) { } /* - * there is no guarantee that a given result is in the range of the + * There is no guarantee that a given result is in the range of the * input because of holes in ranges resulting from signed / unsigned * extension, so we must ensure that the extension bits are all zeros * otherwise we cannot represent the result, and we have to return an - * unrestricted stamp + * empty stamp. * * This case is much less likely to happen than the case for SignExtend * but the following is defensive to ensure that we only perform valid * inversions. */ - long alwaysSetOutputBits = stamp.mustBeSet(); - long alwaysSetExtensionBits = alwaysSetOutputBits >>> inputBits; - if (alwaysSetExtensionBits != 0) { - createEmptyStamp(inputBits); + long mustBeSetOutputBits = stamp.mustBeSet(); + long mustBeSetExtensionBits = mustBeSetOutputBits >>> inputBits; + if (mustBeSetExtensionBits != 0) { + return createEmptyStamp(inputBits); } long inputMask = CodeUtil.mask(inputBits); - return StampFactory.forUnsignedInteger(inputBits, stamp.lowerBound(), stamp.upperBound(), stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); + long inputUpperBound = maxValueForMasks(inputBits, stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); + long inputLowerBound = minValueForMasks(inputBits, stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); + + return StampFactory.forIntegerWithMask(inputBits, inputLowerBound, inputUpperBound, stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); } }, @@ -2029,11 +2032,11 @@ public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) { } /* - * there is no guarantee that a given result bit is in the range of the + * There is no guarantee that a given result bit is in the range of the * input because of holes in ranges resulting from signed / unsigned * extension, so we must ensure that the extension bits are either all * zeros or all ones otherwise we cannot represent the result, and we - * have to return an unrestricted stamp + * have to return an empty stamp. * * As an example: * @formatter:off @@ -2056,21 +2059,38 @@ public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) { * ZeroExtend to get 0xb308, but then we try to invert the SignExtend. * The sign extend could only have produced 0xff__ or 0x00__ from a byte * but 0xb308 has 0xb3, and so we cannot invert the stamp. In this case - * the only sensible inversion is the unrestricted stamp. + * the only sensible inversion is the empty stamp. */ - long alwaysSetOutputBits = stamp.mustBeSet(); - long alwaysSetExtensionBits = alwaysSetOutputBits >>> inputBits; - long outputMask = CodeUtil.mask(resultBits); - if (alwaysSetExtensionBits != 0 && alwaysSetExtensionBits != (outputMask >>> inputBits)) { + long mustBeSetExtensionBits = stamp.mustBeSet() >>> inputBits; + long mayBeSetExtensionBits = stamp.mayBeSet() >>> inputBits; + long extensionMask = CodeUtil.mask(stamp.getBits()) >>> inputBits; + + boolean zeroInExtension = mayBeSetExtensionBits != extensionMask; + boolean oneInExtension = mustBeSetExtensionBits != 0; + boolean inputMSBOne = significantBit(inputBits, stamp.mustBeSet()) == 1; + boolean inputMSBZero = significantBit(inputBits, stamp.mayBeSet()) == 0; + + /* + * Checks for contradictions in the extension and returns an empty stamp in such cases. + * Examples for contradictions for a stamp after an artificial 4->8 bit sign extension: + * + * @formatter:off + * + * 1) 01xx xxxx --> extension cannot contain zeroes and ones + * 2) x0xx 1xxx --> extension cannot contain a zero if the MSB of the extended value is 1 + * 3) xx1x 0xxx --> extension cannot contain a one if the MSB of the extended value is 0 + * + * @formatter:on + */ + if ((zeroInExtension && oneInExtension) || (inputMSBOne && zeroInExtension) || (inputMSBZero && oneInExtension)) { return createEmptyStamp(inputBits); } long inputMask = CodeUtil.mask(inputBits); - if (inputBits < stamp.getBits() && (stamp.contains(CodeUtil.minValue(inputBits) - 1) || stamp.contains(CodeUtil.maxValue(inputBits) + 1))) { - // Truncation will cause this value to wrap around - return create(inputBits).unrestricted(); - } - return StampFactory.forIntegerWithMask(inputBits, stamp.lowerBound(), stamp.upperBound(), stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); + long inputUpperBound = maxValueForMasks(inputBits, stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); + long inputLowerBound = minValueForMasks(inputBits, stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); + + return StampFactory.forIntegerWithMask(inputBits, inputLowerBound, inputUpperBound, stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); } }, diff --git a/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampInverterTest.java b/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampInverterTest.java new file mode 100644 index 000000000000..e687f95484cb --- /dev/null +++ b/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampInverterTest.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.nodes.test; + +import static org.junit.Assert.assertEquals; + +import org.graalvm.compiler.core.common.type.ArithmeticOpTable; +import org.graalvm.compiler.core.common.type.IntegerStamp; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.SignExtend; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.ZeroExtend; +import org.graalvm.compiler.test.GraalTest; +import org.junit.Test; + +import jdk.vm.ci.code.CodeUtil; + +/** + * Tests the expected behavior of inverting stamps for different operations. During stamp inversion, + * the input stamp is calculated from a given output stamp. If a particular stamp cannot be inverted + * because of a contradiction regarding the operation's post condition, the inversion process is + * supposed to return an empty stamp. An example for a contradiction would be both {@code 0} and + * {@code 1} bits in the extension of a {@code SignExtend}. + */ +public class StampInverterTest extends GraalTest { + + private static Stamp invertSignExtend(Stamp toInvert) { + IntegerConvertOp signExtend = ArithmeticOpTable.forStamp(toInvert).getSignExtend(); + return signExtend.invertStamp(8, 32, toInvert); + } + + @Test + public void invertIntegerSignExtend01() { + // 32- > 8bit: xx...xx 11xxxxxx -> 11xxxxxx + IntegerStamp stamp = IntegerStamp.stampForMask(32, 128 | 64, CodeUtil.mask(32)); + Stamp expected = IntegerStamp.stampForMask(8, 128 | 64, CodeUtil.mask(8)); + assertEquals(expected, invertSignExtend(stamp)); + } + + @Test + public void invertIntegerSignExtend02() { + // 32 -> 8bit: xx...10 11xxxxxx -> cannot be inverted + IntegerStamp stamp = IntegerStamp.stampForMask(32, 512 | 128 | 64, CodeUtil.mask(32) ^ 256); + assertTrue("Stamp cannot be inverted and should be empty!", invertSignExtend(stamp).isEmpty()); + } + + @Test + public void invertIntegerSignExtend03() { + // 32 -> 8bit: xx...1x 0xxxxxxx -> cannot be inverted + IntegerStamp stamp = IntegerStamp.stampForMask(32, 512, CodeUtil.mask(32) ^ 128); + assertTrue("Stamp cannot be inverted and should be empty!", invertSignExtend(stamp).isEmpty()); + } + + @Test + public void invertIntegerSignExtend04() { + // 32 -> 8bit: xx...x0 1xxxxxxx -> cannot be inverted + IntegerStamp stamp = IntegerStamp.stampForMask(32, 128, CodeUtil.mask(32) ^ 256); + assertTrue("Stamp cannot be inverted and should be empty!", invertSignExtend(stamp).isEmpty()); + } + + private static Stamp invertZeroExtend(Stamp toInvert) { + IntegerConvertOp signExtend = ArithmeticOpTable.forStamp(toInvert).getZeroExtend(); + return signExtend.invertStamp(8, 32, toInvert); + } + + @Test + public void invertIntegerZeroExtend01() { + // 32- > 8bit: xx...xx 11xxxxxx -> 11xxxxxx + IntegerStamp stamp = IntegerStamp.stampForMask(32, 128 | 64, CodeUtil.mask(32)); + Stamp expected = IntegerStamp.stampForMask(8, 128 | 64, CodeUtil.mask(8)); + assertEquals(expected, invertZeroExtend(stamp)); + } + + @Test + public void invertIntegerZeroExtend02() { + // 32- > 8bit: xx...0x 01xxxxxx -> 01xxxxxx + IntegerStamp stamp = IntegerStamp.stampForMask(32, 64, CodeUtil.mask(32) ^ (512 | 128)); + Stamp expected = IntegerStamp.stampForMask(8, 64, CodeUtil.mask(8) ^ 128); + assertEquals(expected, invertZeroExtend(stamp)); + } + + @Test + public void invertIntegerZeroExtend03() { + // 32- > 8bit: xx...1x 01xxxxxx -> cannot be inverted + IntegerStamp stamp = IntegerStamp.stampForMask(32, 512 | 64, CodeUtil.mask(32) ^ 128); + assertTrue("Stamp cannot be inverted and should be empty!", invertZeroExtend(stamp).isEmpty()); + } +} \ No newline at end of file From 5bcae4c38cd8b1d3318ea9cf6a712f0384e6b401 Mon Sep 17 00:00:00 2001 From: Raphael Mosaner Date: Tue, 3 Oct 2023 13:25:49 +0200 Subject: [PATCH 16/78] [GR-48705] Unittests for stamp inversion during conditional elimination. (cherry picked from commit 1ec8ea434e60173fd5bd23cd23f0bb54cd8d19ca) --- ...ditionalEliminationStampInversionTest.java | 109 ++++++++++++++++++ .../CompareZeroExtendWithConstantTest.java | 20 +++- 2 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationStampInversionTest.java diff --git a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationStampInversionTest.java b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationStampInversionTest.java new file mode 100644 index 000000000000..55b78cac8fd9 --- /dev/null +++ b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationStampInversionTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.core.test; + +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FixedGuardNode; +import org.graalvm.compiler.nodes.IfNode; +import org.graalvm.compiler.nodes.LogicNode; +import org.graalvm.compiler.nodes.NodeView; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.AndNode; +import org.graalvm.compiler.nodes.calc.IntegerEqualsNode; +import org.graalvm.compiler.nodes.calc.IntegerTestNode; +import org.graalvm.compiler.nodes.calc.SignExtendNode; +import org.graalvm.compiler.nodes.util.GraphUtil; +import org.graalvm.compiler.phases.common.ConditionalEliminationPhase; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.junit.Test; + +import jdk.vm.ci.code.InvalidInstalledCodeException; +import jdk.vm.ci.meta.DeoptimizationAction; +import jdk.vm.ci.meta.DeoptimizationReason; + +/** + * Tests the correctness of conditional elimination when inverting stamps along + * {@link SignExtendNode}. The test artificially creates a graph whith the optimizable pattern: + * {@code ((val & CONST) == CONST)}, which provides information about the set bits in val, if the + * condition is used in a guard which is assumed to hold. The partial information about bits which + * are set in {@code x} are propagated "upwards". A {@link SignExtendNode} must treat the partial + * information correctly with respect to the extension bits and handle contradictions. + *

+ * If {@code CONST = 1 << 4 = 0001 0000} and we assume the condition holds, we can refine a stamp + * {@code xxxx xx11} for {@code val} to {@code xxx1 xx11}. Inverting this refined stamp along an + * artificial 4->8 bit sign extension should treat the extension as {@code 1111} and produce an + * inverted stamp of {@code xx11} or, even better {@code 1x11}, because we know the MSB has to be + * one from the extension. + *

+ * If the inversion is performed incorrectly, the inner condition could be considered as always + * false and removing it during conditional elimination. + */ +public class ConditionalEliminationStampInversionTest extends GraalCompilerTest { + + public static boolean snippet(byte b) { + short s = b; + int i = s; + + if ((i & (1 << 16)) == (1 << 16)) { + if (s == -5) { + return true; + } + } + return false; + } + + @Test + public void test() throws InvalidInstalledCodeException { + StructuredGraph g = parseEager("snippet", AllowAssumptions.YES); + + // replace the IntegerTest by an equivalent and/== pattern + ValueNode intTest = g.getNodes().filter(IntegerTestNode.class).first(); + assertTrue("IntegerTestNode expected in graph.", intTest != null); + + ValueNode signExtend = g.getNodes().filter(SignExtendNode.class).first(); + assertTrue("SignExtendNode expected in graph.", signExtend != null); + + ValueNode and = g.addOrUnique(AndNode.create(signExtend, ConstantNode.forInt(1 << 16, g), NodeView.DEFAULT)); + and.inferStamp(); + LogicNode intEq = g.addOrUnique(IntegerEqualsNode.create(and, ConstantNode.forInt(1 << 16, g), NodeView.DEFAULT)); + intEq.inferStamp(); + + intTest.replaceAtUsages(intEq); + + // replace the if by a fixed guard to trigger conditional elimination for the and/== pattern + ValueNode ifNode = (ValueNode) intEq.usages().first(); + assertTrue("IfNode expected as first usage of IntegerEqualsNode.", ifNode != null && ifNode instanceof IfNode); + + FixedGuardNode guard = g.add(new FixedGuardNode(intEq, DeoptimizationReason.ArithmeticException, DeoptimizationAction.InvalidateRecompile)); + GraphUtil.killCFG(((IfNode) ifNode).trueSuccessor()); + g.replaceSplitWithFixed((IfNode) ifNode, guard, ((IfNode) ifNode).falseSuccessor()); + + new ConditionalEliminationPhase(false).apply(g, getDefaultHighTierContext()); + + // the inner condition should still be alive and the following execution return true + assert (boolean) getCode(getResolvedJavaMethod("snippet"), g, true, true, getInitialOptions()).executeVarargs((byte) -5); + } +} \ No newline at end of file diff --git a/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/CompareZeroExtendWithConstantTest.java b/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/CompareZeroExtendWithConstantTest.java index 598fe64fccdc..a0613bf26df9 100644 --- a/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/CompareZeroExtendWithConstantTest.java +++ b/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/CompareZeroExtendWithConstantTest.java @@ -32,7 +32,7 @@ public class CompareZeroExtendWithConstantTest extends GraalCompilerTest { public static byte[] a = {}; - public static void snippet() { + public static void snippet01() { for (byte b : a) { char c = (char) b; GraalDirectives.blackhole(c); @@ -43,7 +43,21 @@ public static void snippet() { } @Test - public void testSnippet() { - test("snippet"); + public void testSnippet01() { + test("snippet01"); + } + + public static boolean snippet02(boolean p0, long p1) { + boolean var0 = p0; + byte b = (byte) p1; + for (long i = 245799965; i >= 245797839; i = 3) { + b = (byte) Character.toUpperCase((char) b); + } + return var0; + } + + @Test + public void testSnippet02() { + test("snippet02", true, 53069L); } } From 6acb9d0da4dd8d7c4203e8e51b66f8643eabbb38 Mon Sep 17 00:00:00 2001 From: Raphael Mosaner Date: Tue, 3 Oct 2023 13:27:07 +0200 Subject: [PATCH 17/78] [GR-48705] Infer input msb during stamp inversion for integer SignExtend. (cherry picked from commit 9be87d0746d8acbf43387e496b013d14754925c2) --- .../core/common/type/IntegerStamp.java | 35 +++++++++++++++++-- .../nodes/test/StampInverterTest.java | 16 +++++++++ 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java index 67c67d9906b3..fecf3a436bb5 100644 --- a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java +++ b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java @@ -2086,11 +2086,40 @@ public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) { return createEmptyStamp(inputBits); } + /* + * Calculate bounds and mayBeSet/mustBeSet bits for the input based on + * bit width and potentially inferred msb. + */ long inputMask = CodeUtil.mask(inputBits); - long inputUpperBound = maxValueForMasks(inputBits, stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); - long inputLowerBound = minValueForMasks(inputBits, stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); + long inputMustBeSet = stamp.mustBeSet() & inputMask; + long inputMayBeSet = stamp.mayBeSet() & inputMask; - return StampFactory.forIntegerWithMask(inputBits, inputLowerBound, inputUpperBound, stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); + if (!inputMSBOne && !inputMSBZero) { + /* + * Input MSB yet unknown, try to infer it from the extension: + * + * @formatter:off + * + * xx0x xxxx implies that the extension is 0000 which implies that the MSB of the input is 0 + * x1xx xxxx implies that the extension is 1111 which implies that the MSB of the input is 1 + * + * @formatter:on + */ + if (zeroInExtension) { + long msbZeroMask = inputMask ^ (1 << (inputBits - 1)); + inputMustBeSet &= msbZeroMask; + inputMayBeSet &= msbZeroMask; + } else if (oneInExtension) { + long msbOneMask = 1 << (inputBits - 1); + inputMustBeSet |= msbOneMask; + inputMayBeSet |= msbOneMask; + } + } + + long inputUpperBound = maxValueForMasks(inputBits, inputMustBeSet, inputMayBeSet); + long inputLowerBound = minValueForMasks(inputBits, inputMustBeSet, inputMayBeSet); + + return StampFactory.forIntegerWithMask(inputBits, inputLowerBound, inputUpperBound, inputMustBeSet, inputMayBeSet); } }, diff --git a/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampInverterTest.java b/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampInverterTest.java index e687f95484cb..eda83ba50904 100644 --- a/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampInverterTest.java +++ b/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampInverterTest.java @@ -80,6 +80,22 @@ public void invertIntegerSignExtend04() { assertTrue("Stamp cannot be inverted and should be empty!", invertSignExtend(stamp).isEmpty()); } + @Test + public void invertIntegerSignExtend05() { + // 32 -> 8bit: xx...x0 xxxxxxxx -> 0xxxxxxx (msb has to be 0) + IntegerStamp stamp = IntegerStamp.stampForMask(32, 0, CodeUtil.mask(32) ^ 256); + Stamp expected = IntegerStamp.stampForMask(8, 0, CodeUtil.mask(7)); + assertEquals(expected, invertSignExtend(stamp)); + } + + @Test + public void invertIntegerSignExtend06() { + // 32 -> 8bit: xx...x1 xxxxxxxx -> 1xxxxxxx (msb has to be 1) + IntegerStamp stamp = IntegerStamp.stampForMask(32, 256, CodeUtil.mask(32)); + Stamp expected = IntegerStamp.stampForMask(8, 128, CodeUtil.mask(8)); + assertEquals(expected, invertSignExtend(stamp)); + } + private static Stamp invertZeroExtend(Stamp toInvert) { IntegerConvertOp signExtend = ArithmeticOpTable.forStamp(toInvert).getZeroExtend(); return signExtend.invertStamp(8, 32, toInvert); From c45cbb08b49f6c4eb200829a4eb0d316f06d10f4 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Mon, 15 Jan 2024 08:27:43 +0100 Subject: [PATCH 18/78] Fix Cpuid1Ecx feature parsing for AMD CPUs. See https://bugs.openjdk.org/browse/JDK-8280867 (cherry picked from commit 4ac2265b3223d06cc34986ba9ec1f2f54c245b83) --- .../include/amd64hotspotcpuinfo.h | 5 ++--- .../src/cpuid.c | 22 ++++++++----------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/substratevm/src/com.oracle.svm.native.libchelper/include/amd64hotspotcpuinfo.h b/substratevm/src/com.oracle.svm.native.libchelper/include/amd64hotspotcpuinfo.h index 6ba282049f49..ac7d2cc7c505 100644 --- a/substratevm/src/com.oracle.svm.native.libchelper/include/amd64hotspotcpuinfo.h +++ b/substratevm/src/com.oracle.svm.native.libchelper/include/amd64hotspotcpuinfo.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -141,12 +141,11 @@ typedef union { uint32_t LahfSahf : 1, CmpLegacy : 1, : 3, - lzcnt_intel : 1, lzcnt : 1, sse4a : 1, misalignsse : 1, prefetchw : 1, - : 22; + : 23; } bits; } ExtCpuid1Ecx; diff --git a/substratevm/src/com.oracle.svm.native.libchelper/src/cpuid.c b/substratevm/src/com.oracle.svm.native.libchelper/src/cpuid.c index b967d65889b8..1ae435454f44 100644 --- a/substratevm/src/com.oracle.svm.native.libchelper/src/cpuid.c +++ b/substratevm/src/com.oracle.svm.native.libchelper/src/cpuid.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -516,19 +516,16 @@ NO_INLINE static void set_cpufeatures(CPUFeatures *features, CpuidInfo *_cpuid_i // Intel features. if (is_intel(_cpuid_info)) { - if (_cpuid_info->ext_cpuid1_ecx.bits.lzcnt_intel != 0) + if (_cpuid_info->ext_cpuid1_ecx.bits.lzcnt != 0) { features->fLZCNT = 1; - // for Intel, ecx.bits.misalignsse bit (bit 8) indicates support for prefetchw - if (_cpuid_info->ext_cpuid1_ecx.bits.misalignsse != 0) - { + } + if (_cpuid_info->ext_cpuid1_ecx.bits.prefetchw != 0) { features->fAMD_3DNOW_PREFETCH = 1; } - if (_cpuid_info->sef_cpuid7_ebx.bits.clwb != 0) - { + if (_cpuid_info->sef_cpuid7_ebx.bits.clwb != 0) { features->fCLWB = 1; } - if (_cpuid_info->sef_cpuid7_edx.bits.serialize != 0) - { + if (_cpuid_info->sef_cpuid7_edx.bits.serialize != 0) { features->fSERIALIZE = 1; } } @@ -536,11 +533,10 @@ NO_INLINE static void set_cpufeatures(CPUFeatures *features, CpuidInfo *_cpuid_i // ZX features. if (is_zx(_cpuid_info)) { - if (_cpuid_info->ext_cpuid1_ecx.bits.lzcnt_intel != 0) + if (_cpuid_info->ext_cpuid1_ecx.bits.lzcnt != 0) { features->fLZCNT = 1; - // for ZX, ecx.bits.misalignsse bit (bit 8) indicates support for prefetchw - if (_cpuid_info->ext_cpuid1_ecx.bits.misalignsse != 0) - { + } + if (_cpuid_info->ext_cpuid1_ecx.bits.prefetchw != 0) { features->fAMD_3DNOW_PREFETCH = 1; } } From 6844df71f225795fec7a05fdce2bb1af73fa3cf0 Mon Sep 17 00:00:00 2001 From: Eugene Sytnik Date: Mon, 18 Dec 2023 11:34:04 +0300 Subject: [PATCH 19/78] fix debug section alignment which can lead to corrupt debug info (cherry picked from commit 50a8e84704d9f94d355c58a1e339b9412f41f29d) --- .../com/oracle/objectfile/elf/ELFObjectFile.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java index 1eb1e156e0ab..9264367c3748 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1182,13 +1182,13 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { DwarfARangesSectionImpl elfARangesSectionImpl = dwarfSections.getARangesSectionImpl(); DwarfLineSectionImpl elfLineSectionImpl = dwarfSections.getLineSectionImpl(); /* Now we can create the section elements with empty content. */ - newUserDefinedSection(elfStrSectionImpl.getSectionName(), elfStrSectionImpl); - newUserDefinedSection(elfAbbrevSectionImpl.getSectionName(), elfAbbrevSectionImpl); - newUserDefinedSection(frameSectionImpl.getSectionName(), frameSectionImpl); - newUserDefinedSection(elfLocSectionImpl.getSectionName(), elfLocSectionImpl); - newUserDefinedSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); - newUserDefinedSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); - newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); + newDebugSection(elfStrSectionImpl.getSectionName(), elfStrSectionImpl); + newDebugSection(elfAbbrevSectionImpl.getSectionName(), elfAbbrevSectionImpl); + newDebugSection(frameSectionImpl.getSectionName(), frameSectionImpl); + newDebugSection(elfLocSectionImpl.getSectionName(), elfLocSectionImpl); + newDebugSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); + newDebugSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); + newDebugSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); /* * Add symbols for the base of all DWARF sections whose content may need to be referenced * using a section global offset. These need to be written using a base relative reloc so From 3c86fd2eede752a97752e598a737618e9f5a7ac5 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Fri, 15 Dec 2023 10:49:47 +0100 Subject: [PATCH 20/78] Add crash log output to exception handling. (cherry picked from commit 80332b8fc2c977e8cec093d142a2d94abc61b919) --- .../core/graal/snippets/CEntryPointSnippets.java | 6 +++--- .../oracle/svm/core/snippets/ExceptionUnwind.java | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java index af7327cec9f5..256b1b1c409f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java @@ -55,7 +55,6 @@ import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Isolate; import org.graalvm.nativeimage.IsolateThread; -import org.graalvm.nativeimage.LogHandler; import org.graalvm.nativeimage.StackValue; import org.graalvm.nativeimage.c.type.CCharPointer; import org.graalvm.nativeimage.c.type.CLongPointer; @@ -649,13 +648,14 @@ private static int reportException(Throwable exception) { private static void reportExceptionInterruptibly(Throwable exception) { logException(exception); - ImageSingletons.lookup(LogHandler.class).fatalError(); + VMError.shouldNotReachHere("Unhandled exception"); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "Must not allocate in fatal error handling.") private static void logException(Throwable exception) { try { - Log.log().exception(exception); + Log.log().string("Unhandled exception: "); + Log.log().exception(exception).newline().newline(); } catch (Throwable ex) { /* Logging failed, so there is nothing we can do anymore to log. */ } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ExceptionUnwind.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ExceptionUnwind.java index 09012f39b6a7..9bc5da9f85d0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ExceptionUnwind.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ExceptionUnwind.java @@ -26,7 +26,6 @@ import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.LogHandler; import org.graalvm.nativeimage.StackValue; import org.graalvm.nativeimage.c.function.CodePointer; import org.graalvm.nativeimage.hosted.Feature; @@ -55,6 +54,7 @@ import com.oracle.svm.core.thread.VMThreads; import com.oracle.svm.core.threadlocal.FastThreadLocalFactory; import com.oracle.svm.core.threadlocal.FastThreadLocalObject; +import com.oracle.svm.core.util.VMError; public abstract class ExceptionUnwind { @@ -143,8 +143,8 @@ private static void unwindExceptionInterruptible(Throwable exception, Pointer ca */ private static void reportRecursiveUnwind(Throwable exception) { Log.log().string("Fatal error: recursion in exception handling: ").string(exception.getClass().getName()); - Log.log().string(" thrown while unwinding ").string(currentException.get().getClass().getName()).newline(); - ImageSingletons.lookup(LogHandler.class).fatalError(); + Log.log().string(" thrown while unwinding ").string(currentException.get().getClass().getName()).newline().newline(); + VMError.shouldNotReachHere("Recursion in exception handling"); } /** @@ -157,8 +157,8 @@ private static void reportRecursiveUnwind(Throwable exception) { */ private static void reportFatalUnwind(Throwable exception) { Log.log().string("Fatal error: exception unwind while thread is not in Java state: "); - Log.log().exception(exception); - ImageSingletons.lookup(LogHandler.class).fatalError(); + Log.log().exception(exception).newline().newline(); + VMError.shouldNotReachHere("Exception unwind while thread is not in Java state"); } /** @@ -169,8 +169,8 @@ private static void reportFatalUnwind(Throwable exception) { */ private static void reportUnhandledException(Throwable exception) { Log.log().string("Fatal error: unhandled exception in isolate ").hex(CurrentIsolate.getIsolate()).string(": "); - Log.log().exception(exception); - ImageSingletons.lookup(LogHandler.class).fatalError(); + Log.log().exception(exception).newline().newline(); + VMError.shouldNotReachHere("Unhandled exception"); } /** Hook to allow a {@link Feature} to install custom exception unwind code. */ From 7adafbae3ef49e0e2a6267e49bbd6716e2c4b343 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Fri, 15 Dec 2023 11:31:40 +0100 Subject: [PATCH 21/78] Catch exceptions that happen while a thread starts. (cherry picked from commit 9e4e7dfd11681597ef2a4b084afedc98a0fea746) --- .../com/oracle/svm/core/thread/PlatformThreads.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java index fd91ae3cfa1f..4df97a21eeba 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java @@ -788,13 +788,14 @@ void startThread(Thread thread, long stackSize) { @SuppressFBWarnings(value = "Ru", justification = "We really want to call Thread.run and not Thread.start because we are in the low-level thread start routine") protected static void threadStartRoutine(ObjectHandle threadHandle) { Thread thread = ObjectHandles.getGlobal().get(threadHandle); - assignCurrent(thread, false); - ObjectHandles.getGlobal().destroy(threadHandle); - - singleton().unattachedStartedThreads.decrementAndGet(); - singleton().beforeThreadRun(thread); try { + assignCurrent(thread, false); + ObjectHandles.getGlobal().destroy(threadHandle); + + singleton().unattachedStartedThreads.decrementAndGet(); + singleton().beforeThreadRun(thread); + if (VMThreads.isTearingDown()) { /* * As a newly started thread, we might not have been interrupted like the Java From 382fbd403fa073fd3aafd82ced5b4cccabe42df6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Mon, 15 Jan 2024 17:18:24 +0100 Subject: [PATCH 22/78] Only use -H:Path validation in non-bundle mode When a bundle gets applied, the -H:Path value is purely virtual before it gets redirected to imagePathOutputDir. Validating the virtual value makes no sense (and causes errors if the path does not exist anymore) (cherry picked from commit 888a494dad0b6c36d47cfbc452a53afb0ff4ccce) --- .../src/com/oracle/svm/driver/NativeImage.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java index a1fe78af6f91..bad0b192298d 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java @@ -1093,13 +1093,15 @@ private int completeImageBuild() { if (!imageNamePathParent.isAbsolute()) { imageNamePathParent = imagePath.resolve(imageNamePathParent); } - if (!Files.isDirectory(imageNamePathParent)) { - throw NativeImage.showError("Writing image to non-existent directory " + imageNamePathParent + " is not allowed. " + - "Create the missing directory if you want the image to be written to that location."); - } - if (!Files.isWritable(imageNamePathParent)) { - throw NativeImage.showError("Writing image to directory without write access " + imageNamePathParent + " is not possible. " + - "Ensure the directory has write access or specify image path with write access."); + if (!useBundle()) { + if (!Files.isDirectory(imageNamePathParent)) { + throw NativeImage.showError("Writing image to non-existent directory " + imageNamePathParent + " is not allowed. " + + "Create the missing directory if you want the image to be written to that location."); + } + if (!Files.isWritable(imageNamePathParent)) { + throw NativeImage.showError("Writing image to directory without write access " + imageNamePathParent + " is not possible. " + + "Ensure the directory has write access or specify image path with write access."); + } } imagePath = imageNamePathParent; /* Update arguments passed to builder */ From 46bd365a1a0fae8947d8db499b972199c841e29f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Mon, 15 Jan 2024 18:16:56 +0100 Subject: [PATCH 23/78] Explain reasoning as comment (cherry picked from commit 58d9e1ba464bed017e64863eb71d7b155040bf59) --- .../src/com/oracle/svm/driver/NativeImage.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java index bad0b192298d..945f3d20ad7d 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java @@ -1094,6 +1094,11 @@ private int completeImageBuild() { imageNamePathParent = imagePath.resolve(imageNamePathParent); } if (!useBundle()) { + /* + * In bundle-mode the value of imagePath is purely virtual before it gets + * substituted by substituteImagePath(imagePath) below. Validating the virtual value + * would make no sense (and cause errors if the path does not exist anymore) + */ if (!Files.isDirectory(imageNamePathParent)) { throw NativeImage.showError("Writing image to non-existent directory " + imageNamePathParent + " is not allowed. " + "Create the missing directory if you want the image to be written to that location."); From 9dfadccdbdface90af1b0360094ca24c2a90f47e Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Wed, 17 Jan 2024 13:23:30 +0000 Subject: [PATCH 24/78] update to jvmci-23.0-b28 --- common.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common.json b/common.json index d465866f7885..294c199cf790 100644 --- a/common.json +++ b/common.json @@ -14,9 +14,9 @@ "labsjdk-ce-17": {"name": "labsjdk", "version": "ce-17.0.9+9-jvmci-23.0-b22", "platformspecific": true }, "labsjdk-ce-17Debug": {"name": "labsjdk", "version": "ce-17.0.9+9-jvmci-23.0-b22-debug", "platformspecific": true }, "labsjdk-ce-17-llvm": {"name": "labsjdk", "version": "ce-17.0.9+9-jvmci-23.0-b22-sulong", "platformspecific": true }, - "labsjdk-ee-17": {"name": "labsjdk", "version": "ee-17.0.10+11-jvmci-23.0-b27", "platformspecific": true }, - "labsjdk-ee-17Debug": {"name": "labsjdk", "version": "ee-17.0.10+11-jvmci-23.0-b27-debug", "platformspecific": true }, - "labsjdk-ee-17-llvm": {"name": "labsjdk", "version": "ee-17.0.10+11-jvmci-23.0-b27-sulong", "platformspecific": true }, + "labsjdk-ee-17": {"name": "labsjdk", "version": "ee-17.0.11+1-jvmci-23.0-b28", "platformspecific": true }, + "labsjdk-ee-17Debug": {"name": "labsjdk", "version": "ee-17.0.11+1-jvmci-23.0-b28-debug", "platformspecific": true }, + "labsjdk-ee-17-llvm": {"name": "labsjdk", "version": "ee-17.0.11+1-jvmci-23.0-b28-sulong", "platformspecific": true }, "oraclejdk19": {"name": "jpg-jdk", "version": "19", "build_id": "26", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, "labsjdk-ce-19": {"name": "labsjdk", "version": "ce-19.0.1+10-jvmci-23.0-b04", "platformspecific": true }, From 3171106729a7e9a1feebcdee214ebd76d9ceeb54 Mon Sep 17 00:00:00 2001 From: Raphael Mosaner Date: Tue, 10 Oct 2023 09:56:10 +0200 Subject: [PATCH 25/78] [GR-48705] Incorporate the bounds of stampToInvert when calculating the bounds of the inverted stamp. (cherry picked from commit b55090942607dfcf2a124ecb0b0fa71078854273) --- .../core/common/type/IntegerStamp.java | 30 +++-- .../core/common/type/StampFactory.java | 24 ++++ ...ditionalEliminationStampInversionTest.java | 2 +- .../nodes/test/StampInverterTest.java | 125 +++++++++++++++++- 4 files changed, 165 insertions(+), 16 deletions(-) diff --git a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java index fecf3a436bb5..6e497f67ce20 100644 --- a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java +++ b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java @@ -1992,11 +1992,15 @@ public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) { return createEmptyStamp(inputBits); } - long inputMask = CodeUtil.mask(inputBits); - long inputUpperBound = maxValueForMasks(inputBits, stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); - long inputLowerBound = minValueForMasks(inputBits, stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); + /* + * The output of a zero extend cannot be negative. Setting the lower + * bound > 0 enables inverting stamps like [-8, 16] without having to + * return an unrestricted stamp. + */ + long lowerBound = Math.max(stamp.lowerBound(), 0); + assert stamp.upperBound() >= 0 : "Cannot invert ZeroExtend for stamp with msb=1, which implies a negative value after ZeroExtend!"; - return StampFactory.forIntegerWithMask(inputBits, inputLowerBound, inputUpperBound, stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); + return StampFactory.forUnsignedInteger(inputBits, lowerBound, stamp.upperBound(), stamp.mustBeSet(), stamp.mayBeSet()); } }, @@ -2086,10 +2090,6 @@ public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) { return createEmptyStamp(inputBits); } - /* - * Calculate bounds and mayBeSet/mustBeSet bits for the input based on - * bit width and potentially inferred msb. - */ long inputMask = CodeUtil.mask(inputBits); long inputMustBeSet = stamp.mustBeSet() & inputMask; long inputMayBeSet = stamp.mayBeSet() & inputMask; @@ -2106,7 +2106,7 @@ public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) { * @formatter:on */ if (zeroInExtension) { - long msbZeroMask = inputMask ^ (1 << (inputBits - 1)); + long msbZeroMask = ~(1 << (inputBits - 1)); inputMustBeSet &= msbZeroMask; inputMayBeSet &= msbZeroMask; } else if (oneInExtension) { @@ -2116,9 +2116,21 @@ public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) { } } + // Calculate conservative bounds for the input. long inputUpperBound = maxValueForMasks(inputBits, inputMustBeSet, inputMayBeSet); long inputLowerBound = minValueForMasks(inputBits, inputMustBeSet, inputMayBeSet); + /* + * If the bounds calculated for the input stamp do not overlap with the + * bounds for the stamp to invert, return an empty stamp. Otherwise, + * refine the conservative stamp for the input. + */ + if ((stamp.upperBound() < inputLowerBound) || (stamp.lowerBound() > inputUpperBound)) { + return createEmptyStamp(inputBits); + } + inputUpperBound = Math.min(inputUpperBound, stamp.upperBound()); + inputLowerBound = Math.max(inputLowerBound, stamp.lowerBound()); + return StampFactory.forIntegerWithMask(inputBits, inputLowerBound, inputUpperBound, inputMustBeSet, inputMayBeSet); } }, diff --git a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java index 13b32d1fd5cc..8da3ce14210c 100644 --- a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java +++ b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java @@ -161,6 +161,30 @@ public static IntegerStamp forUnsignedInteger(int bits, long unsignedLowerBound, return forUnsignedInteger(bits, unsignedLowerBound, unsignedUpperBound, 0, CodeUtil.mask(bits)); } + /** + * Creates an IntegerStamp from the given unsigned bounds and bit masks. This method returns an + * empty stamp if the unsigned lower bound is larger than the unsigned upper bound. If the sign + * of lower and upper bound differs after sign extension to the specified length ({@code bits}), + * this method returns an unrestricted stamp with respect to the bounds. {@code mayBeSet} or + * {@code mustBeSet} can restrict the bounds nevertheless. Take the following example when + * inverting a zero extended 32bit stamp to the 8bit stamp before extension: + * + *

+ * 32bit stamp [0, 192] 00...00 xxxxxxx0 + *

+ * When converting the bounds to 8bit, they have different signs, i.e.: + *

+ * lowerUnsigned = 0000 0000 and upperUnsigned = 1100 0000 + *

+ * In order to respect the (unsigned) boundaries of the extended value, the signed input can be: + *

+ * 0000 0000 - 0111 1111, i.e. 0 to 127
+ * or
+ * 1000 0000 - 1100 0000, i.e. -128 to -64 + *

+ * The resulting interval [-128, -64]u[0, 127] cannot be represented by a single upper and lower + * bound. Thus, we have to return an unrestricted stamp, with respect to the bounds. + */ public static IntegerStamp forUnsignedInteger(int bits, long unsignedLowerBound, long unsignedUpperBound, long mustBeSet, long mayBeSet) { if (Long.compareUnsigned(unsignedLowerBound, unsignedUpperBound) > 0) { return IntegerStamp.createEmptyStamp(bits); diff --git a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationStampInversionTest.java b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationStampInversionTest.java index 55b78cac8fd9..bb5879b8aab2 100644 --- a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationStampInversionTest.java +++ b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationStampInversionTest.java @@ -106,4 +106,4 @@ public void test() throws InvalidInstalledCodeException { // the inner condition should still be alive and the following execution return true assert (boolean) getCode(getResolvedJavaMethod("snippet"), g, true, true, getInitialOptions()).executeVarargs((byte) -5); } -} \ No newline at end of file +} diff --git a/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampInverterTest.java b/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampInverterTest.java index eda83ba50904..69d14a8a4455 100644 --- a/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampInverterTest.java +++ b/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampInverterTest.java @@ -96,14 +96,60 @@ public void invertIntegerSignExtend06() { assertEquals(expected, invertSignExtend(stamp)); } + @Test + public void invertIntegerSignExtend07() { + // 32 -> 8bit: [-128, 126] xx...xx xxxxxxx0 -> [-128, 126] xxxxxxx0 + IntegerStamp stamp = IntegerStamp.create(32, -128, 126, 0, CodeUtil.mask(32) ^ 1); + Stamp expected = IntegerStamp.create(8, -128, 126, 0, CodeUtil.mask(32) ^ 1); + assertEquals(expected, invertSignExtend(stamp)); + } + + @Test + public void invertIntegerSignExtend08() { + // 32 -> 8bit: [-256, 126] xx...xx 0xxxxxx0 -> [0, 126] 0xxxxxx0 + IntegerStamp stamp = IntegerStamp.create(32, -256, 126, 0, CodeUtil.mask(32) ^ (256 | 1)); + Stamp expected = IntegerStamp.create(8, 0, 126, 0, CodeUtil.mask(32) ^ (256 | 1)); + assertEquals(expected, invertSignExtend(stamp)); + } + + @Test + public void invertIntegerSignExtend09() { + // 32 -> 8bit: [-8, 126] xx...xx xxxxxxx0 -> [-8, 126] xxxxxxx0 + IntegerStamp stamp = IntegerStamp.create(32, -8, 126, 0, CodeUtil.mask(32) ^ 1); + Stamp expected = IntegerStamp.create(8, -8, 126, 0, CodeUtil.mask(32) ^ 1); + assertEquals(expected, invertSignExtend(stamp)); + } + + @Test + public void invertIntegerSignExtend10() { + // 32 -> 8bit: [int min, -1024] 1x...xx xxxxxxxx -> empty + IntegerStamp stamp = IntegerStamp.create(32, Integer.MIN_VALUE, -1024); + assertTrue("Stamp cannot be inverted and should be empty!", invertSignExtend(stamp).isEmpty()); + } + + @Test + public void invertIntegerSignExtend11() { + // 32 -> 8bit: [1024, int max] 0x...xx xxxxxxxx -> empty + IntegerStamp stamp = IntegerStamp.create(32, 1024, Integer.MAX_VALUE); + assertTrue("Stamp cannot be inverted and should be empty!", invertSignExtend(stamp).isEmpty()); + } + + @Test + public void invertIntegerSignExtend12() { + // 32 -> 8bit: [0, 255] 00...00 xxxxxxxx -> [0, 127] 0xxxxxxx + IntegerStamp stamp = IntegerStamp.create(32, 0, 255, 0, CodeUtil.mask(8)); + Stamp expected = IntegerStamp.create(8, 0, 127, 0, CodeUtil.mask(7)); + assertEquals(expected, invertSignExtend(stamp)); + } + private static Stamp invertZeroExtend(Stamp toInvert) { - IntegerConvertOp signExtend = ArithmeticOpTable.forStamp(toInvert).getZeroExtend(); - return signExtend.invertStamp(8, 32, toInvert); + IntegerConvertOp zeroExtend = ArithmeticOpTable.forStamp(toInvert).getZeroExtend(); + return zeroExtend.invertStamp(8, 32, toInvert); } @Test public void invertIntegerZeroExtend01() { - // 32- > 8bit: xx...xx 11xxxxxx -> 11xxxxxx + // 32 -> 8bit: xx...xx 11xxxxxx -> 11xxxxxx IntegerStamp stamp = IntegerStamp.stampForMask(32, 128 | 64, CodeUtil.mask(32)); Stamp expected = IntegerStamp.stampForMask(8, 128 | 64, CodeUtil.mask(8)); assertEquals(expected, invertZeroExtend(stamp)); @@ -111,7 +157,7 @@ public void invertIntegerZeroExtend01() { @Test public void invertIntegerZeroExtend02() { - // 32- > 8bit: xx...0x 01xxxxxx -> 01xxxxxx + // 32 -> 8bit: xx...0x 01xxxxxx -> 01xxxxxx IntegerStamp stamp = IntegerStamp.stampForMask(32, 64, CodeUtil.mask(32) ^ (512 | 128)); Stamp expected = IntegerStamp.stampForMask(8, 64, CodeUtil.mask(8) ^ 128); assertEquals(expected, invertZeroExtend(stamp)); @@ -119,8 +165,75 @@ public void invertIntegerZeroExtend02() { @Test public void invertIntegerZeroExtend03() { - // 32- > 8bit: xx...1x 01xxxxxx -> cannot be inverted + // 32 -> 8bit: xx...1x 01xxxxxx -> cannot be inverted IntegerStamp stamp = IntegerStamp.stampForMask(32, 512 | 64, CodeUtil.mask(32) ^ 128); assertTrue("Stamp cannot be inverted and should be empty!", invertZeroExtend(stamp).isEmpty()); } -} \ No newline at end of file + + @Test + public void invertIntegerZeroExtend04() { + // 32 -> 8bit: [int min, int max -1] xx...xx xxxxxxx0 -> [-128, 126] xxxxxxx0 + IntegerStamp stamp = IntegerStamp.create(32, Integer.MIN_VALUE, Integer.MAX_VALUE - 1, 0, CodeUtil.mask(32) ^ 1); + Stamp expected = IntegerStamp.create(8, -128, 126, 0, CodeUtil.mask(8) ^ 1); + assertEquals(expected, invertZeroExtend(stamp)); + } + + @Test + public void invertIntegerZeroExtend5() { + /* + * 32 -> 8bit: [0, 192] 00...00 xxxxxxx0 -> [-128, 126] xxxxxxx0 + * + * The 32bit stamp bounds have different signs when converting to 8bit: + * lowerUnsigned = 0000 0000, upperUnsigned = 1100 0000. + * In order to respect the (unsigned) boundaries of the extended value, the signed input can be: + * @formatter:off + * + * 0000 0000 - 0111 1111, i.e. 0 to 127 + * or + * 1000 0000 - 1100 0000, i.e. -128 to -64 + * + * @formatter:on + * The resulting interval [-128, -64]u[0, 127] cannot be represented by a single upper and + * lower bound. Thus, we have to return an unrestricted stamp, with respect to the bounds. + */ + IntegerStamp stamp = IntegerStamp.create(32, 0, 192, 0, CodeUtil.mask(8) ^ 1); + Stamp expected = IntegerStamp.create(8, -128, 126, 0, CodeUtil.mask(8) ^ 1); + assertEquals(expected, invertZeroExtend(stamp)); + } + + @Test + public void invertIntegerZeroExtend06() { + /* + * 32 -> 8bit: [-8, 16] xx...xx xxxxxxx0 -> [0, 16] xxxxxxx0 + * + * Negative lower bounds can be clamped to 0. + */ + IntegerStamp stamp = IntegerStamp.create(32, -8, 16, 0, CodeUtil.mask(32) ^ 1); + Stamp expected = IntegerStamp.create(8, 0, 16, 0, CodeUtil.mask(8) ^ 1); + assertEquals(expected, invertZeroExtend(stamp)); + } + + @Test + public void invertIntegerZeroExtend07() { + // 32 -> 8bit: [2, 18] 00...00 000xxx10 -> [2, 18] 000xxx10 + IntegerStamp stamp = IntegerStamp.create(32, 2, 18, 2, CodeUtil.mask(5) ^ 1); + Stamp expected = IntegerStamp.create(8, 2, 18, 2, CodeUtil.mask(5) ^ 1); + assertEquals(expected, invertZeroExtend(stamp)); + } + + @Test + public void invertIntegerZeroExtend08() { + // 32 -> 8bit: [128, 254] 00...00 1xxxxxx0 -> [-128, -2] 1xxxxxx0 + IntegerStamp stamp = IntegerStamp.create(32, 128, 254, 128, CodeUtil.mask(8) ^ 1); + Stamp expected = IntegerStamp.create(8, -128, -2, 128, CodeUtil.mask(8) ^ 1); + assertEquals(expected, invertZeroExtend(stamp)); + } + + @Test + public void invertIntegerZeroExtend09() { + // 32 -> 8bit: [int min ^ 128, 254] xx...xx xxxxxxx0 -> [-128, 126] xxxxxxx0 + IntegerStamp stamp = IntegerStamp.create(32, Integer.MIN_VALUE ^ 128, 254, 0, CodeUtil.mask(32) ^ 1); + Stamp expected = IntegerStamp.create(8, -128, 126, 0, CodeUtil.mask(8) ^ 1); + assertEquals(expected, invertZeroExtend(stamp)); + } +} From 1c5f7df33debdb593851b5b9a87bb62ac308423d Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Fri, 19 Jan 2024 09:55:29 +0100 Subject: [PATCH 26/78] Fix a bug in the IsolateArgumentParser. (cherry picked from commit bc86e804ea1f5defa7413186e3d3e5a8c620bfdf) --- .../svm/core/IsolateArgumentParser.java | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/IsolateArgumentParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/IsolateArgumentParser.java index 73d52698a480..9adaa07d8008 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/IsolateArgumentParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/IsolateArgumentParser.java @@ -183,8 +183,22 @@ public void persistOptions(CLongPointer parsedArgs) { public void verifyOptionValues() { for (int i = 0; i < OPTION_COUNT; i++) { - validate(OPTIONS[i], getOptionValue(i)); + RuntimeOptionKey option = OPTIONS[i]; + if (shouldValidate(option)) { + validate(option, getOptionValue(i)); + } + } + } + + private static boolean shouldValidate(RuntimeOptionKey option) { + if (!option.hasBeenSet()) { + /* Workaround for one specific Truffle language that does something weird. */ + return false; + } else if (SubstrateOptions.UseSerialGC.getValue()) { + /* The serial GC supports changing the heap size at run-time to some degree. */ + return option != SubstrateGCOptions.MinHeapSize && option != SubstrateGCOptions.MaxHeapSize && option != SubstrateGCOptions.MaxNewSize; } + return true; } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @@ -218,12 +232,10 @@ private static Object getOptionValue(int index) { } private static void validate(RuntimeOptionKey option, Object oldValue) { - if (option.hasBeenSet()) { - Object newValue = option.getValue(); - if (newValue == null || !newValue.equals(oldValue)) { - throw new IllegalArgumentException( - "The option '" + option.getName() + "' can't be changed after isolate creation. Old value: " + oldValue + ", new value: " + newValue); - } + Object newValue = option.getValue(); + if (newValue == null || !newValue.equals(oldValue)) { + throw new IllegalArgumentException( + "The option '" + option.getName() + "' can't be changed after isolate creation. Old value: " + oldValue + ", new value: " + newValue); } } @@ -332,6 +344,8 @@ private static boolean atojulong(CCharPointer s, CLongPointer result) { } CCharPointerPointer tailPtr = (CCharPointerPointer) StackValue.get(CCharPointer.class); + + LibC.setErrno(0); UnsignedWord n = LibC.strtoull(s, tailPtr, 10); if (LibC.errno() != 0) { return false; From eefa8732199b23c29bfe5d2f38af3a88bb10b1dc Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Tue, 23 Jan 2024 11:07:24 +0000 Subject: [PATCH 27/78] update to jvmci-23.0-b29 --- common.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common.json b/common.json index 294c199cf790..bd1f127a7107 100644 --- a/common.json +++ b/common.json @@ -14,9 +14,9 @@ "labsjdk-ce-17": {"name": "labsjdk", "version": "ce-17.0.9+9-jvmci-23.0-b22", "platformspecific": true }, "labsjdk-ce-17Debug": {"name": "labsjdk", "version": "ce-17.0.9+9-jvmci-23.0-b22-debug", "platformspecific": true }, "labsjdk-ce-17-llvm": {"name": "labsjdk", "version": "ce-17.0.9+9-jvmci-23.0-b22-sulong", "platformspecific": true }, - "labsjdk-ee-17": {"name": "labsjdk", "version": "ee-17.0.11+1-jvmci-23.0-b28", "platformspecific": true }, - "labsjdk-ee-17Debug": {"name": "labsjdk", "version": "ee-17.0.11+1-jvmci-23.0-b28-debug", "platformspecific": true }, - "labsjdk-ee-17-llvm": {"name": "labsjdk", "version": "ee-17.0.11+1-jvmci-23.0-b28-sulong", "platformspecific": true }, + "labsjdk-ee-17": {"name": "labsjdk", "version": "ee-17.0.11+2-jvmci-23.0-b29", "platformspecific": true }, + "labsjdk-ee-17Debug": {"name": "labsjdk", "version": "ee-17.0.11+2-jvmci-23.0-b29-debug", "platformspecific": true }, + "labsjdk-ee-17-llvm": {"name": "labsjdk", "version": "ee-17.0.11+2-jvmci-23.0-b29-sulong", "platformspecific": true }, "oraclejdk19": {"name": "jpg-jdk", "version": "19", "build_id": "26", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, "labsjdk-ce-19": {"name": "labsjdk", "version": "ce-19.0.1+10-jvmci-23.0-b04", "platformspecific": true }, From dafc7ac932c0b0857443c131d740b7090fa9ca4e Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Fri, 13 Oct 2023 17:15:40 +0200 Subject: [PATCH 28/78] Fix Thread.getStackTrace() right after Thread.start(). (cherry picked from commit 6ed33b8d280d1d58d84c045c7f7fd75bf503a56a) --- .../com/oracle/svm/core/jdk/StackTraceUtils.java | 14 ++++++++------ .../com/oracle/svm/core/stack/JavaStackWalker.java | 1 + .../oracle/svm/core/thread/PlatformThreads.java | 4 +++- .../svm/core/thread/Target_java_lang_Thread.java | 4 ++-- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java index 3302cc6017db..3c165606a7a5 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java @@ -49,7 +49,6 @@ import com.oracle.svm.core.thread.JavaVMOperation; import com.oracle.svm.core.thread.LoomSupport; import com.oracle.svm.core.thread.PlatformThreads; -import com.oracle.svm.core.thread.Target_java_lang_Thread; import com.oracle.svm.core.thread.Target_jdk_internal_vm_Continuation; import com.oracle.svm.core.thread.VMOperation; import com.oracle.svm.core.thread.VirtualThreads; @@ -94,6 +93,9 @@ public static StackTraceElement[] getStackTraceAtSafepoint(Thread thread) { public static StackTraceElement[] getThreadStackTraceAtSafepoint(IsolateThread isolateThread, Pointer endSP) { assert VMOperation.isInProgressAtSafepoint(); + if (isolateThread.isNull()) { // recently launched thread + return NO_ELEMENTS; + } BuildStackTraceVisitor visitor = new BuildStackTraceVisitor(false, SubstrateOptions.MaxJavaStackTraceDepth.getValue()); JavaStackWalker.walkThread(isolateThread, endSP, visitor, null); return visitor.trace.toArray(NO_ELEMENTS); @@ -213,6 +215,10 @@ public static ClassLoader latestUserDefinedClassLoader(Pointer startSP) { } public static StackTraceElement[] asyncGetStackTrace(Thread thread) { + if (!thread.isAlive()) { + /* Avoid triggering a safepoint operation below if the thread is not even alive. */ + return NO_ELEMENTS; + } GetStackTraceOperation vmOp = new GetStackTraceOperation(thread); vmOp.enqueue(); return vmOp.result; @@ -229,11 +235,7 @@ private static class GetStackTraceOperation extends JavaVMOperation { @Override protected void operate() { - if (thread.isAlive()) { - result = getStackTraceAtSafepoint(thread); - } else { - result = Target_java_lang_Thread.EMPTY_STACK_TRACE; - } + result = getStackTraceAtSafepoint(thread); } } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/JavaStackWalker.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/JavaStackWalker.java index 10bd6811884c..d61c918290a0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/JavaStackWalker.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/JavaStackWalker.java @@ -298,6 +298,7 @@ public static boolean walkThread(IsolateThread thread, ParameterizedStackFrameVi @Uninterruptible(reason = "Prevent deoptimization of stack frames while in this method.") public static boolean walkThread(IsolateThread thread, Pointer endSP, ParameterizedStackFrameVisitor visitor, Object data) { + assert thread.isNonNull(); JavaStackWalk walk = StackValue.get(JavaStackWalk.class); if (initWalk(walk, thread)) { walk.setEndSP(endSP); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java index 4df97a21eeba..8d2d1c2a8a27 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java @@ -303,10 +303,12 @@ public static IsolateThread getIsolateThreadUnsafe(Thread t) { * Returns the isolate thread associated with a Java thread. The caller must own the * {@linkplain VMThreads#THREAD_MUTEX threads mutex} and release it only after it has finished * using the returned {@link IsolateThread} pointer. + * + * This method can return {@code NULL} if the thread is not alive or if it has been recently + * started but has not completed initialization yet. */ public static IsolateThread getIsolateThread(Thread t) { VMThreads.guaranteeOwnsThreadMutex("Threads mutex must be locked before accessing/iterating the thread list."); - VMError.guarantee(t.isAlive(), "Only running java.lang.Thread objects have a IsolateThread"); return getIsolateThreadUnsafe(t); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java index 189253efe91a..a6929b8507e1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java @@ -69,8 +69,8 @@ public final class Target_java_lang_Thread { // Checkstyle: stop - @Alias // - public static StackTraceElement[] EMPTY_STACK_TRACE; + @Delete // + static StackTraceElement[] EMPTY_STACK_TRACE; @Alias // @TargetElement(onlyWith = JDK19OrLater.class) // From 30172fa89b277dfaefc0a619445b8473a8338d3c Mon Sep 17 00:00:00 2001 From: Raphael Mosaner Date: Wed, 27 Sep 2023 15:33:59 +0200 Subject: [PATCH 29/78] [GR-50823] Fix stamp inversion for ZeroExtend and SignExtend operations. (cherry picked from commit ca8f6344a9c612e4b61399372c99629675dc1935) --- .../core/common/type/ArithmeticOpTable.java | 11 +- .../core/common/type/IntegerStamp.java | 58 ++++++--- .../nodes/test/StampInverterTest.java | 110 ++++++++++++++++++ 3 files changed, 159 insertions(+), 20 deletions(-) create mode 100644 compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampInverterTest.java diff --git a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticOpTable.java b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticOpTable.java index 735e0f887d7f..71670f49419e 100644 --- a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticOpTable.java +++ b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticOpTable.java @@ -985,7 +985,16 @@ public IntegerConvertOp unwrap() { } /** - * Computes the stamp of the input for the given output stamp. + * Computes the stamp of the input for the given output stamp. This method returns + * {@code null} if a stamp cannot be inverted for an operation (i.e., {@link Narrow}). When + * inverting non-exact stamps, i.e. {@code 0xx0xxxx}, the inversion keeps all available + * information. If the stamp to invert contains contradictions regarding the post condition + * of the operation, an empty stamp is returned. An example for a contradiction would be a + * {@code SignExtend} with both {@code 0} and {@code 1} in the extension. + * + * @return {@code null} - if stamp inversion is not supported
+ * empty stamp - if the output stamp contains contradictions
+ * inverted output stamp - otherwise
*/ public abstract Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp); } diff --git a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java index db304041b0ca..67c67d9906b3 100644 --- a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java +++ b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java @@ -1976,24 +1976,27 @@ public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) { } /* - * there is no guarantee that a given result is in the range of the + * There is no guarantee that a given result is in the range of the * input because of holes in ranges resulting from signed / unsigned * extension, so we must ensure that the extension bits are all zeros * otherwise we cannot represent the result, and we have to return an - * unrestricted stamp + * empty stamp. * * This case is much less likely to happen than the case for SignExtend * but the following is defensive to ensure that we only perform valid * inversions. */ - long alwaysSetOutputBits = stamp.mustBeSet(); - long alwaysSetExtensionBits = alwaysSetOutputBits >>> inputBits; - if (alwaysSetExtensionBits != 0) { - createEmptyStamp(inputBits); + long mustBeSetOutputBits = stamp.mustBeSet(); + long mustBeSetExtensionBits = mustBeSetOutputBits >>> inputBits; + if (mustBeSetExtensionBits != 0) { + return createEmptyStamp(inputBits); } long inputMask = CodeUtil.mask(inputBits); - return StampFactory.forUnsignedInteger(inputBits, stamp.lowerBound(), stamp.upperBound(), stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); + long inputUpperBound = maxValueForMasks(inputBits, stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); + long inputLowerBound = minValueForMasks(inputBits, stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); + + return StampFactory.forIntegerWithMask(inputBits, inputLowerBound, inputUpperBound, stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); } }, @@ -2029,11 +2032,11 @@ public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) { } /* - * there is no guarantee that a given result bit is in the range of the + * There is no guarantee that a given result bit is in the range of the * input because of holes in ranges resulting from signed / unsigned * extension, so we must ensure that the extension bits are either all * zeros or all ones otherwise we cannot represent the result, and we - * have to return an unrestricted stamp + * have to return an empty stamp. * * As an example: * @formatter:off @@ -2056,21 +2059,38 @@ public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) { * ZeroExtend to get 0xb308, but then we try to invert the SignExtend. * The sign extend could only have produced 0xff__ or 0x00__ from a byte * but 0xb308 has 0xb3, and so we cannot invert the stamp. In this case - * the only sensible inversion is the unrestricted stamp. + * the only sensible inversion is the empty stamp. */ - long alwaysSetOutputBits = stamp.mustBeSet(); - long alwaysSetExtensionBits = alwaysSetOutputBits >>> inputBits; - long outputMask = CodeUtil.mask(resultBits); - if (alwaysSetExtensionBits != 0 && alwaysSetExtensionBits != (outputMask >>> inputBits)) { + long mustBeSetExtensionBits = stamp.mustBeSet() >>> inputBits; + long mayBeSetExtensionBits = stamp.mayBeSet() >>> inputBits; + long extensionMask = CodeUtil.mask(stamp.getBits()) >>> inputBits; + + boolean zeroInExtension = mayBeSetExtensionBits != extensionMask; + boolean oneInExtension = mustBeSetExtensionBits != 0; + boolean inputMSBOne = significantBit(inputBits, stamp.mustBeSet()) == 1; + boolean inputMSBZero = significantBit(inputBits, stamp.mayBeSet()) == 0; + + /* + * Checks for contradictions in the extension and returns an empty stamp in such cases. + * Examples for contradictions for a stamp after an artificial 4->8 bit sign extension: + * + * @formatter:off + * + * 1) 01xx xxxx --> extension cannot contain zeroes and ones + * 2) x0xx 1xxx --> extension cannot contain a zero if the MSB of the extended value is 1 + * 3) xx1x 0xxx --> extension cannot contain a one if the MSB of the extended value is 0 + * + * @formatter:on + */ + if ((zeroInExtension && oneInExtension) || (inputMSBOne && zeroInExtension) || (inputMSBZero && oneInExtension)) { return createEmptyStamp(inputBits); } long inputMask = CodeUtil.mask(inputBits); - if (inputBits < stamp.getBits() && (stamp.contains(CodeUtil.minValue(inputBits) - 1) || stamp.contains(CodeUtil.maxValue(inputBits) + 1))) { - // Truncation will cause this value to wrap around - return create(inputBits).unrestricted(); - } - return StampFactory.forIntegerWithMask(inputBits, stamp.lowerBound(), stamp.upperBound(), stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); + long inputUpperBound = maxValueForMasks(inputBits, stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); + long inputLowerBound = minValueForMasks(inputBits, stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); + + return StampFactory.forIntegerWithMask(inputBits, inputLowerBound, inputUpperBound, stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); } }, diff --git a/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampInverterTest.java b/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampInverterTest.java new file mode 100644 index 000000000000..d9eede51abb7 --- /dev/null +++ b/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampInverterTest.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.nodes.test; + +import static org.junit.Assert.assertEquals; + +import org.graalvm.compiler.core.common.type.ArithmeticOpTable; +import org.graalvm.compiler.core.common.type.IntegerStamp; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.SignExtend; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.ZeroExtend; +import org.graalvm.compiler.test.GraalTest; +import org.junit.Test; + +import jdk.vm.ci.code.CodeUtil; + +/** + * Tests the expected behavior of inverting stamps for different operations. During stamp inversion, + * the input stamp is calculated from a given output stamp. If a particular stamp cannot be inverted + * because of a contradiction regarding the operation's post condition, the inversion process is + * supposed to return an empty stamp. An example for a contradiction would be both {@code 0} and + * {@code 1} bits in the extension of a {@code SignExtend}. + */ +public class StampInverterTest extends GraalTest { + + private static Stamp invertSignExtend(Stamp toInvert) { + IntegerConvertOp signExtend = ArithmeticOpTable.forStamp(toInvert).getSignExtend(); + return signExtend.invertStamp(8, 32, toInvert); + } + + @Test + public void invertIntegerSignExtend01() { + // 32- > 8bit: xx...xx 11xxxxxx -> 11xxxxxx + IntegerStamp stamp = IntegerStamp.stampForMask(32, 128 | 64, CodeUtil.mask(32)); + Stamp expected = IntegerStamp.stampForMask(8, 128 | 64, CodeUtil.mask(8)); + assertEquals(expected, invertSignExtend(stamp)); + } + + @Test + public void invertIntegerSignExtend02() { + // 32 -> 8bit: xx...10 11xxxxxx -> cannot be inverted + IntegerStamp stamp = IntegerStamp.stampForMask(32, 512 | 128 | 64, CodeUtil.mask(32) ^ 256); + assertTrue("Stamp cannot be inverted and should be empty!", invertSignExtend(stamp).isEmpty()); + } + + @Test + public void invertIntegerSignExtend03() { + // 32 -> 8bit: xx...1x 0xxxxxxx -> cannot be inverted + IntegerStamp stamp = IntegerStamp.stampForMask(32, 512, CodeUtil.mask(32) ^ 128); + assertTrue("Stamp cannot be inverted and should be empty!", invertSignExtend(stamp).isEmpty()); + } + + @Test + public void invertIntegerSignExtend04() { + // 32 -> 8bit: xx...x0 1xxxxxxx -> cannot be inverted + IntegerStamp stamp = IntegerStamp.stampForMask(32, 128, CodeUtil.mask(32) ^ 256); + assertTrue("Stamp cannot be inverted and should be empty!", invertSignExtend(stamp).isEmpty()); + } + + private static Stamp invertZeroExtend(Stamp toInvert) { + IntegerConvertOp signExtend = ArithmeticOpTable.forStamp(toInvert).getZeroExtend(); + return signExtend.invertStamp(8, 32, toInvert); + } + + @Test + public void invertIntegerZeroExtend01() { + // 32- > 8bit: xx...xx 11xxxxxx -> 11xxxxxx + IntegerStamp stamp = IntegerStamp.stampForMask(32, 128 | 64, CodeUtil.mask(32)); + Stamp expected = IntegerStamp.stampForMask(8, 128 | 64, CodeUtil.mask(8)); + assertEquals(expected, invertZeroExtend(stamp)); + } + + @Test + public void invertIntegerZeroExtend02() { + // 32- > 8bit: xx...0x 01xxxxxx -> 01xxxxxx + IntegerStamp stamp = IntegerStamp.stampForMask(32, 64, CodeUtil.mask(32) ^ (512 | 128)); + Stamp expected = IntegerStamp.stampForMask(8, 64, CodeUtil.mask(8) ^ 128); + assertEquals(expected, invertZeroExtend(stamp)); + } + + @Test + public void invertIntegerZeroExtend03() { + // 32- > 8bit: xx...1x 01xxxxxx -> cannot be inverted + IntegerStamp stamp = IntegerStamp.stampForMask(32, 512 | 64, CodeUtil.mask(32) ^ 128); + assertTrue("Stamp cannot be inverted and should be empty!", invertZeroExtend(stamp).isEmpty()); + } +} From 5bc925f8e0b5d03d0ccbf9b74e1f52fd75c6c596 Mon Sep 17 00:00:00 2001 From: Raphael Mosaner Date: Tue, 3 Oct 2023 13:25:49 +0200 Subject: [PATCH 30/78] [GR-50823] Unittests for stamp inversion during conditional elimination. (cherry picked from commit 1ec8ea434e60173fd5bd23cd23f0bb54cd8d19ca) --- ...ditionalEliminationStampInversionTest.java | 109 ++++++++++++++++++ .../CompareZeroExtendWithConstantTest.java | 20 +++- 2 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationStampInversionTest.java diff --git a/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationStampInversionTest.java b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationStampInversionTest.java new file mode 100644 index 000000000000..bb5879b8aab2 --- /dev/null +++ b/compiler/src/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationStampInversionTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.core.test; + +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FixedGuardNode; +import org.graalvm.compiler.nodes.IfNode; +import org.graalvm.compiler.nodes.LogicNode; +import org.graalvm.compiler.nodes.NodeView; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.AndNode; +import org.graalvm.compiler.nodes.calc.IntegerEqualsNode; +import org.graalvm.compiler.nodes.calc.IntegerTestNode; +import org.graalvm.compiler.nodes.calc.SignExtendNode; +import org.graalvm.compiler.nodes.util.GraphUtil; +import org.graalvm.compiler.phases.common.ConditionalEliminationPhase; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.junit.Test; + +import jdk.vm.ci.code.InvalidInstalledCodeException; +import jdk.vm.ci.meta.DeoptimizationAction; +import jdk.vm.ci.meta.DeoptimizationReason; + +/** + * Tests the correctness of conditional elimination when inverting stamps along + * {@link SignExtendNode}. The test artificially creates a graph whith the optimizable pattern: + * {@code ((val & CONST) == CONST)}, which provides information about the set bits in val, if the + * condition is used in a guard which is assumed to hold. The partial information about bits which + * are set in {@code x} are propagated "upwards". A {@link SignExtendNode} must treat the partial + * information correctly with respect to the extension bits and handle contradictions. + *

+ * If {@code CONST = 1 << 4 = 0001 0000} and we assume the condition holds, we can refine a stamp + * {@code xxxx xx11} for {@code val} to {@code xxx1 xx11}. Inverting this refined stamp along an + * artificial 4->8 bit sign extension should treat the extension as {@code 1111} and produce an + * inverted stamp of {@code xx11} or, even better {@code 1x11}, because we know the MSB has to be + * one from the extension. + *

+ * If the inversion is performed incorrectly, the inner condition could be considered as always + * false and removing it during conditional elimination. + */ +public class ConditionalEliminationStampInversionTest extends GraalCompilerTest { + + public static boolean snippet(byte b) { + short s = b; + int i = s; + + if ((i & (1 << 16)) == (1 << 16)) { + if (s == -5) { + return true; + } + } + return false; + } + + @Test + public void test() throws InvalidInstalledCodeException { + StructuredGraph g = parseEager("snippet", AllowAssumptions.YES); + + // replace the IntegerTest by an equivalent and/== pattern + ValueNode intTest = g.getNodes().filter(IntegerTestNode.class).first(); + assertTrue("IntegerTestNode expected in graph.", intTest != null); + + ValueNode signExtend = g.getNodes().filter(SignExtendNode.class).first(); + assertTrue("SignExtendNode expected in graph.", signExtend != null); + + ValueNode and = g.addOrUnique(AndNode.create(signExtend, ConstantNode.forInt(1 << 16, g), NodeView.DEFAULT)); + and.inferStamp(); + LogicNode intEq = g.addOrUnique(IntegerEqualsNode.create(and, ConstantNode.forInt(1 << 16, g), NodeView.DEFAULT)); + intEq.inferStamp(); + + intTest.replaceAtUsages(intEq); + + // replace the if by a fixed guard to trigger conditional elimination for the and/== pattern + ValueNode ifNode = (ValueNode) intEq.usages().first(); + assertTrue("IfNode expected as first usage of IntegerEqualsNode.", ifNode != null && ifNode instanceof IfNode); + + FixedGuardNode guard = g.add(new FixedGuardNode(intEq, DeoptimizationReason.ArithmeticException, DeoptimizationAction.InvalidateRecompile)); + GraphUtil.killCFG(((IfNode) ifNode).trueSuccessor()); + g.replaceSplitWithFixed((IfNode) ifNode, guard, ((IfNode) ifNode).falseSuccessor()); + + new ConditionalEliminationPhase(false).apply(g, getDefaultHighTierContext()); + + // the inner condition should still be alive and the following execution return true + assert (boolean) getCode(getResolvedJavaMethod("snippet"), g, true, true, getInitialOptions()).executeVarargs((byte) -5); + } +} diff --git a/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/CompareZeroExtendWithConstantTest.java b/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/CompareZeroExtendWithConstantTest.java index 598fe64fccdc..a0613bf26df9 100644 --- a/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/CompareZeroExtendWithConstantTest.java +++ b/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/CompareZeroExtendWithConstantTest.java @@ -32,7 +32,7 @@ public class CompareZeroExtendWithConstantTest extends GraalCompilerTest { public static byte[] a = {}; - public static void snippet() { + public static void snippet01() { for (byte b : a) { char c = (char) b; GraalDirectives.blackhole(c); @@ -43,7 +43,21 @@ public static void snippet() { } @Test - public void testSnippet() { - test("snippet"); + public void testSnippet01() { + test("snippet01"); + } + + public static boolean snippet02(boolean p0, long p1) { + boolean var0 = p0; + byte b = (byte) p1; + for (long i = 245799965; i >= 245797839; i = 3) { + b = (byte) Character.toUpperCase((char) b); + } + return var0; + } + + @Test + public void testSnippet02() { + test("snippet02", true, 53069L); } } From 9dc51843f7e1483f56e89a891001df16927efcdc Mon Sep 17 00:00:00 2001 From: Raphael Mosaner Date: Tue, 3 Oct 2023 13:27:07 +0200 Subject: [PATCH 31/78] [GR-50823] Infer input msb during stamp inversion for integer SignExtend. (cherry picked from commit 9be87d0746d8acbf43387e496b013d14754925c2) --- .../core/common/type/IntegerStamp.java | 35 +++++++++++++++++-- .../nodes/test/StampInverterTest.java | 16 +++++++++ 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java index 67c67d9906b3..fecf3a436bb5 100644 --- a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java +++ b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java @@ -2086,11 +2086,40 @@ public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) { return createEmptyStamp(inputBits); } + /* + * Calculate bounds and mayBeSet/mustBeSet bits for the input based on + * bit width and potentially inferred msb. + */ long inputMask = CodeUtil.mask(inputBits); - long inputUpperBound = maxValueForMasks(inputBits, stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); - long inputLowerBound = minValueForMasks(inputBits, stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); + long inputMustBeSet = stamp.mustBeSet() & inputMask; + long inputMayBeSet = stamp.mayBeSet() & inputMask; - return StampFactory.forIntegerWithMask(inputBits, inputLowerBound, inputUpperBound, stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); + if (!inputMSBOne && !inputMSBZero) { + /* + * Input MSB yet unknown, try to infer it from the extension: + * + * @formatter:off + * + * xx0x xxxx implies that the extension is 0000 which implies that the MSB of the input is 0 + * x1xx xxxx implies that the extension is 1111 which implies that the MSB of the input is 1 + * + * @formatter:on + */ + if (zeroInExtension) { + long msbZeroMask = inputMask ^ (1 << (inputBits - 1)); + inputMustBeSet &= msbZeroMask; + inputMayBeSet &= msbZeroMask; + } else if (oneInExtension) { + long msbOneMask = 1 << (inputBits - 1); + inputMustBeSet |= msbOneMask; + inputMayBeSet |= msbOneMask; + } + } + + long inputUpperBound = maxValueForMasks(inputBits, inputMustBeSet, inputMayBeSet); + long inputLowerBound = minValueForMasks(inputBits, inputMustBeSet, inputMayBeSet); + + return StampFactory.forIntegerWithMask(inputBits, inputLowerBound, inputUpperBound, inputMustBeSet, inputMayBeSet); } }, diff --git a/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampInverterTest.java b/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampInverterTest.java index d9eede51abb7..ac91399a2e32 100644 --- a/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampInverterTest.java +++ b/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampInverterTest.java @@ -80,6 +80,22 @@ public void invertIntegerSignExtend04() { assertTrue("Stamp cannot be inverted and should be empty!", invertSignExtend(stamp).isEmpty()); } + @Test + public void invertIntegerSignExtend05() { + // 32 -> 8bit: xx...x0 xxxxxxxx -> 0xxxxxxx (msb has to be 0) + IntegerStamp stamp = IntegerStamp.stampForMask(32, 0, CodeUtil.mask(32) ^ 256); + Stamp expected = IntegerStamp.stampForMask(8, 0, CodeUtil.mask(7)); + assertEquals(expected, invertSignExtend(stamp)); + } + + @Test + public void invertIntegerSignExtend06() { + // 32 -> 8bit: xx...x1 xxxxxxxx -> 1xxxxxxx (msb has to be 1) + IntegerStamp stamp = IntegerStamp.stampForMask(32, 256, CodeUtil.mask(32)); + Stamp expected = IntegerStamp.stampForMask(8, 128, CodeUtil.mask(8)); + assertEquals(expected, invertSignExtend(stamp)); + } + private static Stamp invertZeroExtend(Stamp toInvert) { IntegerConvertOp signExtend = ArithmeticOpTable.forStamp(toInvert).getZeroExtend(); return signExtend.invertStamp(8, 32, toInvert); From d27644e0fc86e5bd6e307bf8c49b4e61ab2149b0 Mon Sep 17 00:00:00 2001 From: Raphael Mosaner Date: Tue, 10 Oct 2023 09:56:10 +0200 Subject: [PATCH 32/78] [GR-50823] Incorporate the bounds of stampToInvert when calculating the bounds of the inverted stamp. (cherry picked from commit b55090942607dfcf2a124ecb0b0fa71078854273) --- .../core/common/type/IntegerStamp.java | 30 +++-- .../core/common/type/StampFactory.java | 24 ++++ .../nodes/test/StampInverterTest.java | 123 +++++++++++++++++- 3 files changed, 163 insertions(+), 14 deletions(-) diff --git a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java index fecf3a436bb5..6e497f67ce20 100644 --- a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java +++ b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java @@ -1992,11 +1992,15 @@ public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) { return createEmptyStamp(inputBits); } - long inputMask = CodeUtil.mask(inputBits); - long inputUpperBound = maxValueForMasks(inputBits, stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); - long inputLowerBound = minValueForMasks(inputBits, stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); + /* + * The output of a zero extend cannot be negative. Setting the lower + * bound > 0 enables inverting stamps like [-8, 16] without having to + * return an unrestricted stamp. + */ + long lowerBound = Math.max(stamp.lowerBound(), 0); + assert stamp.upperBound() >= 0 : "Cannot invert ZeroExtend for stamp with msb=1, which implies a negative value after ZeroExtend!"; - return StampFactory.forIntegerWithMask(inputBits, inputLowerBound, inputUpperBound, stamp.mustBeSet() & inputMask, stamp.mayBeSet() & inputMask); + return StampFactory.forUnsignedInteger(inputBits, lowerBound, stamp.upperBound(), stamp.mustBeSet(), stamp.mayBeSet()); } }, @@ -2086,10 +2090,6 @@ public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) { return createEmptyStamp(inputBits); } - /* - * Calculate bounds and mayBeSet/mustBeSet bits for the input based on - * bit width and potentially inferred msb. - */ long inputMask = CodeUtil.mask(inputBits); long inputMustBeSet = stamp.mustBeSet() & inputMask; long inputMayBeSet = stamp.mayBeSet() & inputMask; @@ -2106,7 +2106,7 @@ public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) { * @formatter:on */ if (zeroInExtension) { - long msbZeroMask = inputMask ^ (1 << (inputBits - 1)); + long msbZeroMask = ~(1 << (inputBits - 1)); inputMustBeSet &= msbZeroMask; inputMayBeSet &= msbZeroMask; } else if (oneInExtension) { @@ -2116,9 +2116,21 @@ public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) { } } + // Calculate conservative bounds for the input. long inputUpperBound = maxValueForMasks(inputBits, inputMustBeSet, inputMayBeSet); long inputLowerBound = minValueForMasks(inputBits, inputMustBeSet, inputMayBeSet); + /* + * If the bounds calculated for the input stamp do not overlap with the + * bounds for the stamp to invert, return an empty stamp. Otherwise, + * refine the conservative stamp for the input. + */ + if ((stamp.upperBound() < inputLowerBound) || (stamp.lowerBound() > inputUpperBound)) { + return createEmptyStamp(inputBits); + } + inputUpperBound = Math.min(inputUpperBound, stamp.upperBound()); + inputLowerBound = Math.max(inputLowerBound, stamp.lowerBound()); + return StampFactory.forIntegerWithMask(inputBits, inputLowerBound, inputUpperBound, inputMustBeSet, inputMayBeSet); } }, diff --git a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java index 13b32d1fd5cc..8da3ce14210c 100644 --- a/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java +++ b/compiler/src/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java @@ -161,6 +161,30 @@ public static IntegerStamp forUnsignedInteger(int bits, long unsignedLowerBound, return forUnsignedInteger(bits, unsignedLowerBound, unsignedUpperBound, 0, CodeUtil.mask(bits)); } + /** + * Creates an IntegerStamp from the given unsigned bounds and bit masks. This method returns an + * empty stamp if the unsigned lower bound is larger than the unsigned upper bound. If the sign + * of lower and upper bound differs after sign extension to the specified length ({@code bits}), + * this method returns an unrestricted stamp with respect to the bounds. {@code mayBeSet} or + * {@code mustBeSet} can restrict the bounds nevertheless. Take the following example when + * inverting a zero extended 32bit stamp to the 8bit stamp before extension: + * + *

+ * 32bit stamp [0, 192] 00...00 xxxxxxx0 + *

+ * When converting the bounds to 8bit, they have different signs, i.e.: + *

+ * lowerUnsigned = 0000 0000 and upperUnsigned = 1100 0000 + *

+ * In order to respect the (unsigned) boundaries of the extended value, the signed input can be: + *

+ * 0000 0000 - 0111 1111, i.e. 0 to 127
+ * or
+ * 1000 0000 - 1100 0000, i.e. -128 to -64 + *

+ * The resulting interval [-128, -64]u[0, 127] cannot be represented by a single upper and lower + * bound. Thus, we have to return an unrestricted stamp, with respect to the bounds. + */ public static IntegerStamp forUnsignedInteger(int bits, long unsignedLowerBound, long unsignedUpperBound, long mustBeSet, long mayBeSet) { if (Long.compareUnsigned(unsignedLowerBound, unsignedUpperBound) > 0) { return IntegerStamp.createEmptyStamp(bits); diff --git a/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampInverterTest.java b/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampInverterTest.java index ac91399a2e32..69d14a8a4455 100644 --- a/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampInverterTest.java +++ b/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/StampInverterTest.java @@ -96,14 +96,60 @@ public void invertIntegerSignExtend06() { assertEquals(expected, invertSignExtend(stamp)); } + @Test + public void invertIntegerSignExtend07() { + // 32 -> 8bit: [-128, 126] xx...xx xxxxxxx0 -> [-128, 126] xxxxxxx0 + IntegerStamp stamp = IntegerStamp.create(32, -128, 126, 0, CodeUtil.mask(32) ^ 1); + Stamp expected = IntegerStamp.create(8, -128, 126, 0, CodeUtil.mask(32) ^ 1); + assertEquals(expected, invertSignExtend(stamp)); + } + + @Test + public void invertIntegerSignExtend08() { + // 32 -> 8bit: [-256, 126] xx...xx 0xxxxxx0 -> [0, 126] 0xxxxxx0 + IntegerStamp stamp = IntegerStamp.create(32, -256, 126, 0, CodeUtil.mask(32) ^ (256 | 1)); + Stamp expected = IntegerStamp.create(8, 0, 126, 0, CodeUtil.mask(32) ^ (256 | 1)); + assertEquals(expected, invertSignExtend(stamp)); + } + + @Test + public void invertIntegerSignExtend09() { + // 32 -> 8bit: [-8, 126] xx...xx xxxxxxx0 -> [-8, 126] xxxxxxx0 + IntegerStamp stamp = IntegerStamp.create(32, -8, 126, 0, CodeUtil.mask(32) ^ 1); + Stamp expected = IntegerStamp.create(8, -8, 126, 0, CodeUtil.mask(32) ^ 1); + assertEquals(expected, invertSignExtend(stamp)); + } + + @Test + public void invertIntegerSignExtend10() { + // 32 -> 8bit: [int min, -1024] 1x...xx xxxxxxxx -> empty + IntegerStamp stamp = IntegerStamp.create(32, Integer.MIN_VALUE, -1024); + assertTrue("Stamp cannot be inverted and should be empty!", invertSignExtend(stamp).isEmpty()); + } + + @Test + public void invertIntegerSignExtend11() { + // 32 -> 8bit: [1024, int max] 0x...xx xxxxxxxx -> empty + IntegerStamp stamp = IntegerStamp.create(32, 1024, Integer.MAX_VALUE); + assertTrue("Stamp cannot be inverted and should be empty!", invertSignExtend(stamp).isEmpty()); + } + + @Test + public void invertIntegerSignExtend12() { + // 32 -> 8bit: [0, 255] 00...00 xxxxxxxx -> [0, 127] 0xxxxxxx + IntegerStamp stamp = IntegerStamp.create(32, 0, 255, 0, CodeUtil.mask(8)); + Stamp expected = IntegerStamp.create(8, 0, 127, 0, CodeUtil.mask(7)); + assertEquals(expected, invertSignExtend(stamp)); + } + private static Stamp invertZeroExtend(Stamp toInvert) { - IntegerConvertOp signExtend = ArithmeticOpTable.forStamp(toInvert).getZeroExtend(); - return signExtend.invertStamp(8, 32, toInvert); + IntegerConvertOp zeroExtend = ArithmeticOpTable.forStamp(toInvert).getZeroExtend(); + return zeroExtend.invertStamp(8, 32, toInvert); } @Test public void invertIntegerZeroExtend01() { - // 32- > 8bit: xx...xx 11xxxxxx -> 11xxxxxx + // 32 -> 8bit: xx...xx 11xxxxxx -> 11xxxxxx IntegerStamp stamp = IntegerStamp.stampForMask(32, 128 | 64, CodeUtil.mask(32)); Stamp expected = IntegerStamp.stampForMask(8, 128 | 64, CodeUtil.mask(8)); assertEquals(expected, invertZeroExtend(stamp)); @@ -111,7 +157,7 @@ public void invertIntegerZeroExtend01() { @Test public void invertIntegerZeroExtend02() { - // 32- > 8bit: xx...0x 01xxxxxx -> 01xxxxxx + // 32 -> 8bit: xx...0x 01xxxxxx -> 01xxxxxx IntegerStamp stamp = IntegerStamp.stampForMask(32, 64, CodeUtil.mask(32) ^ (512 | 128)); Stamp expected = IntegerStamp.stampForMask(8, 64, CodeUtil.mask(8) ^ 128); assertEquals(expected, invertZeroExtend(stamp)); @@ -119,8 +165,75 @@ public void invertIntegerZeroExtend02() { @Test public void invertIntegerZeroExtend03() { - // 32- > 8bit: xx...1x 01xxxxxx -> cannot be inverted + // 32 -> 8bit: xx...1x 01xxxxxx -> cannot be inverted IntegerStamp stamp = IntegerStamp.stampForMask(32, 512 | 64, CodeUtil.mask(32) ^ 128); assertTrue("Stamp cannot be inverted and should be empty!", invertZeroExtend(stamp).isEmpty()); } + + @Test + public void invertIntegerZeroExtend04() { + // 32 -> 8bit: [int min, int max -1] xx...xx xxxxxxx0 -> [-128, 126] xxxxxxx0 + IntegerStamp stamp = IntegerStamp.create(32, Integer.MIN_VALUE, Integer.MAX_VALUE - 1, 0, CodeUtil.mask(32) ^ 1); + Stamp expected = IntegerStamp.create(8, -128, 126, 0, CodeUtil.mask(8) ^ 1); + assertEquals(expected, invertZeroExtend(stamp)); + } + + @Test + public void invertIntegerZeroExtend5() { + /* + * 32 -> 8bit: [0, 192] 00...00 xxxxxxx0 -> [-128, 126] xxxxxxx0 + * + * The 32bit stamp bounds have different signs when converting to 8bit: + * lowerUnsigned = 0000 0000, upperUnsigned = 1100 0000. + * In order to respect the (unsigned) boundaries of the extended value, the signed input can be: + * @formatter:off + * + * 0000 0000 - 0111 1111, i.e. 0 to 127 + * or + * 1000 0000 - 1100 0000, i.e. -128 to -64 + * + * @formatter:on + * The resulting interval [-128, -64]u[0, 127] cannot be represented by a single upper and + * lower bound. Thus, we have to return an unrestricted stamp, with respect to the bounds. + */ + IntegerStamp stamp = IntegerStamp.create(32, 0, 192, 0, CodeUtil.mask(8) ^ 1); + Stamp expected = IntegerStamp.create(8, -128, 126, 0, CodeUtil.mask(8) ^ 1); + assertEquals(expected, invertZeroExtend(stamp)); + } + + @Test + public void invertIntegerZeroExtend06() { + /* + * 32 -> 8bit: [-8, 16] xx...xx xxxxxxx0 -> [0, 16] xxxxxxx0 + * + * Negative lower bounds can be clamped to 0. + */ + IntegerStamp stamp = IntegerStamp.create(32, -8, 16, 0, CodeUtil.mask(32) ^ 1); + Stamp expected = IntegerStamp.create(8, 0, 16, 0, CodeUtil.mask(8) ^ 1); + assertEquals(expected, invertZeroExtend(stamp)); + } + + @Test + public void invertIntegerZeroExtend07() { + // 32 -> 8bit: [2, 18] 00...00 000xxx10 -> [2, 18] 000xxx10 + IntegerStamp stamp = IntegerStamp.create(32, 2, 18, 2, CodeUtil.mask(5) ^ 1); + Stamp expected = IntegerStamp.create(8, 2, 18, 2, CodeUtil.mask(5) ^ 1); + assertEquals(expected, invertZeroExtend(stamp)); + } + + @Test + public void invertIntegerZeroExtend08() { + // 32 -> 8bit: [128, 254] 00...00 1xxxxxx0 -> [-128, -2] 1xxxxxx0 + IntegerStamp stamp = IntegerStamp.create(32, 128, 254, 128, CodeUtil.mask(8) ^ 1); + Stamp expected = IntegerStamp.create(8, -128, -2, 128, CodeUtil.mask(8) ^ 1); + assertEquals(expected, invertZeroExtend(stamp)); + } + + @Test + public void invertIntegerZeroExtend09() { + // 32 -> 8bit: [int min ^ 128, 254] xx...xx xxxxxxx0 -> [-128, 126] xxxxxxx0 + IntegerStamp stamp = IntegerStamp.create(32, Integer.MIN_VALUE ^ 128, 254, 0, CodeUtil.mask(32) ^ 1); + Stamp expected = IntegerStamp.create(8, -128, 126, 0, CodeUtil.mask(8) ^ 1); + assertEquals(expected, invertZeroExtend(stamp)); + } } From 3ec89db79ce52f5b29cdaa3d2866cd3e737b8086 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Mon, 18 Dec 2023 19:46:27 +0100 Subject: [PATCH 33/78] Preprocess `_MSC_FULL_VER` to detect `cl.exe` version info. The previous approach relied on the version string of `cl.exe`, which is localized and thus not always correctly detected when the system language is not English. (cherry picked from commit 162d5c09216d12d53e37f4e92df0ba24445021a8) --- .../hosted/c/codegen/CCompilerInvoker.java | 69 ++++++++++--------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java index d53f78e4e220..7e49bb3e99d3 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java @@ -32,7 +32,6 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.NoSuchElementException; import java.util.Optional; @@ -52,6 +51,7 @@ import com.oracle.svm.core.option.SubstrateOptionsParser; import com.oracle.svm.core.util.InterruptImageBuilding; import com.oracle.svm.core.util.UserError; +import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.c.libc.HostedLibCBase; import com.oracle.svm.hosted.c.util.FileUtils; import com.oracle.svm.util.ClassUtil; @@ -138,47 +138,52 @@ protected InputStream getCompilerErrorStream(Process compilingProcess) { @Override protected List getVersionInfoOptions() { - return Collections.emptyList(); + Path detectVersionInfoFile = tempDirectory.resolve("detect-cl-version-info.c").toAbsolutePath(); + try { + Files.write(detectVersionInfoFile, List.of("M_X64=_M_X64", "M_ARM64EC=_M_ARM64EC", "MSC_FULL_VER=_MSC_FULL_VER")); + } catch (IOException ioe) { + throw VMError.shouldNotReachHere("Unable to create file to detect cl version info", ioe); + } + return List.of("/EP", detectVersionInfoFile.toString()); } @Override - protected CompilerInfo createCompilerInfo(Path compilerPath, Scanner outerScanner) { - try (Scanner scanner = new Scanner(outerScanner.nextLine())) { - String targetArch = null; - /* For cl.exe the first line holds all necessary information */ - if (scanner.hasNext("\u7528\u4E8E")) { - /* Simplified-Chinese has targetArch first */ - scanner.next(); - targetArch = scanner.next(); + protected CompilerInfo createCompilerInfo(Path compilerPath, Scanner scanner) { + try { + if (scanner.findInLine("Microsoft.*\\(R\\)") == null) { + return null; // not a Microsoft compiler } - /* - * Some cl.exe print "... Microsoft (R) C/C++ ... ##.##.#####" while others print - * "...C/C++ ... Microsoft (R) ... ##.##.#####". - */ - if (scanner.findInLine("Microsoft.*\\(R\\) C/C\\+\\+") == null && - scanner.findInLine("C/C\\+\\+.*Microsoft.*\\(R\\)") == null) { + scanner.nextLine(); // skip rest of first line + scanner.nextLine(); // skip copyright line + scanner.nextLine(); // skip blank separator line + skipLineIfHasNext(scanner, "detect-cl-version-info.c"); + scanner.nextLine(); // skip blank separator line + skipLineIfHasNext(scanner, "M_X64=100"); // _M_X64 is defined + skipLineIfHasNext(scanner, "M_ARM64EC=_M_ARM64EC"); // _M_ARM64EC is not defined + if (scanner.findInLine("MSC_FULL_VER=") == null) { return null; } - scanner.useDelimiter("\\D"); - while (!scanner.hasNextInt()) { - scanner.next(); - } - int major = scanner.nextInt(); - int minor0 = scanner.nextInt(); - int minor1 = scanner.nextInt(); - if (targetArch == null) { - scanner.reset(); - while (scanner.hasNext()) { - /* targetArch is last token in line */ - targetArch = scanner.next(); - } + String mscFullVerValue = scanner.nextLine(); + if (mscFullVerValue.length() < 5) { + return null; } - return new CompilerInfo(compilerPath, "microsoft", "C/C++ Optimizing Compiler", "cl", major, minor0, minor1, targetArch); - } catch (NoSuchElementException e) { + int major = Integer.parseInt(mscFullVerValue.substring(0, 2)); + int minor0 = Integer.parseInt(mscFullVerValue.substring(2, 4)); + int minor1 = Integer.parseInt(mscFullVerValue.substring(4)); + return new CompilerInfo(compilerPath, "microsoft", "C/C++ Optimizing Compiler", "cl", major, minor0, minor1, "x64"); + } catch (NoSuchElementException | NumberFormatException e) { return null; } } + private void skipLineIfHasNext(Scanner scanner, String expectedToken) { + if (scanner.hasNext(expectedToken)) { + scanner.nextLine(); + } else { + throw new NoSuchElementException(expectedToken); + } + } + @Override protected void verify() { // See details on _MSC_VER at @@ -415,7 +420,7 @@ private CompilerInfo getCCompilerInfo() { } protected List getVersionInfoOptions() { - return Arrays.asList("-v"); + return List.of("-v"); } protected abstract CompilerInfo createCompilerInfo(Path compilerPath, Scanner scanner); From 0d15e3818f94433455985113992906551d721730 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Wed, 20 Dec 2023 12:31:40 +0100 Subject: [PATCH 34/78] Drop redundant architecture error for Windows. (cherry picked from commit 3a00ce650849ab41290b68254684892128f79ce0) --- .../com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java index 7e49bb3e99d3..2afd80b331ee 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java @@ -194,11 +194,6 @@ protected void verify() { UserError.abort("On Windows, GraalVM Native Image for JDK %s requires %s or later (C/C++ Optimizing Compiler Version %s.%s or later).%nCompiler info detected: %s", JavaVersionUtil.JAVA_SPEC, VISUAL_STUDIO_MINIMUM_REQUIRED_VERSION, minimumMajorVersion, minimumMinorVersion, compilerInfo.getShortDescription()); } - if (guessArchitecture(compilerInfo.targetArch) != AMD64.class) { - String targetPrefix = compilerInfo.targetArch.matches("(.*x|i\\d)86$") ? "32-bit architecture " : ""; - UserError.abort("Native-image building on Windows currently only supports target architecture: %s (%s%s unsupported)", - AMD64.class.getSimpleName(), targetPrefix, compilerInfo.targetArch); - } } @Override From fa26b2feb88c9479d3c8a90fb224fe5bc74b347a Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Wed, 24 Jan 2024 08:32:43 +0100 Subject: [PATCH 35/78] Mark `skipLineIfHasNext` as static. --- .../src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java index 2afd80b331ee..8e8c9b6c8327 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CCompilerInvoker.java @@ -176,7 +176,7 @@ protected CompilerInfo createCompilerInfo(Path compilerPath, Scanner scanner) { } } - private void skipLineIfHasNext(Scanner scanner, String expectedToken) { + private static void skipLineIfHasNext(Scanner scanner, String expectedToken) { if (scanner.hasNext(expectedToken)) { scanner.nextLine(); } else { From 3029285c53e8699c460c85106f555172d71923fd Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Fri, 12 Jan 2024 17:18:11 +0100 Subject: [PATCH 36/78] Add memory barrier to HeapImpl.getAllClasses(). --- .../src/com/oracle/svm/core/genscavenge/HeapImpl.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) 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 3ff72c4c8549..2171d248b0a9 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 @@ -32,6 +32,7 @@ import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.core.common.SuppressFBWarnings; +import org.graalvm.compiler.nodes.extended.MembarNode; import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; import org.graalvm.compiler.word.Word; import org.graalvm.nativeimage.CurrentIsolate; @@ -42,17 +43,16 @@ import org.graalvm.word.UnsignedWord; import com.oracle.svm.core.MemoryWalker; +import com.oracle.svm.core.NeverInline; import com.oracle.svm.core.SubstrateDiagnostics; import com.oracle.svm.core.SubstrateDiagnostics.DiagnosticThunk; import com.oracle.svm.core.SubstrateDiagnostics.DiagnosticThunkRegistry; import com.oracle.svm.core.SubstrateDiagnostics.ErrorContext; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateUtil; -import com.oracle.svm.core.NeverInline; -import com.oracle.svm.core.heap.RestrictHeapAccess; +import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; -import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.genscavenge.AlignedHeapChunk.AlignedHeader; import com.oracle.svm.core.genscavenge.ThreadLocalAllocation.Descriptor; @@ -69,6 +69,7 @@ import com.oracle.svm.core.heap.ReferenceHandler; import com.oracle.svm.core.heap.ReferenceHandlerThread; import com.oracle.svm.core.heap.ReferenceInternals; +import com.oracle.svm.core.heap.RestrictHeapAccess; import com.oracle.svm.core.heap.RuntimeCodeInfoGCSupport; import com.oracle.svm.core.jdk.UninterruptibleUtils.AtomicReference; import com.oracle.svm.core.locks.VMCondition; @@ -337,6 +338,9 @@ protected List> getAllClasses() { ArrayList> list = new ArrayList<>(1024); ImageHeapWalker.walkRegions(imageHeapInfo, new ClassListBuilderVisitor(list)); list.trimToSize(); + + /* Ensure that other threads see consistent values once the list is published. */ + MembarNode.memoryBarrier(MembarNode.FenceKind.STORE_STORE); classList = list; } assert classList.size() == imageHeapInfo.dynamicHubCount; From e4960ed015a7eb129b674acbb41706a527faa208 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Fri, 12 Jan 2024 18:43:43 +0100 Subject: [PATCH 37/78] Crash log improvements. --- .../src/org/graalvm/nativeimage/Platform.java | 10 +- .../oracle/svm/core/genscavenge/HeapImpl.java | 64 +-- .../posix/PosixSubstrateSegfaultHandler.java | 6 +- .../WindowsSubstrateSegfaultHandler.java | 3 +- .../com/oracle/svm/core/CPUFeatureAccess.java | 8 + .../src/com/oracle/svm/core/DebugHelper.java | 2 +- .../src/com/oracle/svm/core/Isolates.java | 27 + .../com/oracle/svm/core/JavaMainWrapper.java | 4 +- .../oracle/svm/core/SubstrateDiagnostics.java | 465 ++++++++++++------ .../com/oracle/svm/core/SubstrateOptions.java | 3 + .../svm/core/SubstrateSegfaultHandler.java | 9 + .../oracle/svm/core/code/CodeInfoAccess.java | 2 +- .../oracle/svm/core/code/CodeInfoDecoder.java | 9 +- .../svm/core/code/FrameInfoDecoder.java | 4 +- .../svm/core/code/RuntimeCodeInfoHistory.java | 20 +- .../oracle/svm/core/deopt/Deoptimizer.java | 6 +- .../graal/snippets/CEntryPointSnippets.java | 1 + .../svm/core/jdk/VMErrorSubstitutions.java | 3 +- .../oracle/svm/core/locks/VMLockSupport.java | 2 +- .../src/com/oracle/svm/core/log/Log.java | 48 +- .../src/com/oracle/svm/core/log/RealLog.java | 33 +- .../svm/core/stack/ThreadStackPrinter.java | 69 ++- .../svm/core/thread/PlatformThreads.java | 4 +- .../svm/core/thread/VMOperationControl.java | 9 +- .../com/oracle/svm/core/thread/VMThreads.java | 23 +- .../core/threadlocal/VMThreadLocalInfos.java | 35 +- .../src/com/oracle/svm/core/util/Counter.java | 23 +- .../oracle/svm/core/util/CounterSupport.java | 60 +++ .../com/oracle/svm/core/util/RingBuffer.java | 6 - 29 files changed, 667 insertions(+), 291 deletions(-) create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/CounterSupport.java diff --git a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/Platform.java b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/Platform.java index dee4d153f9ad..b95e2ca9fbb9 100644 --- a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/Platform.java +++ b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/Platform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, 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 @@ -179,7 +179,7 @@ interface LINUX extends InternalPlatform.PLATFORM_JNI, InternalPlatform.NATIVE_O * @since 21.0 */ default String getOS() { - return LINUX.class.getSimpleName().toLowerCase(); + return "linux"; } } @@ -196,7 +196,7 @@ interface ANDROID extends LINUX { * @since 21.0 */ default String getOS() { - return ANDROID.class.getSimpleName().toLowerCase(); + return "android"; } } @@ -221,7 +221,7 @@ interface IOS extends DARWIN { * @since 21.0 */ default String getOS() { - return IOS.class.getSimpleName().toLowerCase(); + return "ios"; } } @@ -255,7 +255,7 @@ interface WINDOWS extends InternalPlatform.PLATFORM_JNI, InternalPlatform.NATIVE * @since 21.0 */ default String getOS() { - return WINDOWS.class.getSimpleName().toLowerCase(); + return "windows"; } } 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 2171d248b0a9..219cc0c50edf 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 @@ -291,39 +291,42 @@ void logImageHeapPartitionBoundaries(Log log) { log.string("Native image heap boundaries:").indent(true); imageHeapInfo.print(log); log.indent(false); + + if (AuxiliaryImageHeap.isPresent()) { + ImageHeapInfo auxHeapInfo = AuxiliaryImageHeap.singleton().getImageHeapInfo(); + if (auxHeapInfo != null) { + log.string("Auxiliary image heap boundaries:").indent(true); + auxHeapInfo.print(log); + log.indent(false); + } + } } /** Log the zap values to make it easier to search for them. */ - static Log zapValuesToLog(Log log) { + static void logZapValues(Log log) { if (HeapParameters.getZapProducedHeapChunks() || HeapParameters.getZapConsumedHeapChunks()) { - log.string("[Heap Chunk zap values: ").indent(true); /* Padded with spaces so the columns line up between the int and word variants. */ if (HeapParameters.getZapProducedHeapChunks()) { - log.string(" producedHeapChunkZapInt: ") - .string(" hex: ").spaces(8).hex(HeapParameters.getProducedHeapChunkZapInt()) - .string(" signed: ").spaces(9).signed(HeapParameters.getProducedHeapChunkZapInt()) - .string(" unsigned: ").spaces(10).unsigned(HeapParameters.getProducedHeapChunkZapInt()).newline(); - log.string(" producedHeapChunkZapWord:") - .string(" hex: ").hex(HeapParameters.getProducedHeapChunkZapWord()) - .string(" signed: ").signed(HeapParameters.getProducedHeapChunkZapWord()) - .string(" unsigned: ").unsigned(HeapParameters.getProducedHeapChunkZapWord()); - if (HeapParameters.getZapConsumedHeapChunks()) { - log.newline(); - } + log.string("producedHeapChunkZapInt: ") + .string(" hex: ").spaces(8).hex(HeapParameters.getProducedHeapChunkZapInt()) + .string(" signed: ").spaces(9).signed(HeapParameters.getProducedHeapChunkZapInt()) + .string(" unsigned: ").spaces(10).unsigned(HeapParameters.getProducedHeapChunkZapInt()).newline(); + log.string("producedHeapChunkZapWord:") + .string(" hex: ").hex(HeapParameters.getProducedHeapChunkZapWord()) + .string(" signed: ").signed(HeapParameters.getProducedHeapChunkZapWord()) + .string(" unsigned: ").unsigned(HeapParameters.getProducedHeapChunkZapWord()).newline(); } if (HeapParameters.getZapConsumedHeapChunks()) { - log.string(" consumedHeapChunkZapInt: ") - .string(" hex: ").spaces(8).hex(HeapParameters.getConsumedHeapChunkZapInt()) - .string(" signed: ").spaces(10).signed(HeapParameters.getConsumedHeapChunkZapInt()) - .string(" unsigned: ").spaces(10).unsigned(HeapParameters.getConsumedHeapChunkZapInt()).newline(); - log.string(" consumedHeapChunkZapWord:") - .string(" hex: ").hex(HeapParameters.getConsumedHeapChunkZapWord()) - .string(" signed: ").signed(HeapParameters.getConsumedHeapChunkZapWord()) - .string(" unsigned: ").unsigned(HeapParameters.getConsumedHeapChunkZapWord()); + log.string("consumedHeapChunkZapInt: ") + .string(" hex: ").spaces(8).hex(HeapParameters.getConsumedHeapChunkZapInt()) + .string(" signed: ").spaces(10).signed(HeapParameters.getConsumedHeapChunkZapInt()) + .string(" unsigned: ").spaces(10).unsigned(HeapParameters.getConsumedHeapChunkZapInt()).newline(); + log.string("consumedHeapChunkZapWord:") + .string(" hex: ").hex(HeapParameters.getConsumedHeapChunkZapWord()) + .string(" signed: ").signed(HeapParameters.getConsumedHeapChunkZapWord()) + .string(" unsigned: ").unsigned(HeapParameters.getConsumedHeapChunkZapWord()).newline(); } - log.redent(false).string("]"); } - return log; } @Override @@ -649,7 +652,7 @@ public boolean printLocationInfo(Log log, UnsignedWord value, boolean allowJavaH if (printLocationInfo(log, ptr, allowJavaHeapAccess, allowUnsafeOperations)) { if (allowJavaHeapAccess && objectHeaderImpl.pointsToObjectHeader(ptr)) { log.indent(true); - SubstrateDiagnostics.printObjectInfo(log, ptr); + SubstrateDiagnostics.printObjectInfo(log, ptr.toObject()); log.redent(false); } return true; @@ -870,19 +873,23 @@ public int maxInvocationCount() { @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLevel, int invocationCount) { - GCImpl gc = GCImpl.getGCImpl(); - log.string("Heap settings and statistics:").indent(true); log.string("Supports isolates: ").bool(SubstrateOptions.SpawnIsolates.getValue()).newline(); if (SubstrateOptions.SpawnIsolates.getValue()) { log.string("Heap base: ").zhex(KnownIntrinsics.heapBase()).newline(); } log.string("Object reference size: ").signed(ConfigurationValues.getObjectLayout().getReferenceSize()).newline(); + log.string("Reserved object header bits: 0b").number(Heap.getHeap().getObjectHeader().getReservedBitsMask(), 2, false).newline(); + log.string("Aligned chunk size: ").unsigned(HeapParameters.getAlignedHeapChunkSize()).newline(); + log.string("Large array threshold: ").unsigned(HeapParameters.getLargeArrayThreshold()).newline(); - GCAccounting accounting = gc.getAccounting(); + GCAccounting accounting = GCImpl.getGCImpl().getAccounting(); log.string("Incremental collections: ").unsigned(accounting.getIncrementalCollectionCount()).newline(); log.string("Complete collections: ").unsigned(accounting.getCompleteCollectionCount()).newline(); + + logZapValues(log); + log.indent(false); } } @@ -898,7 +905,8 @@ public int maxInvocationCount() { public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLevel, int invocationCount) { HeapImpl heap = HeapImpl.getHeapImpl(); heap.logImageHeapPartitionBoundaries(log); - zapValuesToLog(log).newline(); + log.newline(); + heap.report(log, true); log.newline(); } diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java index 1c1cdd0c4abe..48792f464adc 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java @@ -28,6 +28,7 @@ import org.graalvm.nativeimage.c.function.CEntryPoint.Publish; import org.graalvm.nativeimage.c.function.CEntryPointLiteral; import org.graalvm.nativeimage.c.struct.SizeOf; +import org.graalvm.nativeimage.c.type.VoidPointer; import org.graalvm.word.PointerBase; import org.graalvm.word.WordFactory; @@ -77,7 +78,10 @@ protected void printSignalInfo(Log log, PointerBase signalInfo) { if (sigInfo.si_errno() != 0) { log.string(", si_errno: ").signed(sigInfo.si_errno()); } - log.string(", si_addr: ").zhex(sigInfo.si_addr()); + + VoidPointer addr = sigInfo.si_addr(); + log.string(", si_addr: "); + printSegfaultAddressInfo(log, addr.rawValue()); log.newline(); } } diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java index 57c374592a62..a6c251dde7b1 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java @@ -119,7 +119,8 @@ protected void printSignalInfo(Log log, PointerBase signalInfo) { } else { log.string(", ExceptionInformation=").zhex(operation); } - log.string(" ").zhex(exInfo.addressOf(1).read()); + log.string(" "); + printSegfaultAddressInfo(log, exInfo.addressOf(1).read()); } else { if (numParameters > 0) { log.string(", ExceptionInformation="); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/CPUFeatureAccess.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/CPUFeatureAccess.java index 722895055c59..3ba98a900645 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/CPUFeatureAccess.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/CPUFeatureAccess.java @@ -26,9 +26,17 @@ import java.util.EnumSet; +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.nativeimage.ImageSingletons; + import jdk.vm.ci.code.Architecture; public interface CPUFeatureAccess { + @Fold + static CPUFeatureAccess singleton() { + return ImageSingletons.lookup(CPUFeatureAccess.class); + } + int verifyHostSupportsArchitectureEarly(); void verifyHostSupportsArchitectureEarlyOrExit(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/DebugHelper.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/DebugHelper.java index 6520d15983ed..1b348b5cf279 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/DebugHelper.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/DebugHelper.java @@ -264,7 +264,7 @@ public static void printHub(@SuppressWarnings("unused") IsolateThread thread, Po @CEntryPoint(name = "svm_dbg_print_obj", include = IncludeDebugHelperMethods.class, publishAs = Publish.SymbolOnly) @CEntryPointOptions(prologue = SetThreadAndHeapBasePrologue.class, epilogue = NoEpilogue.class) public static void printObject(@SuppressWarnings("unused") IsolateThread thread, Pointer objPtr) { - SubstrateDiagnostics.printObjectInfo(Log.log(), objPtr); + SubstrateDiagnostics.printObjectInfo(Log.log(), objPtr.toObject()); } @Uninterruptible(reason = "Called with a raw object pointer.", calleeMustBe = false) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/Isolates.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/Isolates.java index 6d2ecb783f73..a1dbaef5fe6f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/Isolates.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/Isolates.java @@ -58,6 +58,8 @@ public class Isolates { public static final CGlobalData IMAGE_HEAP_WRITABLE_BEGIN = CGlobalDataFactory.forSymbol(IMAGE_HEAP_WRITABLE_BEGIN_SYMBOL_NAME); public static final CGlobalData IMAGE_HEAP_WRITABLE_END = CGlobalDataFactory.forSymbol(IMAGE_HEAP_WRITABLE_END_SYMBOL_NAME); + private static long startTimeMillis; + private static long startNanoTime; private static Boolean isCurrentFirst; /** @@ -77,6 +79,31 @@ public static void setCurrentIsFirstIsolate(boolean value) { isCurrentFirst = value; } + public static void assignCurrentStartTime() { + assert startTimeMillis == 0 : startTimeMillis; + assert startNanoTime == 0 : startNanoTime; + startTimeMillis = System.currentTimeMillis(); + startNanoTime = System.nanoTime(); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static long getCurrentStartTimeMillis() { + assert startTimeMillis != 0; + return startTimeMillis; + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static long getCurrentUptimeMillis() { + assert startTimeMillis != 0; + return System.currentTimeMillis() - startTimeMillis; + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static long getCurrentStartNanoTime() { + assert startNanoTime != 0; + return startNanoTime; + } + @Uninterruptible(reason = "Thread state not yet set up.") public static int checkIsolate(Isolate isolate) { if (SubstrateOptions.SpawnIsolates.getValue()) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java index e05ac0ac79c1..78794d2a7995 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java @@ -73,7 +73,7 @@ import com.oracle.svm.core.thread.PlatformThreads; import com.oracle.svm.core.thread.ThreadListenerSupport; import com.oracle.svm.core.thread.VMThreads; -import com.oracle.svm.core.util.Counter; +import com.oracle.svm.core.util.CounterSupport; import com.oracle.svm.core.util.VMError; @InternalVMMethod @@ -206,7 +206,7 @@ private static void runShutdown0() { */ RuntimeSupport.getRuntimeSupport().shutdown(); - Counter.logValues(Log.log()); + CounterSupport.singleton().logValues(Log.log()); } @Uninterruptible(reason = "Thread state not set up yet.") diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java index a0840126a6df..1f6ee7bf506b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java @@ -26,6 +26,7 @@ import static com.oracle.svm.core.option.RuntimeOptionKey.RuntimeOptionKeyFlag.RelevantForCompilationIsolates; +import java.util.ArrayList; import java.util.Arrays; import org.graalvm.collections.EconomicMap; @@ -33,9 +34,11 @@ import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.core.common.SuppressFBWarnings; import org.graalvm.compiler.nodes.PauseNode; +import org.graalvm.compiler.nodes.java.ArrayLengthNode; import org.graalvm.compiler.options.Option; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.word.ObjectAccess; import org.graalvm.compiler.word.Word; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.ImageSingletons; @@ -68,12 +71,17 @@ import com.oracle.svm.core.graal.RuntimeCompilation; import com.oracle.svm.core.graal.stackvalue.UnsafeStackValue; import com.oracle.svm.core.heap.Heap; +import com.oracle.svm.core.heap.PhysicalMemory; import com.oracle.svm.core.heap.RestrictHeapAccess; import com.oracle.svm.core.hub.DynamicHub; +import com.oracle.svm.core.hub.LayoutEncoding; +import com.oracle.svm.core.jdk.Jvm; +import com.oracle.svm.core.jdk.UninterruptibleUtils; import com.oracle.svm.core.jdk.UninterruptibleUtils.AtomicWord; import com.oracle.svm.core.locks.VMLockSupport; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.option.RuntimeOptionKey; +import com.oracle.svm.core.os.VirtualMemoryProvider; import com.oracle.svm.core.stack.JavaFrameAnchor; import com.oracle.svm.core.stack.JavaFrameAnchors; import com.oracle.svm.core.stack.JavaStackWalker; @@ -89,7 +97,9 @@ import com.oracle.svm.core.threadlocal.FastThreadLocalBytes; import com.oracle.svm.core.threadlocal.FastThreadLocalFactory; import com.oracle.svm.core.threadlocal.VMThreadLocalInfos; -import com.oracle.svm.core.util.Counter; +import com.oracle.svm.core.util.CounterSupport; +import com.oracle.svm.core.util.TimeUtils; +import com.oracle.svm.core.util.VMError; public class SubstrateDiagnostics { private static final int MAX_THREADS_TO_PRINT = 100_000; @@ -144,16 +154,59 @@ public static void printLocationInfo(Log log, UnsignedWord value, boolean allowJ } } - @Uninterruptible(reason = "Called with a raw object pointer.", calleeMustBe = false) - public static void printObjectInfo(Log log, Pointer ptr) { - DynamicHub objHub = Heap.getHeap().getObjectHeader().readDynamicHubFromPointer(ptr); - if (objHub == DynamicHub.fromClass(DynamicHub.class)) { - // The pointer is already a hub, so print some information about the hub. - DynamicHub hub = (DynamicHub) ptr.toObject(); + public static void printObjectInfo(Log log, Object obj) { + if (obj instanceof DynamicHub hub) { + // The object itself is a dynamic hub, so print some information about the hub. log.string("is the hub of ").string(hub.getName()); + return; + } + + // Print some information about the object. + log.string("is an object of type "); + + if (obj instanceof Throwable e) { + log.exception(e, 2); } else { - // The pointer is an object, so print some information about the object's hub. - log.string("is an object of type ").string(objHub.getName()); + log.string(obj.getClass().getName()); + + if (obj instanceof String s) { + log.string(": ").string(s, 60); + } else { + int layoutEncoding = DynamicHub.fromClass(obj.getClass()).getLayoutEncoding(); + + if (LayoutEncoding.isArrayLike(layoutEncoding)) { + int length = ArrayLengthNode.arrayLength(obj); + log.string(" with length ").signed(length).string(": "); + + printSomeArrayData(log, obj, length, layoutEncoding); + } + } + } + } + + private static void printSomeArrayData(Log log, Object obj, int length, int layoutEncoding) { + int elementSize = LayoutEncoding.getArrayIndexScale(layoutEncoding); + int arrayBaseOffset = LayoutEncoding.getArrayBaseOffsetAsInt(layoutEncoding); + + int maxPrintedBytes = elementSize == 1 ? 8 : 16; + int printedElements = UninterruptibleUtils.Math.min(length, maxPrintedBytes / elementSize); + + UnsignedWord curOffset = WordFactory.unsigned(arrayBaseOffset); + UnsignedWord endOffset = curOffset.add(WordFactory.unsigned(printedElements).multiply(elementSize)); + while (curOffset.belowThan(endOffset)) { + switch (elementSize) { + case 1 -> log.zhex(ObjectAccess.readByte(obj, curOffset)); + case 2 -> log.zhex(ObjectAccess.readShort(obj, curOffset)); + case 4 -> log.zhex(ObjectAccess.readInt(obj, curOffset)); + case 8 -> log.zhex(ObjectAccess.readLong(obj, curOffset)); + default -> throw VMError.shouldNotReachHere(); + } + log.spaces(1); + curOffset = curOffset.add(elementSize); + } + + if (printedElements < length) { + log.string("..."); } } @@ -213,15 +266,6 @@ public static boolean printFatalError(Log log, Pointer sp, CodePointer ip) { */ public static boolean printFatalError(Log log, Pointer sp, CodePointer ip, RegisterDumper.Context registerContext, boolean frameHasCalleeSavedRegisters) { log.newline(); - /* - * Save the state of the initial error so that this state is consistently used, even if - * further errors occur while printing diagnostics. - */ - if (!fatalErrorState().trySet(log, sp, ip, registerContext, frameHasCalleeSavedRegisters) && !isFatalErrorHandlingThread()) { - log.string("Error: printFatalError already in progress by another thread.").newline(); - log.newline(); - return false; - } /* * Execute an endless loop if requested. This makes it easier to attach a debugger lazily. @@ -232,6 +276,16 @@ public static boolean printFatalError(Log log, Pointer sp, CodePointer ip, Regis PauseNode.pause(); } + /* + * Save the state of the initial error so that this state is consistently used, even if + * further errors occur while printing diagnostics. + */ + if (!fatalErrorState().trySet(log, sp, ip, registerContext, frameHasCalleeSavedRegisters) && !isFatalErrorHandlingThread()) { + log.string("Error: printFatalError already in progress by another thread.").newline(); + log.newline(); + return false; + } + printFatalErrorForCurrentState(); return true; } @@ -242,10 +296,12 @@ private static void printFatalErrorForCurrentState() { FatalErrorState fatalErrorState = fatalErrorState(); Log log = fatalErrorState.log; - if (fatalErrorState.diagnosticThunkIndex > 0) { + if (fatalErrorState.diagnosticThunkIndex >= 0) { // An error must have happened earlier as the code for printing diagnostics was invoked // recursively. log.resetIndentation().newline(); + } else { + fatalErrorState.diagnosticThunkIndex = 0; } // Print the various sections of the diagnostics and skip all sections that were already @@ -393,7 +449,7 @@ private static void updateInitialInvocationCount(String entry) throws IllegalArg } if (matches == 0) { - throw new IllegalArgumentException("the pattern '" + entry + "' not match any diagnostic thunk."); + throw new IllegalArgumentException("The pattern '" + entry + "' not match any diagnostic thunk."); } } @@ -412,7 +468,7 @@ private static int parseInvocationCount(String entry, int pos) { } private static boolean matches(String text, String pattern) { - assert pattern.length() > 0; + assert pattern.length() > 0 : pattern; return matches(text, 0, pattern, 0); } @@ -450,6 +506,31 @@ private static boolean matches(String text, int t, String pattern, int p) { return patternPos == pattern.length(); } + /* Scan the stack until we find a valid return address. We may encounter false-positives. */ + private static Pointer findPotentialReturnAddressPosition(Pointer originalSp) { + UnsignedWord stackBase = VMThreads.StackBase.get(); + if (stackBase.equal(0)) { + /* We don't know the stack boundaries, so only search within 32 bytes. */ + stackBase = originalSp.add(32); + } + + int wordSize = ConfigurationValues.getTarget().wordSize; + Pointer pos = originalSp; + while (pos.belowThan(stackBase)) { + CodePointer possibleIp = pos.readWord(0); + if (pointsIntoNativeImageCode(possibleIp)) { + return pos; + } + pos = pos.add(wordSize); + } + return WordFactory.nullPointer(); + } + + @Uninterruptible(reason = "Prevent the GC from freeing the CodeInfo.") + private static boolean pointsIntoNativeImageCode(CodePointer possibleIp) { + return CodeInfoTable.lookupCodeInfo(possibleIp).isNonNull(); + } + public static class FatalErrorState { AtomicWord diagnosticThread; volatile int diagnosticThunkIndex; @@ -460,7 +541,7 @@ public static class FatalErrorState { @Platforms(Platform.HOSTED_ONLY.class) public FatalErrorState() { diagnosticThread = new AtomicWord<>(); - diagnosticThunkIndex = 0; + diagnosticThunkIndex = -1; invocationCount = 0; log = null; @@ -475,7 +556,7 @@ public ErrorContext getErrorContext() { @SuppressWarnings("hiding") public boolean trySet(Log log, Pointer sp, CodePointer ip, RegisterDumper.Context registerContext, boolean frameHasCalleeSavedRegisters) { if (diagnosticThread.compareAndSet(WordFactory.nullPointer(), CurrentIsolate.getCurrentThread())) { - assert diagnosticThunkIndex == 0; + assert diagnosticThunkIndex == -1; assert invocationCount == 0; this.log = log; @@ -498,26 +579,13 @@ public void clear() { errorContext.setRegisterContext(WordFactory.nullPointer()); errorContext.setFrameHasCalleeSavedRegisters(false); - diagnosticThunkIndex = 0; + diagnosticThunkIndex = -1; invocationCount = 0; diagnosticThread.set(WordFactory.nullPointer()); } } - private static class DumpCurrentTimestamp extends DiagnosticThunk { - @Override - public int maxInvocationCount() { - return 1; - } - - @Override - @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("Current timestamp: ").unsigned(System.currentTimeMillis()).newline().newline(); - } - } - private static class DumpRegisters extends DiagnosticThunk { @Override public int maxInvocationCount() { @@ -543,34 +611,48 @@ public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLev private static class DumpInstructions extends DiagnosticThunk { @Override public int maxInvocationCount() { - return 3; + return 4; } @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLevel, int invocationCount) { - if (invocationCount < 3) { - printBytesBeforeAndAfterIp(log, context.getInstructionPointer(), invocationCount); - } else if (invocationCount == 3) { - printWord(log, context.getInstructionPointer()); - } - } + CodePointer ip = context.getInstructionPointer(); + log.string("Printing instructions (ip=").zhex(ip).string("):"); - private static void printBytesBeforeAndAfterIp(Log log, CodePointer ip, int invocationCount) { - // print 64 or 32 instruction bytes. - int bytesToPrint = 64 >> invocationCount; - hexDump(log, ip, bytesToPrint, bytesToPrint); - } + if (((Pointer) ip).belowThan(VirtualMemoryProvider.get().getGranularity())) { + /* IP points into the first page of the virtual address space. */ + Pointer originalSp = context.getStackPointer(); + log.string(" IP is invalid"); - private static void printWord(Log log, CodePointer ip) { - // just print one word starting at the ip - hexDump(log, ip, 0, ConfigurationValues.getTarget().wordSize); + Pointer returnAddressPos = findPotentialReturnAddressPosition(originalSp); + if (returnAddressPos.isNull()) { + log.string(", instructions cannot be printed.").newline(); + return; + } + + ip = returnAddressPos.readWord(0); + Pointer sp = returnAddressPos.add(FrameAccess.returnAddressSize()); + log.string(", printing instructions (ip=").zhex(ip).string(") of the most likely caller (sp + ").unsigned(sp.subtract(originalSp)).string(") instead"); + } + + log.indent(true); + if (invocationCount < 4) { + /* Print 512, 128, or 32 instruction bytes. */ + int bytesToPrint = 1024 >> (invocationCount * 2); + hexDump(log, ip, bytesToPrint, bytesToPrint); + } else if (invocationCount == 4) { + /* Just print one word starting at the ip. */ + hexDump(log, ip, 0, ConfigurationValues.getTarget().wordSize); + } + log.indent(false).newline(); } private static void hexDump(Log log, CodePointer ip, int bytesBefore, int bytesAfter) { - log.string("Printing Instructions (ip=").zhex(ip).string("):").indent(true); - log.hexdump(((Pointer) ip).subtract(bytesBefore), 1, bytesBefore + bytesAfter); - log.indent(false).newline(); + log.hexdump(((Pointer) ip).subtract(bytesBefore), 1, bytesBefore); + log.indent(false); + log.string("> ").redent(true); + log.hexdump(ip, 1, bytesAfter); } } @@ -583,30 +665,42 @@ public int maxInvocationCount() { @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLevel, int invocationCount) { + /* + * We have to be careful here and not dump too much of the stack: if there are not many + * frames on the stack, we segfault when going past the beginning of the stack. + */ Pointer sp = context.getStackPointer(); - UnsignedWord stackBase = VMThreads.StackBase.get(); - log.string("Top of stack (sp=").zhex(sp).string("):").indent(true); - - int bytesToPrint = computeBytesToPrint(sp, stackBase); - log.hexdump(sp, 8, bytesToPrint / 8); - log.indent(false).newline(); - } + UnsignedWord stackEnd = VMThreads.StackEnd.get(); // low + UnsignedWord stackBase = VMThreads.StackBase.get(); // high + int wordSize = ConfigurationValues.getTarget().wordSize; - private static int computeBytesToPrint(Pointer sp, UnsignedWord stackBase) { - if (stackBase.equal(0)) { - /* - * We have to be careful here and not dump too much of the stack: if there are not - * many frames on the stack, we segfault when going past the beginning of the stack. - */ - return 128; + log.string("Top of stack (sp=").zhex(sp).string("):").indent(true); + int bytesToPrintBelowSp = 32; + if (stackEnd.notEqual(0)) { + UnsignedWord availableBytes = sp.subtract(stackEnd); + if (availableBytes.belowThan(bytesToPrintBelowSp)) { + bytesToPrintBelowSp = NumUtil.safeToInt(availableBytes.rawValue()); + } } - int bytesToPrint = 512; - UnsignedWord availableBytes = stackBase.subtract(sp); - if (availableBytes.belowThan(bytesToPrint)) { - bytesToPrint = NumUtil.safeToInt(availableBytes.rawValue()); + int bytesToPrintAboveSp = 128; + if (stackBase.notEqual(0)) { + bytesToPrintAboveSp = 512; + UnsignedWord availableBytes = stackBase.subtract(sp); + if (availableBytes.belowThan(bytesToPrintAboveSp)) { + bytesToPrintAboveSp = NumUtil.safeToInt(availableBytes.rawValue()); + } } - return bytesToPrint; + + int wordsToPrintBelowSp = bytesToPrintBelowSp / wordSize; + log.hexdump(sp.subtract(wordsToPrintBelowSp * wordSize), wordSize, wordsToPrintBelowSp, 32); + log.indent(false); + + log.string("> ").redent(true); + log.hexdump(sp, wordSize, bytesToPrintAboveSp / wordSize, 32); + log.indent(false); + + log.newline(); } } @@ -619,13 +713,11 @@ public int maxInvocationCount() { @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLevel, int invocationCount) { - if (DeoptimizationSupport.enabled()) { - log.string("DeoptStubPointer address: ").zhex(DeoptimizationSupport.getDeoptStubPointer()).newline().newline(); - } + log.string("DeoptStubPointer address: ").zhex(DeoptimizationSupport.getDeoptStubPointer()).newline().newline(); } } - private static class DumpTopFrame extends DiagnosticThunk { + private static class DumpTopDeoptimizedFrame extends DiagnosticThunk { @Override public int maxInvocationCount() { return 1; @@ -634,39 +726,19 @@ public int maxInvocationCount() { @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLevel, int invocationCount) { - // We already dump all safe values first, so there is nothing we could retry if an error - // occurs. Pointer sp = context.getStackPointer(); CodePointer ip = context.getInstructionPointer(); if (sp.isNonNull() && ip.isNonNull()) { - log.string("Top frame info:").indent(true); long totalFrameSize = getTotalFrameSize(sp, ip); DeoptimizedFrame deoptFrame = Deoptimizer.checkDeoptimized(sp); if (deoptFrame != null) { + log.string("Top frame info:").indent(true); log.string("RSP ").zhex(sp).string(" frame was deoptimized:").newline(); log.string("SourcePC ").zhex(deoptFrame.getSourcePC()).newline(); log.string("SourceTotalFrameSize ").signed(totalFrameSize).newline(); - } else if (totalFrameSize != -1) { - log.string("TotalFrameSize in CodeInfoTable ").signed(totalFrameSize).newline(); + log.indent(false); } - - if (totalFrameSize == -1) { - log.string("Does not look like a Java Frame. Use JavaFrameAnchors to find LastJavaSP:").newline(); - JavaFrameAnchor anchor = JavaFrameAnchors.getFrameAnchor(); - while (anchor.isNonNull() && anchor.getLastJavaSP().belowOrEqual(sp)) { - anchor = anchor.getPreviousAnchor(); - } - - if (anchor.isNonNull()) { - log.string("Found matching Anchor:").zhex(anchor).newline(); - Pointer lastSp = anchor.getLastJavaSP(); - log.string("LastJavaSP ").zhex(lastSp).newline(); - CodePointer lastIp = anchor.getLastJavaIP(); - log.string("LastJavaIP ").zhex(lastIp).newline(); - } - } - log.indent(false); } } } @@ -680,8 +752,8 @@ public int maxInvocationCount() { @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLevel, int invocationCount) { - boolean allowJavaHeapAccess = DiagnosticLevel.javaHeapAccessAllowed(maxDiagnosticLevel) && invocationCount < 3; - boolean allowUnsafeOperations = DiagnosticLevel.unsafeOperationsAllowed(maxDiagnosticLevel) && invocationCount < 2; + boolean allowJavaHeapAccess = DiagnosticLevel.javaHeapAccessAllowed(maxDiagnosticLevel) && invocationCount < 2; + boolean allowUnsafeOperations = DiagnosticLevel.unsafeOperationsAllowed(maxDiagnosticLevel) && invocationCount < 3; /* * If we are not at a safepoint, then it is unsafe to access the thread locals of * another thread as the IsolateThread could be freed at any time. @@ -703,9 +775,13 @@ public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLev if (allowJavaHeapAccess) { Thread threadObj = PlatformThreads.fromVMThread(thread); - log.string(" \"").string(threadObj.getName()).string("\" - ").zhex(Word.objectToUntrackedPointer(threadObj)); - if (threadObj != null && threadObj.isDaemon()) { - log.string(", daemon"); + if (threadObj == null) { + log.string(" null"); + } else { + log.string(" \"").string(threadObj.getName()).string("\" - ").zhex(Word.objectToUntrackedPointer(threadObj)); + if (threadObj.isDaemon()) { + log.string(", daemon"); + } } } log.string(", stack(").zhex(VMThreads.StackEnd.get(thread)).string(",").zhex(VMThreads.StackBase.get(thread)).string(")"); @@ -780,10 +856,8 @@ public int maxInvocationCount() { @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLevel, int invocationCount) { - if (RuntimeCompilation.isEnabled()) { - boolean allowJavaHeapAccess = DiagnosticLevel.javaHeapAccessAllowed(maxDiagnosticLevel) && invocationCount < 2; - RuntimeCodeInfoHistory.singleton().printRecentOperations(log, allowJavaHeapAccess); - } + boolean allowJavaHeapAccess = DiagnosticLevel.javaHeapAccessAllowed(maxDiagnosticLevel) && invocationCount < 2; + RuntimeCodeInfoHistory.singleton().printRecentOperations(log, allowJavaHeapAccess); } } @@ -796,11 +870,9 @@ public int maxInvocationCount() { @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLevel, int invocationCount) { - if (RuntimeCompilation.isEnabled()) { - boolean allowJavaHeapAccess = DiagnosticLevel.javaHeapAccessAllowed(maxDiagnosticLevel) && invocationCount < 3; - boolean allowUnsafeOperations = DiagnosticLevel.unsafeOperationsAllowed(maxDiagnosticLevel) && invocationCount < 2; - RuntimeCodeInfoMemory.singleton().printTable(log, allowJavaHeapAccess, allowUnsafeOperations); - } + boolean allowJavaHeapAccess = DiagnosticLevel.javaHeapAccessAllowed(maxDiagnosticLevel) && invocationCount < 3; + boolean allowUnsafeOperations = DiagnosticLevel.unsafeOperationsAllowed(maxDiagnosticLevel) && invocationCount < 2; + RuntimeCodeInfoMemory.singleton().printTable(log, allowJavaHeapAccess, allowUnsafeOperations); } } @@ -813,9 +885,74 @@ public int maxInvocationCount() { @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLevel, int invocationCount) { - if (DeoptimizationSupport.enabled()) { - Deoptimizer.logRecentDeoptimizationEvents(log); + Deoptimizer.logRecentDeoptimizationEvents(log); + } + } + + static class DumpVMInfo extends DiagnosticThunk { + @Override + public int maxInvocationCount() { + return 1; + } + + @Override + @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("Build time information:").indent(true); + + VM vm = ImageSingletons.lookup(VM.class); + log.string("Version: ").string(vm.version).string(", ").string(vm.info).newline(); + + Platform platform = ImageSingletons.lookup(Platform.class); + log.string("Platform: ").string(platform.getOS()).string("/").string(platform.getArchitecture()).newline(); + log.string("Page size: ").unsigned(SubstrateOptions.getPageSize()).newline(); + log.string("Container support: ").bool(Containers.Options.UseContainerSupport.getValue()).newline(); + log.string("CPU features used for AOT compiled code: ").string(getBuildTimeCpuFeatures()).newline(); + log.indent(false); + } + + @Fold + static String getBuildTimeCpuFeatures() { + return String.join(", ", CPUFeatureAccess.singleton().buildtimeCPUFeatures().stream().map(Enum::toString).toList()); + } + } + + public static class DumpMachineInfo extends DiagnosticThunk { + @Override + public int maxInvocationCount() { + return 1; + } + + @Override + @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("Runtime information:").indent(true); + + log.string("CPU cores (OS): "); + if (SubstrateOptions.JNI.getValue()) { + log.signed(Jvm.JVM_ActiveProcessorCount()).newline(); + } else { + log.string("unknown").newline(); } + + log.string("Memory: "); + if (PhysicalMemory.isInitialized()) { + log.rational(PhysicalMemory.getCachedSize(), 1024 * 1024, 0).string("M").newline(); + } else { + log.string("unknown").newline(); + } + + log.string("Page size: ").unsigned(VirtualMemoryProvider.get().getGranularity()).newline(); + log.string("VM uptime: ").rational(Isolates.getCurrentUptimeMillis(), TimeUtils.millisPerSecond, 3).string("s").newline(); + log.string("Current timestamp: ").unsigned(System.currentTimeMillis()).newline(); + + CodeInfo info = CodeInfoTable.getImageCodeInfo(); + Pointer codeStart = (Pointer) CodeInfoAccess.getCodeStart(info); + UnsignedWord codeSize = CodeInfoAccess.getCodeSize(info); + Pointer codeEnd = codeStart.add(codeSize).subtract(1); + log.string("AOT compiled code: ").zhex(codeStart).string(" - ").zhex(codeEnd).newline(); + + log.indent(false); } } @@ -828,9 +965,12 @@ public int maxInvocationCount() { @Override @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("Counters:").indent(true); - Counter.logValues(log); - log.indent(false); + CounterSupport counters = CounterSupport.singleton(); + if (counters.hasCounters()) { + log.string("Counters:").indent(true); + counters.logValues(log); + log.indent(false); + } } } @@ -862,7 +1002,7 @@ public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLev Pointer sp = context.getStackPointer(); CodePointer ip = context.getInstructionPointer(); - log.string("Stacktrace for the failing thread ").zhex(CurrentIsolate.getCurrentThread()).string(":").indent(true); + log.string("Stacktrace for the failing thread ").zhex(CurrentIsolate.getCurrentThread()).string(" (A=AOT compiled, J=JIT compiled, D=deoptimized, i=inlined):").indent(true); boolean success = ThreadStackPrinter.printStacktrace(sp, ip, printVisitors[invocationCount - 1].reset(), log); if (!success && DiagnosticLevel.unsafeOperationsAllowed(maxDiagnosticLevel)) { @@ -885,31 +1025,16 @@ public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLev } private static void startStackWalkInMostLikelyCaller(Log log, int invocationCount, Pointer originalSp) { - UnsignedWord stackBase = VMThreads.StackBase.get(); - if (stackBase.equal(0)) { - /* We don't know the stack boundaries, so only search within 32 bytes. */ - stackBase = originalSp.add(32); + Pointer returnAddressPos = findPotentialReturnAddressPosition(originalSp); + if (returnAddressPos.isNull()) { + return; } - /* Search until we find a valid return address. We may encounter false-positives. */ - int wordSize = ConfigurationValues.getTarget().wordSize; - Pointer pos = originalSp; - while (pos.belowThan(stackBase)) { - CodePointer possibleIp = pos.readWord(0); - if (pointsIntoNativeImageCode(possibleIp)) { - Pointer sp = pos.add(wordSize); - log.newline(); - log.string("Starting the stack walk in a possible caller:").newline(); - ThreadStackPrinter.printStacktrace(sp, possibleIp, printVisitors[invocationCount - 1].reset(), log); - break; - } - pos = pos.add(wordSize); - } - } - - @Uninterruptible(reason = "Prevent the GC from freeing the CodeInfo.") - private static boolean pointsIntoNativeImageCode(CodePointer possibleIp) { - return CodeInfoTable.lookupCodeInfo(possibleIp).isNonNull(); + CodePointer possibleIp = returnAddressPos.readWord(0); + Pointer sp = returnAddressPos.add(FrameAccess.returnAddressSize()); + log.newline(); + log.string("Starting the stack walk in a possible caller (sp + ").unsigned(sp.subtract(originalSp)).string("):").newline(); + ThreadStackPrinter.printStacktrace(sp, possibleIp, printVisitors[invocationCount - 1].reset(), log); } } @@ -961,7 +1086,7 @@ private static void printStackTrace(Log log, IsolateThread vmThread, int invocat } } - private static class DumpAOTCompiledCodeInfo extends DiagnosticThunk { + private static class DumpCommandLine extends DiagnosticThunk { @Override public int maxInvocationCount() { return 1; @@ -970,13 +1095,14 @@ public int maxInvocationCount() { @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate while printing diagnostics.") public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLevel, int invocationCount) { - CodeInfo info = CodeInfoTable.getImageCodeInfo(); - Pointer codeStart = (Pointer) CodeInfoAccess.getCodeStart(info); - UnsignedWord codeSize = CodeInfoAccess.getCodeSize(info); - Pointer codeEnd = codeStart.add(codeSize).subtract(1); - - log.string("AOT compiled code is mapped at ").zhex(codeStart).string(" - ").zhex(codeEnd).newline(); - log.newline(); + String[] args = ImageSingletons.lookup(JavaMainWrapper.JavaMainSupport.class).mainArgs; + if (args != null) { + log.string("Command line: "); + for (String arg : args) { + log.string("'").string(arg).string("' "); + } + log.newline().newline(); + } } } @@ -1003,9 +1129,9 @@ public boolean printLocationInfo(Log log, UnsignedWord value) { } if (CodeInfoAccess.contains(imageCodeInfo, (CodePointer) value)) { + log.string("points into AOT compiled code "); FrameInfoQueryResult compilationRoot = getCompilationRoot(imageCodeInfo, (CodePointer) value); if (compilationRoot != null) { - log.string("points into AOT compiled code "); compilationRoot.log(log); } return true; @@ -1113,18 +1239,39 @@ public static synchronized DiagnosticThunkRegistry singleton() { @Platforms(Platform.HOSTED_ONLY.class) DiagnosticThunkRegistry() { - this.diagnosticThunks = new DiagnosticThunk[]{new DumpCurrentTimestamp(), new DumpRegisters(), new DumpInstructions(), new DumpTopOfCurrentThreadStack(), new DumpDeoptStubPointer(), - new DumpTopFrame(), new DumpThreads(), new DumpCurrentThreadLocals(), new DumpCurrentVMOperation(), new DumpVMOperationHistory(), new DumpCodeCacheHistory(), - new DumpRuntimeCodeInfoMemory(), new DumpRecentDeoptimizations(), new DumpCounters(), new DumpCurrentThreadFrameAnchors(), new DumpCurrentThreadDecodedStackTrace(), - new DumpOtherStackTraces(), new VMLockSupport.DumpVMMutexes(), new DumpAOTCompiledCodeInfo()}; + ArrayList thunks = new ArrayList<>(); + thunks.add(new DumpRegisters()); + thunks.add(new DumpInstructions()); + thunks.add(new DumpTopOfCurrentThreadStack()); + if (RuntimeCompilation.isEnabled()) { + thunks.add(new DumpTopDeoptimizedFrame()); + } + thunks.add(new DumpCurrentThreadLocals()); + thunks.add(new DumpCurrentThreadFrameAnchors()); + thunks.add(new DumpCurrentThreadDecodedStackTrace()); + thunks.add(new DumpThreads()); + thunks.add(new DumpOtherStackTraces()); + thunks.add(new DumpCurrentVMOperation()); + thunks.add(new DumpVMOperationHistory()); + thunks.add(new VMLockSupport.DumpVMMutexes()); + thunks.add(new DumpVMInfo()); + thunks.add(new DumpMachineInfo()); + if (ImageSingletons.contains(JavaMainWrapper.JavaMainSupport.class)) { + thunks.add(new DumpCommandLine()); + } + thunks.add(new DumpCounters()); + if (RuntimeCompilation.isEnabled()) { + thunks.add(new DumpCodeCacheHistory()); + thunks.add(new DumpRuntimeCodeInfoMemory()); + thunks.add(new DumpDeoptStubPointer()); + thunks.add(new DumpRecentDeoptimizations()); + } + this.diagnosticThunks = thunks.toArray(new DiagnosticThunk[0]); this.initialInvocationCount = new int[diagnosticThunks.length]; Arrays.fill(initialInvocationCount, 1); } - /** - * Register a diagnostic thunk to be called after a segfault. - */ @Platforms(Platform.HOSTED_ONLY.class) public synchronized void register(DiagnosticThunk diagnosticThunk) { diagnosticThunks = Arrays.copyOf(diagnosticThunks, diagnosticThunks.length + 1); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index 0bae9f604f8a..42a0f9279d86 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -889,6 +889,9 @@ protected void onValueUpdate(EconomicMap, Object> values, String ol } }; + @Option(help = "Specifies the number of entries that diagnostic buffers have.", type = OptionType.Debug)// + public static final HostedOptionKey DiagnosticBufferSize = new HostedOptionKey<>(30); + @SuppressWarnings("unused")// @APIOption(name = "configure-reflection-metadata")// @Option(help = "Enable runtime instantiation of reflection objects for non-invoked methods.", type = OptionType.Expert, deprecated = true)// diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java index 8fd81421c09d..a931b4b974dc 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java @@ -187,6 +187,15 @@ private static void dumpInterruptibly(PointerBase signalInfo, RegisterDumper.Con logHandler.fatalError(); } + protected static void printSegfaultAddressInfo(Log log, long addr) { + log.zhex(addr); + if (addr != 0) { + long delta = addr - CurrentIsolate.getIsolate().rawValue(); + String sign = (delta >= 0 ? "+" : "-"); + log.string(" (heapBase ").string(sign).string(" ").signed(Math.abs(delta)).string(")"); + } + } + static class SingleIsolateSegfaultSetup implements IsolateListener { /** diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java index 330962dda3b1..f8891f44c5cb 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java @@ -309,7 +309,7 @@ public static void setEncodings(CodeInfo info, NonmovableObjectArray obj } public static Log log(CodeInfo info, Log log) { - return info.isNull() ? log.string("null") : log.string(CodeInfo.class.getName()).string("@").hex(info); + return info.isNull() ? log.string("null") : log.string("CodeInfo@").hex(info); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoDecoder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoDecoder.java index a2b7ebab5822..480e17602f5d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoDecoder.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoDecoder.java @@ -515,7 +515,8 @@ static CodeInfoDecoderCounters counters() { /** * This class can be used to iterate the Java-level stack trace information for a given * instruction pointer (IP). A single physical stack frame may correspond to multiple Java-level - * stack frames. + * stack frames. Iteration starts in the deepest inlined method and ends at the compilation + * root. */ public static class FrameInfoCursor { private final ReusableTypeReader frameInfoReader = new ReusableTypeReader(); @@ -550,6 +551,12 @@ public boolean advance() { return result != null; } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public boolean hasCaller() { + assert result != null; + return !state.isDone; + } + /** * Returns the information for the current frame. * diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoDecoder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoDecoder.java index 9d5703a38b98..ab54d50ca4a1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoDecoder.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoDecoder.java @@ -377,7 +377,7 @@ private static FrameInfoQueryResult decodeUncompressedFrameInfo(boolean isDeoptE FrameInfoQueryResult prev = null; ValueInfo[][] virtualObjects = null; - while (true) { + while (!state.isDone) { long start = readBuffer.getByteIndex(); int encodedBci = readBuffer.getSVInt(); if (encodedBci == NO_CALLER_BCI) { @@ -460,6 +460,8 @@ private static FrameInfoQueryResult decodeUncompressedFrameInfo(boolean isDeoptE state.isFirstFrame = false; } + + return result; } @Uninterruptible(reason = "Some allocators are interruptible.", calleeMustBe = false) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java index 5b849f06dc7e..a69e765279bb 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeCodeInfoHistory.java @@ -24,22 +24,25 @@ */ package com.oracle.svm.core.code; -import com.oracle.svm.core.Uninterruptible; -import com.oracle.svm.core.code.CodeInfoAccess.HasInstalledCode; -import com.oracle.svm.core.deopt.SubstrateInstalledCode; -import com.oracle.svm.core.thread.Safepoint; import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.function.CodePointer; +import org.graalvm.word.UnsignedWord; +import com.oracle.svm.core.Isolates; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.code.CodeInfoAccess.HasInstalledCode; +import com.oracle.svm.core.deopt.SubstrateInstalledCode; import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.log.Log; +import com.oracle.svm.core.thread.Safepoint; import com.oracle.svm.core.thread.VMOperation; import com.oracle.svm.core.thread.VMThreads; import com.oracle.svm.core.util.RingBuffer; -import org.graalvm.word.UnsignedWord; +import com.oracle.svm.core.util.TimeUtils; public class RuntimeCodeInfoHistory { private static final RingBuffer.Consumer PRINT_WITH_JAVA_HEAP_DATA = RuntimeCodeInfoHistory::printEntryWithJavaHeapData; @@ -49,7 +52,7 @@ public class RuntimeCodeInfoHistory { @Platforms(Platform.HOSTED_ONLY.class) RuntimeCodeInfoHistory() { - recentOperations = new RingBuffer<>(20, CodeCacheLogEntry::new); + recentOperations = new RingBuffer<>(SubstrateOptions.DiagnosticBufferSize.getValue(), CodeCacheLogEntry::new); } @Fold @@ -98,7 +101,7 @@ private static void traceCodeCache(String kind, CodeInfo info, boolean allowJava } public void printRecentOperations(Log log, boolean allowJavaHeapAccess) { - log.string("The ").signed(recentOperations.size()).string(" most recent RuntimeCodeInfo operations (oldest first): ").indent(true); + log.string("The ").signed(recentOperations.size()).string(" most recent RuntimeCodeInfo operations: ").indent(true); recentOperations.foreach(log, allowJavaHeapAccess ? PRINT_WITH_JAVA_HEAP_DATA : PRINT_WITHOUT_JAVA_HEAP_DATA); log.indent(false); } @@ -159,7 +162,8 @@ public void setValues(String kind, CodeInfo codeInfo, int codeInfoState, String public void print(Log log, boolean allowJavaHeapAccess) { if (kind != null) { - log.unsigned(timestamp).string(" - ").string(kind).spaces(1); + long uptime = timestamp - Isolates.getCurrentStartTimeMillis(); + log.rational(uptime, TimeUtils.millisPerSecond, 3).string("s - ").string(kind).spaces(1); String name = allowJavaHeapAccess ? codeName : null; CodeInfoAccess.printCodeInfo(log, codeInfo, codeInfoState, name, codeStart, codeEnd, hasInstalledCode, installedCodeAddress, installedCodeEntryPoint); log.string(", safepointId: ").unsigned(safepointId).newline(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java index c478fb1c7ffd..c3346a4450ce 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java @@ -48,6 +48,7 @@ import org.graalvm.word.WordFactory; import com.oracle.svm.core.FrameAccess; +import com.oracle.svm.core.Isolates; import com.oracle.svm.core.NeverInline; import com.oracle.svm.core.ReservedRegisters; import com.oracle.svm.core.SubstrateOptions; @@ -83,6 +84,7 @@ import com.oracle.svm.core.thread.VMOperation; import com.oracle.svm.core.thread.VMThreads; import com.oracle.svm.core.util.RingBuffer; +import com.oracle.svm.core.util.TimeUtils; import com.oracle.svm.core.util.VMError; import jdk.internal.misc.Unsafe; @@ -149,7 +151,7 @@ */ public final class Deoptimizer { private static final int MAX_DEOPTIMIZATION_EVENT_PRINT_LENGTH = 1000; - private static final RingBuffer recentDeoptimizationEvents = new RingBuffer<>(); + private static final RingBuffer recentDeoptimizationEvents = new RingBuffer<>(SubstrateOptions.DiagnosticBufferSize.getValue()); private static final int actionShift = 0; private static final int actionBits = Integer.SIZE - Integer.numberOfLeadingZeros(DeoptimizationAction.values().length); @@ -1133,7 +1135,7 @@ private static JavaConstant readConstant(Pointer addr, SignedWord offset, JavaKi } private static void printDeoptimizedFrame(Log log, Pointer sp, DeoptimizedFrame deoptimizedFrame, FrameInfoQueryResult sourceFrameInfo, boolean printOnlyTopFrames) { - log.string("[Deoptimization of frame (timestamp ").unsigned(System.currentTimeMillis()).string(")").newline(); + log.string("[Deoptimization of frame (").rational(Isolates.getCurrentUptimeMillis(), TimeUtils.millisPerSecond, 3).string("s)").newline(); SubstrateInstalledCode installedCode = deoptimizedFrame.getSourceInstalledCode(); if (installedCode != null) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java index 256b1b1c409f..68a5040b17fc 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java @@ -305,6 +305,7 @@ private static int initializeIsolateInterruptibly0(CEntryPointCreateIsolateParam boolean firstIsolate = Unsafe.getUnsafe().compareAndSetInt(null, initStateAddr, FirstIsolateInitStates.UNINITIALIZED, FirstIsolateInitStates.IN_PROGRESS); Isolates.setCurrentIsFirstIsolate(firstIsolate); + Isolates.assignCurrentStartTime(); if (!firstIsolate) { int state = Unsafe.getUnsafe().getInt(initStateAddr); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VMErrorSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VMErrorSubstitutions.java index 6cabfd232d07..5a5e6c2e91a0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VMErrorSubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/VMErrorSubstitutions.java @@ -135,9 +135,8 @@ private static void doShutdown(CodePointer callerIP, String msg, Throwable ex) { } if (ex != null) { log.string(": ").exception(ex); - } else { - log.newline(); } + log.newline(); SubstrateDiagnostics.printFatalError(log, KnownIntrinsics.readCallerStackPointer(), KnownIntrinsics.readReturnAddress()); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java index 9a640c058e81..bbafc2c39575 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/locks/VMLockSupport.java @@ -68,7 +68,7 @@ public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLev } if (support == null || support.getMutexes() == null) { - log.string("No mutex information is available."); + log.string("No mutex information is available.").newline(); } else { VMMutex[] mutexes = support.getMutexes(); for (int i = 0; i < mutexes.length; i++) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/Log.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/Log.java index 3fb00f676b84..400365dbd85d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/Log.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/Log.java @@ -36,6 +36,7 @@ import org.graalvm.nativeimage.c.function.CodePointer; import org.graalvm.nativeimage.c.type.CCharPointer; import org.graalvm.word.PointerBase; +import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordBase; /** @@ -139,6 +140,12 @@ protected Log() { */ public abstract Log string(String str, int fill, int align); + /** + * Prints the string characters, up to the given maximum length. Does not do any platform- or + * charset-depending conversions. + */ + public abstract Log string(String value, int maxLen); + /** * Prints all characters in the array, without any platform- or charset-depending conversions. */ @@ -202,13 +209,18 @@ protected Log() { */ public abstract Log signed(long value); + /** + * Prints the value, treated as a signed value, filling spaces before or after. + */ + public abstract Log signed(long value, int fill, int align); + /** * Prints the value, treated as an unsigned value, in decimal format. */ public abstract Log unsigned(WordBase value); /** - * Prints the value, treated as an unsigned value, filing spaces before or after. + * Prints the value, treated as an unsigned value, filling spaces before or after. */ public abstract Log unsigned(WordBase value, int fill, int align); @@ -223,12 +235,14 @@ protected Log() { public abstract Log unsigned(long value); /** - * Prints the value, treated as an unsigned value, filing spaces before or after. + * Prints the value, treated as an unsigned value, filling spaces before or after. */ public abstract Log unsigned(long value, int fill, int align); public abstract Log rational(long numerator, long denominator, long decimals); + public abstract Log rational(UnsignedWord numerator, long denominator, long decimals); + /** * Prints the value, treated as an unsigned value, in hexadecimal format. */ @@ -283,6 +297,16 @@ protected Log() { */ public abstract Log hexdump(PointerBase from, int wordSize, int numWords); + /** + * Prints a hexdump. + * + * @param from pointer to memory where dumping should start from + * @param wordSize size in bytes that a single word should have + * @param numWords number of words to dump + * @param bytesPerLine number of bytes that should be printed on one line + */ + public abstract Log hexdump(PointerBase from, int wordSize, int numWords, int bytesPerLine); + /** * Change current amount of indentation. Indentation determines the amount of spaces emitted * after each newline. @@ -393,6 +417,11 @@ public Log string(String str, int fill, int align) { return this; } + @Override + public Log string(String value, int maxLen) { + return this; + } + @Override public Log string(char[] value) { return this; @@ -443,6 +472,11 @@ public Log signed(long value) { return this; } + @Override + public Log signed(long value, int fill, int align) { + return this; + } + @Override public Log unsigned(WordBase value) { return this; @@ -473,6 +507,11 @@ public Log rational(long numerator, long denominator, long decimals) { return this; } + @Override + public Log rational(UnsignedWord numerator, long denominator, long decimals) { + return this; + } + @Override public Log hex(WordBase value) { return this; @@ -543,6 +582,11 @@ public Log hexdump(PointerBase from, int wordSize, int numWords) { return this; } + @Override + public Log hexdump(PointerBase from, int wordSize, int numWords, int bytesPerLine) { + return this; + } + @Override public Log exception(Throwable t) { return this; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java index ba19178f8bdf..0a5d62801ab0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java @@ -87,6 +87,14 @@ public Log string(String str, int fill, int align) { return this; } + @Override + @NeverInline("Logging is always slow-path code") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") + public Log string(String value, int maxLen) { + rawString(value, maxLen); + return this; + } + private static final char[] NULL_CHARS = "null".toCharArray(); @Override @@ -291,6 +299,12 @@ public Log signed(long value) { return this; } + @Override + public Log signed(long value, int fill, int align) { + number(value, 10, true, fill, align); + return this; + } + @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public Log unsigned(WordBase value) { @@ -373,6 +387,12 @@ public Log rational(long numerator, long denominator, long decimals) { return this; } + @Override + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") + public Log rational(UnsignedWord numerator, long denominator, long decimals) { + return rational(numerator.rawValue(), denominator, decimals); + } + @Override @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public Log hex(WordBase value) { @@ -560,13 +580,19 @@ public Log zhex(byte value) { } @Override - @NeverInline("Logging is always slow-path code") @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") public Log hexdump(PointerBase from, int wordSize, int numWords) { + return hexdump(from, wordSize, numWords, 16); + } + + @Override + @NeverInline("Logging is always slow-path code") + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not allocate when logging.") + public Log hexdump(PointerBase from, int wordSize, int numWords, int bytesPerLine) { Pointer base = WordFactory.pointer(from.rawValue()); int sanitizedWordsize = wordSize > 0 ? Integer.highestOneBit(Math.min(wordSize, 8)) : 2; for (int offset = 0; offset < sanitizedWordsize * numWords; offset += sanitizedWordsize) { - if (offset % 16 == 0) { + if (offset % bytesPerLine == 0) { zhex(base.add(offset)); string(":"); } @@ -585,7 +611,7 @@ public Log hexdump(PointerBase from, int wordSize, int numWords) { zhex(base.readLong(offset)); break; } - if ((offset + sanitizedWordsize) % 16 == 0 && (offset + sanitizedWordsize) < sanitizedWordsize * numWords) { + if ((offset + sanitizedWordsize) % bytesPerLine == 0 && (offset + sanitizedWordsize) < sanitizedWordsize * numWords) { newline(); } } @@ -632,7 +658,6 @@ public Log exception(Throwable t, int maxFrames) { newline().string(" ... ").unsigned(remaining).string(" more"); } } - newline(); return this; } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/ThreadStackPrinter.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/ThreadStackPrinter.java index 3e434fb3949d..447da531ab1b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/ThreadStackPrinter.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/stack/ThreadStackPrinter.java @@ -27,6 +27,7 @@ import org.graalvm.nativeimage.StackValue; import org.graalvm.nativeimage.c.function.CodePointer; import org.graalvm.word.Pointer; +import org.graalvm.word.WordFactory; import com.oracle.svm.core.NeverInline; import com.oracle.svm.core.Uninterruptible; @@ -53,7 +54,7 @@ public StackFramePrintVisitor() { @Override protected void logFrame(Log log, Pointer sp, CodePointer ip, CodeInfo codeInfo, DeoptimizedFrame deoptFrame) { if (deoptFrame != null) { - logVirtualFrames(log, sp, ip, deoptFrame); + logVirtualFrames(log, sp, ip, codeInfo, deoptFrame); return; } @@ -68,17 +69,21 @@ protected void logFrame(Log log, Pointer sp, CodePointer ip, CodeInfo codeInfo, if (!isFirst) { log.newline(); } - logFrameRaw(log, sp, ip); - FrameInfoQueryResult frame = frameInfoCursor.get(); - logFrameInfo(log, frame, CodeInfoAccess.getName(codeInfo)); + boolean compilationRoot = !frameInfoCursor.hasCaller(); + printFrameIdentifier(log, codeInfo, null, compilationRoot); + logFrameRaw(log, sp, ip, codeInfo); + + String codeInfoName = DeoptimizationSupport.enabled() ? CodeInfoAccess.getName(codeInfo) : null; + logFrameInfo(log, frameInfoCursor.get(), codeInfoName); isFirst = false; printedFrames++; } if (isFirst) { - /* The code above failed, so print less detailed information. */ - super.logFrame(log, sp, ip, codeInfo, deoptFrame); + /* We don't have any metadata, so print less detailed information. */ + super.logFrame(log, sp, ip, codeInfo, null); + log.string("missing metadata"); } } } @@ -111,7 +116,7 @@ protected final boolean visitFrame(Pointer sp, CodePointer ip, CodeInfo codeInfo @Override protected final boolean unknownFrame(Pointer sp, CodePointer ip, DeoptimizedFrame deoptimizedFrame, Object data) { Log log = (Log) data; - logFrameRaw(log, sp, ip); + logFrameRaw(log, sp, ip, WordFactory.nullPointer()); if (DeoptimizationSupport.enabled()) { log.string(" deoptFrame=").object(deoptimizedFrame); } @@ -122,14 +127,17 @@ protected final boolean unknownFrame(Pointer sp, CodePointer ip, DeoptimizedFram @SuppressWarnings("unused") protected void logFrame(Log log, Pointer sp, CodePointer ip, CodeInfo codeInfo, DeoptimizedFrame deoptFrame) { - logFrameRaw(log, sp, ip); - log.string(" FrameSize ").signed(CodeInfoAccess.lookupTotalFrameSize(codeInfo, CodeInfoAccess.relativeIP(codeInfo, ip))); + logFrameRaw(log, sp, ip, codeInfo); printedFrames++; } - protected static void logFrameRaw(Log log, Pointer sp, CodePointer ip) { + protected static void logFrameRaw(Log log, Pointer sp, CodePointer ip, CodeInfo codeInfo) { log.string("SP ").zhex(sp); log.string(" IP ").zhex(ip); + if (codeInfo.isNonNull()) { + long frameSize = CodeInfoAccess.lookupTotalFrameSize(codeInfo, CodeInfoAccess.relativeIP(codeInfo, ip)); + log.string(" size=").signed(frameSize, 4, Log.LEFT_ALIGN); + } } } @@ -140,22 +148,24 @@ public Stage1StackFramePrintVisitor() { @Override protected void logFrame(Log log, Pointer sp, CodePointer ip, CodeInfo codeInfo, DeoptimizedFrame deoptFrame) { if (deoptFrame != null) { - logVirtualFrames(log, sp, ip, deoptFrame); + logVirtualFrames(log, sp, ip, codeInfo, deoptFrame); } else { logStackFrame(log, sp, ip, codeInfo); } } - protected void logVirtualFrames(Log log, Pointer sp, CodePointer ip, DeoptimizedFrame deoptFrame) { + protected void logVirtualFrames(Log log, Pointer sp, CodePointer ip, CodeInfo codeInfo, DeoptimizedFrame deoptFrame) { for (DeoptimizedFrame.VirtualFrame frame = deoptFrame.getTopFrame(); frame != null; frame = frame.getCaller()) { if (printedFrames >= MAX_STACK_FRAMES_PER_THREAD_TO_PRINT) { log.string("... (truncated)").newline(); break; } - logFrameRaw(log, sp, ip); + boolean compilationRoot = frame.getCaller() == null; + printFrameIdentifier(log, WordFactory.nullPointer(), deoptFrame, compilationRoot); + logFrameRaw(log, sp, ip, codeInfo); logFrameInfo(log, frame.getFrameInfo(), ImageCodeInfo.CODE_INFO_NAME + ", deopt"); - if (frame.getCaller() != null) { + if (!compilationRoot) { log.newline(); } printedFrames++; @@ -163,10 +173,12 @@ protected void logVirtualFrames(Log log, Pointer sp, CodePointer ip, Deoptimized } private void logStackFrame(Log log, Pointer sp, CodePointer ip, CodeInfo codeInfo) { - logFrameRaw(log, sp, ip); + printFrameIdentifier(log, codeInfo, null, true); + logFrameRaw(log, sp, ip, codeInfo); log.spaces(2); - CodeInfoAccess.log(codeInfo, log); - log.string(" name = ").string(CodeInfoAccess.getName(codeInfo)); + if (DeoptimizationSupport.enabled()) { + log.string("[").string(CodeInfoAccess.getName(codeInfo)).string("] "); + } printedFrames++; } @@ -177,9 +189,28 @@ protected static void logFrameInfo(Log log, FrameInfoQueryResult frameInfo, Stri } frameInfo.log(log); } + + protected static void printFrameIdentifier(Log log, CodeInfo codeInfo, DeoptimizedFrame deoptFrame, boolean isCompilationRoot) { + char ch = getFrameIdentifier(codeInfo, deoptFrame, isCompilationRoot); + log.character(ch).spaces(2); + } + + private static char getFrameIdentifier(CodeInfo codeInfo, DeoptimizedFrame deoptFrame, boolean isCompilationRoot) { + if (deoptFrame != null) { + return 'D'; + } else if (!isCompilationRoot) { + return 'i'; + } else if (codeInfo == CodeInfoTable.getImageCodeInfo()) { + return 'A'; + } else { + return 'J'; + } + } } - /** Walk the stack printing each frame. */ + /** + * Walk the stack printing each frame. + */ @NeverInline("debugger breakpoint") @Uninterruptible(reason = "Called from uninterruptible code.") public static void printBacktrace() { @@ -204,7 +235,7 @@ public static boolean printStacktrace(Pointer startSP, CodePointer startIP, Stag @Uninterruptible(reason = "CodeInfo in JavaStackWalk is currently null, so printing to log is safe right now.", calleeMustBe = false) private static void logFrameAnchor(Log log, Pointer startSP, CodePointer startIP) { - Stage0StackFramePrintVisitor.logFrameRaw(log, startSP, startIP); + Stage0StackFramePrintVisitor.logFrameRaw(log, startSP, startIP, WordFactory.nullPointer()); log.string(" IP is not within Java code. Trying frame anchor of last Java frame instead.").newline(); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java index 4df97a21eeba..0098b03d992f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java @@ -601,7 +601,7 @@ private static boolean tearDownPlatformThreads() { try { thread.interrupt(); // not final and subclasses can unexpectedly throw } catch (Throwable t) { - trace.string(" threw (ignored): ").exception(t); + trace.string(" threw (ignored): ").exception(t).newline(); } trace.newline().flush(); @@ -642,7 +642,7 @@ private static boolean tearDownPlatformThreads() { pool.shutdownNow(); } } catch (Throwable t) { - trace.string(" threw (ignored): ").exception(t); + trace.string(" threw (ignored): ").exception(t).newline(); } trace.newline().flush(); trace.string(" shutdown initiated: ").object(pool).newline().flush(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java index a17aa4afaac4..4b04201c0d9f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMOperationControl.java @@ -39,6 +39,7 @@ import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; +import com.oracle.svm.core.Isolates; import com.oracle.svm.core.NeverInline; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateOptions.ConcealedOptions; @@ -57,6 +58,7 @@ import com.oracle.svm.core.thread.VMThreads.SafepointBehavior; import com.oracle.svm.core.thread.VMThreads.StatusSupport; import com.oracle.svm.core.util.RingBuffer; +import com.oracle.svm.core.util.TimeUtils; import com.oracle.svm.core.util.VMError; /** @@ -902,7 +904,7 @@ private static class VMOpHistory { @Platforms(Platform.HOSTED_ONLY.class) VMOpHistory() { - history = new RingBuffer<>(15, VMOpStatusChange::new); + history = new RingBuffer<>(SubstrateOptions.DiagnosticBufferSize.getValue(), VMOpStatusChange::new); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @@ -920,7 +922,7 @@ public void add(VMOpStatus status, VMOperation operation, IsolateThread queueing } public void print(Log log, boolean allowJavaHeapAccess) { - log.string("The ").signed(history.size()).string(" most recent VM operation status changes (oldest first):").indent(true); + log.string("The ").signed(history.size()).string(" most recent VM operation status changes:").indent(true); history.foreach(log, allowJavaHeapAccess ? PRINT_WITH_JAVA_HEAP_DATA : PRINT_WITHOUT_JAVA_HEAP_DATA); log.indent(false); } @@ -967,7 +969,8 @@ private static class VMOpStatusChange { void print(Log log, boolean allowJavaHeapAccess) { VMOpStatus localStatus = status; if (localStatus != null) { - log.unsigned(timestamp).string(" - ").spaces(nestingLevel * 2).string(localStatus.name()); + long uptime = timestamp - Isolates.getCurrentStartTimeMillis(); + log.rational(uptime, TimeUtils.millisPerSecond, 3).string("s - ").spaces(nestingLevel * 2).string(localStatus.name()); if (allowJavaHeapAccess) { log.string(" ").string(name); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java index 8f7abe154e14..7039f1981208 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java @@ -606,21 +606,26 @@ public static boolean ownsThreadMutex() { } public static boolean printLocationInfo(Log log, UnsignedWord value, boolean allowUnsafeOperations) { + if (!allowUnsafeOperations && !VMOperation.isInProgressAtSafepoint()) { + /* + * Iterating the threads or accessing thread locals of other threads is unsafe if we are + * outside a VM operation because the IsolateThread data structure could be freed at any + * time (we can't use any locking to prevent races). + */ + return false; + } + for (IsolateThread thread = firstThreadUnsafe(); thread.isNonNull(); thread = nextThread(thread)) { if (thread.equal(value)) { log.string("is a thread"); return true; } - if (allowUnsafeOperations || VMOperation.isInProgressAtSafepoint()) { - // If we are not at a safepoint, then it is unsafe to access thread locals of - // another thread as the IsolateThread could be freed at any time. - UnsignedWord stackBase = StackBase.get(thread); - UnsignedWord stackEnd = StackEnd.get(thread); - if (value.belowThan(stackBase) && value.aboveOrEqual(stackEnd)) { - log.string("points into the stack for thread ").zhex(thread); - return true; - } + UnsignedWord stackBase = StackBase.get(thread); + UnsignedWord stackEnd = StackEnd.get(thread); + if (value.belowThan(stackBase) && value.aboveOrEqual(stackEnd)) { + log.string("points into the stack for thread ").zhex(thread); + return true; } if (SubstrateOptions.MultiThreaded.getValue()) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfos.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfos.java index 9539435e422f..a5fbc2d9068e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfos.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/threadlocal/VMThreadLocalInfos.java @@ -37,6 +37,7 @@ import org.graalvm.word.WordBase; import org.graalvm.word.WordFactory; +import com.oracle.svm.core.SubstrateDiagnostics; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; @@ -61,33 +62,43 @@ public static boolean setInfos(Collection infos) { public static void dumpToLog(Log log, IsolateThread thread, boolean isJavaHeapAccessAllowed) { for (VMThreadLocalInfo info : ImageSingletons.lookup(VMThreadLocalInfos.class).infos) { - log.signed(info.offset).string(" (").signed(info.sizeInBytes).string(" bytes): ").string(info.name).string(" = "); + log.signed(info.offset).string(": ").string(info.name).string(" = "); if (info.threadLocalClass == FastThreadLocalInt.class) { int value = primitiveData(thread).readInt(WordFactory.signed(info.offset)); - log.string("(int) ").signed(value).string(" (").zhex(value).string(")"); + log.string("(int) ").zhex(value).string(" (").signed(value).string(")"); } else if (info.threadLocalClass == FastThreadLocalLong.class) { long value = primitiveData(thread).readLong(WordFactory.signed(info.offset)); - log.string("(long) ").signed(value).string(" (").zhex(value).string(")"); + log.string("(long) ").zhex(value).string(" (").signed(value).string(")"); } else if (info.threadLocalClass == FastThreadLocalWord.class) { WordBase value = primitiveData(thread).readWord(WordFactory.signed(info.offset)); - log.string("(Word) ").signed(value).string(" (").zhex(value).string(")"); + log.string("(Word) ").zhex(value).string(" (").signed(value).string(")"); } else if (info.threadLocalClass == FastThreadLocalObject.class) { if (isJavaHeapAccessAllowed) { Object value = ObjectAccess.readObject(objectData(thread), WordFactory.signed(info.offset)); - log.string("(Object) "); - if (value == null) { - log.string("null"); - } else { - log.string(value.getClass().getName()).string(" (").zhex(Word.objectToUntrackedPointer(value)).string(")"); + log.string("(Object) ").zhex(Word.objectToUntrackedPointer(value)); + if (value != null) { + log.indent(true); + SubstrateDiagnostics.printObjectInfo(log, value); + log.redent(false); } } else { Word value = ReferenceAccess.singleton().readObjectAsUntrackedPointer(Word.objectToUntrackedPointer(objectData(thread)).add(info.offset), true); log.string("(Object) ").zhex(value); } } else if (info.threadLocalClass == FastThreadLocalBytes.class) { - log.string("(bytes) ").indent(true); - log.hexdump(primitiveData(thread).add(WordFactory.signed(info.offset)), 8, info.sizeInBytes / 8); - log.redent(false); + log.string("(bytes) "); + Pointer data = primitiveData(thread).add(WordFactory.signed(info.offset)); + if (info.sizeInBytes == 8) { + log.zhex(data.readWord(0)); + } else { + log.indent(true); + if (info.sizeInBytes % 8 == 0) { + log.hexdump(data, 8, info.sizeInBytes / 8); + } else { + log.hexdump(data, 1, info.sizeInBytes); + } + log.redent(false); + } } else { log.string("unknown class ").string(info.threadLocalClass.getName()); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/Counter.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/Counter.java index ed8925cc0c35..5e262bb516c0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/Counter.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/Counter.java @@ -48,8 +48,8 @@ * option is enabled. Counters are {@link Group grouped} for printing. * * Currently there is no shutdown hook in Substrate VM that is invoked automatically, so - * {@link Counter#logValues} needs to be called manually at the end of the application to print - * counter values. + * {@link CounterSupport#logValues} needs to be called manually at the end of the application to + * print counter values. * * Use this class in the following way: * @@ -206,15 +206,6 @@ public void add(long increment) { public void reset() { value = 0; } - - /** - * Prints all counters of all enabled groups to the {@link Log}. - */ - public static void logValues(Log log) { - for (Counter.Group group : ImageSingletons.lookup(CounterSupport.class).enabledGroups) { - group.logValues(log); - } - } } @TargetClass(com.oracle.svm.core.util.Counter.class) @@ -243,13 +234,3 @@ public void addGroup(Group group) { value.add(group); } } - -class CounterSupport { - - final Counter.Group[] enabledGroups; - - CounterSupport(Counter.Group[] enabledGroups) { - this.enabledGroups = enabledGroups; - } - -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/CounterSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/CounterSupport.java new file mode 100644 index 000000000000..ebab33d660a2 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/CounterSupport.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.util; + +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +import com.oracle.svm.core.log.Log; + +public class CounterSupport { + private final Counter.Group[] enabledGroups; + + @Platforms(Platform.HOSTED_ONLY.class) + CounterSupport(Counter.Group[] enabledGroups) { + this.enabledGroups = enabledGroups; + } + + @Fold + public static CounterSupport singleton() { + return ImageSingletons.lookup(CounterSupport.class); + } + + /** + * Prints all counters of all enabled groups to the {@link Log}. + */ + public void logValues(Log log) { + for (Counter.Group group : enabledGroups) { + group.logValues(log); + } + } + + public boolean hasCounters() { + return enabledGroups != null && enabledGroups.length > 0; + } + +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/RingBuffer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/RingBuffer.java index dd4f6f2ba971..827bfd17d613 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/RingBuffer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/RingBuffer.java @@ -32,8 +32,6 @@ * Keeps the last-n entries and allows to read the out on demand.. */ public final class RingBuffer { - private static final int DEFAULT_BUFFER_SIZE = 30; - private final T[] entries; private int pos; private boolean wrapped; @@ -42,10 +40,6 @@ public interface Consumer { void accept(Object context, T t); } - public RingBuffer() { - this(DEFAULT_BUFFER_SIZE); - } - @SuppressWarnings("unchecked") public RingBuffer(int numEntries) { this.entries = (T[]) new Object[numEntries]; From 9628a666f395ffde65d947beca2476323368d212 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Wed, 6 Dec 2023 12:42:28 +0100 Subject: [PATCH 38/78] Minor fixes and cleanups. (cherry picked from commit 3b3907b7edfd3e7b2db4ca8c55c9b95ae4f44d03) --- .../oracle/svm/core/posix/pthread/PthreadConditionUtils.java | 2 +- .../com/oracle/svm/core/code/CompilationResultFrameTree.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/pthread/PthreadConditionUtils.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/pthread/PthreadConditionUtils.java index c66f1da01112..4d177086aee1 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/pthread/PthreadConditionUtils.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/pthread/PthreadConditionUtils.java @@ -87,7 +87,7 @@ public static int initConditionWithRelativeTime(pthread_cond_t cond) { if (status == 0) { try { if (useMonotonicClockForRelativeWait()) { - LinuxPthread.pthread_condattr_setclock(attr, LinuxTime.CLOCK_MONOTONIC()); + status = LinuxPthread.pthread_condattr_setclock(attr, LinuxTime.CLOCK_MONOTONIC()); if (status != 0) { return status; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CompilationResultFrameTree.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CompilationResultFrameTree.java index 4692a58d23fe..e37d6a72f454 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CompilationResultFrameTree.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CompilationResultFrameTree.java @@ -329,7 +329,7 @@ public String getLocalsStr() { sb.append(", "); } sb.append("li("); - Local local = locals != null ? locals[i] : null; + Local local = locals[i]; if (local != null) { sb.append(local.getName()); sb.append("="); From 298e76d0fddb5b47c8af8b3df12d3380c3388485 Mon Sep 17 00:00:00 2001 From: Hamza Ghaissi Date: Thu, 25 Jan 2024 12:25:32 +0100 Subject: [PATCH 39/78] Adapt fix to 23.0 --- .../com/oracle/svm/core/thread/Target_java_lang_Thread.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java index a6929b8507e1..189253efe91a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java @@ -69,8 +69,8 @@ public final class Target_java_lang_Thread { // Checkstyle: stop - @Delete // - static StackTraceElement[] EMPTY_STACK_TRACE; + @Alias // + public static StackTraceElement[] EMPTY_STACK_TRACE; @Alias // @TargetElement(onlyWith = JDK19OrLater.class) // From 641d834a4a6d06ed360c44c9afe99a3b4a4eda58 Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Tue, 24 Oct 2023 14:20:07 +0200 Subject: [PATCH 40/78] Correctly print JSON values in agent trace files. (cherry picked from commit c8542a9dc3c4b6a30d8e5eb307d6ed5f4951fb74) --- .../svm/agent/tracing/TraceFileWriter.java | 6 ++--- .../oracle/svm/core/util/json/JsonWriter.java | 27 +++++++++++++------ .../com/oracle/svm/driver/BundleSupport.java | 4 +-- .../ImageHeapConnectedComponentsPrinter.java | 2 +- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/tracing/TraceFileWriter.java b/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/tracing/TraceFileWriter.java index 8dc3bdf164fd..391bd6e20ba8 100644 --- a/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/tracing/TraceFileWriter.java +++ b/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/tracing/TraceFileWriter.java @@ -98,13 +98,13 @@ private static void printArray(JsonWriter json, Object[] array) throws IOExcepti } private static void printValue(JsonWriter json, Object value) throws IOException { - String s = null; + Object s = null; if (value instanceof byte[]) { s = Base64.getEncoder().encodeToString((byte[]) value); } else if (value != null) { - s = value.toString(); + s = value; } - json.quote(s); + json.printValue(s); } private void traceEntry(String s) throws IOException { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/json/JsonWriter.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/json/JsonWriter.java index 7f2783f3d554..954eb0ee827e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/json/JsonWriter.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/json/JsonWriter.java @@ -83,7 +83,7 @@ public JsonWriter appendFieldSeparator() throws IOException { } public JsonWriter appendKeyValue(String key, Object value) throws IOException { - return quote(key).appendFieldSeparator().quote(value); + return quote(key).appendFieldSeparator().printValue(value); } @SuppressWarnings("unchecked") @@ -103,7 +103,7 @@ public void print(Map map) throws IOException { } else if (value instanceof List) { print((List) value); // Must always be } else { - quote(value); + printValue(value); } if (keySetIter.hasNext()) { append(','); @@ -132,15 +132,26 @@ public void print(List list, Function mapper) throws IOExcepti append(']'); } - public JsonWriter quote(Object o) throws IOException { + public JsonWriter printValue(Object o) throws IOException { if (o == null) { return append("null"); - } else if (Boolean.TRUE.equals(o)) { - return append("true"); - } else if (Boolean.FALSE.equals(o)) { - return append("false"); - } else if (o instanceof Number) { + } else if (o instanceof Boolean || o instanceof Byte || o instanceof Short || o instanceof Integer || o instanceof Long) { + /* + * Note that sub-integer values here most likely become Integer objects when parsing, + * and comparisons such as equals() or compareTo() on boxed values only work on the + * exact same type. (Boolean values, however, should be deserialized as Boolean). + */ return append(o.toString()); + } else if (o instanceof Float f) { + if (f.isNaN() || f.isInfinite()) { + return quote(f.toString()); // cannot express, best we can do without failing + } + return append(f.toString()); + } else if (o instanceof Double d) { + if (d.isNaN() || d.isInfinite()) { + return quote(d.toString()); // cannot express, best we can do without failing + } + return append(d.toString()); } else { return quote(o.toString()); } diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/BundleSupport.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/BundleSupport.java index ad1011edb3de..0a99dc713451 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/BundleSupport.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/BundleSupport.java @@ -670,8 +670,8 @@ private static Manifest createManifest() { private static final String substitutionMapDstField = "dst"; private static void printPathMapping(Map.Entry entry, JsonWriter w) throws IOException { - w.append('{').quote(substitutionMapSrcField).append(':').quote(entry.getKey()); - w.append(',').quote(substitutionMapDstField).append(':').quote(entry.getValue()); + w.append('{').quote(substitutionMapSrcField).append(':').printValue(entry.getKey()); + w.append(',').quote(substitutionMapDstField).append(':').printValue(entry.getValue()); w.append('}'); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/ImageHeapConnectedComponentsPrinter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/ImageHeapConnectedComponentsPrinter.java index d8b53b5f6e64..04d41fd051c6 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/ImageHeapConnectedComponentsPrinter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/ImageHeapConnectedComponentsPrinter.java @@ -214,7 +214,7 @@ public void printSummaryInfoForEveryObjectInConnectedComponents(PrintWriter out) for (Iterator iterator = connectedComponents.iterator(); iterator.hasNext();) { ConnectedComponent connectedComponent = iterator.next(); writer.append('{').newline(); - writer.quote("componentId").append(':').quote(connectedComponent.getId()).append(',').newline(); + writer.quote("componentId").append(':').printValue(connectedComponent.getId()).append(',').newline(); writer.quote("sizeInBytes").append(':').append(String.valueOf(connectedComponent.getSizeInBytes())).append(',').newline(); writer.quote("objects").append(":["); List objects = connectedComponent.getObjects(); From d5be7d27a60851a38445506fa639fb82b9df8f3c Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Tue, 24 Oct 2023 14:36:59 +0200 Subject: [PATCH 41/78] Support access-filter-file for native-image-configure. (cherry picked from commit 2d30af2a2f71ef8f3ef9a71e5c3824c264bf5739) --- .../command/ConfigurationGenerateCommand.java | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/command/ConfigurationGenerateCommand.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/command/ConfigurationGenerateCommand.java index 173a443c33ce..07f7f1e43010 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/command/ConfigurationGenerateCommand.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/command/ConfigurationGenerateCommand.java @@ -145,6 +145,7 @@ protected static void generate(Iterator argumentsIterator, boolean accep boolean builtinCallerFilter = true; boolean builtinHeuristicFilter = true; List callerFilters = new ArrayList<>(); + List accessFilters = new ArrayList<>(); ConfigurationFileCollection omittedCollection = new ConfigurationFileCollection(); ConfigurationFileCollection inputCollection = new ConfigurationFileCollection(); @@ -219,6 +220,9 @@ protected static void generate(Iterator argumentsIterator, boolean accep case "--caller-filter-file": callerFilters.add(requirePathUri(option, value)); break; + case "--access-filter-file": + accessFilters.add(requirePathUri(option, value)); + break; case "--": if (acceptTraceFileArgs) { argumentsIterator.forEachRemaining(arg -> traceInputs.add(Paths.get(arg).toUri())); @@ -247,15 +251,12 @@ protected static void generate(Iterator argumentsIterator, boolean accep callersFilterHierarchyFilterNode = AccessAdvisor.copyBuiltinCallerFilterTree(); callersFilter = new ComplexFilter(callersFilterHierarchyFilterNode); } - for (URI uri : callerFilters) { - try { - FilterConfigurationParser parser = new FilterConfigurationParser(callersFilter); - parser.parseAndRegister(uri); - } catch (Exception e) { - throw new ConfigurationUsageException("Cannot parse filter file " + uri + ": " + e); - } - } - callersFilter.getHierarchyFilterNode().removeRedundantNodes(); + parseFilterFiles(callersFilter, callerFilters); + } + ComplexFilter accessFilter = null; + if (!accessFilters.isEmpty()) { + accessFilter = new ComplexFilter(AccessAdvisor.copyBuiltinAccessFilterTree()); + parseFilterFiles(accessFilter, accessFilters); } ConfigurationSet configurationSet; @@ -286,6 +287,9 @@ protected static void generate(Iterator argumentsIterator, boolean accep if (callersFilter != null) { advisor.setCallerFilterTree(callersFilter); } + if (accessFilter != null) { + advisor.setAccessFilterTree(accessFilter); + } TraceProcessor processor = new TraceProcessor(advisor); for (URI uri : traceInputs) { @@ -330,6 +334,17 @@ protected static void generate(Iterator argumentsIterator, boolean accep } } + private static void parseFilterFiles(ComplexFilter filter, List filterFiles) { + for (URI uri : filterFiles) { + try { + new FilterConfigurationParser(filter).parseAndRegister(uri); + } catch (Exception e) { + throw new ConfigurationUsageException("Cannot parse filter file " + uri + ": " + e); + } + } + filter.getHierarchyFilterNode().removeRedundantNodes(); + } + @SuppressWarnings("fallthrough") private static void failIfAgentLockFilesPresent(ConfigurationFileCollection... collections) { Set paths = null; From 8670a41732b27162cbc4879878c171790dd5c44a Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Sun, 28 Jan 2024 11:45:07 +0000 Subject: [PATCH 42/78] update to jvmci-23.0-b30 --- common.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common.json b/common.json index bd1f127a7107..46af265c8f3d 100644 --- a/common.json +++ b/common.json @@ -14,9 +14,9 @@ "labsjdk-ce-17": {"name": "labsjdk", "version": "ce-17.0.9+9-jvmci-23.0-b22", "platformspecific": true }, "labsjdk-ce-17Debug": {"name": "labsjdk", "version": "ce-17.0.9+9-jvmci-23.0-b22-debug", "platformspecific": true }, "labsjdk-ce-17-llvm": {"name": "labsjdk", "version": "ce-17.0.9+9-jvmci-23.0-b22-sulong", "platformspecific": true }, - "labsjdk-ee-17": {"name": "labsjdk", "version": "ee-17.0.11+2-jvmci-23.0-b29", "platformspecific": true }, - "labsjdk-ee-17Debug": {"name": "labsjdk", "version": "ee-17.0.11+2-jvmci-23.0-b29-debug", "platformspecific": true }, - "labsjdk-ee-17-llvm": {"name": "labsjdk", "version": "ee-17.0.11+2-jvmci-23.0-b29-sulong", "platformspecific": true }, + "labsjdk-ee-17": {"name": "labsjdk", "version": "ee-17.0.11+3-jvmci-23.0-b30", "platformspecific": true }, + "labsjdk-ee-17Debug": {"name": "labsjdk", "version": "ee-17.0.11+3-jvmci-23.0-b30-debug", "platformspecific": true }, + "labsjdk-ee-17-llvm": {"name": "labsjdk", "version": "ee-17.0.11+3-jvmci-23.0-b30-sulong", "platformspecific": true }, "oraclejdk19": {"name": "jpg-jdk", "version": "19", "build_id": "26", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, "labsjdk-ce-19": {"name": "labsjdk", "version": "ce-19.0.1+10-jvmci-23.0-b04", "platformspecific": true }, From c5c226db9aa12e737ea431163440ccdb3eaa82d5 Mon Sep 17 00:00:00 2001 From: Marouane El Hallaoui Date: Mon, 29 Jan 2024 12:17:00 +0100 Subject: [PATCH 43/78] Fix identity hash offset assertion --- .../src/com/oracle/svm/core/hub/DynamicHub.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 1ec07a04d2a8..1c1fd0fe70bb 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 @@ -433,7 +433,7 @@ public void setData(int layoutEncoding, int typeID, int monitorOffset, int optio ObjectLayout ol = ConfigurationValues.getObjectLayout(); assert ol.hasFixedIdentityHashField() ? (optionalIdentityHashOffset == ol.getFixedIdentityHashOffset()) : (optionalIdentityHashOffset > 0); } else { - assert optionalIdentityHashOffset == -1; + assert optionalIdentityHashOffset == 0; } VMError.guarantee(monitorOffset == (char) monitorOffset, "Class %s has an invalid monitor field offset. Most likely, its objects are larger than supported.", name); VMError.guarantee(optionalIdentityHashOffset == (char) optionalIdentityHashOffset, "Class %s has an invalid identity hash code field offset. Most likely, its objects are larger than supported.", name); From d07148bcf7da809916469cb853db316820b05afd Mon Sep 17 00:00:00 2001 From: Marouane El Hallaoui Date: Mon, 29 Jan 2024 13:20:44 +0100 Subject: [PATCH 44/78] fix style issue --- .../src/com/oracle/svm/core/hub/DynamicHub.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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 1c1fd0fe70bb..856d12a7aa0f 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 @@ -436,12 +436,13 @@ public void setData(int layoutEncoding, int typeID, int monitorOffset, int optio assert optionalIdentityHashOffset == 0; } VMError.guarantee(monitorOffset == (char) monitorOffset, "Class %s has an invalid monitor field offset. Most likely, its objects are larger than supported.", name); - VMError.guarantee(optionalIdentityHashOffset == (char) optionalIdentityHashOffset, "Class %s has an invalid identity hash code field offset. Most likely, its objects are larger than supported.", name); + VMError.guarantee(optionalIdentityHashOffset == (char) optionalIdentityHashOffset, + "Class %s has an invalid identity hash code field offset. Most likely, its objects are larger than supported.", name); this.layoutEncoding = layoutEncoding; this.typeID = typeID; - this.monitorOffset = (char)monitorOffset; - this.optionalIdentityHashOffset = (char)optionalIdentityHashOffset; + this.monitorOffset = (char) monitorOffset; + this.optionalIdentityHashOffset = (char) optionalIdentityHashOffset; this.typeCheckStart = typeCheckStart; this.typeCheckRange = typeCheckRange; From 331a4089c4bb0afa3d744b60ef9f5b29d1301608 Mon Sep 17 00:00:00 2001 From: Anas El korchi Date: Mon, 29 Jan 2024 14:10:17 +0100 Subject: [PATCH 45/78] update VSCode version --- ci/common.jsonnet | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/common.jsonnet b/ci/common.jsonnet index 850994500915..b86336176cef 100644 --- a/ci/common.jsonnet +++ b/ci/common.jsonnet @@ -49,7 +49,7 @@ local common_json = import "../common.json"; # The devkits versions reflect those used to build the JVMCI JDKs (e.g., see devkit_platform_revisions in /make/conf/jib-profiles.js) devkits: { - "windows-jdk17": { packages+: { "devkit:VS2022-17.1.0+1": "==0" }}, + "windows-jdk17": { packages+: { "devkit:VS2022-17.6.5+1": "==0" }}, "windows-jdk19": { packages+: { "devkit:VS2022-17.1.0+1": "==0" }}, "windows-jdk20": { packages+: { "devkit:VS2022-17.1.0+1": "==0" }}, "linux-jdk17": { packages+: { "devkit:gcc10.3.0-OL6.4+1": "==0" }}, From cf89f682d155874fb3cd18e7f8e37b026147e1d7 Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Fri, 19 Jan 2024 09:59:10 +0100 Subject: [PATCH 46/78] induction variables: only non overflowing constant properties should be considered constant properties (cherry picked from commit 254c019486767709ef6cdb67183354221ec065b9) --- .../DerivedConvertedInductionVariable.java | 20 +++--- .../loop/DerivedOffsetInductionVariable.java | 65 ++++++++++++++----- .../loop/DerivedScaledInductionVariable.java | 64 ++++++++++++++---- 3 files changed, 107 insertions(+), 42 deletions(-) diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedConvertedInductionVariable.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedConvertedInductionVariable.java index 7bdc2f0d0d83..b54ec052cef3 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedConvertedInductionVariable.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedConvertedInductionVariable.java @@ -81,6 +81,16 @@ public long constantStride() { return base.constantStride(); } + @Override + public boolean isConstantExtremum() { + return base.isConstantExtremum(); + } + + @Override + public long constantExtremum() { + return base.constantExtremum(); + } + @Override public ValueNode extremumNode(boolean assumeLoopEntered, Stamp s) { // base.extremumNode will already perform any necessary conversion operation based on the @@ -102,16 +112,6 @@ public ValueNode exitValueNode() { return op(base.exitValueNode(), true); } - @Override - public boolean isConstantExtremum() { - return base.isConstantExtremum(); - } - - @Override - public long constantExtremum() { - return base.constantExtremum(); - } - @Override public void deleteUnusedNodes() { } diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedOffsetInductionVariable.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedOffsetInductionVariable.java index 0dbed91f6044..7bffa1a3a8e3 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedOffsetInductionVariable.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedOffsetInductionVariable.java @@ -28,6 +28,7 @@ import static org.graalvm.compiler.nodes.loop.MathUtil.sub; import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.debug.Assertions; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.ValueNode; @@ -71,7 +72,15 @@ public ValueNode valueNode() { @Override public boolean isConstantInit() { - return offset.isConstant() && base.isConstantInit(); + try { + if (offset.isConstant() && base.isConstantInit()) { + constantInitSafe(); + return true; + } + } catch (ArithmeticException e) { + // fall through to return false + } + return false; } @Override @@ -81,17 +90,47 @@ public boolean isConstantStride() { @Override public long constantInit() { - return op(base.constantInit(), offset.asJavaConstant().asLong()); + return constantInitSafe(); + } + + private long constantInitSafe() throws ArithmeticException { + return opSafe(base.constantInit(), offset.asJavaConstant().asLong()); } @Override public long constantStride() { + return constantStrideSafe(); + } + + private long constantStrideSafe() throws ArithmeticException { if (value instanceof SubNode && base.valueNode() == value.getY()) { - return -base.constantStride(); + return Math.multiplyExact(base.constantStride(), -1); } return base.constantStride(); } + @Override + public boolean isConstantExtremum() { + try { + if (offset.isConstant() && base.isConstantExtremum()) { + constantExtremumSafe(); + return true; + } + } catch (ArithmeticException e) { + // fall through to return false + } + return false; + } + + @Override + public long constantExtremum() { + return constantExtremumSafe(); + } + + private long constantExtremumSafe() throws ArithmeticException { + return opSafe(base.constantExtremum(), offset.asJavaConstant().asLong()); + } + @Override public ValueNode initNode() { return op(base.initNode(), offset); @@ -120,26 +159,16 @@ public ValueNode exitValueNode() { return op(base.exitValueNode(), offset); } - @Override - public boolean isConstantExtremum() { - return offset.isConstant() && base.isConstantExtremum(); - } - - @Override - public long constantExtremum() { - return op(base.constantExtremum(), offset.asJavaConstant().asLong()); - } - - private long op(long b, long o) { + private long opSafe(long b, long o) throws ArithmeticException { if (value instanceof AddNode) { - return b + o; + return Math.addExact(b, o); } if (value instanceof SubNode) { if (base.valueNode() == value.getX()) { - return b - o; + return Math.subtractExact(b, o); } else { - assert base.valueNode() == value.getY(); - return o - b; + assert base.valueNode() == value.getY() : Assertions.errorMessage(base, base.valueNode(), value, value.getY()); + return Math.subtractExact(b, o); } } throw GraalError.shouldNotReachHere(); // ExcludeFromJacocoGeneratedReport diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedScaledInductionVariable.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedScaledInductionVariable.java index d40266243a42..bd4f7abbd98e 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedScaledInductionVariable.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedScaledInductionVariable.java @@ -91,47 +91,83 @@ public ValueNode strideNode() { @Override public boolean isConstantInit() { - return scale.isConstant() && base.isConstantInit(); + try { + if (scale.isConstant() && base.isConstantInit()) { + constantInitSafe(); + return true; + } + } catch (ArithmeticException e) { + // fall through to return false + } + return false; } @Override public boolean isConstantStride() { - return scale.isConstant() && base.isConstantStride(); + try { + if (scale.isConstant() && base.isConstantStride()) { + constantStrideSafe(); + return true; + } + } catch (ArithmeticException e) { + // fall through to return false + } + return false; } @Override public long constantInit() { - return base.constantInit() * scale.asJavaConstant().asLong(); + return constantInitSafe(); + } + + private long constantInitSafe() throws ArithmeticException { + return Math.multiplyExact(base.constantInit(), scale.asJavaConstant().asLong()); } @Override public long constantStride() { - return base.constantStride() * scale.asJavaConstant().asLong(); + return constantStrideSafe(); + } + + private long constantStrideSafe() throws ArithmeticException { + return Math.multiplyExact(base.constantStride(), scale.asJavaConstant().asLong()); } @Override - public ValueNode extremumNode(boolean assumeLoopEntered, Stamp stamp) { - return mul(graph(), base.extremumNode(assumeLoopEntered, stamp), IntegerConvertNode.convert(scale, stamp, graph(), NodeView.DEFAULT)); + public boolean isConstantExtremum() { + try { + if (scale.isConstant() && base.isConstantExtremum()) { + constantExtremumSafe(); + return true; + } + } catch (ArithmeticException e) { + // fall through to return false + } + return false; } @Override - public ValueNode extremumNode(boolean assumeLoopEntered, Stamp stamp, ValueNode maxTripCount) { - return mul(graph(), base.extremumNode(assumeLoopEntered, stamp, maxTripCount), IntegerConvertNode.convert(scale, stamp, graph(), NodeView.DEFAULT)); + public long constantExtremum() { + return constantExtremumSafe(); + } + + private long constantExtremumSafe() throws ArithmeticException { + return Math.multiplyExact(base.constantExtremum(), scale.asJavaConstant().asLong()); } @Override - public ValueNode exitValueNode() { - return mul(graph(), base.exitValueNode(), scale); + public ValueNode extremumNode(boolean assumeLoopEntered, Stamp stamp) { + return mul(graph(), base.extremumNode(assumeLoopEntered, stamp), IntegerConvertNode.convert(scale, stamp, graph(), NodeView.DEFAULT)); } @Override - public boolean isConstantExtremum() { - return scale.isConstant() && base.isConstantExtremum(); + public ValueNode extremumNode(boolean assumeLoopEntered, Stamp stamp, ValueNode maxTripCount) { + return mul(graph(), base.extremumNode(assumeLoopEntered, stamp, maxTripCount), IntegerConvertNode.convert(scale, stamp, graph(), NodeView.DEFAULT)); } @Override - public long constantExtremum() { - return base.constantExtremum() * scale.asJavaConstant().asLong(); + public ValueNode exitValueNode() { + return mul(graph(), base.exitValueNode(), scale); } @Override From a892411c6dc0c1b1364caf241fdb1803a0094cca Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Tue, 30 Jan 2024 10:12:05 +0100 Subject: [PATCH 47/78] Use a common ThreadStartRoutinePrologue on all platforms. --- .../posix/thread/PosixPlatformThreads.java | 20 +------------------ .../core/windows/WindowsPlatformThreads.java | 20 +------------------ .../svm/core/thread/PlatformThreads.java | 19 ++++++++++++++++++ 3 files changed, 21 insertions(+), 38 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixPlatformThreads.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixPlatformThreads.java index fdc2cc341257..a58b2b5e025f 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixPlatformThreads.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixPlatformThreads.java @@ -36,7 +36,6 @@ import org.graalvm.nativeimage.c.function.CEntryPointLiteral; import org.graalvm.nativeimage.c.function.CFunctionPointer; import org.graalvm.nativeimage.c.struct.SizeOf; -import org.graalvm.nativeimage.c.type.CCharPointer; import org.graalvm.nativeimage.c.type.CTypeConversion; import org.graalvm.nativeimage.c.type.CTypeConversion.CCharPointerHolder; import org.graalvm.nativeimage.c.type.WordPointer; @@ -51,10 +50,6 @@ import com.oracle.svm.core.annotate.Inject; import com.oracle.svm.core.annotate.RecomputeFieldValue; import com.oracle.svm.core.annotate.TargetClass; -import com.oracle.svm.core.c.CGlobalData; -import com.oracle.svm.core.c.CGlobalDataFactory; -import com.oracle.svm.core.c.function.CEntryPointActions; -import com.oracle.svm.core.c.function.CEntryPointErrors; import com.oracle.svm.core.c.function.CEntryPointOptions; import com.oracle.svm.core.c.function.CEntryPointSetup.LeaveDetachThreadEpilogue; import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; @@ -188,21 +183,8 @@ protected void yieldCurrent() { private static final CEntryPointLiteral pthreadStartRoutine = CEntryPointLiteral.create(PosixPlatformThreads.class, "pthreadStartRoutine", ThreadStartData.class); - private static class PthreadStartRoutinePrologue implements CEntryPointOptions.Prologue { - private static final CGlobalData errorMessage = CGlobalDataFactory.createCString("Failed to attach a newly launched thread."); - - @SuppressWarnings("unused") - @Uninterruptible(reason = "prologue") - static void enter(ThreadStartData data) { - int code = CEntryPointActions.enterAttachThread(data.getIsolate(), true, false); - if (code != CEntryPointErrors.NO_ERROR) { - CEntryPointActions.failFatally(code, errorMessage.get()); - } - } - } - @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = Publish.NotPublished) - @CEntryPointOptions(prologue = PthreadStartRoutinePrologue.class, epilogue = LeaveDetachThreadEpilogue.class) + @CEntryPointOptions(prologue = ThreadStartRoutinePrologue.class, epilogue = LeaveDetachThreadEpilogue.class) static WordBase pthreadStartRoutine(ThreadStartData data) { ObjectHandle threadHandle = data.getThreadHandle(); freeStartData(data); diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPlatformThreads.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPlatformThreads.java index bc3a406c228a..4d521f6b1ed7 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPlatformThreads.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPlatformThreads.java @@ -35,7 +35,6 @@ import org.graalvm.nativeimage.c.struct.RawField; import org.graalvm.nativeimage.c.struct.RawStructure; import org.graalvm.nativeimage.c.struct.SizeOf; -import org.graalvm.nativeimage.c.type.CCharPointer; import org.graalvm.nativeimage.c.type.CIntPointer; import org.graalvm.nativeimage.c.type.WordPointer; import org.graalvm.word.PointerBase; @@ -43,10 +42,6 @@ import org.graalvm.word.WordFactory; import com.oracle.svm.core.Uninterruptible; -import com.oracle.svm.core.c.CGlobalData; -import com.oracle.svm.core.c.CGlobalDataFactory; -import com.oracle.svm.core.c.function.CEntryPointActions; -import com.oracle.svm.core.c.function.CEntryPointErrors; import com.oracle.svm.core.c.function.CEntryPointOptions; import com.oracle.svm.core.c.function.CEntryPointSetup.LeaveDetachThreadEpilogue; import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; @@ -155,21 +150,8 @@ interface WindowsThreadStartData extends ThreadStartData { private static final CEntryPointLiteral osThreadStartRoutine = CEntryPointLiteral.create(WindowsPlatformThreads.class, "osThreadStartRoutine", WindowsThreadStartData.class); - private static class OSThreadStartRoutinePrologue implements CEntryPointOptions.Prologue { - private static final CGlobalData errorMessage = CGlobalDataFactory.createCString("Failed to attach a newly launched thread."); - - @SuppressWarnings("unused") - @Uninterruptible(reason = "prologue") - static void enter(WindowsThreadStartData data) { - int code = CEntryPointActions.enterAttachThread(data.getIsolate(), true, false); - if (code != CEntryPointErrors.NO_ERROR) { - CEntryPointActions.failFatally(code, errorMessage.get()); - } - } - } - @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = Publish.NotPublished) - @CEntryPointOptions(prologue = OSThreadStartRoutinePrologue.class, epilogue = LeaveDetachThreadEpilogue.class) + @CEntryPointOptions(prologue = ThreadStartRoutinePrologue.class, epilogue = LeaveDetachThreadEpilogue.class) static WordBase osThreadStartRoutine(WindowsThreadStartData data) { ObjectHandle threadHandle = data.getThreadHandle(); WinBase.HANDLE osThreadHandle = data.getOSThreadHandle(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java index 61a02663e105..900a6f2c01f9 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java @@ -65,6 +65,7 @@ import org.graalvm.nativeimage.c.function.CFunctionPointer; import org.graalvm.nativeimage.c.struct.RawField; import org.graalvm.nativeimage.c.struct.RawStructure; +import org.graalvm.nativeimage.c.type.CCharPointer; import org.graalvm.nativeimage.c.type.WordPointer; import org.graalvm.word.Pointer; import org.graalvm.word.PointerBase; @@ -78,6 +79,11 @@ import com.oracle.svm.core.annotate.Alias; import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.annotate.TargetElement; +import com.oracle.svm.core.c.CGlobalData; +import com.oracle.svm.core.c.CGlobalDataFactory; +import com.oracle.svm.core.c.function.CEntryPointActions; +import com.oracle.svm.core.c.function.CEntryPointErrors; +import com.oracle.svm.core.c.function.CEntryPointOptions; import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.ReferenceHandler; import com.oracle.svm.core.heap.ReferenceHandlerThread; @@ -1185,6 +1191,19 @@ static void blockedOn(Target_sun_nio_ch_Interruptible b) { if (JavaVersionUtil.JAVA_SPEC >= 19) { synchronized (me.interruptLock) { me.nioBlocker = b; + } + } + + protected static class ThreadStartRoutinePrologue implements CEntryPointOptions.Prologue { + private static final CGlobalData errorMessage = CGlobalDataFactory.createCString("Failed to attach a newly launched thread."); + + @SuppressWarnings("unused") + @Uninterruptible(reason = "prologue") + static void enter(ThreadStartData data) { + int code = CEntryPointActions.enterAttachThread(data.getIsolate(), true, false); + if (code != CEntryPointErrors.NO_ERROR) { + CEntryPointActions.failFatally(code, errorMessage.get()); + } } } else { synchronized (me.blockerLock) { From 7000a5b4a1d6cfa1c9e11e3785e053fc78291ec9 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Thu, 18 Jan 2024 12:30:59 +0100 Subject: [PATCH 48/78] Fix a Windows-specific thread handle leak. --- .../posix/thread/PosixPlatformThreads.java | 32 +--------- .../core/windows/WindowsPlatformThreads.java | 62 +++---------------- .../com/oracle/svm/core/JavaMainWrapper.java | 3 +- .../svm/core/thread/PlatformThreads.java | 31 +++++++--- .../com/oracle/svm/core/thread/VMThreads.java | 10 ++- 5 files changed, 43 insertions(+), 95 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixPlatformThreads.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixPlatformThreads.java index a58b2b5e025f..2337541db441 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixPlatformThreads.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixPlatformThreads.java @@ -26,14 +26,10 @@ import org.graalvm.compiler.core.common.SuppressFBWarnings; import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.ObjectHandle; import org.graalvm.nativeimage.Platform.HOSTED_ONLY; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.StackValue; import org.graalvm.nativeimage.UnmanagedMemory; -import org.graalvm.nativeimage.c.function.CEntryPoint; -import org.graalvm.nativeimage.c.function.CEntryPoint.Publish; -import org.graalvm.nativeimage.c.function.CEntryPointLiteral; import org.graalvm.nativeimage.c.function.CFunctionPointer; import org.graalvm.nativeimage.c.struct.SizeOf; import org.graalvm.nativeimage.c.type.CTypeConversion; @@ -43,15 +39,12 @@ import org.graalvm.word.Pointer; import org.graalvm.word.PointerBase; import org.graalvm.word.UnsignedWord; -import org.graalvm.word.WordBase; import org.graalvm.word.WordFactory; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.annotate.Inject; import com.oracle.svm.core.annotate.RecomputeFieldValue; import com.oracle.svm.core.annotate.TargetClass; -import com.oracle.svm.core.c.function.CEntryPointOptions; -import com.oracle.svm.core.c.function.CEntryPointSetup.LeaveDetachThreadEpilogue; import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; import com.oracle.svm.core.graal.stackvalue.UnsafeStackValue; import com.oracle.svm.core.os.IsDefined; @@ -71,6 +64,7 @@ import com.oracle.svm.core.thread.Parker; import com.oracle.svm.core.thread.Parker.ParkerFactory; import com.oracle.svm.core.thread.PlatformThreads; +import com.oracle.svm.core.thread.VMThreads.OSThreadHandle; import com.oracle.svm.core.util.UnsignedUtils; import com.oracle.svm.core.util.VMError; @@ -115,7 +109,7 @@ protected boolean doStartThread(Thread thread, long stackSize) { ThreadStartData startData = prepareStart(thread, SizeOf.get(ThreadStartData.class)); Pthread.pthread_tPointer newThread = UnsafeStackValue.get(Pthread.pthread_tPointer.class); - if (Pthread.pthread_create(newThread, attributes, PosixPlatformThreads.pthreadStartRoutine.getFunctionPointer(), startData) != 0) { + if (Pthread.pthread_create(newThread, attributes, threadStartRoutine.getFunctionPointer(), startData) != 0) { undoPrepareStartOnError(thread, startData); return false; } @@ -181,19 +175,6 @@ protected void yieldCurrent() { Sched.sched_yield(); } - private static final CEntryPointLiteral pthreadStartRoutine = CEntryPointLiteral.create(PosixPlatformThreads.class, "pthreadStartRoutine", ThreadStartData.class); - - @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = Publish.NotPublished) - @CEntryPointOptions(prologue = ThreadStartRoutinePrologue.class, epilogue = LeaveDetachThreadEpilogue.class) - static WordBase pthreadStartRoutine(ThreadStartData data) { - ObjectHandle threadHandle = data.getThreadHandle(); - freeStartData(data); - - threadStartRoutine(threadHandle); - - return WordFactory.nullPointer(); - } - @Override protected void beforeThreadRun(Thread thread) { /* Complete the initialization of the thread, now that it is (nearly) running. */ @@ -236,7 +217,7 @@ public OSThreadHandle startThreadUnmanaged(CFunctionPointer threadRoutine, Point return WordFactory.nullPointer(); } - return (OSThreadHandle) newThread.read(); + return newThread.read(); } finally { Pthread.pthread_attr_destroy_no_transition(attributes); } @@ -248,13 +229,6 @@ public boolean joinThreadUnmanaged(OSThreadHandle threadHandle, WordPointer thre int status = Pthread.pthread_join_no_transition((Pthread.pthread_t) threadHandle, threadExitStatus); return status == 0; } - - @Override - @SuppressWarnings("unused") - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public void closeOSThreadHandle(OSThreadHandle threadHandle) { - // pthread_t doesn't need closing - } } @TargetClass(Thread.class) diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPlatformThreads.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPlatformThreads.java index 4d521f6b1ed7..174fd8859b83 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPlatformThreads.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPlatformThreads.java @@ -24,32 +24,24 @@ */ package com.oracle.svm.core.windows; -import org.graalvm.nativeimage.ObjectHandle; +import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platform.HOSTED_ONLY; import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.c.function.CEntryPoint; -import org.graalvm.nativeimage.c.function.CEntryPoint.Publish; -import org.graalvm.nativeimage.c.function.CEntryPointLiteral; import org.graalvm.nativeimage.c.function.CFunctionPointer; -import org.graalvm.nativeimage.c.struct.RawField; -import org.graalvm.nativeimage.c.struct.RawStructure; import org.graalvm.nativeimage.c.struct.SizeOf; import org.graalvm.nativeimage.c.type.CIntPointer; import org.graalvm.nativeimage.c.type.WordPointer; import org.graalvm.word.PointerBase; -import org.graalvm.word.WordBase; import org.graalvm.word.WordFactory; import com.oracle.svm.core.Uninterruptible; -import com.oracle.svm.core.c.function.CEntryPointOptions; -import com.oracle.svm.core.c.function.CEntryPointSetup.LeaveDetachThreadEpilogue; import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; -import com.oracle.svm.core.graal.stackvalue.UnsafeStackValue; import com.oracle.svm.core.stack.StackOverflowCheck; import com.oracle.svm.core.thread.Parker; import com.oracle.svm.core.thread.Parker.ParkerFactory; import com.oracle.svm.core.thread.PlatformThreads; +import com.oracle.svm.core.thread.VMThreads.OSThreadHandle; import com.oracle.svm.core.util.TimeUtils; import com.oracle.svm.core.util.VMError; import com.oracle.svm.core.windows.headers.Process; @@ -65,27 +57,21 @@ public final class WindowsPlatformThreads extends PlatformThreads { @Override protected boolean doStartThread(Thread thread, long stackSize) { - int threadStackSize = (int) stackSize; - int initFlag = Process.CREATE_SUSPENDED(); - - WindowsThreadStartData startData = prepareStart(thread, SizeOf.get(WindowsThreadStartData.class)); + int threadStackSize = NumUtil.safeToUInt(stackSize); + int initFlag = 0; // If caller specified a stack size, don't commit it all at once. if (threadStackSize != 0) { initFlag |= Process.STACK_SIZE_PARAM_IS_A_RESERVATION(); } - CIntPointer osThreadID = UnsafeStackValue.get(CIntPointer.class); - WinBase.HANDLE osThreadHandle = Process._beginthreadex(WordFactory.nullPointer(), threadStackSize, - WindowsPlatformThreads.osThreadStartRoutine.getFunctionPointer(), startData, initFlag, osThreadID); + ThreadStartData startData = prepareStart(thread, SizeOf.get(ThreadStartData.class)); + WinBase.HANDLE osThreadHandle = Process._beginthreadex(WordFactory.nullPointer(), threadStackSize, threadStartRoutine.getFunctionPointer(), startData, initFlag, WordFactory.nullPointer()); if (osThreadHandle.isNull()) { undoPrepareStartOnError(thread, startData); return false; } - startData.setOSThreadHandle(osThreadHandle); - - // Start the thread running - Process.ResumeThread(osThreadHandle); + WinBase.CloseHandle(osThreadHandle); return true; } @@ -101,7 +87,7 @@ public OSThreadHandle startThreadUnmanaged(CFunctionPointer threadRoutine, Point WinBase.HANDLE osThreadHandle = Process.NoTransitions._beginthreadex(WordFactory.nullPointer(), stackSize, threadRoutine, userData, initFlag, WordFactory.nullPointer()); - return (PlatformThreads.OSThreadHandle) osThreadHandle; + return (OSThreadHandle) osThreadHandle; } @Override @@ -137,38 +123,6 @@ protected void setNativeName(Thread thread, String name) { protected void yieldCurrent() { Process.SwitchToThread(); } - - @RawStructure - interface WindowsThreadStartData extends ThreadStartData { - - @RawField - WinBase.HANDLE getOSThreadHandle(); - - @RawField - void setOSThreadHandle(WinBase.HANDLE osHandle); - } - - private static final CEntryPointLiteral osThreadStartRoutine = CEntryPointLiteral.create(WindowsPlatformThreads.class, "osThreadStartRoutine", WindowsThreadStartData.class); - - @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = Publish.NotPublished) - @CEntryPointOptions(prologue = ThreadStartRoutinePrologue.class, epilogue = LeaveDetachThreadEpilogue.class) - static WordBase osThreadStartRoutine(WindowsThreadStartData data) { - ObjectHandle threadHandle = data.getThreadHandle(); - WinBase.HANDLE osThreadHandle = data.getOSThreadHandle(); - freeStartData(data); - - try { - threadStartRoutine(threadHandle); - } finally { - /* - * Note that there is another handle to the thread stored in VMThreads.OSThreadHandleTL. - * This is necessary to ensure that the operating system does not release the thread - * resources too early. - */ - WinBase.CloseHandle(osThreadHandle); - } - return WordFactory.nullPointer(); - } } /** diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java index 78794d2a7995..a252cd892d12 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java @@ -74,6 +74,7 @@ import com.oracle.svm.core.thread.ThreadListenerSupport; import com.oracle.svm.core.thread.VMThreads; import com.oracle.svm.core.util.CounterSupport; +import com.oracle.svm.core.thread.VMThreads.OSThreadHandle; import com.oracle.svm.core.util.VMError; @InternalVMMethod @@ -253,7 +254,7 @@ private static int doRunInNewThread(int argc, CCharPointerPointer argv) { MAIN_ISOLATE_PARAMETERS.get().setArgc(argc); MAIN_ISOLATE_PARAMETERS.get().setArgv(argv); long stackSize = SubstrateOptions.StackSize.getHostedValue(); - PlatformThreads.OSThreadHandle osThreadHandle = PlatformThreads.singleton().startThreadUnmanaged(RUN_MAIN_ROUTINE.get(), WordFactory.nullPointer(), (int) stackSize); + OSThreadHandle osThreadHandle = PlatformThreads.singleton().startThreadUnmanaged(RUN_MAIN_ROUTINE.get(), WordFactory.nullPointer(), (int) stackSize); if (osThreadHandle.isNull()) { CEntryPointActions.failFatally(1, START_THREAD_UNMANAGED_ERROR_MESSAGE.get()); return 1; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java index 900a6f2c01f9..210b8cf3ff8a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java @@ -62,6 +62,7 @@ import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.UnmanagedMemory; import org.graalvm.nativeimage.c.function.CEntryPoint; +import org.graalvm.nativeimage.c.function.CEntryPointLiteral; import org.graalvm.nativeimage.c.function.CFunctionPointer; import org.graalvm.nativeimage.c.struct.RawField; import org.graalvm.nativeimage.c.struct.RawStructure; @@ -69,6 +70,7 @@ import org.graalvm.nativeimage.c.type.WordPointer; import org.graalvm.word.Pointer; import org.graalvm.word.PointerBase; +import org.graalvm.word.WordBase; import org.graalvm.word.WordFactory; import com.oracle.svm.core.NeverInline; @@ -84,6 +86,7 @@ import com.oracle.svm.core.c.function.CEntryPointActions; import com.oracle.svm.core.c.function.CEntryPointErrors; import com.oracle.svm.core.c.function.CEntryPointOptions; +import com.oracle.svm.core.c.function.CEntryPointSetup; import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.ReferenceHandler; import com.oracle.svm.core.heap.ReferenceHandlerThread; @@ -97,6 +100,7 @@ import com.oracle.svm.core.nodes.CFunctionEpilogueNode; import com.oracle.svm.core.nodes.CFunctionPrologueNode; import com.oracle.svm.core.stack.StackOverflowCheck; +import com.oracle.svm.core.thread.VMThreads.OSThreadHandle; import com.oracle.svm.core.thread.VMThreads.StatusSupport; import com.oracle.svm.core.threadlocal.FastThreadLocal; import com.oracle.svm.core.threadlocal.FastThreadLocalFactory; @@ -127,6 +131,8 @@ public static PlatformThreads singleton() { return ImageSingletons.lookup(PlatformThreads.class); } + protected static final CEntryPointLiteral threadStartRoutine = CEntryPointLiteral.create(PlatformThreads.class, "threadStartRoutine", ThreadStartData.class); + /** The platform {@link java.lang.Thread} for the {@link IsolateThread}. */ static final FastThreadLocalObject currentThread = FastThreadLocalFactory.createObject(Thread.class, "PlatformThreads.currentThread").setMaxOffset(FastThreadLocal.BYTE_OFFSET); @@ -570,7 +576,7 @@ public boolean joinThreadUnmanaged(OSThreadHandle threadHandle, WordPointer thre @SuppressWarnings("unused") @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public void closeOSThreadHandle(OSThreadHandle threadHandle) { - throw VMError.shouldNotReachHere("Shouldn't call PlatformThreads.closeOSThreadHandle directly."); + /* On most platforms, OS thread handles don't need to be closed. */ } static final Method FORK_JOIN_POOL_TRY_TERMINATE_METHOD; @@ -793,6 +799,16 @@ void startThread(Thread thread, long stackSize) { */ protected abstract boolean doStartThread(Thread thread, long stackSize); + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = ThreadStartRoutinePrologue.class, epilogue = CEntryPointSetup.LeaveDetachThreadEpilogue.class) + protected static WordBase threadStartRoutine(ThreadStartData data) { + ObjectHandle threadHandle = data.getThreadHandle(); + freeStartData(data); + + threadStartRoutine(threadHandle); + return WordFactory.nullPointer(); + } + @SuppressFBWarnings(value = "Ru", justification = "We really want to call Thread.run and not Thread.start because we are in the low-level thread start routine") protected static void threadStartRoutine(ObjectHandle threadHandle) { Thread thread = ObjectHandles.getGlobal().get(threadHandle); @@ -1191,6 +1207,11 @@ static void blockedOn(Target_sun_nio_ch_Interruptible b) { if (JavaVersionUtil.JAVA_SPEC >= 19) { synchronized (me.interruptLock) { me.nioBlocker = b; + } + } else { + synchronized (me.blockerLock) { + me.blocker = b; + } } } @@ -1204,16 +1225,8 @@ static void enter(ThreadStartData data) { if (code != CEntryPointErrors.NO_ERROR) { CEntryPointActions.failFatally(code, errorMessage.get()); } - } - } else { - synchronized (me.blockerLock) { - me.blocker = b; - } } } - - public interface OSThreadHandle extends PointerBase { - } } @TargetClass(value = ThreadPoolExecutor.class, innerClass = "Worker") diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java index 7039f1981208..0bc3ce545d3d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java @@ -338,9 +338,11 @@ public void detachThread(IsolateThread thread) { assert thread.equal(CurrentIsolate.getCurrentThread()) : "Cannot detach different thread with this method"; // read thread local data (can't be accessed further below as the IsolateThread is freed) + OSThreadHandle threadHandle = OSThreadHandleTL.get(thread); OSThreadHandle nextOsThreadToCleanup = WordFactory.nullPointer(); - if (wasStartedByCurrentIsolate(thread)) { - nextOsThreadToCleanup = OSThreadHandleTL.get(thread); + boolean wasStartedByCurrentIsolate = wasStartedByCurrentIsolate(thread); + if (wasStartedByCurrentIsolate) { + nextOsThreadToCleanup = threadHandle; } threadExit(thread); @@ -374,6 +376,10 @@ public void detachThread(IsolateThread thread) { THREAD_MUTEX.unlock(); } + if (!wasStartedByCurrentIsolate) { + /* If a thread was attached, we need to free its thread handle. */ + PlatformThreads.singleton().closeOSThreadHandle(threadHandle); + } cleanupExitedOsThread(threadToCleanup); } From cada29fea91847a1165453b480a3730a15d4be93 Mon Sep 17 00:00:00 2001 From: Hamza Ghaissi Date: Wed, 31 Jan 2024 16:01:54 +0100 Subject: [PATCH 49/78] Adapt fix to 23.0 --- .../compiler/nodes/loop/DerivedOffsetInductionVariable.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedOffsetInductionVariable.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedOffsetInductionVariable.java index 7bffa1a3a8e3..65cf53f5fb29 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedOffsetInductionVariable.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/DerivedOffsetInductionVariable.java @@ -28,7 +28,6 @@ import static org.graalvm.compiler.nodes.loop.MathUtil.sub; import org.graalvm.compiler.core.common.type.Stamp; -import org.graalvm.compiler.debug.Assertions; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.ValueNode; @@ -167,7 +166,7 @@ private long opSafe(long b, long o) throws ArithmeticException { if (base.valueNode() == value.getX()) { return Math.subtractExact(b, o); } else { - assert base.valueNode() == value.getY() : Assertions.errorMessage(base, base.valueNode(), value, value.getY()); + assert base.valueNode() == value.getY() : String.format("[base]=%s;[value]=%s", base.valueNode(), value.getY()); return Math.subtractExact(b, o); } } From 6bc5e3bd8a1f888878d54929928e38e7be7080ee Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Mon, 8 Jan 2024 10:56:29 +0100 Subject: [PATCH 50/78] Avoid deadlocks when the VM is out-of-memory and other threading-related fixes. --- .../core/genscavenge/HeapChunkProvider.java | 4 +- .../posix/thread/PosixPlatformThreads.java | 34 +++- .../core/windows/WindowsPlatformThreads.java | 31 +++- .../com/oracle/svm/core/JavaMainWrapper.java | 3 - .../core/c/function/CEntryPointActions.java | 9 +- .../graal/snippets/CEntryPointSnippets.java | 38 +++-- .../JfrRecurringCallbackExecutionSampler.java | 14 +- .../oracle/svm/core/monitor/JavaMonitor.java | 4 +- .../JavaMonitorQueuedSynchronizer.java | 153 +++++++++++------ .../monitor/MultiThreadedMonitorSupport.java | 34 ++-- .../oracle/svm/core/thread/JavaThreads.java | 32 ++-- .../svm/core/thread/PlatformThreads.java | 160 ++++++++++++------ .../svm/core/thread/ThreadListener.java | 9 + .../core/thread/ThreadListenerSupport.java | 24 ++- .../com/oracle/svm/core/thread/VMThreads.java | 6 + .../svm/hosted/HostedConfiguration.java | 12 +- 16 files changed, 385 insertions(+), 182 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunkProvider.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunkProvider.java index 6db2eec7d7bc..52696391504c 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunkProvider.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapChunkProvider.java @@ -24,7 +24,6 @@ */ package com.oracle.svm.core.genscavenge; -import com.oracle.svm.core.heap.OutOfMemoryUtil; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.word.Pointer; @@ -32,14 +31,15 @@ import org.graalvm.word.WordBase; import org.graalvm.word.WordFactory; +import com.oracle.svm.core.AlwaysInline; import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.MemoryWalker; import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.AlwaysInline; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.genscavenge.AlignedHeapChunk.AlignedHeader; import com.oracle.svm.core.genscavenge.HeapChunk.Header; import com.oracle.svm.core.genscavenge.UnalignedHeapChunk.UnalignedHeader; +import com.oracle.svm.core.heap.OutOfMemoryUtil; import com.oracle.svm.core.jdk.UninterruptibleUtils; import com.oracle.svm.core.jdk.UninterruptibleUtils.AtomicUnsigned; import com.oracle.svm.core.log.Log; diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixPlatformThreads.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixPlatformThreads.java index 2337541db441..20446e1c9e4e 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixPlatformThreads.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixPlatformThreads.java @@ -106,18 +106,33 @@ protected boolean doStartThread(Thread thread, long stackSize) { } } - ThreadStartData startData = prepareStart(thread, SizeOf.get(ThreadStartData.class)); + /* + * Prevent stack overflow errors so that starting the thread and reverting back to a + * safe state (in case of an error) works reliably. + */ + StackOverflowCheck.singleton().makeYellowZoneAvailable(); + try { + return doStartThread0(thread, attributes); + } finally { + StackOverflowCheck.singleton().protectYellowZone(); + } + } finally { + Pthread.pthread_attr_destroy(attributes); + } + } + /** Starts a thread to the point so that it is executing. */ + private boolean doStartThread0(Thread thread, pthread_attr_t attributes) { + ThreadStartData startData = prepareStart(thread, SizeOf.get(ThreadStartData.class)); + try { Pthread.pthread_tPointer newThread = UnsafeStackValue.get(Pthread.pthread_tPointer.class); if (Pthread.pthread_create(newThread, attributes, threadStartRoutine.getFunctionPointer(), startData) != 0) { undoPrepareStartOnError(thread, startData); return false; } - - setPthreadIdentifier(thread, newThread.read()); return true; - } finally { - Pthread.pthread_attr_destroy(attributes); + } catch (Throwable e) { + throw VMError.shouldNotReachHere("No exception must be thrown after creating the thread start data.", e); } } @@ -143,8 +158,8 @@ static boolean hasThreadIdentifier(Thread thread) { protected void setNativeName(Thread thread, String name) { if (!hasThreadIdentifier(thread)) { /* - * The thread was not started from Java code, but started from C code and attached - * manually to SVM. We do not want to interfere with such threads. + * The thread was a. not started yet, b. not started from Java code (i.e., only attached + * to SVM). We do not want to interfere with such threads. */ return; } @@ -175,6 +190,11 @@ protected void yieldCurrent() { Sched.sched_yield(); } + /** + * Note that this method is only executed for Java threads that are started via + * {@link Thread#start()}. It is not executed if an existing native thread is attached to an + * isolate. + */ @Override protected void beforeThreadRun(Thread thread) { /* Complete the initialization of the thread, now that it is (nearly) running. */ diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPlatformThreads.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPlatformThreads.java index 174fd8859b83..bcea0d4764f0 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPlatformThreads.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPlatformThreads.java @@ -58,21 +58,38 @@ public final class WindowsPlatformThreads extends PlatformThreads { @Override protected boolean doStartThread(Thread thread, long stackSize) { int threadStackSize = NumUtil.safeToUInt(stackSize); - int initFlag = 0; // If caller specified a stack size, don't commit it all at once. if (threadStackSize != 0) { initFlag |= Process.STACK_SIZE_PARAM_IS_A_RESERVATION(); } + /* + * Prevent stack overflow errors so that starting the thread and reverting back to a safe + * state (in case of an error) works reliably. + */ + StackOverflowCheck.singleton().makeYellowZoneAvailable(); + try { + return doStartThread0(thread, threadStackSize, initFlag); + } finally { + StackOverflowCheck.singleton().protectYellowZone(); + } + } + + /** Starts a thread to the point so that it is executing. */ + private boolean doStartThread0(Thread thread, int threadStackSize, int initFlag) { ThreadStartData startData = prepareStart(thread, SizeOf.get(ThreadStartData.class)); - WinBase.HANDLE osThreadHandle = Process._beginthreadex(WordFactory.nullPointer(), threadStackSize, threadStartRoutine.getFunctionPointer(), startData, initFlag, WordFactory.nullPointer()); - if (osThreadHandle.isNull()) { - undoPrepareStartOnError(thread, startData); - return false; + try { + WinBase.HANDLE osThreadHandle = Process._beginthreadex(WordFactory.nullPointer(), threadStackSize, threadStartRoutine.getFunctionPointer(), startData, initFlag, WordFactory.nullPointer()); + if (osThreadHandle.isNull()) { + undoPrepareStartOnError(thread, startData); + return false; + } + WinBase.CloseHandle(osThreadHandle); + return true; + } catch (Throwable e) { + throw VMError.shouldNotReachHere("No exception must be thrown after creating the thread start data.", e); } - WinBase.CloseHandle(osThreadHandle); - return true; } @Override diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java index a252cd892d12..b792387c3483 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java @@ -71,7 +71,6 @@ import com.oracle.svm.core.log.Log; import com.oracle.svm.core.thread.JavaThreads; import com.oracle.svm.core.thread.PlatformThreads; -import com.oracle.svm.core.thread.ThreadListenerSupport; import com.oracle.svm.core.thread.VMThreads; import com.oracle.svm.core.util.CounterSupport; import com.oracle.svm.core.thread.VMThreads.OSThreadHandle; @@ -165,8 +164,6 @@ private static int runCore0() { } } - ThreadListenerSupport.get().beforeThreadRun(); - // Ensure that native code using JNI_GetCreatedJavaVMs finds this isolate. JNIJavaVMList.addJavaVM(JNIFunctionTables.singleton().getGlobalJavaVM()); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/function/CEntryPointActions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/function/CEntryPointActions.java index 263a370bc9fa..db7356c8ce58 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/function/CEntryPointActions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/function/CEntryPointActions.java @@ -65,10 +65,11 @@ private CEntryPointActions() { * @param startedByIsolate Whether the current thread has been launched directly by the isolate * (as opposed to being an externally started thread), which makes the isolate * responsible for cleanups when the thread detaches. - * @param ensureJavaThread when set to true, the method ensures that the {@link Thread} object - * for the newly attached thread is created. If the parameter is set to false, a - * later call to one of the {@link PlatformThreads#ensureCurrentAssigned} methods - * early after the prologue must be used to do the initialization manually. + * @param ensureJavaThread when set to true, {@link PlatformThreads#ensureCurrentAssigned()} is + * called to ensure that the Java {@link Thread} is fully initialized. If the + * parameter is set to false, the initialization must be done manually (early after + * the prologue). + * * @return 0 on success, otherwise non-zero. */ public static native int enterAttachThread(Isolate isolate, boolean startedByIsolate, boolean ensureJavaThread); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java index 0691b0191f1f..3de1a1d63225 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java @@ -104,6 +104,7 @@ import com.oracle.svm.core.stack.StackOverflowCheck; import com.oracle.svm.core.thread.PlatformThreads; import com.oracle.svm.core.thread.Safepoint; +import com.oracle.svm.core.thread.ThreadListenerSupport; import com.oracle.svm.core.thread.VMOperationControl; import com.oracle.svm.core.thread.VMThreads; import com.oracle.svm.core.thread.VMThreads.SafepointBehavior; @@ -191,7 +192,6 @@ public static int createIsolateSnippet(CEntryPointCreateIsolateParameters parame writeCurrentVMThread(WordFactory.nullPointer()); } int result = runtimeCall(CREATE_ISOLATE, parameters, vmThreadSize); - if (result != CEntryPointErrors.NO_ERROR) { return result; } @@ -247,8 +247,7 @@ private static int createIsolate0(CLongPointer parsedArgs, WordPointer isolate, if (error != CEntryPointErrors.NO_ERROR) { return error; } - - PlatformThreads.singleton().initializeIsolate(); + PlatformThreads.singleton().assignMainThread(); return CEntryPointErrors.NO_ERROR; } @@ -383,6 +382,14 @@ private static int initializeIsolateInterruptibly0(CEntryPointCreateIsolateParam return CEntryPointErrors.ISOLATE_INITIALIZATION_FAILED; } + /* The isolate is now initialized, so we can finally finish initializing the main thread. */ + try { + ThreadListenerSupport.get().beforeThreadRun(); + } catch (Throwable t) { + System.err.println("Uncaught exception in beforeThreadRun():"); + t.printStackTrace(); + return CEntryPointErrors.ISOLATE_INITIALIZATION_FAILED; + } return CEntryPointErrors.NO_ERROR; } @@ -401,8 +408,9 @@ public static int attachThreadSnippet(Isolate isolate, boolean startedByIsolate, if (MultiThreaded.getValue() && !inCrashHandler) { Safepoint.transitionNativeToJava(false); } + if (ensureJavaThread) { - runtimeCallEnsureJavaThread(ENSURE_JAVA_THREAD); + return runtimeCallEnsureJavaThread(ENSURE_JAVA_THREAD); } return CEntryPointErrors.NO_ERROR; } @@ -465,11 +473,22 @@ private static int attachUnattachedThread(Isolate isolate, boolean startedByIsol } @NodeIntrinsic(value = ForeignCallNode.class) - public static native void runtimeCallEnsureJavaThread(@ConstantNodeParameter ForeignCallDescriptor descriptor); + public static native int runtimeCallEnsureJavaThread(@ConstantNodeParameter ForeignCallDescriptor descriptor); + @Uninterruptible(reason = "Prevent stack overflow errors; thread is no longer attached in error case.", calleeMustBe = false) @SubstrateForeignCallTarget(stubCallingConvention = false) - private static void ensureJavaThread() { - PlatformThreads.ensureCurrentAssigned(); + private static int ensureJavaThread() { + try { + PlatformThreads.ensureCurrentAssigned(); + return CEntryPointErrors.NO_ERROR; + } catch (Throwable e) { + int result = CEntryPointErrors.UNCAUGHT_EXCEPTION; + if (e instanceof OutOfMemoryError) { + result = CEntryPointErrors.ALLOCATION_FAILED; + } + CEntryPointActions.leaveDetachThread(); + return result; + } } @Snippet(allowMissingProbabilities = true) @@ -479,11 +498,6 @@ public static int detachThreadSnippet() { IsolateThread thread = CurrentIsolate.getCurrentThread(); result = runtimeCall(DETACH_THREAD_MT, thread); } - /* - * Note that we do not reset the fixed registers used for the thread and isolate to null: - * Since these values are not copied to different registers when they are used, we need to - * keep the registers intact until the last possible point where we are in Java code. - */ return result; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/sampler/JfrRecurringCallbackExecutionSampler.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/sampler/JfrRecurringCallbackExecutionSampler.java index e070684ef53a..668fc9958493 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/sampler/JfrRecurringCallbackExecutionSampler.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/sampler/JfrRecurringCallbackExecutionSampler.java @@ -27,10 +27,9 @@ import static com.oracle.svm.core.snippets.KnownIntrinsics.readCallerStackPointer; import static com.oracle.svm.core.snippets.KnownIntrinsics.readReturnAddress; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; -import com.oracle.svm.core.feature.InternalFeature; -import com.oracle.svm.core.jfr.JfrFeature; -import com.oracle.svm.core.thread.ThreadListenerSupport; +import java.util.Collections; +import java.util.List; + import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.IsolateThread; @@ -43,17 +42,18 @@ import com.oracle.svm.core.NeverInline; import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.core.jfr.JfrFeature; import com.oracle.svm.core.jfr.SubstrateJVM; import com.oracle.svm.core.thread.ThreadListener; +import com.oracle.svm.core.thread.ThreadListenerSupport; import com.oracle.svm.core.thread.ThreadingSupportImpl; import com.oracle.svm.core.thread.ThreadingSupportImpl.RecurringCallbackTimer; import com.oracle.svm.core.thread.VMOperation; import com.oracle.svm.core.thread.VMThreads; import com.oracle.svm.core.util.TimeUtils; -import java.util.Collections; -import java.util.List; - public class JfrRecurringCallbackExecutionSampler extends AbstractJfrExecutionSampler implements ThreadListener { private static final ExecutionSampleCallback CALLBACK = new ExecutionSampleCallback(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitor.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitor.java index 9bbd4a564846..e70d66a9ceb7 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitor.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitor.java @@ -43,7 +43,7 @@ /** * {@link JavaMonitor} is based on the code of {@link java.util.concurrent.locks.ReentrantLock} as - * of JDK 19 (git commit hash: f640fc5a1eb876a657d0de011dcd9b9a42b88eec, JDK tag: jdk-19+30). + * of JDK 21+26. * * Only the relevant methods from the JDK sources have been kept. Some additional Native * Image-specific functionality has been added. @@ -86,7 +86,7 @@ protected JavaMonitorConditionObject getOrCreateCondition(boolean createIfNotExi return existingCondition; } JavaMonitorConditionObject newCondition = new JavaMonitorConditionObject(); - if (!U.compareAndSetObject(this, CONDITION_FIELD_OFFSET, null, newCondition)) { + if (!U.compareAndSetReference(this, CONDITION_FIELD_OFFSET, null, newCondition)) { newCondition = condition; } return newCondition; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitorQueuedSynchronizer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitorQueuedSynchronizer.java index e21372597fe8..db217c7de5ec 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitorQueuedSynchronizer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitorQueuedSynchronizer.java @@ -29,6 +29,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.LockSupport; +import com.oracle.svm.core.NeverInline; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.jfr.JfrTicks; import com.oracle.svm.core.jfr.SubstrateJVM; @@ -39,10 +40,9 @@ /** * {@link JavaMonitorQueuedSynchronizer} is based on the code of - * {@link java.util.concurrent.locks.AbstractQueuedLongSynchronizer} as of JDK 19 (git commit hash: - * f640fc5a1eb876a657d0de011dcd9b9a42b88eec, JDK tag: jdk-19+30). This class could be merged with - * {@link JavaMonitor} but we keep it separate because that way diffing against the JDK sources is - * easier. + * {@link java.util.concurrent.locks.AbstractQueuedLongSynchronizer} as of JDK 21+26. This class + * could be merged with {@link JavaMonitor} but we keep it separate because that way diffing against + * the JDK sources is easier. * * Only the relevant methods from the JDK sources have been kept. Some additional Native * Image-specific functionality has been added. @@ -75,12 +75,12 @@ abstract static class Node { // see AbstractQueuedLongSynchronizer.Node.casPrev(Node, Node) final boolean casPrev(Node c, Node v) { - return weakCompareAndSetReference(this, PREV, c, v); + return U.weakCompareAndSetReference(this, PREV, c, v); } // see AbstractQueuedLongSynchronizer.Node.casNext(Node, Node) final boolean casNext(Node c, Node v) { - return weakCompareAndSetReference(this, NEXT, c, v); + return U.weakCompareAndSetReference(this, NEXT, c, v); } // see AbstractQueuedLongSynchronizer.Node.getAndUnsetStatus(int) @@ -90,7 +90,7 @@ final int getAndUnsetStatus(int v) { // see AbstractQueuedLongSynchronizer.Node.setPrevRelaxed(Node) final void setPrevRelaxed(Node p) { - putReference(this, PREV, p); + U.putReference(this, PREV, p); } // see AbstractQueuedLongSynchronizer.Node.setStatusRelaxed(int) @@ -169,33 +169,52 @@ protected final boolean compareAndSetState(long expect, long update) { // see AbstractQueuedLongSynchronizer.casTail(Node, Node) private boolean casTail(Node c, Node v) { - return compareAndSetReference(this, TAIL, c, v); + return U.compareAndSetReference(this, TAIL, c, v); } // see AbstractQueuedLongSynchronizer.tryInitializeHead() - private void tryInitializeHead() { - Node h = new ExclusiveNode(); - if (compareAndSetReference(this, HEAD, null, h)) { - tail = h; + private Node tryInitializeHead() { + for (Node h = null, t;;) { + if ((t = tail) != null) { + return t; + } else if (head != null) { + Thread.onSpinWait(); + } else { + if (h == null) { + try { + h = allocateExclusiveNode(); + } catch (OutOfMemoryError oome) { + return null; + } + } + if (U.compareAndSetReference(this, HEAD, null, h)) { + return tail = h; + } + } } } // see AbstractQueuedLongSynchronizer.enqueue(Node) - final void enqueue(Node node) { + final void enqueue(ConditionNode node) { if (node != null) { - for (;;) { - Node t = tail; - node.setPrevRelaxed(t); // avoid unnecessary fence - if (t == null) { // initialize - tryInitializeHead(); - } else if (casTail(t, node)) { + boolean unpark = false; + for (Node t;;) { + if ((t = tail) == null && (t = tryInitializeHead()) == null) { + unpark = true; // wake up to spin on OOME + break; + } + node.setPrevRelaxed(t); // avoid unnecessary fence + if (casTail(t, node)) { t.next = node; - if (t.status < 0) { // wake up to clean link - LockSupport.unpark(node.waiter); + if (t.status < 0) { // wake up to clean link + unpark = true; } break; } } + if (unpark) { + LockSupport.unpark(node.waiter); + } } } @@ -298,15 +317,21 @@ final int acquire(Node node, long arg) { return 1; } } - if (node == null) { // allocate; retry before enqueue - node = new ExclusiveNode(); + Node t; + if ((t = tail) == null) { // initialize queue + if (tryInitializeHead() == null) { + return acquireOnOOME(arg); + } + } else if (node == null) { // allocate; retry before enqueue + try { + node = allocateExclusiveNode(); + } catch (OutOfMemoryError oome) { + return acquireOnOOME(arg); + } } else if (pred == null) { // try to enqueue node.waiter = current; - Node t = tail; node.setPrevRelaxed(t); // avoid unnecessary fence - if (t == null) { - tryInitializeHead(); - } else if (!casTail(t, node)) { + if (!casTail(t, node)) { node.setPrevRelaxed(null); // back out } else { t.next = node; @@ -324,6 +349,19 @@ final int acquire(Node node, long arg) { } } + // see AbstractQueuedLongSynchronizer.acquireOnOOME(boolean, long) + private int acquireOnOOME(long arg) { + for (long nanos = 1L;;) { + if (tryAcquire(arg)) { + return 1; + } + U.park(false, nanos); // must use Unsafe park to sleep + if (nanos < 1L << 30) { // max about 1 second + nanos <<= 1; + } + } + } + // see AbstractQueuedLongSynchronizer.cleanQueue() private void cleanQueue() { for (;;) { // restart point @@ -358,6 +396,11 @@ private void cleanQueue() { } } + @NeverInline("Can be removed once GR-51172 is resolved") + private static ExclusiveNode allocateExclusiveNode() { + return new ExclusiveNode(); + } + // see AbstractQueuedLongSynchronizer.cancelAcquire(Node, boolean, boolean) private int cancelAcquire(Node node) { if (node != null) { @@ -400,6 +443,8 @@ public final class JavaMonitorConditionObject { private transient ConditionNode firstWaiter; private transient ConditionNode lastWaiter; + static final long OOME_COND_WAIT_DELAY = 10L * 1000L * 1000L; // 10 ms + // see AbstractQueuedLongSynchronizer.ConditionObject.doSignal(ConditionNode, boolean) @SuppressWarnings("all") private void doSignal(ConditionNode first, boolean all) { @@ -424,8 +469,7 @@ public void signal() { ConditionNode first = firstWaiter; if (!isHeldExclusively()) { throw new IllegalMonitorStateException(); - } - if (first != null) { + } else if (first != null) { doSignal(first, false); } } @@ -435,8 +479,7 @@ public void signalAll() { ConditionNode first = firstWaiter; if (!isHeldExclusively()) { throw new IllegalMonitorStateException(); - } - if (first != null) { + } else if (first != null) { doSignal(first, true); } } @@ -495,6 +538,29 @@ private void unlinkCancelledWaiters(ConditionNode node) { } } + // see AbstractQueuedLongSynchronizer.ConditionObject.newConditionNode() + private ConditionNode newConditionNode() { + long savedState; + if (tryInitializeHead() != null) { + try { + return allocateConditionNode(); + } catch (OutOfMemoryError oome) { + } + } + // fall through if encountered OutOfMemoryError + if (!isHeldExclusively() || !release(savedState = getState())) { + throw new IllegalMonitorStateException(); + } + U.park(false, OOME_COND_WAIT_DELAY); + acquireOnOOME(savedState); + return null; + } + + @NeverInline("Can be removed once GR-51172 is resolved") + private static ConditionNode allocateConditionNode() { + return new ConditionNode(); + } + // see AbstractQueuedLongSynchronizer.ConditionObject.await() @SuppressWarnings("all") public void await(Object obj) throws InterruptedException { @@ -503,7 +569,10 @@ public void await(Object obj) throws InterruptedException { JavaMonitorWaitEvent.emit(startTicks, obj, 0, 0L, false); throw new InterruptedException(); } - ConditionNode node = new ConditionNode(); + ConditionNode node = newConditionNode(); + if (node == null) { + return; + } long savedAcquisitions = enableWait(node); boolean interrupted = false; boolean cancelled = false; @@ -540,7 +609,10 @@ public boolean await(Object obj, long time, TimeUnit unit) throws InterruptedExc JavaMonitorWaitEvent.emit(startTicks, obj, 0, 0L, false); throw new InterruptedException(); } - ConditionNode node = new ConditionNode(); + ConditionNode node = newConditionNode(); + if (node == null) { + return false; + } long savedAcquisitions = enableWait(node); long nanos = (nanosTimeout < 0L) ? 0L : nanosTimeout; long deadline = System.nanoTime() + nanos; @@ -571,21 +643,6 @@ public boolean await(Object obj, long time, TimeUnit unit) throws InterruptedExc } } - @SuppressWarnings("deprecation") - static boolean compareAndSetReference(Object object, long offset, Node expected, Node newValue) { - return U.compareAndSetObject(object, offset, expected, newValue); - } - - @SuppressWarnings("deprecation") - static boolean weakCompareAndSetReference(Object object, long offset, Node expected, Node newValue) { - return U.weakCompareAndSetObject(object, offset, expected, newValue); - } - - @SuppressWarnings("deprecation") - static void putReference(Object object, long offset, Node p) { - U.putObject(object, offset, p); - } - // Unsafe private static final Unsafe U = Unsafe.getUnsafe(); static final long STATE = U.objectFieldOffset(JavaMonitorQueuedSynchronizer.class, "state"); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java index 3d551fcffc6a..339fe9f9687b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java @@ -26,9 +26,8 @@ import java.lang.ref.ReferenceQueue; import java.util.Collections; -import java.util.HashSet; +import java.util.HashMap; import java.util.Map; -import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.LockSupport; @@ -105,10 +104,11 @@ public class MultiThreadedMonitorSupport extends MonitorSupport { * Types that are used to implement the secondary storage for monitor slots cannot themselves * use the additionalMonitors map. That could result in recursive manipulation of the * additionalMonitors map which could lead to table corruptions and double insertion of a - * monitor for the same object. Therefore these types will always get a monitor slot. + * monitor for the same object. Therefore, these types will always get a monitor slot. The + * boolean value specifies if the monitor slot is also needed for subtypes. */ @Platforms(Platform.HOSTED_ONLY.class)// - public static final Set> FORCE_MONITOR_SLOT_TYPES; + public static final Map, Boolean> FORCE_MONITOR_SLOT_TYPES; static { try { @@ -117,16 +117,16 @@ public class MultiThreadedMonitorSupport extends MonitorSupport { * com.oracle.svm.core.monitor.MultiThreadedMonitorSupport#additionalMonitors map uses * java.lang.ref.ReferenceQueue internally. */ - HashSet> monitorTypes = new HashSet<>(); + HashMap, Boolean> monitorTypes = new HashMap<>(); if (JavaVersionUtil.JAVA_SPEC <= 17) { /* * Until JDK 17, the ReferenceQueue uses the inner static class Lock for all its * locking needs. */ - monitorTypes.add(Class.forName("java.lang.ref.ReferenceQueue$Lock")); + monitorTypes.put(Class.forName("java.lang.ref.ReferenceQueue$Lock"), false); } /* The WeakIdentityHashMap also synchronizes on its internal ReferenceQueue field. */ - monitorTypes.add(java.lang.ref.ReferenceQueue.class); + monitorTypes.put(java.lang.ref.ReferenceQueue.class, false); /* * Whenever the monitor allocation in @@ -135,7 +135,7 @@ public class MultiThreadedMonitorSupport extends MonitorSupport { * LinuxPhysicalMemory$PhysicalMemorySupportImpl.sizeFromCGroup() is called which * triggers file IO using the synchronized java.io.FileDescriptor.attach(). */ - monitorTypes.add(java.io.FileDescriptor.class); + monitorTypes.put(java.io.FileDescriptor.class, false); /* * LinuxPhysicalMemory$PhysicalMemorySupportImpl.sizeFromCGroup() also calls @@ -146,7 +146,7 @@ public class MultiThreadedMonitorSupport extends MonitorSupport { * This should also take care of the synchronization in * ReferenceInternals.processPendingReferences(). */ - monitorTypes.add(java.lang.Object.class); + monitorTypes.put(java.lang.Object.class, false); /* * The map access in MultiThreadedMonitorSupport.getOrCreateMonitorFromMap() calls @@ -155,7 +155,7 @@ public class MultiThreadedMonitorSupport extends MonitorSupport { * SplittableRandomAccessors.initialize() which synchronizes on an instance of * SplittableRandomAccessors. */ - monitorTypes.add(Class.forName("com.oracle.svm.core.jdk.SplittableRandomAccessors")); + monitorTypes.put(Class.forName("com.oracle.svm.core.jdk.SplittableRandomAccessors"), false); if (JavaVersionUtil.JAVA_SPEC >= 11) { /* @@ -164,16 +164,24 @@ public class MultiThreadedMonitorSupport extends MonitorSupport { * slow-path-new-instance allocation which in turn can trigger a GC which processes * all the pending cleaners. */ - monitorTypes.add(Class.forName("jdk.internal.ref.PhantomCleanable")); + monitorTypes.put(Class.forName("jdk.internal.ref.PhantomCleanable"), false); } /* * Use as the delegate for locking on {@link Class} (i.e. {@link DynamicHub}) since the * hub itself must be immutable. */ - monitorTypes.add(DynamicHubCompanion.class); + monitorTypes.put(DynamicHubCompanion.class, false); - FORCE_MONITOR_SLOT_TYPES = Collections.unmodifiableSet(monitorTypes); + /* + * When a thread exits, it locks its own thread mutex and changes its state to + * TERMINATED. Without an explict monitor slot, the thread could get parked when + * unlocking its own mutex (because we need to lock the shared monitor map). If the + * thread gets blocked during unlocking, its thread state would change unexpectedly. + */ + monitorTypes.put(Thread.class, true); + + FORCE_MONITOR_SLOT_TYPES = Collections.unmodifiableMap(monitorTypes); } catch (ClassNotFoundException e) { throw VMError.shouldNotReachHere("Error building the list of types that always need a monitor slot.", e); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreads.java index 53dacdd1b157..44fbffc362bf 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreads.java @@ -46,6 +46,7 @@ import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.annotate.Alias; import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.log.Log; import com.oracle.svm.core.jdk.JDK19OrLater; import com.oracle.svm.core.jfr.events.ThreadSleepEventJDK17; import com.oracle.svm.core.snippets.KnownIntrinsics; @@ -245,26 +246,27 @@ public static StackTraceElement[] getStackTrace(boolean filterExceptions, Thread return PlatformThreads.getStackTrace(filterExceptions, thread, callerSP); } - /** If there is an uncaught exception handler, call it. */ public static void dispatchUncaughtException(Thread thread, Throwable throwable) { - /* Get the uncaught exception handler for the Thread, or the default one. */ - UncaughtExceptionHandler handler = thread.getUncaughtExceptionHandler(); - if (handler == null) { - handler = Thread.getDefaultUncaughtExceptionHandler(); - } - if (handler != null) { - try { + try { + /* Get the uncaught exception handler for the Thread, or the default one. */ + UncaughtExceptionHandler handler = thread.getUncaughtExceptionHandler(); + if (handler == null) { + handler = Thread.getDefaultUncaughtExceptionHandler(); + } + + if (handler != null) { handler.uncaughtException(thread, throwable); - } catch (Throwable t) { + } else { /* - * The JavaDoc for {@code Thread.UncaughtExceptionHandler.uncaughtException} says - * the VM ignores any exceptions thrown. + * If no uncaught exception handler is present, then just report the Throwable in + * the same way as it is done by ThreadGroup.uncaughtException(). */ + System.err.print("Exception in thread \"" + thread.getName() + "\" "); + throwable.printStackTrace(System.err); } - } else { - /* If no uncaught exception handler is present, then just report the throwable. */ - System.err.print("Exception in thread \"" + Thread.currentThread().getName() + "\" "); - throwable.printStackTrace(); + } catch (Throwable e) { + /* See JavaThread::exit() in HotSpot. */ + Log.log().newline().string("Exception: ").string(e.getClass().getName()).string(" thrown from the UncaughtExceptionHandler in thread \"").string(thread.getName()).string("\"").newline(); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java index 210b8cf3ff8a..14422d173cfa 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java @@ -25,6 +25,7 @@ package com.oracle.svm.core.thread; import static com.oracle.svm.core.SubstrateOptions.MultiThreaded; +import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE; import static com.oracle.svm.core.thread.JavaThreads.fromTarget; import static com.oracle.svm.core.thread.JavaThreads.isCurrentThreadVirtual; import static com.oracle.svm.core.thread.JavaThreads.isVirtual; @@ -136,6 +137,9 @@ public static PlatformThreads singleton() { /** The platform {@link java.lang.Thread} for the {@link IsolateThread}. */ static final FastThreadLocalObject currentThread = FastThreadLocalFactory.createObject(Thread.class, "PlatformThreads.currentThread").setMaxOffset(FastThreadLocal.BYTE_OFFSET); + /** The number of running non-daemon threads. */ + private static final UninterruptibleUtils.AtomicInteger nonDaemonThreads = new UninterruptibleUtils.AtomicInteger(0); + /** * The {@linkplain JavaThreads#getThreadId thread id} of the {@link Thread#currentThread()}, * which can be a {@linkplain Target_java_lang_Thread#vthread virtual thread} or the @@ -153,12 +157,6 @@ public static PlatformThreads singleton() { */ static final FastThreadLocalObject lockHelper = FastThreadLocalFactory.createObject(Object.class, "PlatformThreads.lockHelper").setMaxOffset(FastThreadLocal.BYTE_OFFSET); - /** - * The number of running non-daemon threads. The initial value accounts for the main thread, - * which is implicitly running when the isolate is created. - */ - private static final UninterruptibleUtils.AtomicInteger nonDaemonThreads = new UninterruptibleUtils.AtomicInteger(1); - /** * Tracks the number of threads that have been started, but are not yet executing Java code. For * a small window of time, threads are still accounted for in this count while they are already @@ -463,7 +461,11 @@ public static boolean ensureCurrentAssigned() { */ public static boolean ensureCurrentAssigned(String name, ThreadGroup group, boolean asDaemon) { if (currentThread.get() == null) { - assignCurrent(fromTarget(new Target_java_lang_Thread(name, group, asDaemon)), true); + boolean wasStartedByCurrentIsolated = VMThreads.wasStartedByCurrentIsolate(CurrentIsolate.getCurrentThread()); + Thread thread = fromTarget(new Target_java_lang_Thread(name, group, asDaemon)); + assignCurrent(thread, wasStartedByCurrentIsolated); + assignThreadToThreadGroup(thread, wasStartedByCurrentIsolated); + ThreadListenerSupport.get().beforeThreadRun(); return true; } return false; @@ -471,32 +473,28 @@ public static boolean ensureCurrentAssigned(String name, ThreadGroup group, bool /** * Assign a {@link Thread} object to the current thread, which must have already been attached - * {@link VMThreads} as an {@link IsolateThread}. - * - * The manuallyStarted parameter is true if this thread was started directly by calling - * {@link #ensureCurrentAssigned(String, ThreadGroup, boolean)}. It is false when the thread is - * started via {@link #doStartThread} and {@link #threadStartRoutine}. + * as an {@link IsolateThread}. */ - static void assignCurrent(Thread thread, boolean manuallyStarted) { + @Uninterruptible(reason = "Ensure consistency of nonDaemonThreads.") + static void assignCurrent(Thread thread, boolean wasStartedByCurrentIsolated) { + if (!wasStartedByCurrentIsolated && thread.isDaemon()) { + /* Correct the value of nonDaemonThreads, now that we have a Thread object. */ + decrementNonDaemonThreadsAndNotify(); + } + /* - * First of all, ensure we are in RUNNABLE state. If !manuallyStarted, we race with the - * thread that launched us to set the status and we could still be in status NEW. + * First of all, ensure we are in RUNNABLE state. If wasStartedByCurrentIsolated, we race + * with the thread that launched us to set the status and we could still be in status NEW. */ setThreadStatus(thread, ThreadStatus.RUNNABLE); - assignCurrent0(thread); + } - /* If the thread was manually started, finish initializing it. */ - if (manuallyStarted) { - final ThreadGroup group = thread.getThreadGroup(); - if (JavaVersionUtil.JAVA_SPEC < 19 && !(VirtualThreads.isSupported() && VirtualThreads.singleton().isVirtual(thread))) { - toTarget(group).addUnstarted(); - toTarget(group).add(thread); - } - - if (!thread.isDaemon()) { - nonDaemonThreads.incrementAndGet(); - } + private static void assignThreadToThreadGroup(Thread thread, boolean wasStartedByCurrentIsolated) { + if (JavaVersionUtil.JAVA_SPEC < 19 && !wasStartedByCurrentIsolated && !(VirtualThreads.isSupported() && VirtualThreads.singleton().isVirtual(thread))) { + ThreadGroup group = thread.getThreadGroup(); + toTarget(group).addUnstarted(); + toTarget(group).add(thread); } } @@ -519,10 +517,15 @@ static void setCurrentThread(Thread carrier, Thread thread) { currentVThreadId.set(JavaThreads.getThreadId(thread)); } - @Uninterruptible(reason = "Called during isolate initialization") - public void initializeIsolate() { + @Uninterruptible(reason = "Called during isolate creation.") + public void assignMainThread() { /* The thread that creates the isolate is considered the "main" thread. */ assignCurrent0(mainThread); + + /* + * Note that we can't call ThreadListenerSupport.beforeThreadRun() because the isolate is + * not fully initialized yet. This is done later on, during isolate initialization. + */ } /** @@ -555,9 +558,17 @@ public static void detachThread(IsolateThread vmThread) { if (thread != null) { toTarget(thread).threadData.detach(); toTarget(thread).isolateThread = WordFactory.nullPointer(); + if (!thread.isDaemon()) { - nonDaemonThreads.decrementAndGet(); + decrementNonDaemonThreads(); } + } else if (!VMThreads.wasStartedByCurrentIsolate(vmThread)) { + /* + * Attached threads are treated like non-daemon threads before they are assigned a + * thread object which defines whether they are a daemon thread (which might never + * happen). + */ + decrementNonDaemonThreads(); } } @@ -692,7 +703,6 @@ private static boolean waitForTearDown() { loopNanos = TimeUtils.doNotLoopTooLong(startNanos, loopNanos, warningNanos, warningMessage); final boolean fatallyTooLong = TimeUtils.maybeFatallyTooLong(startNanos, failureNanos, failureMessage); if (fatallyTooLong) { - /* I took too long to tear down the VM. */ trace.string("Took too long to tear down the VM.").newline(); /* * Debugging tip: Insert a `BreakpointNode.breakpoint()` here to stop in gdb or get @@ -715,21 +725,25 @@ private static boolean isApplicationThread(IsolateThread isolateThread) { @SuppressFBWarnings(value = "NN", justification = "notifyAll is necessary for Java semantics, no shared state needs to be modified beforehand") public static void exit(Thread thread) { ThreadListenerSupport.get().afterThreadRun(); + /* * First call Thread.exit(). This allows waiters on the thread object to observe that a * daemon ThreadGroup is destroyed as well if this thread happens to be the last thread of a * daemon group. */ - toTarget(thread).exit(); - /* - * Then set the threadStatus to TERMINATED. This makes Thread.isAlive() return false and - * allows Thread.join() to complete once we notify all the waiters below. - */ - setThreadStatus(thread, ThreadStatus.TERMINATED); - /* - * And finally, wake up any threads waiting to join this one. - */ + try { + toTarget(thread).exit(); + } catch (Throwable e) { + /* Ignore exception. */ + } + synchronized (thread) { + /* + * Then set the threadStatus to TERMINATED. This makes Thread.isAlive() return false and + * allows Thread.join() to complete once we notify all the waiters below. + */ + setThreadStatus(thread, ThreadStatus.TERMINATED); + /* And finally, wake up any threads waiting to join this one. */ thread.notifyAll(); } } @@ -751,27 +765,67 @@ protected interface ThreadStartData extends PointerBase { } protected T prepareStart(Thread thread, int startDataSize) { - T startData = UnmanagedMemory.malloc(startDataSize); - startData.setIsolate(CurrentIsolate.getIsolate()); - startData.setThreadHandle(ObjectHandles.getGlobal().create(thread)); - if (!thread.isDaemon()) { - nonDaemonThreads.incrementAndGet(); + T startData = WordFactory.nullPointer(); + ObjectHandle threadHandle = WordFactory.zero(); + try { + startData = UnmanagedMemory.malloc(startDataSize); + threadHandle = ObjectHandles.getGlobal().create(thread); + + startData.setIsolate(CurrentIsolate.getIsolate()); + startData.setThreadHandle(threadHandle); + } catch (Throwable e) { + if (startData.isNonNull()) { + UnmanagedMemory.free(startData); + } + if (threadHandle.notEqual(WordFactory.zero())) { + ObjectHandles.getGlobal().destroy(threadHandle); + } + throw e; + } + + /* To ensure that we have consistent thread counts, no exception must be thrown. */ + try { + int numThreads = unattachedStartedThreads.incrementAndGet(); + assert numThreads > 0; + + if (!thread.isDaemon()) { + incrementNonDaemonThreads(); + } + return startData; + } catch (Throwable e) { + throw VMError.shouldNotReachHere("No exception must be thrown after creating the thread start data.", e); } - return startData; } protected void undoPrepareStartOnError(Thread thread, ThreadStartData startData) { if (!thread.isDaemon()) { - undoPrepareNonDaemonStartOnError(); + decrementNonDaemonThreadsAndNotify(); } + + int numThreads = unattachedStartedThreads.decrementAndGet(); + assert numThreads >= 0; + freeStartData(startData); } + @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) + static void incrementNonDaemonThreads() { + int numThreads = nonDaemonThreads.incrementAndGet(); + assert numThreads > 0; + } + + /** A caller must call THREAD_LIST_CONDITION.broadcast() manually. */ + @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) + private static void decrementNonDaemonThreads() { + int numThreads = nonDaemonThreads.decrementAndGet(); + assert numThreads >= 0; + } + @Uninterruptible(reason = "Holding threads lock.") - private static void undoPrepareNonDaemonStartOnError() { + private static void decrementNonDaemonThreadsAndNotify() { VMThreads.lockThreadMutexInNativeCode(); try { - nonDaemonThreads.decrementAndGet(); + decrementNonDaemonThreads(); VMThreads.THREAD_LIST_CONDITION.broadcast(); } finally { VMThreads.THREAD_MUTEX.unlock(); @@ -783,10 +837,8 @@ protected static void freeStartData(ThreadStartData startData) { } void startThread(Thread thread, long stackSize) { - unattachedStartedThreads.incrementAndGet(); boolean started = doStartThread(thread, stackSize); if (!started) { - unattachedStartedThreads.decrementAndGet(); throw new OutOfMemoryError("unable to create native thread: possibly out of memory or process/resource limits reached"); } } @@ -814,7 +866,8 @@ protected static void threadStartRoutine(ObjectHandle threadHandle) { Thread thread = ObjectHandles.getGlobal().get(threadHandle); try { - assignCurrent(thread, false); + assignCurrent(thread, true); + assignThreadToThreadGroup(thread, true); ObjectHandles.getGlobal().destroy(threadHandle); singleton().unattachedStartedThreads.decrementAndGet(); @@ -1036,11 +1089,14 @@ static Thread.State getThreadState(Thread thread) { return Target_jdk_internal_misc_VM.toThreadState(getThreadStatus(thread)); } + @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) public static void setThreadStatus(Thread thread, int threadStatus) { assert !isVirtual(thread); if (JavaVersionUtil.JAVA_SPEC >= 19) { + assert toTarget(thread).holder.threadStatus != ThreadStatus.TERMINATED : "once a thread is marked as terminated, its status must not change"; toTarget(thread).holder.threadStatus = threadStatus; } else { + assert toTarget(thread).threadStatus != ThreadStatus.TERMINATED : "once a thread is marked as terminated, its status must not change"; toTarget(thread).threadStatus = threadStatus; } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/ThreadListener.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/ThreadListener.java index 7db21aad40e8..ce3480130689 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/ThreadListener.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/ThreadListener.java @@ -37,9 +37,18 @@ default void beforeThreadStart(IsolateThread isolateThread, Thread javaThread) { default void beforeThreadRun() { } + /** + * Implementations must not throw any exceptions. Note that this method is called on listeners + * in the reverse order of {@link #beforeThreadRun}. + */ + @Uninterruptible(reason = "Only uninterruptible because we need to prevent stack overflow errors. Implementations may execute interruptible code.") default void afterThreadRun() { } + /** + * Implementations must not throw any exceptions. Note that this method is called on listeners + * in the reverse order of {@link #beforeThreadStart}. + */ @Uninterruptible(reason = "Only uninterruptible code may be executed after Thread.exit.") @SuppressWarnings("unused") default void afterThreadExit(IsolateThread isolateThread, Thread javaThread) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/ThreadListenerSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/ThreadListenerSupport.java index 8104fbb28c66..2dcb36ada104 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/ThreadListenerSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/ThreadListenerSupport.java @@ -34,6 +34,7 @@ import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; +import com.oracle.svm.core.util.VMError; @AutomaticallyRegisteredImageSingleton public class ThreadListenerSupport { @@ -60,27 +61,36 @@ public static ThreadListenerSupport get() { @Uninterruptible(reason = "Force that all listeners are uninterruptible.") public void beforeThreadStart(IsolateThread isolateThread, Thread javaThread) { - for (int i = 0; i < listeners.length; i++) { - listeners[i].beforeThreadStart(isolateThread, javaThread); + for (ThreadListener listener : listeners) { + listener.beforeThreadStart(isolateThread, javaThread); } } public void beforeThreadRun() { - for (int i = 0; i < listeners.length; i++) { - listeners[i].beforeThreadRun(); + for (ThreadListener listener : listeners) { + listener.beforeThreadRun(); } } + @Uninterruptible(reason = "Force that all listeners are uninterruptible.") public void afterThreadRun() { - for (int i = 0; i < listeners.length; i++) { - listeners[i].afterThreadRun(); + for (int i = listeners.length - 1; i >= 0; i--) { + try { + listeners[i].afterThreadRun(); + } catch (Throwable e) { + throw VMError.shouldNotReachHere(e); + } } } @Uninterruptible(reason = "Force that all listeners are uninterruptible.") public void afterThreadExit(IsolateThread isolateThread, Thread javaThread) { for (int i = listeners.length - 1; i >= 0; i--) { - listeners[i].afterThreadExit(isolateThread, javaThread); + try { + listeners[i].afterThreadExit(isolateThread, javaThread); + } catch (Throwable e) { + throw VMError.shouldNotReachHere(e); + } } } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java index 0bc3ce545d3d..769f56983764 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/VMThreads.java @@ -304,6 +304,7 @@ public int attachThread(IsolateThread thread, boolean startedByCurrentIsolate) { return attachThread(thread); } + /* Needs to be protected due to legacy code. */ @Uninterruptible(reason = "Thread is not attached yet.") protected int attachThread(IsolateThread thread) { assert StatusSupport.isStatusCreated(thread) : "Status should be initialized on creation."; @@ -318,6 +319,11 @@ protected int attachThread(IsolateThread thread) { try { nextTL.set(thread, head); head = thread; + + if (!wasStartedByCurrentIsolate(thread)) { + /* Treat attached threads as non-daemon threads until we know better. */ + PlatformThreads.incrementNonDaemonThreads(); + } Heap.getHeap().attachThread(CurrentIsolate.getCurrentThread()); /* On the initial transition to java code this thread should be synchronized. */ ActionOnTransitionToJavaSupport.setSynchronizeCode(thread); 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 ab8704e5b8eb..22b024936b65 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 @@ -248,9 +248,15 @@ public void collectMonitorFieldInfo(BigBang bb, HostedUniverse hUniverse, Set getForceMonitorSlotTypes(BigBang bb) { Set forceMonitorTypes = new HashSet<>(); - for (Class forceMonitorType : MultiThreadedMonitorSupport.FORCE_MONITOR_SLOT_TYPES) { - Optional aType = bb.getMetaAccess().optionalLookupJavaType(forceMonitorType); - aType.ifPresent(forceMonitorTypes::add); + for (var entry : MultiThreadedMonitorSupport.FORCE_MONITOR_SLOT_TYPES.entrySet()) { + Optional optionalType = bb.getMetaAccess().optionalLookupJavaType(entry.getKey()); + if (optionalType.isPresent()) { + AnalysisType aType = optionalType.get(); + forceMonitorTypes.add(aType); + if (entry.getValue()) { + forceMonitorTypes.addAll(aType.getAllSubtypes()); + } + } } return forceMonitorTypes; } From 49971ddafd04b8ed8538c54e3baca024289d692e Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Thu, 25 Jan 2024 20:39:31 +0100 Subject: [PATCH 51/78] Add checks for recently started threads without Thread object. --- .../src/com/oracle/svm/core/jdk/StackTraceUtils.java | 5 ++++- .../com/oracle/svm/core/thread/LoomVirtualThreads.java | 4 ++-- .../src/com/oracle/svm/core/thread/PlatformThreads.java | 8 +++++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java index 3c165606a7a5..d949b1f524a1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java @@ -85,6 +85,9 @@ public static StackTraceElement[] getStackTrace(boolean filterExceptions, Pointe @NeverInline("Potentially starting a stack walk in the caller frame") public static StackTraceElement[] getStackTraceAtSafepoint(Thread thread) { assert VMOperation.isInProgressAtSafepoint(); + if (thread == null) { + return NO_ELEMENTS; + } if (VirtualThreads.isSupported()) { // NOTE: also for platform threads! return VirtualThreads.singleton().getVirtualOrPlatformThreadStackTraceAtSafepoint(thread, readCallerStackPointer()); } @@ -215,7 +218,7 @@ public static ClassLoader latestUserDefinedClassLoader(Pointer startSP) { } public static StackTraceElement[] asyncGetStackTrace(Thread thread) { - if (!thread.isAlive()) { + if (thread == null || !thread.isAlive()) { /* Avoid triggering a safepoint operation below if the thread is not even alive. */ return NO_ELEMENTS; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/LoomVirtualThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/LoomVirtualThreads.java index 6462334e5b43..bc1ecf0ba15d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/LoomVirtualThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/LoomVirtualThreads.java @@ -153,7 +153,7 @@ public StackTraceElement[] getVirtualOrPlatformThreadStackTrace(boolean filterEx if (!isVirtual(thread)) { return getPlatformThreadStackTrace(filterExceptions, thread, callerSP); } - if (thread == Thread.currentThread()) { + if (thread != null && thread == Thread.currentThread()) { return getVirtualThreadStackTrace(filterExceptions, thread, callerSP); } assert !filterExceptions : "exception stack traces can be taken only for the current thread"; @@ -217,7 +217,7 @@ private static StackTraceElement[] asyncMountedGetStackTrace(Target_java_lang_Vi } private static StackTraceElement[] getPlatformThreadStackTrace(boolean filterExceptions, Thread thread, Pointer callerSP) { - if (thread == PlatformThreads.currentThread.get()) { + if (thread != null && thread == PlatformThreads.currentThread.get()) { Pointer startSP = getCarrierSPOrElse(thread, callerSP); return StackTraceUtils.getStackTrace(filterExceptions, startSP, WordFactory.nullPointer()); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java index 61a02663e105..2265960197e0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java @@ -837,7 +837,7 @@ protected static void wakeUpVMConditionWaiters(Thread thread) { static StackTraceElement[] getStackTrace(boolean filterExceptions, Thread thread, Pointer callerSP) { assert !isVirtual(thread); - if (thread == currentThread.get()) { + if (thread != null && thread == currentThread.get()) { return StackTraceUtils.getStackTrace(filterExceptions, callerSP, WordFactory.nullPointer()); } assert !filterExceptions : "exception stack traces can be taken only for the current thread"; @@ -845,7 +845,7 @@ static StackTraceElement[] getStackTrace(boolean filterExceptions, Thread thread } public static StackTraceElement[] getStackTraceAtSafepoint(Thread thread, Pointer callerSP) { - assert !isVirtual(thread); + assert thread != null && !isVirtual(thread); IsolateThread isolateThread = getIsolateThread(thread); if (isolateThread == CurrentIsolate.getCurrentThread()) { /* @@ -1059,7 +1059,9 @@ private static class GetAllStackTracesOperation extends JavaVMOperation { protected void operate() { for (IsolateThread cur = VMThreads.firstThread(); cur.isNonNull(); cur = VMThreads.nextThread(cur)) { Thread thread = PlatformThreads.fromVMThread(cur); - result.put(thread, StackTraceUtils.getStackTraceAtSafepoint(thread)); + if (thread != null) { + result.put(thread, StackTraceUtils.getStackTraceAtSafepoint(thread)); + } } } } From 76378a5a079ce6a33b636c28c2e8cd52f4ab4705 Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Thu, 25 Jan 2024 20:34:33 +0100 Subject: [PATCH 52/78] Substitute synchronized NullPointerException.fillInStackTrace which is not permitted in VMOperation. --- .../svm/core/jdk/JavaLangSubstitutions.java | 13 +++++++ .../oracle/svm/truffle/TruffleFeature.java | 36 ++----------------- 2 files changed, 15 insertions(+), 34 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java index be25cdbe90c8..12180b17c5b3 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java @@ -731,6 +731,19 @@ static void disable() { @TargetClass(java.lang.NullPointerException.class) final class Target_java_lang_NullPointerException { + /** + * {@link NullPointerException} overrides {@link Throwable#fillInStackTrace()} with a + * {@code synchronized} method which is not permitted in a {@code VMOperation}. + */ + @Substitute + @TargetElement(onlyWith = JDK17OrLater.class) + @Platforms(InternalPlatform.NATIVE_ONLY.class) + Target_java_lang_Throwable fillInStackTrace() { + Target_java_lang_Throwable t = SubstrateUtil.cast(this, Target_java_lang_Throwable.class); + t.stackTrace = JavaThreads.getStackTrace(true, Thread.currentThread()); + return t; + } + @Substitute @TargetElement(onlyWith = JDK17OrLater.class) @SuppressWarnings("static-method") diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java index 0cae79e8d896..bffe68346e57 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java @@ -224,7 +224,6 @@ public boolean getAsBoolean() { private final Set blocklistMethods; private final Set tempTargetAllowlistMethods; - private final Set implementationOnlyBlocklist; private final Set warnMethods; private final Set> neverPartOfCompilationViolations; Set runtimeCompiledMethods; @@ -232,7 +231,6 @@ public boolean getAsBoolean() { public TruffleFeature() { blocklistMethods = new HashSet<>(); tempTargetAllowlistMethods = new HashSet<>(); - implementationOnlyBlocklist = new HashSet<>(); warnMethods = new HashSet<>(); neverPartOfCompilationViolations = ConcurrentHashMap.newKeySet(); } @@ -550,16 +548,6 @@ boolean isBlocklisted(ResolvedJavaMethod method) { return blocklistMethods.contains(method); } - boolean isTargetBlocklisted(ResolvedJavaMethod target, ResolvedJavaMethod implementation) { - boolean blocklisted = !((AnalysisMethod) target).allowRuntimeCompilation() || blocklistMethods.contains(target); - - if (blocklisted && !implementation.equals(target) && implementationOnlyBlocklist.contains(target)) { - blocklisted = isBlocklisted(implementation); - } - - return blocklisted; - } - @SuppressWarnings("deprecation") private boolean deoptimizeOnException(ResolvedJavaMethod method) { if (method == null) { @@ -579,9 +567,7 @@ private void initializeMethodBlocklist(MetaAccessProvider metaAccess, FeatureAcc blocklistMethod(metaAccess, String.class, "indexOf", int.class, int.class); blocklistMethod(metaAccess, String.class, "indexOf", String.class); blocklistMethod(metaAccess, String.class, "indexOf", String.class, int.class); - blocklistMethod(metaAccess, Throwable.class, "fillInStackTrace"); - // Implementations which don't call Throwable.fillInStackTrace are allowed - implementationOnlyBlocklist(metaAccess, Throwable.class, "fillInStackTrace"); + blocklistMethod(metaAccess, Throwable.class, "fillInStackTrace", int.class); blocklistMethod(metaAccess, Throwable.class, "initCause", Throwable.class); blocklistMethod(metaAccess, Throwable.class, "addSuppressed", Throwable.class); blocklistMethod(metaAccess, System.class, "getProperty", String.class); @@ -744,24 +730,6 @@ private void removeFromBlocklist(MetaAccessProvider metaAccess, Class clazz, } } - /** - * Methods on this list are allowed to be runtime compiled as long as the method being runtime - * compiled (i.e., the implementation method & not the target) is not on blocklist. - */ - private void implementationOnlyBlocklist(MetaAccessProvider metaAccess, Class clazz, String name, Class... parameterTypes) { - try { - Executable method; - if ("".equals(name)) { - method = clazz.getDeclaredConstructor(parameterTypes); - } else { - method = clazz.getDeclaredMethod(name, parameterTypes); - } - implementationOnlyBlocklist.add(metaAccess.lookupJavaMethod(method)); - } catch (NoSuchMethodException ex) { - throw VMError.shouldNotReachHere(ex); - } - } - private void warnAllMethods(MetaAccessProvider metaAccess, Class clazz) { for (Executable m : clazz.getDeclaredMethods()) { /* @@ -792,7 +760,7 @@ public void beforeCompilation(BeforeCompilationAccess config) { // Determine blocklist violations if (!runtimeCompilationForbidden(candidate.getImplementationMethod())) { - if (isBlocklisted(candidate.getImplementationMethod()) || isTargetBlocklisted(candidate.getTargetMethod(), candidate.getImplementationMethod())) { + if (isBlocklisted(candidate.getImplementationMethod())) { boolean tempAllow = !candidate.getTargetMethod().equals(candidate.getImplementationMethod()) && tempTargetAllowlistMethods.contains(candidate.getTargetMethod()) && !isBlocklisted(candidate.getImplementationMethod()); From c2f7326e0b40e050d6ad149973b3c8b3b7558306 Mon Sep 17 00:00:00 2001 From: Tom Shull Date: Fri, 2 Feb 2024 20:11:12 +0100 Subject: [PATCH 53/78] guard against deleting canonicalizer replacement. (cherry picked from commit 49d71b7982ae3959f12a7b25e03b08cb5194dfd6) --- .../phases/common/CanonicalizerPhase.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java index ae865f66af86..cc15de67787c 100644 --- a/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java +++ b/compiler/src/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java @@ -646,10 +646,19 @@ private static boolean performReplacement(final Node node, Node newCanonical, To node.replaceAtUsages(null); GraphUtil.unlinkAndKillExceptionEdge(withException); GraphUtil.killWithUnusedFloatingInputs(withException); - } else if (canonical instanceof FloatingNode) { + } else if (canonical instanceof FloatingNode floating) { // case 4 - withException.killExceptionEdge(); - graph.replaceSplitWithFloating(withException, (FloatingNode) canonical, withException.next()); + /* + * In corner cases it is possible for the killing of the exception edge to + * trigger the killing of the replacement node. We therefore wait to kill + * the exception edge until after replacing the WithException node. + */ + var exceptionEdge = withException.exceptionEdge(); + withException.setExceptionEdge(null); + graph.replaceSplitWithFloating(withException, floating, withException.next()); + if (exceptionEdge != null) { + GraphUtil.killCFG(exceptionEdge); + } } else { assert canonical instanceof FixedNode; if (canonical.predecessor() == null) { From 203e6f0a11f5de4ff71449056b64468f949607d4 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Fri, 2 Feb 2024 18:09:28 +0100 Subject: [PATCH 54/78] regression test (cherry picked from commit c8987ca7baeafda45f4f638cee8703f8ca5d4d67) --- .../HotSpotReflectionGetCallerClassTest.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 compiler/src/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/HotSpotReflectionGetCallerClassTest.java diff --git a/compiler/src/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/HotSpotReflectionGetCallerClassTest.java b/compiler/src/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/HotSpotReflectionGetCallerClassTest.java new file mode 100644 index 000000000000..34edc66d86e0 --- /dev/null +++ b/compiler/src/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/HotSpotReflectionGetCallerClassTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.graal.compiler.replacements.test; + +import org.junit.Test; + +public class HotSpotReflectionGetCallerClassTest extends MethodSubstitutionTest { + @Test + public void regressionTest() throws Exception { + test("getInstance"); + } + + // Replicates the code pattern from sun.net.ext.ExtendedSocketOptions.getInstance + // while avoiding a dependency on that class. + public static HotSpotReflectionGetCallerClassTest getInstance() { + HotSpotReflectionGetCallerClassTest ext = instance; + if (ext != null) { + return ext; + } + try { + Class.forName("jdk.graal.compiler.replacements.test.HotSpotReflectionGetCallerClassTest"); + ext = instance; + } catch (ClassNotFoundException e) { + synchronized (HotSpotReflectionGetCallerClassTest.class) { + ext = instance; + if (ext != null) { + return ext; + } + ext = instance = new HotSpotReflectionGetCallerClassTest(); + } + } + return ext; + } + + private static HotSpotReflectionGetCallerClassTest instance; +} From c8695a895965f8b427db6bcfceb01d335e5631ae Mon Sep 17 00:00:00 2001 From: Hamza Ghaissi Date: Tue, 6 Feb 2024 10:29:18 +0100 Subject: [PATCH 55/78] Adapt fix to 23.0 --- .../test/HotSpotReflectionGetCallerClassTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/HotSpotReflectionGetCallerClassTest.java b/compiler/src/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/HotSpotReflectionGetCallerClassTest.java index 34edc66d86e0..3f0c393744d6 100644 --- a/compiler/src/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/HotSpotReflectionGetCallerClassTest.java +++ b/compiler/src/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/HotSpotReflectionGetCallerClassTest.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.graal.compiler.replacements.test; +package org.graalvm.compiler.replacements.test; import org.junit.Test; @@ -40,7 +40,7 @@ public static HotSpotReflectionGetCallerClassTest getInstance() { return ext; } try { - Class.forName("jdk.graal.compiler.replacements.test.HotSpotReflectionGetCallerClassTest"); + Class.forName("org.graalvm.compiler.replacements.test.HotSpotReflectionGetCallerClassTest"); ext = instance; } catch (ClassNotFoundException e) { synchronized (HotSpotReflectionGetCallerClassTest.class) { From f23928a6130b3c78810b046c534de37c0da61094 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 7 Feb 2024 09:33:00 +0000 Subject: [PATCH 56/78] [GR-51110] Could not load library @rpath/libjsig.dylib for nodejs native standalone on GraalVM for JDK17. PullRequest: js/3029 --- vm/mx.vm/suite.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index b8b34ec7d447..23304a188343 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -39,7 +39,7 @@ "name": "graal-nodejs", "subdir": True, "dynamic": True, - "version": "0eb794c0d3286f72a158b512d67d5fb6788e2ea1", + "version": "4cef57015938f2c58666df5d199221ec1f54edd7", "urls" : [ {"url" : "https://github.com/graalvm/graaljs.git", "kind" : "git"}, {"url": "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind": "binary"}, @@ -49,7 +49,7 @@ "name": "graal-js", "subdir": True, "dynamic": True, - "version": "0eb794c0d3286f72a158b512d67d5fb6788e2ea1", + "version": "4cef57015938f2c58666df5d199221ec1f54edd7", "urls": [ {"url": "https://github.com/graalvm/graaljs.git", "kind" : "git"}, {"url": "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind": "binary"}, From 8e91e9e056af86c7523b7589526806a28af2987d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C3=B6=20Barany?= Date: Fri, 15 Sep 2023 15:49:10 +0200 Subject: [PATCH 57/78] Don't try to incorrectly move virtual state inputs out of loops (cherry picked from commit 009e43ca25c7201f054bcc4e47a080107adae155) --- .../phases/schedule/SchedulePhase.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java b/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java index 967947d3c6d8..401deb18b098 100644 --- a/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java +++ b/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java @@ -578,7 +578,7 @@ protected void calcLatestBlock(HIRBlock earliestBlock, SchedulingStrategy strate */ continue; } - latestBlock = calcBlockForUsage(currentNode, usage, latestBlock, currentNodeMap, moveInputsIntoDominator); + latestBlock = calcLatestBlockForUsage(currentNode, usage, earliestBlock, latestBlock, currentNodeMap, moveInputsIntoDominator); } assert latestBlock != null : currentNode; @@ -678,9 +678,10 @@ private static Node getUnproxifiedUncompressed(Node node) { return result; } - private static HIRBlock calcBlockForUsage(Node node, Node usage, HIRBlock startBlock, NodeMap currentNodeMap, NodeBitMap moveInputsToDominator) { + private static HIRBlock calcLatestBlockForUsage(Node node, Node usage, HIRBlock earliestBlock, HIRBlock initialLatestBlock, NodeMap currentNodeMap, + NodeBitMap moveInputsToDominator) { assert !(node instanceof PhiNode); - HIRBlock currentBlock = startBlock; + HIRBlock currentBlock = initialLatestBlock; if (usage instanceof PhiNode) { // An input to a PhiNode is used at the end of the predecessor block that // corresponds to the PhiNode input. One PhiNode can use an input multiple times. @@ -702,7 +703,16 @@ private static HIRBlock calcBlockForUsage(Node node, Node usage, HIRBlock startB } if (!(node instanceof VirtualState) && !moveInputsToDominator.isNew(usage) && moveInputsToDominator.isMarked(usage)) { - otherBlock = otherBlock.getDominator(); + /* + * The usage is marked as forcing its inputs into the dominator. Respect that if + * we can, but the dominator might not be a legal position for the node. This is + * the case for loop-variant floating nodes between a loop phi and a virtual + * state on the loop begin. + */ + HIRBlock dominator = otherBlock.getDominator(); + if (AbstractControlFlowGraph.dominates(earliestBlock, dominator)) { + otherBlock = dominator; + } GraalError.guarantee(otherBlock != null, "Dominators need to be computed in the CFG"); } From 744425ba380f60b0b565c7ebedf05accab6aa80d Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Fri, 11 Aug 2023 13:10:35 +0200 Subject: [PATCH 58/78] graph order: run some form of schedule verification in all tiers if possible (cherry picked from commit 88d24368239407260a0e316e2a8f63783f8833ec) --- .../graalvm/compiler/phases/util/GraphOrder.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/GraphOrder.java b/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/GraphOrder.java index 5dd05724f255..ffe9c02843e0 100644 --- a/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/GraphOrder.java +++ b/compiler/src/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/GraphOrder.java @@ -29,6 +29,7 @@ import org.graalvm.collections.EconomicMap; import org.graalvm.collections.Equivalence; +import org.graalvm.compiler.debug.Assertions; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.GraalGraphError; @@ -150,12 +151,24 @@ private static void visitForward(ArrayList nodes, NodeBitMap visited, Node } } + public static boolean assertSchedulableGraph(StructuredGraph g) { + assert GraphOrder.assertNonCyclicGraph(g); + assert g.getGuardsStage() == GuardsStage.AFTER_FSA || GraphOrder.assertScheduleableBeforeFSA(g); + if (g.getGuardsStage() == GuardsStage.AFTER_FSA && Assertions.detailedAssertionsEnabled(g.getOptions())) { + // we still want to do a memory verification of the schedule even if we can + // no longer use assertSchedulableGraph after the floating reads phase + SchedulePhase.runWithoutContextOptimizations(g, SchedulePhase.SchedulingStrategy.LATEST_OUT_OF_LOOPS, true); + } + assert g.verify(); + return true; + } + /** * This method schedules the graph and makes sure that, for every node, all inputs are available * at the position where it is scheduled. This is a very expensive assertion. */ @SuppressWarnings("try") - public static boolean assertSchedulableGraph(final StructuredGraph graph) { + private static boolean assertScheduleableBeforeFSA(final StructuredGraph graph) { assert graph.getGuardsStage() != GuardsStage.AFTER_FSA : "Cannot use the BlockIteratorClosure after FrameState Assignment, HIR Loop Data Structures are no longer valid."; try (DebugContext.Scope s = graph.getDebug().scope("AssertSchedulableGraph")) { SchedulePhase.runWithoutContextOptimizations(graph, getSchedulingPolicy(graph), true); From 93d21e0e8ebbe98e606fe47b0d16c10d78f14d90 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Thu, 1 Feb 2024 19:33:59 +0100 Subject: [PATCH 59/78] Properly catch exceptions during shutdown. (cherry picked from commit 2b20f124e84e6f919983f9eb183af2ffe1750e8b) --- .../com/oracle/svm/core/JavaMainWrapper.java | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java index b792387c3483..c8240293ef87 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java @@ -71,6 +71,7 @@ import com.oracle.svm.core.log.Log; import com.oracle.svm.core.thread.JavaThreads; import com.oracle.svm.core.thread.PlatformThreads; +import com.oracle.svm.core.thread.ThreadingSupportImpl; import com.oracle.svm.core.thread.VMThreads; import com.oracle.svm.core.util.CounterSupport; import com.oracle.svm.core.thread.VMThreads.OSThreadHandle; @@ -189,22 +190,32 @@ private static int runCore0() { @Uninterruptible(reason = "The caller initialized the thread state, so the callees do not need to be uninterruptible.", calleeMustBe = false) private static void runShutdown() { + ThreadingSupportImpl.pauseRecurringCallback("Recurring callbacks can't be executed during shutdown."); runShutdown0(); } private static void runShutdown0() { - PlatformThreads.ensureCurrentAssigned("DestroyJavaVM", null, false); + try { + PlatformThreads.ensureCurrentAssigned("DestroyJavaVM", null, false); + } catch (Throwable e) { + Log.log().string("PlatformThreads.ensureCurrentAssigned() failed during shutdown: ").exception(e).newline(); + return; + } - // Shutdown sequence: First wait for all non-daemon threads to exit. + /* Wait for all non-daemon threads to exit. */ PlatformThreads.singleton().joinAllNonDaemons(); - /* - * Run shutdown hooks (both our own hooks and application-registered hooks. Note that this - * can start new non-daemon threads. We are not responsible to wait until they have exited. - */ - RuntimeSupport.getRuntimeSupport().shutdown(); - - CounterSupport.singleton().logValues(Log.log()); + try { + /* + * Run shutdown hooks (both our own hooks and application-registered hooks). Note that + * this can start new non-daemon threads. We are not responsible to wait until they have + * exited. + */ + RuntimeSupport.getRuntimeSupport().shutdown(); + CounterSupport.singleton().logValues(Log.log()); + } catch (Throwable e) { + Log.log().string("Exception occurred while executing shutdown hooks: ").exception(e).newline(); + } } @Uninterruptible(reason = "Thread state not set up yet.") @@ -223,6 +234,7 @@ private static int doRun(int argc, CCharPointerPointer argv) { try { CPUFeatureAccess cpuFeatureAccess = ImageSingletons.lookup(CPUFeatureAccess.class); cpuFeatureAccess.verifyHostSupportsArchitectureEarlyOrExit(); + // Create the isolate and attach the current C thread as the main Java thread. EnterCreateIsolateWithCArgumentsPrologue.enter(argc, argv); assert !VMThreads.wasStartedByCurrentIsolate(CurrentIsolate.getCurrentThread()) : "re-attach would cause issues otherwise"; From 60f34f8ecd4d3d999d677fb482d4b54bfd9aea3f Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Fri, 15 Dec 2023 12:48:39 -0800 Subject: [PATCH 60/78] Constant fold reflection lookups in sun.nio.ch.Reflect (cherry picked from commit 410a192e2882b90151e0e853c376d3333106441c) --- .../oracle/svm/hosted/snippets/ReflectionPlugins.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/ReflectionPlugins.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/ReflectionPlugins.java index ce27e6b2375a..c7ca53b2704f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/ReflectionPlugins.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/ReflectionPlugins.java @@ -261,6 +261,15 @@ private void registerClassPlugins(InvocationPlugins plugins) { "getField", "getMethod", "getConstructor", "getDeclaredField", "getDeclaredMethod", "getDeclaredConstructor"); + /* + * The class sun.nio.ch.Reflect contains various reflection lookup methods that then pass + * parameters through to the actual methods in java.lang.Class. But they do additional + * things like calling setAccessible(true), so method inlining before analysis cannot + * constant-fold them automatically. So we register them manually here for folding too. + */ + registerFoldInvocationPlugins(plugins, ReflectionUtil.lookupClass(false, "sun.nio.ch.Reflect"), + "lookupConstructor", "lookupMethod", "lookupField"); + if (MissingReflectionRegistrationUtils.throwMissingRegistrationErrors() && reason.duringAnalysis() && reason != ParsingReason.JITCompilation) { registerBulkInvocationPlugin(plugins, Class.class, "getClasses", RuntimeReflection::registerAllClasses); registerBulkInvocationPlugin(plugins, Class.class, "getDeclaredClasses", RuntimeReflection::registerAllDeclaredClasses); From a26dc5c9b0df798eabd6ea097d890ce252ea1252 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Fri, 9 Feb 2024 11:16:47 +0100 Subject: [PATCH 61/78] Fix MacOS-specific perf data issue. (cherry picked from commit d8a4b9659c21a2e9052d9ae0077e4b035a1d7905) --- .../src/com/oracle/svm/core/posix/headers/Fcntl.java | 2 +- .../com.oracle.svm.native.libchelper/src/varargs_helper.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Fcntl.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Fcntl.java index 185b9a2b9c76..4c06021f338e 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Fcntl.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Fcntl.java @@ -65,7 +65,7 @@ public static class NoTransitions { @CFunction(value = "openSII", transition = NO_TRANSITION) public static native int open(CCharPointer pathname, int flags, int mode); - @CFunction(transition = NO_TRANSITION) + @CFunction(value = "openatISII", transition = NO_TRANSITION) public static native int openat(int dirfd, @CConst CCharPointer pathname, int flags, int mode); @CFunction(transition = NO_TRANSITION) diff --git a/substratevm/src/com.oracle.svm.native.libchelper/src/varargs_helper.c b/substratevm/src/com.oracle.svm.native.libchelper/src/varargs_helper.c index fc4048fb76f2..68db4f8a7692 100644 --- a/substratevm/src/com.oracle.svm.native.libchelper/src/varargs_helper.c +++ b/substratevm/src/com.oracle.svm.native.libchelper/src/varargs_helper.c @@ -48,4 +48,9 @@ int openSII(const char *pathname, int flags, int mode) return open(pathname, flags, mode); } +int openatISII(int dirfd, const char *pathname, int flags, int mode) +{ + return openat(dirfd, pathname, flags, mode); +} + #endif From 43d6c00147e2aad50fe68cb3504fcb68bcf0fafc Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Wed, 7 Feb 2024 17:13:15 +0100 Subject: [PATCH 62/78] Fix a deadlock in IsolateAwareTruffleCompiler.tearDownIsolateOnShutdown. (cherry picked from commit 162adee0de93bd81edcbc9f98102cc6d3b5fd850) --- .../oracle/svm/core/jdk/RuntimeSupport.java | 2 +- .../isolated/IsolateAwareTruffleCompiler.java | 24 +++++++++++++------ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RuntimeSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RuntimeSupport.java index 10a81b3ffc48..75ad7691793f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RuntimeSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RuntimeSupport.java @@ -126,7 +126,7 @@ public static void executeInitializationHooks() { /** * Adds a hook which will execute during isolate tear-down. Note it is possible for the - * {@link #tearDownHooks} to called without the {@link #initializationHooks} executing first. + * {@link #tearDownHooks} to be called without the {@link #initializationHooks} executing first. */ public void addTearDownHook(Hook tearDownHook) { addHook(tearDownHooks, tearDownHook); diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolateAwareTruffleCompiler.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolateAwareTruffleCompiler.java index 1ab4523c7c09..2ce848f2224e 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolateAwareTruffleCompiler.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolateAwareTruffleCompiler.java @@ -151,10 +151,18 @@ protected CompilerIsolateThread beforeCompilation() { Isolate isolate = getSharedIsolate(); if (isolate.isNull()) { if (sharedIsolate.compareAndSet(WordFactory.nullPointer(), (Isolate) ISOLATE_INITIALIZING)) { - CompilerIsolateThread thread = IsolatedGraalUtils.createCompilationIsolate(); - Runtime.getRuntime().addShutdownHook(new Thread(this::sharedIsolateShutdown)); - sharedIsolate.set(Isolates.getIsolate(thread)); - return thread; // (already attached) + try { + /* Adding the shutdown hook may fail if a shutdown is already in progress. */ + Runtime.getRuntime().addShutdownHook(new Thread(this::sharedIsolateShutdown)); + CompilerIsolateThread thread = IsolatedGraalUtils.createCompilationIsolate(); + sharedIsolate.set(Isolates.getIsolate(thread)); + return thread; // (already attached) + } catch (Throwable e) { + /* Reset the value so that the teardown hook doesn't hang. */ + assert sharedIsolate.get().equal(ISOLATE_INITIALIZING); + sharedIsolate.set(WordFactory.nullPointer()); + throw e; + } } isolate = getSharedIsolate(); assert isolate.isNonNull(); @@ -173,9 +181,11 @@ private Isolate getSharedIsolate() { private void sharedIsolateShutdown() { Isolate isolate = getSharedIsolate(); - CompilerIsolateThread context = (CompilerIsolateThread) Isolates.attachCurrentThread(isolate); - compilerIsolateThreadShutdown(context); - Isolates.detachThread(context); + if (isolate.isNonNull()) { + CompilerIsolateThread context = (CompilerIsolateThread) Isolates.attachCurrentThread(isolate); + compilerIsolateThreadShutdown(context); + Isolates.detachThread(context); + } } @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) From 7753d83d55a5b0f11ceebe4ad3e0b3582d89a433 Mon Sep 17 00:00:00 2001 From: Anas El korchi Date: Mon, 12 Feb 2024 08:03:26 +0100 Subject: [PATCH 63/78] Remove GU catalogs for CE --- vm/ci/ci_includes/vm.jsonnet | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/ci/ci_includes/vm.jsonnet b/vm/ci/ci_includes/vm.jsonnet index 230d2e4aaa7e..9f1c119b7bdd 100644 --- a/vm/ci/ci_includes/vm.jsonnet +++ b/vm/ci/ci_includes/vm.jsonnet @@ -34,7 +34,7 @@ local graal_common = import '../../../ci/ci_common/common.jsonnet'; short_name:: 'ce', setup+: [ ['set-export', 'VM_ENV', 'ce'], - ['set-export', 'RELEASE_CATALOG', 'https://www.graalvm.org/component-catalog/v2/graal-updater-component-catalog-java${BASE_JDK_SHORT_VERSION}.properties|{ee=GraalVM Enterprise Edition}rest://gds.oracle.com/api/20220101/'], + ['set-export', 'RELEASE_CATALOG', '{ee=GraalVM Enterprise Edition}rest://gds.oracle.com/api/20220101/'], ['set-export', 'RELEASE_PRODUCT_ID', 'D53FAE8052773FFAE0530F15000AA6C6'], ['set-export', 'SNAPSHOT_CATALOG', ['mx', 'urlrewrite', 'http://www.graalvm.org/catalog/ce/java${BASE_JDK_SHORT_VERSION}']], ['cd', 'vm'], From bd4f83223839503207671db15424155a8fee875d Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Mon, 5 Feb 2024 16:48:17 +0100 Subject: [PATCH 64/78] ensure CompilationResult.methods does not contain duplicates (cherry picked from commit 727dc2362dafb5a20186153772cc0badcc8fc051) --- .../compiler/code/CompilationResult.java | 39 +++++++------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/compiler/src/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java b/compiler/src/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java index 30d94a7b3781..4ca8f3a6e6eb 100644 --- a/compiler/src/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java +++ b/compiler/src/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java @@ -257,7 +257,7 @@ public String toString() { private Assumption[] assumptions; /** - * The list of the methods whose bytecodes were used as input to the compilation. If + * The set of the methods whose bytecodes were used as input to the compilation. If * {@code null}, then the compilation did not record method dependencies. Otherwise, the first * element of this array is the root method of the compilation. */ @@ -361,45 +361,36 @@ public Assumption[] getAssumptions() { } /** - * Sets the methods whose bytecodes were used as input to the compilation. + * Records the set of methods whose bytecodes were used as input to the compilation. * * @param rootMethod the root method of the compilation - * @param inlinedMethods the methods inlined during compilation + * @param inlinedMethods the methods inlined during compilation (may contain duplicates) */ public void setMethods(ResolvedJavaMethod rootMethod, Collection inlinedMethods) { checkOpen(); assert rootMethod != null; assert inlinedMethods != null; - if (inlinedMethods.contains(rootMethod)) { - methods = inlinedMethods.toArray(new ResolvedJavaMethod[inlinedMethods.size()]); - for (int i = 0; i < methods.length; i++) { - if (methods[i].equals(rootMethod)) { - if (i != 0) { - ResolvedJavaMethod tmp = methods[0]; - methods[0] = methods[i]; - methods[i] = tmp; - } - break; - } - } - } else { - methods = new ResolvedJavaMethod[1 + inlinedMethods.size()]; - methods[0] = rootMethod; - int i = 1; - for (ResolvedJavaMethod m : inlinedMethods) { - methods[i++] = m; - } + + EconomicSet methodSet = EconomicSet.create(inlinedMethods.size()); + methodSet.addAll(inlinedMethods); + methodSet.remove(rootMethod); + methods = new ResolvedJavaMethod[1 + methodSet.size()]; + methods[0] = rootMethod; + int i = 1; + for (ResolvedJavaMethod m : methodSet) { + methods[i++] = m; } } /** - * Gets the methods whose bytecodes were used as input to the compilation. + * Gets the set of methods whose bytecodes were used as input to the compilation. * * The caller must not modify the contents of the returned array. * * @return {@code null} if the compilation did not record method dependencies otherwise the * methods whose bytecodes were used as input to the compilation with the first element - * being the root method of the compilation + * being the root method of the compilation. The entries in a non-null returned array + * are guaranteed to be unique. */ public ResolvedJavaMethod[] getMethods() { return methods; From 54b29bf1dc0f3ca1c8b42d2e09e4402f9d8096c0 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Thu, 8 Feb 2024 13:50:00 +0100 Subject: [PATCH 65/78] Workaround for a build-time crash. (cherry picked from commit f9522b368727206e7e8c8e77638f0a6f867655c2) --- .../com/oracle/svm/core/posix/thread/PosixPlatformThreads.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixPlatformThreads.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixPlatformThreads.java index 20446e1c9e4e..de01408eecb1 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixPlatformThreads.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixPlatformThreads.java @@ -41,6 +41,7 @@ import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; +import com.oracle.svm.core.NeverInline; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.annotate.Inject; import com.oracle.svm.core.annotate.RecomputeFieldValue; @@ -122,6 +123,7 @@ protected boolean doStartThread(Thread thread, long stackSize) { } /** Starts a thread to the point so that it is executing. */ + @NeverInline("Workaround for GR-51925 - prevent that reads float from this method into the caller.") private boolean doStartThread0(Thread thread, pthread_attr_t attributes) { ThreadStartData startData = prepareStart(thread, SizeOf.get(ThreadStartData.class)); try { From 45b881bc7bd83bba3a0c05a6b0df79f849067d02 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 16 Feb 2024 08:28:25 +0000 Subject: [PATCH 66/78] update to jvmci-23.0-b31 --- common.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common.json b/common.json index 46af265c8f3d..e4218eb0bd04 100644 --- a/common.json +++ b/common.json @@ -14,9 +14,9 @@ "labsjdk-ce-17": {"name": "labsjdk", "version": "ce-17.0.9+9-jvmci-23.0-b22", "platformspecific": true }, "labsjdk-ce-17Debug": {"name": "labsjdk", "version": "ce-17.0.9+9-jvmci-23.0-b22-debug", "platformspecific": true }, "labsjdk-ce-17-llvm": {"name": "labsjdk", "version": "ce-17.0.9+9-jvmci-23.0-b22-sulong", "platformspecific": true }, - "labsjdk-ee-17": {"name": "labsjdk", "version": "ee-17.0.11+3-jvmci-23.0-b30", "platformspecific": true }, - "labsjdk-ee-17Debug": {"name": "labsjdk", "version": "ee-17.0.11+3-jvmci-23.0-b30-debug", "platformspecific": true }, - "labsjdk-ee-17-llvm": {"name": "labsjdk", "version": "ee-17.0.11+3-jvmci-23.0-b30-sulong", "platformspecific": true }, + "labsjdk-ee-17": {"name": "labsjdk", "version": "ee-17.0.11+4-jvmci-23.0-b31", "platformspecific": true }, + "labsjdk-ee-17Debug": {"name": "labsjdk", "version": "ee-17.0.11+4-jvmci-23.0-b31-debug", "platformspecific": true }, + "labsjdk-ee-17-llvm": {"name": "labsjdk", "version": "ee-17.0.11+4-jvmci-23.0-b31-sulong", "platformspecific": true }, "oraclejdk19": {"name": "jpg-jdk", "version": "19", "build_id": "26", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, "labsjdk-ce-19": {"name": "labsjdk", "version": "ce-19.0.1+10-jvmci-23.0-b04", "platformspecific": true }, From 1b0ea0d68aafe95d6f0946047fb25d3b195e443e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C3=B6=20Barany?= Date: Fri, 2 Feb 2024 17:29:46 +0100 Subject: [PATCH 67/78] Don't optimize away Narrow in comparisons with mixed signedness (cherry picked from commit 911be471b727e50ecd93326d686f4c4eaf833d1c) --- .../nodes/test/NarrowPreservesOrderTest.java | 8 ++++---- .../compiler/nodes/calc/NarrowNode.java | 18 +++++++++++++++--- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/NarrowPreservesOrderTest.java b/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/NarrowPreservesOrderTest.java index c471fcc18c1c..dd941f7f22cc 100644 --- a/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/NarrowPreservesOrderTest.java +++ b/compiler/src/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/NarrowPreservesOrderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -97,7 +97,7 @@ public void testByte() { testPreserveOrder(forConstantInt(NumUtil.maxValueUnsigned(8)), 8, LT, false); testPreserveOrder(forConstantInt(NumUtil.maxValueUnsigned(8)), 8, BT, true); testPreserveOrder(signExtend(StampFactory.forKind(JavaKind.Byte), 32), 8, LT, true); - testPreserveOrder(signExtend(StampFactory.forKind(JavaKind.Byte), 32), 8, BT, true); + testPreserveOrder(signExtend(StampFactory.forKind(JavaKind.Byte), 32), 8, BT, false); testPreserveOrder(zeroExtend(StampFactory.forUnsignedInteger(8), 32), 8, LT, false); testPreserveOrder(zeroExtend(StampFactory.forUnsignedInteger(8), 32), 8, BT, true); @@ -114,7 +114,7 @@ public void testShort() { testPreserveOrder(forConstantInt(NumUtil.maxValueUnsigned(16)), 16, LT, false); testPreserveOrder(forConstantInt(NumUtil.maxValueUnsigned(16)), 16, BT, true); testPreserveOrder(signExtend(StampFactory.forKind(JavaKind.Short), 32), 16, LT, true); - testPreserveOrder(signExtend(StampFactory.forKind(JavaKind.Short), 32), 16, BT, true); + testPreserveOrder(signExtend(StampFactory.forKind(JavaKind.Short), 32), 16, BT, false); testPreserveOrder(zeroExtend(StampFactory.forUnsignedInteger(16), 32), 16, LT, false); testPreserveOrder(zeroExtend(StampFactory.forUnsignedInteger(16), 32), 16, BT, true); @@ -131,7 +131,7 @@ public void testInt() { testPreserveOrder(forConstantLong(NumUtil.maxValueUnsigned(32)), 32, LT, false); testPreserveOrder(forConstantLong(NumUtil.maxValueUnsigned(32)), 32, BT, true); testPreserveOrder(signExtend(StampFactory.forKind(JavaKind.Int), 64), 32, LT, true); - testPreserveOrder(signExtend(StampFactory.forKind(JavaKind.Int), 64), 32, BT, true); + testPreserveOrder(signExtend(StampFactory.forKind(JavaKind.Int), 64), 32, BT, false); testPreserveOrder(zeroExtend(StampFactory.forUnsignedInteger(32), 64), 32, LT, false); testPreserveOrder(zeroExtend(StampFactory.forUnsignedInteger(32), 64), 32, BT, true); diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NarrowNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NarrowNode.java index f325b713a440..caefc754ec4d 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NarrowNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NarrowNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -130,10 +130,22 @@ public boolean preservesOrder(CanonicalCondition cond) { switch (cond) { case LT: return isSignedLossless(); + /* + * We may use signed stamps to represent unsigned integers. This narrow preserves order + * if it is signed lossless and is being compared to another narrow that is signed + * lossless, or if it is unsigned lossless and the other narrow is also unsigned + * lossless. We don't have access to the other narrow here, so we must make a + * conservative choice. We can rely on the fact that the same computation will be + * performed on the other narrow, so it will make the same choice. + * + * Most Java values are signed, so we expect the signed case to be more relevant for + * equals comparison. In contrast, the unsigned case should be more relevant for + * unsigned less than comparisons. + */ case EQ: + return isSignedLossless(); case BT: - // We may use signed stamps to represent unsigned integers. - return isSignedLossless() || isUnsignedLossless(); + return isUnsignedLossless(); default: throw GraalError.shouldNotReachHere("Unsupported canonical condition."); // ExcludeFromJacocoGeneratedReport } From c3babdbfb53ce7ff7280e109d8803766f231461f Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Thu, 22 Feb 2024 19:54:25 +0000 Subject: [PATCH 68/78] update to jvmci-23.0-b32 --- common.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common.json b/common.json index e4218eb0bd04..378a46e97e33 100644 --- a/common.json +++ b/common.json @@ -14,9 +14,9 @@ "labsjdk-ce-17": {"name": "labsjdk", "version": "ce-17.0.9+9-jvmci-23.0-b22", "platformspecific": true }, "labsjdk-ce-17Debug": {"name": "labsjdk", "version": "ce-17.0.9+9-jvmci-23.0-b22-debug", "platformspecific": true }, "labsjdk-ce-17-llvm": {"name": "labsjdk", "version": "ce-17.0.9+9-jvmci-23.0-b22-sulong", "platformspecific": true }, - "labsjdk-ee-17": {"name": "labsjdk", "version": "ee-17.0.11+4-jvmci-23.0-b31", "platformspecific": true }, - "labsjdk-ee-17Debug": {"name": "labsjdk", "version": "ee-17.0.11+4-jvmci-23.0-b31-debug", "platformspecific": true }, - "labsjdk-ee-17-llvm": {"name": "labsjdk", "version": "ee-17.0.11+4-jvmci-23.0-b31-sulong", "platformspecific": true }, + "labsjdk-ee-17": {"name": "labsjdk", "version": "ee-17.0.11+5-jvmci-23.0-b32", "platformspecific": true }, + "labsjdk-ee-17Debug": {"name": "labsjdk", "version": "ee-17.0.11+5-jvmci-23.0-b32-debug", "platformspecific": true }, + "labsjdk-ee-17-llvm": {"name": "labsjdk", "version": "ee-17.0.11+5-jvmci-23.0-b32-sulong", "platformspecific": true }, "oraclejdk19": {"name": "jpg-jdk", "version": "19", "build_id": "26", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, "labsjdk-ce-19": {"name": "labsjdk", "version": "ce-19.0.1+10-jvmci-23.0-b04", "platformspecific": true }, From 056e1fee19e9250bf94e40e94c52bdaa906fe40e Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 10 Jul 2023 05:44:00 +0200 Subject: [PATCH 69/78] Allow TRegex to be used in SandboxPolicy.UNTRUSTED. (cherry picked from commit 9d765e87e7de0632f4dde20dfb00cdd9c56d8e8d) --- .../src/com/oracle/truffle/regex/RegexLanguage.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/RegexLanguage.java b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/RegexLanguage.java index 4f36751d8817..51fb50958390 100644 --- a/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/RegexLanguage.java +++ b/regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/RegexLanguage.java @@ -40,6 +40,8 @@ */ package com.oracle.truffle.regex; +import org.graalvm.polyglot.SandboxPolicy; + import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; @@ -116,7 +118,7 @@ * // result2.getStart(...) and result2.getEnd(...) are undefined * } * - * + * * Debug loggers: {@link com.oracle.truffle.regex.tregex.util.Loggers}. * * @see RegexOptions @@ -130,6 +132,7 @@ contextPolicy = TruffleLanguage.ContextPolicy.SHARED, // internal = true, // interactive = false, // + sandbox = SandboxPolicy.UNTRUSTED, // website = "https://github.com/oracle/graal/tree/master/regex") @ProvidedTags(StandardTags.RootTag.class) public final class RegexLanguage extends TruffleLanguage { From fdde7664fd593f58f549e3644f5e70bb104080b9 Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Mon, 19 Feb 2024 12:14:32 +0100 Subject: [PATCH 70/78] loop fragment: ensure we are not killing control flow when we have nodes in head/tail counted position that are actually empty themselves (skipable) (cherry picked from commit 89ce6d15dcfccbd1eccfa3ced3cd1fd3a7a554d4) --- .../compiler/nodes/loop/LoopFragmentInside.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/LoopFragmentInside.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/LoopFragmentInside.java index 34abba7e7d98..18b814e2b643 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/LoopFragmentInside.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/loop/LoopFragmentInside.java @@ -285,6 +285,8 @@ protected CompareNode placeNewSegmentAndCleanup(LoopEx loop, EconomicMap Date: Tue, 11 Jul 2023 23:28:28 -0700 Subject: [PATCH 71/78] Workarounds for wrong class initialization configuration in microservice frameworks (cherry picked from commit baf612ced12afef53062a80d29bfe2ebcac06d94) --- java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py b/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py index 4714ef318ea0..ba349933e9ba 100644 --- a/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py +++ b/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py @@ -408,7 +408,10 @@ def extra_image_build_argument(self, benchmark, args): if mx.get_jdk().version < expectedJdkVersion: mx.abort(benchmark + " needs at least JDK version " + str(expectedJdkVersion)) - return super(BaseTikaBenchmarkSuite, self).extra_image_build_argument(benchmark, args) + return [ + # Workaround for wrong class initialization configuration in Quarkus Tika + '--initialize-at-build-time=org.apache.pdfbox.rendering.ImageType,org.apache.pdfbox.rendering.ImageType$1,org.apache.pdfbox.rendering.ImageType$2,org.apache.pdfbox.rendering.ImageType$3,org.apache.pdfbox.rendering.ImageType$4', + ] + super(BaseTikaBenchmarkSuite, self).extra_image_build_argument(benchmark, args) class TikaWrkBenchmarkSuite(BaseTikaBenchmarkSuite, mx_sdk_benchmark.BaseWrkBenchmarkSuite): @@ -478,6 +481,9 @@ def build_assertions(self, benchmark, is_gate): def extra_image_build_argument(self, benchmark, args): return [ '--add-exports=org.graalvm.nativeimage.builder/com.oracle.svm.core.jdk=ALL-UNNAMED', + # Workaround for wrong class initialization configuration in Micronaut 3.9 + '--initialize-at-build-time=io.netty.handler.codec.http.cookie.ServerCookieEncoder', + '--initialize-at-build-time=org.xml.sax.helpers.AttributesImpl,org.xml.sax.helpers.LocatorImpl', ] + super(BaseMicronautBenchmarkSuite, self).extra_image_build_argument(benchmark, args) def default_stages(self): From 801442b64b7a66a72809eb67d134385ddf697b7c Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Mon, 5 Feb 2024 15:25:30 +0100 Subject: [PATCH 72/78] fixed read nodes must only be removed if they are not used as null checks (cherry picked from commit e989f7cee05fc14457a75ca61f38c6fd379fce72) --- .../amd64/test/ReadEliminateLowTierTest.java | 134 ++++++++++++++++++ .../compiler/nodes/memory/ReadNode.java | 17 ++- 2 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 compiler/src/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/ReadEliminateLowTierTest.java diff --git a/compiler/src/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/ReadEliminateLowTierTest.java b/compiler/src/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/ReadEliminateLowTierTest.java new file mode 100644 index 000000000000..0a1d80c4d280 --- /dev/null +++ b/compiler/src/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/ReadEliminateLowTierTest.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.graal.compiler.hotspot.amd64.test; + +import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_0; +import static jdk.graal.compiler.nodeinfo.NodeSize.SIZE_0; + +import org.junit.Test; + +import jdk.graal.compiler.api.directives.GraalDirectives; +import jdk.graal.compiler.core.common.type.StampFactory; +import jdk.graal.compiler.core.test.GraalCompilerTest; +import jdk.graal.compiler.graph.Node; +import jdk.graal.compiler.graph.NodeClass; +import jdk.graal.compiler.nodeinfo.InputType; +import jdk.graal.compiler.nodeinfo.NodeInfo; +import jdk.graal.compiler.nodes.FixedWithNextNode; +import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.calc.IsNullNode; +import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin; +import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration; +import jdk.graal.compiler.nodes.memory.ReadNode; +import jdk.graal.compiler.nodes.spi.Canonicalizable; +import jdk.graal.compiler.nodes.spi.CanonicalizerTool; +import jdk.graal.compiler.phases.common.UseTrappingNullChecksPhase; +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.code.InvalidInstalledCodeException; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Test to ensure that late elimination of memory reads preserves necessary null check semantic with + * respect to {@link UseTrappingNullChecksPhase}. + */ +public class ReadEliminateLowTierTest extends GraalCompilerTest { + static class T { + int x; + int y; + int z; + } + + public static int trappingSnippet(T t) { + if (t == null) { + GraalDirectives.deoptimizeAndInvalidate(); + return -1; + } + /* + * The first read from t here will act as trapping null check for all the others. We must + * not remove this read if its used as a null check even if it does not have any usages any + * more. + */ + foldAfterTrappingNullChecks(t.x); + int result = t.y + t.z; + return result; + } + + static void foldAfterTrappingNullChecks(@SuppressWarnings("unused") int i) { + } + + @Override + protected Plugins getDefaultGraphBuilderPlugins() { + Plugins p = super.getDefaultGraphBuilderPlugins(); + Registration r = new Registration(p.getInvocationPlugins(), ReadEliminateLowTierTest.class); + r.register(new InvocationPlugin("foldAfterTrappingNullChecks", int.class) { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) { + b.append(new FixedUsageUntilFinalCanon(arg)); + return true; + } + }); + return p; + } + + /** + * Node that gets optimized away be late canonicalization. + */ + @NodeInfo(cycles = CYCLES_0, size = SIZE_0, allowedUsageTypes = {InputType.Anchor}) + public static class FixedUsageUntilFinalCanon extends FixedWithNextNode implements Canonicalizable { + public static final NodeClass TYPE = NodeClass.create(FixedUsageUntilFinalCanon.class); + + @OptionalInput ValueNode object; + + public FixedUsageUntilFinalCanon(ValueNode object) { + super(TYPE, StampFactory.forVoid()); + this.object = object; + } + + @Override + public Node canonical(CanonicalizerTool tool) { + // after trapping nulls + if (graph().getNodes().filter(IsNullNode.class).count() == 0) { + if (tool.allUsagesAvailable() && object instanceof ReadNode) { + ReadNode r = (ReadNode) object; + if (r.hasExactlyOneUsage() && r.usages().first().equals(this)) { + return null; + } + } + } + return this; + } + } + + @Test + public void test() throws InvalidInstalledCodeException { + InstalledCode ic = getCode(getResolvedJavaMethod("trappingSnippet")); + assert lastCompiledGraph != null; + ic.executeVarargs(new T()); + ic.executeVarargs((Object) null); + } + +} diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/ReadNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/ReadNode.java index 86bfd8b5eb79..2996dc74bf42 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/ReadNode.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/ReadNode.java @@ -127,8 +127,21 @@ public void generate(NodeLIRBuilderTool gen) { @Override public Node canonical(CanonicalizerTool tool) { - if (tool.allUsagesAvailable() && hasNoUsages()) { - // Read without usages or guard can be safely removed. + if (!getUsedAsNullCheck() && tool.allUsagesAvailable() && hasNoUsages()) { + /** + * Read without usages or guard can be safely removed as long as it does not act as the + * null check for dominated memory accesses. + * + *
+             * readWithNullCheck(object.a);
+             * read(object.b);
+             * read(object.c);
+             * 
+ * + * In this pattern the first read is the null check for the dominated reads of b and c. + * Thus, the read of a must not be removed after fix reads phase even if it has no + * usages. + */ return null; } if (!getUsedAsNullCheck() && !extendsAccess()) { From c868c7139106e4baac19937af11d637b6f822819 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Thu, 7 Dec 2023 15:49:00 +0100 Subject: [PATCH 73/78] Make segfault handler more robust. --- .../aarch64/SubstrateAArch64Backend.java | 6 +- .../graal/amd64/SubstrateAMD64Backend.java | 4 +- .../posix/PosixSubstrateSegfaultHandler.java | 3 + .../WindowsSubstrateSegfaultHandler.java | 9 +- .../svm/core/SubstrateSegfaultHandler.java | 138 +++++++++++++++--- .../meta/SubstrateBasicLoweringProvider.java | 2 +- .../oracle/svm/core/heap/ObjectHeader.java | 6 - .../oracle/svm/core/heap/ReferenceAccess.java | 5 + .../svm/core/heap/ReferenceAccessImpl.java | 6 + 9 files changed, 141 insertions(+), 38 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java index 9ef88c2646d0..2b82aa5e9b66 100755 --- a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java +++ b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java @@ -293,7 +293,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { Register immediateScratch = sc1.getRegister(); Register addressScratch = sc2.getRegister(); - CompressEncoding compressEncoding = ReferenceAccess.singleton().getCompressEncoding(); + int compressionShift = ReferenceAccess.singleton().getCompressionShift(); Register computeRegister = asRegister(addressBase); int addressBitSize = addressBase.getPlatformKind().getSizeInBytes() * Byte.SIZE; boolean nextMemoryAccessNeedsDecompress = false; @@ -317,7 +317,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { * currently in use: references are relative to the heap base register, * with an optional shift. */ - masm.add(64, addressScratch, ReservedRegisters.singleton().getHeapBaseRegister(), computeRegister, ShiftType.LSL, compressEncoding.getShift()); + masm.add(64, addressScratch, ReservedRegisters.singleton().getHeapBaseRegister(), computeRegister, ShiftType.LSL, compressionShift); memoryAddress = masm.makeAddress(addressBitSize, addressScratch, field.getOffset(), immediateScratch); } else { memoryAddress = masm.makeAddress(addressBitSize, computeRegister, field.getOffset(), immediateScratch); @@ -346,7 +346,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { } else { masm.mov(addressScratch, 0xDEADDEADDEADDEADL, true); } - masm.add(64, addressScratch, ReservedRegisters.singleton().getHeapBaseRegister(), addressScratch, ShiftType.LSL, compressEncoding.getShift()); + masm.add(64, addressScratch, ReservedRegisters.singleton().getHeapBaseRegister(), addressScratch, ShiftType.LSL, compressionShift); memoryAddress = masm.makeAddress(addressBitSize, addressScratch, field.getOffset(), immediateScratch); } else { memoryAddress = masm.makeAddress(addressBitSize, ReservedRegisters.singleton().getHeapBaseRegister(), field.getOffset() + constantReflection.getImageHeapOffset(object), diff --git a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java index d791b3a9fe33..1ba419235451 100644 --- a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java +++ b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java @@ -322,7 +322,7 @@ public SubstrateAMD64ComputedIndirectCallOp(ResolvedJavaMethod callTarget, Value public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { VMError.guarantee(SubstrateOptions.SpawnIsolates.getValue(), "Memory access without isolates is not implemented"); - CompressEncoding compressEncoding = ReferenceAccess.singleton().getCompressEncoding(); + int compressionShift = ReferenceAccess.singleton().getCompressionShift(); Register computeRegister = asRegister(addressBase); AMD64BaseAssembler.OperandSize lastOperandSize = AMD64BaseAssembler.OperandSize.get(addressBase.getPlatformKind()); boolean nextMemoryAccessNeedsDecompress = false; @@ -346,7 +346,7 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { * an optional shift that is known to be a valid addressing mode. */ memoryAddress = new AMD64Address(ReservedRegisters.singleton().getHeapBaseRegister(), - computeRegister, Stride.fromLog2(compressEncoding.getShift()), + computeRegister, Stride.fromLog2(compressionShift), field.getOffset()); } else { memoryAddress = new AMD64Address(computeRegister, field.getOffset()); diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java index 48792f464adc..1084a4459db2 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSegfaultHandler.java @@ -66,6 +66,9 @@ private static void dispatch(@SuppressWarnings("unused") int signalNumber, @Supp dump(sigInfo, uContext); throw VMError.shouldNotReachHere(); } + + /* Attach failed - kill the process because the segfault handler must not return. */ + LibC.abort(); } @Override diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java index a6c251dde7b1..11ab74a7ff05 100644 --- a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsSubstrateSegfaultHandler.java @@ -75,8 +75,7 @@ protected void installInternal() { } } - private static final CEntryPointLiteral HANDLER_LITERAL = CEntryPointLiteral.create(WindowsSubstrateSegfaultHandler.class, - "handler", ErrHandlingAPI.EXCEPTION_POINTERS.class); + private static final CEntryPointLiteral HANDLER_LITERAL = CEntryPointLiteral.create(WindowsSubstrateSegfaultHandler.class, "handler", ErrHandlingAPI.EXCEPTION_POINTERS.class); @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = Publish.NotPublished) @CEntryPointOptions(prologue = NoPrologue.class, epilogue = NoEpilogue.class) @@ -94,7 +93,11 @@ private static int handler(ErrHandlingAPI.EXCEPTION_POINTERS exceptionInfo) { dump(exceptionInfo, context); throw shouldNotReachHere(); } - /* Nothing we can do. */ + + /* + * Attach failed - nothing we need to do. If there is no other OS-level exception handler + * installed, then Windows will abort the process. + */ return ErrHandlingAPI.EXCEPTION_CONTINUE_SEARCH(); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java index a931b4b974dc..e0ff50aa5ef9 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateSegfaultHandler.java @@ -26,21 +26,27 @@ import static com.oracle.svm.core.heap.RestrictHeapAccess.Access.NO_ALLOCATION; +import java.lang.reflect.Field; +import java.nio.ByteBuffer; import java.util.Collections; import java.util.List; import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.word.Word; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Isolate; import org.graalvm.nativeimage.IsolateThread; import org.graalvm.nativeimage.LogHandler; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.function.CodePointer; import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.word.LocationIdentity; import org.graalvm.word.Pointer; import org.graalvm.word.PointerBase; +import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; import com.oracle.svm.core.IsolateListenerSupport.IsolateListener; @@ -49,18 +55,20 @@ import com.oracle.svm.core.c.CGlobalDataFactory; import com.oracle.svm.core.c.function.CEntryPointActions; import com.oracle.svm.core.c.function.CEntryPointErrors; +import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.graal.nodes.WriteCurrentVMThreadNode; import com.oracle.svm.core.graal.snippets.CEntryPointSnippets; +import com.oracle.svm.core.heap.ReferenceAccess; import com.oracle.svm.core.heap.RestrictHeapAccess; import com.oracle.svm.core.jdk.RuntimeSupport; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.option.RuntimeOptionKey; -import com.oracle.svm.core.snippets.KnownIntrinsics; import com.oracle.svm.core.stack.StackOverflowCheck; import com.oracle.svm.core.thread.VMThreads; import com.oracle.svm.core.thread.VMThreads.SafepointBehavior; +import com.oracle.svm.util.ReflectionUtil; @AutomaticallyRegisteredFeature class SubstrateSegfaultHandlerFeature implements InternalFeature { @@ -72,15 +80,31 @@ public List> getRequiredFeatures() { @Override public void beforeAnalysis(BeforeAnalysisAccess access) { if (!ImageSingletons.contains(SubstrateSegfaultHandler.class)) { - return; /* No segfault handler. */ + return; } + /* Register the marker as accessed so that we have a field with a well-known value. */ + access.registerAsUnsafeAccessed(getStaticFieldWithWellKnownValue()); + SingleIsolateSegfaultSetup singleIsolateSegfaultSetup = new SingleIsolateSegfaultSetup(); ImageSingletons.add(SingleIsolateSegfaultSetup.class, singleIsolateSegfaultSetup); IsolateListenerSupport.singleton().register(singleIsolateSegfaultSetup); RuntimeSupport.getRuntimeSupport().addStartupHook(new SubstrateSegfaultHandlerStartupHook()); } + + @Override + public void beforeCompilation(BeforeCompilationAccess access) { + if (!ImageSingletons.contains(SubstrateSegfaultHandler.class)) { + return; + } + + SubstrateSegfaultHandler.offsetOfStaticFieldWithWellKnownValue = access.objectFieldOffset(getStaticFieldWithWellKnownValue()); + } + + private static Field getStaticFieldWithWellKnownValue() { + return ReflectionUtil.lookupField(SubstrateSegfaultHandler.class, "staticFieldWithWellKnownValue"); + } } final class SubstrateSegfaultHandlerStartupHook implements RuntimeSupport.Hook { @@ -101,6 +125,16 @@ public static class Options { static final RuntimeOptionKey InstallSegfaultHandler = new RuntimeOptionKey<>(null); } + @Platforms(Platform.HOSTED_ONLY.class) // + static long offsetOfStaticFieldWithWellKnownValue; + + private static final long MARKER_VALUE = 0x0123456789ABCDEFL; + private static final CGlobalData OFFSET_OF_STATIC_FIELD_WITH_WELL_KNOWN_VALUE = CGlobalDataFactory.createBytes(() -> { + assert ConfigurationValues.getTarget().wordSize == Long.BYTES; + return ByteBuffer.allocate(Long.BYTES).order(ConfigurationValues.getTarget().arch.getByteOrder()).putLong(offsetOfStaticFieldWithWellKnownValue).array(); + }); + @SuppressWarnings("unused") private static long staticFieldWithWellKnownValue = MARKER_VALUE; + private boolean installed; @Fold @@ -122,39 +156,97 @@ public void install() { protected abstract void printSignalInfo(Log log, PointerBase signalInfo); - /** Called from the platform dependent segfault handler to enter the isolate. */ + /** + * Called from the platform dependent segfault handler to enter the isolate. Note that this code + * may trigger a new segfault, which can lead to recursion. In the worst case, the recursion is + * only stopped once we trigger a native stack overflow. + */ @Uninterruptible(reason = "Thread state not set up yet.") @RestrictHeapAccess(access = NO_ALLOCATION, reason = "Must not allocate in segfault handler.") protected static boolean tryEnterIsolate(RegisterDumper.Context context) { - // Check if we have sufficient information to enter the correct isolate. + /* If there is only a single isolate, we can just enter that isolate. */ Isolate isolate = SingleIsolateSegfaultSetup.singleton().getIsolate(); if (isolate.rawValue() != -1) { - // There is only a single isolate, so lets attach to that isolate. int error = CEntryPointActions.enterAttachThreadFromCrashHandler(isolate); return error == CEntryPointErrors.NO_ERROR; - } else if (!SubstrateOptions.useLLVMBackend()) { - // Try to determine the isolate via the register information. This very likely fails if - // the crash happened in native code that was linked into Native Image. - if (SubstrateOptions.SpawnIsolates.getValue()) { - PointerBase heapBase = RegisterDumper.singleton().getHeapBase(context); - CEntryPointSnippets.setHeapBase(heapBase); - } - if (SubstrateOptions.MultiThreaded.getValue()) { - PointerBase threadPointer = RegisterDumper.singleton().getThreadPointer(context); - WriteCurrentVMThreadNode.writeCurrentVMThread((IsolateThread) threadPointer); + } + + /* The LLVM backend doesn't support the register-based approach. */ + if (SubstrateOptions.useLLVMBackend()) { + return false; + } + + /* Try to determine the isolate via the thread register. */ + if (SubstrateOptions.MultiThreaded.getValue() && tryEnterIsolateViaThreadRegister(context)) { + return true; + } + + /* Try to determine the isolate via the heap base register. */ + return SubstrateOptions.SpawnIsolates.getValue() && tryEnterIsolateViaHeapBaseRegister(context); + } + + @Uninterruptible(reason = "Thread state not set up yet.") + @NeverInline("Prevent register writes from floating") + private static boolean tryEnterIsolateViaThreadRegister(RegisterDumper.Context context) { + /* + * Set the thread register to null so that we don't execute this code more than once if we + * trigger a recursive segfault. + */ + WriteCurrentVMThreadNode.writeCurrentVMThread(WordFactory.nullPointer()); + + IsolateThread isolateThread = (IsolateThread) RegisterDumper.singleton().getThreadPointer(context); + if (isolateThread.isNonNull()) { + Isolate isolate = VMThreads.IsolateTL.get(isolateThread); + if (isValid(isolate)) { + if (SubstrateOptions.SpawnIsolates.getValue()) { + CEntryPointSnippets.setHeapBase(isolate); + } + + WriteCurrentVMThreadNode.writeCurrentVMThread(isolateThread); + return true; } + } + return false; + } + + @Uninterruptible(reason = "Thread state not set up yet.") + @NeverInline("Prevent register writes from floating") + private static boolean tryEnterIsolateViaHeapBaseRegister(RegisterDumper.Context context) { + /* + * Set the heap base register to null so that we don't execute this code more than once if + * we trigger a recursive segfault. + */ + CEntryPointSnippets.setHeapBase(WordFactory.nullPointer()); - /* - * The following probing is subject to implicit recursion as it may trigger a new - * segfault. However, this is fine, as it will eventually result in native stack - * overflow. - */ - isolate = VMThreads.IsolateTL.get(); - return Isolates.checkIsolate(isolate) == CEntryPointErrors.NO_ERROR && (!SubstrateOptions.SpawnIsolates.getValue() || isolate.equal(KnownIntrinsics.heapBase())); + Isolate isolate = (Isolate) RegisterDumper.singleton().getHeapBase(context); + if (isValid(isolate)) { + int error = CEntryPointActions.enterAttachThreadFromCrashHandler(isolate); + return error == CEntryPointErrors.NO_ERROR; } return false; } + @Uninterruptible(reason = "Thread state not set up yet.") + private static boolean isValid(Isolate isolate) { + if (Isolates.checkIsolate(isolate) != CEntryPointErrors.NO_ERROR) { + return false; + } + + /* + * Read a static field in the image heap and compare its value with a well-known marker + * value as an extra sanity check. Note that the heap base register still contains an + * invalid value when we execute this code, which makes things a bit more complex. + */ + if (SubstrateOptions.SpawnIsolates.getValue()) { + UnsignedWord staticFieldsOffsets = ReferenceAccess.singleton().getCompressedRepresentation(StaticFieldsSupport.getStaticPrimitiveFields()); + UnsignedWord wellKnownFieldOffset = staticFieldsOffsets.shiftLeft(ReferenceAccess.singleton().getCompressionShift()).add(OFFSET_OF_STATIC_FIELD_WITH_WELL_KNOWN_VALUE.get().readWord(0)); + Pointer wellKnownField = ((Pointer) isolate).add(wellKnownFieldOffset); + return wellKnownField.readLong(0) == MARKER_VALUE; + } + + return true; + } + /** Called from the platform dependent segfault handler to print diagnostics. */ @Uninterruptible(reason = "Must be uninterruptible until we get immune to safepoints.", calleeMustBe = false) @RestrictHeapAccess(access = NO_ALLOCATION, reason = "Must not allocate in segfault handler.") @@ -196,7 +288,7 @@ protected static void printSegfaultAddressInfo(Log log, long addr) { } } - static class SingleIsolateSegfaultSetup implements IsolateListener { + public static class SingleIsolateSegfaultSetup implements IsolateListener { /** * Stores the address of the first isolate created. This is meant to attempt to detect the 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 7ab5ed7f986f..2dcb09313469 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 @@ -228,7 +228,7 @@ protected ValueNode createReadHub(StructuredGraph graph, ValueNode object, Lower // 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); - int compressionShift = ReferenceAccess.singleton().getCompressEncoding().getShift(); + int compressionShift = ReferenceAccess.singleton().getCompressionShift(); int numAlignmentBits = CodeUtil.log2(objectLayout.getAlignment()); assert compressionShift <= numAlignmentBits : "compression discards bits"; if (numReservedBits == numAlignmentBits && compressionShift == 0) { 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 5e83ff7a0932..f6b0edb0da02 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 @@ -24,7 +24,6 @@ */ package com.oracle.svm.core.heap; -import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.word.Word; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -97,9 +96,4 @@ public boolean pointsToObjectHeader(Pointer ptr) { @Uninterruptible(reason = "Prevent a GC interfering with the object's identity hash state.", callerMustBe = true) public abstract void setIdentityHashFromAddress(Pointer ptr, Word currentHeader); - - @Fold - protected static int getCompressionShift() { - return ReferenceAccess.singleton().getCompressEncoding().getShift(); - } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ReferenceAccess.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ReferenceAccess.java index b2a174de1492..730ea54795d2 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ReferenceAccess.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ReferenceAccess.java @@ -118,6 +118,11 @@ static ReferenceAccess singleton() { */ CompressEncoding getCompressEncoding(); + /** + * Returns a compile-time constant for {@link CompressEncoding#getShift()}. + */ + int getCompressionShift(); + /** * Returns the size of the address space, based on the reference size. */ diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ReferenceAccessImpl.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ReferenceAccessImpl.java index c3f22e0e6bf2..7709a96f4ce1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ReferenceAccessImpl.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/ReferenceAccessImpl.java @@ -117,4 +117,10 @@ public UnsignedWord getAddressSpaceSize() { // Assume that 48 bit is the maximum address space that can be used. return WordFactory.unsigned((1L << 48) - 1); } + + @Fold + @Override + public int getCompressionShift() { + return getCompressEncoding().getShift(); + } } From 1b76fac7b13c41b0baa0b9ae26f4a8ae7bcad47f Mon Sep 17 00:00:00 2001 From: Karim Assifar Date: Wed, 28 Feb 2024 15:23:21 +0100 Subject: [PATCH 74/78] Adapt fix --- .../amd64/test/ReadEliminateLowTierTest.java | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/compiler/src/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/ReadEliminateLowTierTest.java b/compiler/src/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/ReadEliminateLowTierTest.java index 0a1d80c4d280..7bbf7192330e 100644 --- a/compiler/src/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/ReadEliminateLowTierTest.java +++ b/compiler/src/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/ReadEliminateLowTierTest.java @@ -22,31 +22,31 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.graal.compiler.hotspot.amd64.test; +package org.graalvm.compiler.hotspot.amd64.test; -import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_0; -import static jdk.graal.compiler.nodeinfo.NodeSize.SIZE_0; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; import org.junit.Test; +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.InputType; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.IsNullNode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration; +import org.graalvm.compiler.nodes.memory.ReadNode; +import org.graalvm.compiler.nodes.spi.Canonicalizable; +import org.graalvm.compiler.nodes.spi.CanonicalizerTool; +import org.graalvm.compiler.phases.common.UseTrappingNullChecksPhase; -import jdk.graal.compiler.api.directives.GraalDirectives; -import jdk.graal.compiler.core.common.type.StampFactory; -import jdk.graal.compiler.core.test.GraalCompilerTest; -import jdk.graal.compiler.graph.Node; -import jdk.graal.compiler.graph.NodeClass; -import jdk.graal.compiler.nodeinfo.InputType; -import jdk.graal.compiler.nodeinfo.NodeInfo; -import jdk.graal.compiler.nodes.FixedWithNextNode; -import jdk.graal.compiler.nodes.ValueNode; -import jdk.graal.compiler.nodes.calc.IsNullNode; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; -import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin; -import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration; -import jdk.graal.compiler.nodes.memory.ReadNode; -import jdk.graal.compiler.nodes.spi.Canonicalizable; -import jdk.graal.compiler.nodes.spi.CanonicalizerTool; -import jdk.graal.compiler.phases.common.UseTrappingNullChecksPhase; import jdk.vm.ci.code.InstalledCode; import jdk.vm.ci.code.InvalidInstalledCodeException; import jdk.vm.ci.meta.ResolvedJavaMethod; From ea3e3c8a1f3884a8b1ff8fc369120fb4b29997b0 Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Mon, 12 Feb 2024 11:53:52 +0100 Subject: [PATCH 75/78] Improve uncaught exception handler and error handling in CEntryPointSnippets.initializeIsolate(). --- .../graal/snippets/CEntryPointSnippets.java | 14 ++++- .../src/com/oracle/svm/core/jdk/JDKUtils.java | 10 ++++ .../svm/core/jdk/JavaLangSubstitutions.java | 3 ++ .../src/com/oracle/svm/core/log/RealLog.java | 53 +++++++++++-------- 4 files changed, 58 insertions(+), 22 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java index 3de1a1d63225..d7232a5af9ea 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java @@ -290,6 +290,16 @@ private static int initializeIsolateInterruptibly(CEntryPointCreateIsolateParame } private static int initializeIsolateInterruptibly0(CEntryPointCreateIsolateParameters parameters) { + try { + return initializeIsolateInterruptibly1(parameters); + } catch (Throwable t) { + Log.log().string("Uncaught exception while initializing isolate: ").exception(t).newline(); + return CEntryPointErrors.ISOLATE_INITIALIZATION_FAILED; + } + } + + @NeverInline("GR-24649") + private static int initializeIsolateInterruptibly1(CEntryPointCreateIsolateParameters parameters) { /* * The VM operation thread must be started early as no VM operations can be scheduled before * this thread is fully started. The isolate teardown may also use VM operations. @@ -374,10 +384,11 @@ private static int initializeIsolateInterruptibly0(CEntryPointCreateIsolateParam assert !isolateInitialized; isolateInitialized = true; + /* Run isolate initialization hooks. */ try { RuntimeSupport.executeInitializationHooks(); } catch (Throwable t) { - System.err.println("Uncaught exception while running initialization hooks:"); + System.err.println("Uncaught exception while running isolate initialization hooks:"); t.printStackTrace(); return CEntryPointErrors.ISOLATE_INITIALIZATION_FAILED; } @@ -390,6 +401,7 @@ private static int initializeIsolateInterruptibly0(CEntryPointCreateIsolateParam t.printStackTrace(); return CEntryPointErrors.ISOLATE_INITIALIZATION_FAILED; } + return CEntryPointErrors.NO_ERROR; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDKUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDKUtils.java index c584daf3c838..ad5ef7f39dc6 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDKUtils.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JDKUtils.java @@ -37,6 +37,16 @@ public static String getRawMessage(Throwable ex) { return SubstrateUtil.cast(ex, Target_java_lang_Throwable.class).detailMessage; } + /** + * Returns the raw cause stored in {@link Throwable} and returned by default from + * {@link Throwable#getCause}. This method ignores possible overrides of + * {@link Throwable#getCause} and is therefore guaranteed to be allocation free. + */ + public static Throwable getRawCause(Throwable ex) { + Throwable cause = SubstrateUtil.cast(ex, Target_java_lang_Throwable.class).cause; + return cause == ex ? null : cause; + } + public static StackTraceElement[] getRawStackTrace(Throwable ex) { return SubstrateUtil.cast(ex, Target_java_lang_Throwable.class).stackTrace; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java index 12180b17c5b3..e2046f282f2e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java @@ -295,6 +295,9 @@ final class Target_java_lang_Throwable { @Alias @RecomputeFieldValue(kind = Reset)// private Object backtrace; + @Alias// + Throwable cause; + @Alias @RecomputeFieldValue(kind = Reset)// StackTraceElement[] stackTrace; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java index 0a5d62801ab0..da6edc867851 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/log/RealLog.java @@ -634,30 +634,41 @@ public Log exception(Throwable t, int maxFrames) { return this; } - /* - * We do not want to call getMessage(), since it can be overridden by subclasses of - * Throwable. So we access the raw detailMessage directly from the field in Throwable. That - * is better than printing nothing. - */ - String detailMessage = JDKUtils.getRawMessage(t); - StackTraceElement[] stackTrace = JDKUtils.getRawStackTrace(t); - - string(t.getClass().getName()).string(": ").string(detailMessage); - if (stackTrace != null) { - int i; - for (i = 0; i < stackTrace.length && i < maxFrames; i++) { - StackTraceElement element = stackTrace[i]; - if (element != null) { - newline(); - string(" at ").string(element.getClassName()).string(".").string(element.getMethodName()); - string("(").string(element.getFileName()).string(":").signed(element.getLineNumber()).string(")"); - } + Throwable cur = t; + int maxCauses = 25; + for (int i = 0; i < maxCauses && cur != null; i++) { + if (i > 0) { + newline().string("Caused by: "); } - int remaining = stackTrace.length - i; - if (remaining > 0) { - newline().string(" ... ").unsigned(remaining).string(" more"); + + /* + * We do not want to call getMessage(), since it can be overridden by subclasses of + * Throwable. So we access the raw detailMessage directly from the field in Throwable. + * That is better than printing nothing. + */ + String detailMessage = JDKUtils.getRawMessage(cur); + StackTraceElement[] stackTrace = JDKUtils.getRawStackTrace(cur); + + string(cur.getClass().getName()).string(": ").string(detailMessage); + if (stackTrace != null) { + int j; + for (j = 0; j < stackTrace.length && j < maxFrames; j++) { + StackTraceElement element = stackTrace[j]; + if (element != null) { + newline(); + string(" at ").string(element.getClassName()).string(".").string(element.getMethodName()); + string("(").string(element.getFileName()).string(":").signed(element.getLineNumber()).string(")"); + } + } + int remaining = stackTrace.length - j; + if (remaining > 0) { + newline().string(" ... ").unsigned(remaining).string(" more"); + } } + + cur = JDKUtils.getRawCause(cur); } + return this; } } From 4d321e6a36e650dae0433e0d39a237300307ff5f Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Mon, 5 Feb 2024 17:02:02 +0100 Subject: [PATCH 76/78] Add option ImplicitExceptionWithoutStacktraceIsFatal. --- .../com/oracle/svm/core/SubstrateOptions.java | 3 + .../svm/core/snippets/ImplicitExceptions.java | 101 +++++++++--------- 2 files changed, 55 insertions(+), 49 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index 42a0f9279d86..71cbf24a3e0c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -892,6 +892,9 @@ protected void onValueUpdate(EconomicMap, Object> values, String ol @Option(help = "Specifies the number of entries that diagnostic buffers have.", type = OptionType.Debug)// public static final HostedOptionKey DiagnosticBufferSize = new HostedOptionKey<>(30); + @Option(help = "Determines if implicit exceptions are fatal if they don't have a stack trace.", type = OptionType.Debug)// + public static final RuntimeOptionKey ImplicitExceptionWithoutStacktraceIsFatal = new RuntimeOptionKey<>(false); + @SuppressWarnings("unused")// @APIOption(name = "configure-reflection-metadata")// @Option(help = "Enable runtime instantiation of reflection objects for non-invoked methods.", type = OptionType.Expert, deprecated = true)// diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ImplicitExceptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ImplicitExceptions.java index ea7e4814bd91..ca8f86796837 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ImplicitExceptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ImplicitExceptions.java @@ -27,6 +27,7 @@ import java.lang.reflect.GenericSignatureFormatError; import com.oracle.svm.core.SubstrateDiagnostics; +import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.code.FactoryMethodMarker; import com.oracle.svm.core.heap.RestrictHeapAccess; import com.oracle.svm.core.jdk.InternalVMMethod; @@ -157,8 +158,10 @@ public static void deactivateImplicitExceptionsAreFatal() { implicitExceptionsAreFatal.set(implicitExceptionsAreFatal.get() - 1); } - private static void vmErrorIfImplicitExceptionsAreFatal() { - if ((implicitExceptionsAreFatal.get() > 0 || ExceptionUnwind.exceptionsAreFatal()) && !SubstrateDiagnostics.isFatalErrorHandlingThread()) { + private static void vmErrorIfImplicitExceptionsAreFatal(boolean cachedException) { + if (cachedException && SubstrateOptions.ImplicitExceptionWithoutStacktraceIsFatal.getValue()) { + throw VMError.shouldNotReachHere("AssertionError without stack trace."); + } else if ((implicitExceptionsAreFatal.get() > 0 || ExceptionUnwind.exceptionsAreFatal()) && !SubstrateDiagnostics.isFatalErrorHandlingThread()) { throw VMError.shouldNotReachHere("Implicit exception thrown in code where such exceptions are fatal errors"); } } @@ -166,21 +169,21 @@ private static void vmErrorIfImplicitExceptionsAreFatal() { /** Foreign call: {@link #CREATE_NULL_POINTER_EXCEPTION}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static NullPointerException createNullPointerException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); return new NullPointerException(); } /** Foreign call: {@link #CREATE_OUT_OF_BOUNDS_EXCEPTION}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static ArrayIndexOutOfBoundsException createIntrinsicOutOfBoundsException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); return new ArrayIndexOutOfBoundsException(); } /** Foreign call: {@link #CREATE_OUT_OF_BOUNDS_EXCEPTION}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static ArrayIndexOutOfBoundsException createOutOfBoundsException(int index, int length) { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); /* * JDK 11 added the length to the error message, we can do that for all Java versions to be * consistent. @@ -192,7 +195,7 @@ private static ArrayIndexOutOfBoundsException createOutOfBoundsException(int ind @SubstrateForeignCallTarget(stubCallingConvention = true) private static ClassCastException createClassCastException(Object object, Object expectedClass) { assert object != null : "null can be cast to any type, so it cannot show up as a source of a ClassCastException"; - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); String expectedClassName; if (expectedClass instanceof Class) { expectedClassName = ((Class) expectedClass).getTypeName(); @@ -206,84 +209,84 @@ private static ClassCastException createClassCastException(Object object, Object @SubstrateForeignCallTarget(stubCallingConvention = true) private static ArrayStoreException createArrayStoreException(Object value) { assert value != null : "null can be stored into any array, so it cannot show up as a source of an ArrayStoreException"; - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); return new ArrayStoreException(value.getClass().getTypeName()); } /** Foreign call: {@link #CREATE_INCOMPATIBLE_CLASS_CHANGE_ERROR}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static IncompatibleClassChangeError createIncompatibleClassChangeError() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); return new IncompatibleClassChangeError(); } /** Foreign call: {@link #CREATE_ILLEGAL_ARGUMENT_EXCEPTION}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static IllegalArgumentException createIllegalArgumentException(String message) { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); return new IllegalArgumentException(message); } /** Foreign call: {@link #CREATE_NEGATIVE_ARRAY_SIZE_EXCEPTION}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static NegativeArraySizeException createNegativeArraySizeException(int length) { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); return new NegativeArraySizeException(String.valueOf(length)); } /** Foreign call: {@link #CREATE_DIVISION_BY_ZERO_EXCEPTION}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static ArithmeticException createDivisionByZeroException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); return new ArithmeticException("/ by zero"); } /** Foreign call: {@link #CREATE_INTEGER_OVERFLOW_EXCEPTION}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static ArithmeticException createIntegerOverflowException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); return new ArithmeticException("integer overflow"); } /** Foreign call: {@link #CREATE_LONG_OVERFLOW_EXCEPTION}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static ArithmeticException createLongOverflowException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); return new ArithmeticException("long overflow"); } /** Foreign call: {@link #CREATE_ASSERTION_ERROR_NULLARY}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static AssertionError createAssertionErrorNullary() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); return new AssertionError(); } /** Foreign call: {@link #CREATE_ASSERTION_ERROR_OBJECT}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static AssertionError createAssertionErrorObject(Object detailMessage) { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); return new AssertionError(detailMessage); } /** Foreign call: {@link #THROW_NEW_NULL_POINTER_EXCEPTION}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwNewNullPointerException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); throw new NullPointerException(); } /** Foreign call: {@link #THROW_NEW_INTRINSIC_OUT_OF_BOUNDS_EXCEPTION}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwNewIntrinsicOutOfBoundsException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); throw new ArrayIndexOutOfBoundsException(); } /** Foreign call: {@link #THROW_NEW_OUT_OF_BOUNDS_EXCEPTION_WITH_ARGS}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwNewOutOfBoundsExceptionWithArgs(int index, int length) { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); /* * JDK 11 added the length to the error message, we can do that for all Java versions to be * consistent. @@ -294,7 +297,7 @@ private static void throwNewOutOfBoundsExceptionWithArgs(int index, int length) /** Foreign call: {@link #THROW_NEW_CLASS_CAST_EXCEPTION}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwNewClassCastException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); throw new ClassCastException(); } @@ -302,7 +305,7 @@ private static void throwNewClassCastException() { @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwNewClassCastExceptionWithArgs(Object object, Object expectedClass) { assert object != null : "null can be cast to any type, so it cannot show up as a source of a ClassCastException"; - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); String expectedClassName; if (expectedClass instanceof Class) { expectedClassName = ((Class) expectedClass).getTypeName(); @@ -315,7 +318,7 @@ private static void throwNewClassCastExceptionWithArgs(Object object, Object exp /** Foreign call: {@link #THROW_NEW_ARRAY_STORE_EXCEPTION}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwNewArrayStoreException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); throw new ArrayStoreException(); } @@ -323,70 +326,70 @@ private static void throwNewArrayStoreException() { @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwNewArrayStoreExceptionWithArgs(Object value) { assert value != null : "null can be stored into any array, so it cannot show up as a source of an ArrayStoreException"; - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); throw new ArrayStoreException(value.getClass().getTypeName()); } /** Foreign call: {@link #THROW_NEW_INCOMPATIBLE_CLASS_CHANGE_ERROR}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwNewIncompatibleClassChangeError() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); throw new IncompatibleClassChangeError(); } /** Foreign call: {@link #THROW_NEW_ILLEGAL_ARGUMENT_EXCEPTION_WITH_ARGS}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwNewIllegalArgumentExceptionWithArgs(String message) { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); throw new IllegalArgumentException(message); } /** Foreign call: {@link #THROW_NEW_NEGATIVE_ARRAY_SIZE_EXCEPTION}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwNewNegativeArraySizeException(int length) { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); throw new NegativeArraySizeException(String.valueOf(length)); } /** Foreign call: {@link #THROW_NEW_ARITHMETIC_EXCEPTION}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwNewArithmeticException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); throw new ArithmeticException(); } /** Foreign call: {@link #THROW_NEW_DIVISION_BY_ZERO_EXCEPTION}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwNewDivisionByZeroException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); throw new ArithmeticException("/ by zero"); } /** Foreign call: {@link #THROW_NEW_INTEGER_OVERFLOW_EXCEPTION}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwNewIntegerOverflowException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); throw new ArithmeticException("integer overflow"); } /** Foreign call: {@link #THROW_NEW_LONG_OVERFLOW_EXCEPTION}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwNewLongOverflowException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); throw new ArithmeticException("long overflow"); } /** Foreign call: {@link #THROW_NEW_ASSERTION_ERROR_NULLARY}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwNewAssertionErrorNullary() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); throw new AssertionError(); } /** Foreign call: {@link #THROW_NEW_ASSERTION_ERROR_OBJECT}. */ @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwNewAssertionErrorObject(Object detailMessage) { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(false); throw new AssertionError(detailMessage); } @@ -394,7 +397,7 @@ private static void throwNewAssertionErrorObject(Object detailMessage) { @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Called to report an implicit exception in code that must not allocate.") @SubstrateForeignCallTarget(stubCallingConvention = true) private static NullPointerException getCachedNullPointerException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(true); return CACHED_NULL_POINTER_EXCEPTION; } @@ -402,7 +405,7 @@ private static NullPointerException getCachedNullPointerException() { @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Called to report an implicit exception in code that must not allocate.") @SubstrateForeignCallTarget(stubCallingConvention = true) private static ArrayIndexOutOfBoundsException getCachedOutOfBoundsException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(true); return CACHED_OUT_OF_BOUNDS_EXCEPTION; } @@ -410,7 +413,7 @@ private static ArrayIndexOutOfBoundsException getCachedOutOfBoundsException() { @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Called to report an implicit exception in code that must not allocate.") @SubstrateForeignCallTarget(stubCallingConvention = true) private static ClassCastException getCachedClassCastException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(true); return CACHED_CLASS_CAST_EXCEPTION; } @@ -418,7 +421,7 @@ private static ClassCastException getCachedClassCastException() { @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Called to report an implicit exception in code that must not allocate.") @SubstrateForeignCallTarget(stubCallingConvention = true) private static ArrayStoreException getCachedArrayStoreException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(true); return CACHED_ARRAY_STORE_EXCEPTION; } @@ -426,7 +429,7 @@ private static ArrayStoreException getCachedArrayStoreException() { @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Called to report an implicit exception in code that must not allocate.") @SubstrateForeignCallTarget(stubCallingConvention = true) private static IncompatibleClassChangeError getCachedIncompatibleClassChangeError() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(true); return CACHED_INCOMPATIBLE_CLASS_CHANGE_ERROR; } @@ -434,7 +437,7 @@ private static IncompatibleClassChangeError getCachedIncompatibleClassChangeErro @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Called to report an implicit exception in code that must not allocate.") @SubstrateForeignCallTarget(stubCallingConvention = true) private static IllegalArgumentException getCachedIllegalArgumentException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(true); return CACHED_ILLEGAL_ARGUMENT_EXCEPTION; } @@ -442,7 +445,7 @@ private static IllegalArgumentException getCachedIllegalArgumentException() { @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Called to report an implicit exception in code that must not allocate.") @SubstrateForeignCallTarget(stubCallingConvention = true) private static NegativeArraySizeException getCachedNegativeArraySizeException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(true); return CACHED_NEGATIVE_ARRAY_SIZE_EXCEPTION; } @@ -450,7 +453,7 @@ private static NegativeArraySizeException getCachedNegativeArraySizeException() @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Called to report an implicit exception in code that must not allocate.") @SubstrateForeignCallTarget(stubCallingConvention = true) private static ArithmeticException getCachedArithmeticException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(true); return CACHED_ARITHMETIC_EXCEPTION; } @@ -458,7 +461,7 @@ private static ArithmeticException getCachedArithmeticException() { @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Called to report an implicit exception in code that must not allocate.") @SubstrateForeignCallTarget(stubCallingConvention = true) private static AssertionError getCachedAssertionError() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(true); return CACHED_ASSERTION_ERROR; } @@ -466,7 +469,7 @@ private static AssertionError getCachedAssertionError() { @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Called to report an implicit exception in code that must not allocate.") @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwCachedNullPointerException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(true); throw CACHED_NULL_POINTER_EXCEPTION; } @@ -474,7 +477,7 @@ private static void throwCachedNullPointerException() { @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Called to report an implicit exception in code that must not allocate.") @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwCachedOutOfBoundsException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(true); throw CACHED_OUT_OF_BOUNDS_EXCEPTION; } @@ -482,7 +485,7 @@ private static void throwCachedOutOfBoundsException() { @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Called to report an implicit exception in code that must not allocate.") @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwCachedClassCastException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(true); throw CACHED_CLASS_CAST_EXCEPTION; } @@ -490,7 +493,7 @@ private static void throwCachedClassCastException() { @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Called to report an implicit exception in code that must not allocate.") @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwCachedArrayStoreException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(true); throw CACHED_ARRAY_STORE_EXCEPTION; } @@ -498,7 +501,7 @@ private static void throwCachedArrayStoreException() { @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Called to report an implicit exception in code that must not allocate.") @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwCachedIncompatibleClassChangeError() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(true); throw CACHED_INCOMPATIBLE_CLASS_CHANGE_ERROR; } @@ -506,7 +509,7 @@ private static void throwCachedIncompatibleClassChangeError() { @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Called to report an implicit exception in code that must not allocate.") @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwCachedIllegalArgumentException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(true); throw CACHED_ILLEGAL_ARGUMENT_EXCEPTION; } @@ -514,7 +517,7 @@ private static void throwCachedIllegalArgumentException() { @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Called to report an implicit exception in code that must not allocate.") @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwCachedNegativeArraySizeException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(true); throw CACHED_NEGATIVE_ARRAY_SIZE_EXCEPTION; } @@ -522,7 +525,7 @@ private static void throwCachedNegativeArraySizeException() { @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Called to report an implicit exception in code that must not allocate.") @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwCachedArithmeticException() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(true); throw CACHED_ARITHMETIC_EXCEPTION; } @@ -530,7 +533,7 @@ private static void throwCachedArithmeticException() { @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Called to report an implicit exception in code that must not allocate.") @SubstrateForeignCallTarget(stubCallingConvention = true) private static void throwCachedAssertionError() { - vmErrorIfImplicitExceptionsAreFatal(); + vmErrorIfImplicitExceptionsAreFatal(true); throw CACHED_ASSERTION_ERROR; } From ca1ea97ae4677d0d796b9b00520d960858aa8306 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 29 Feb 2024 18:48:21 +0000 Subject: [PATCH 77/78] [GR-52326] Backport to 23.0: Deopt loops in NetSuite JS code. PullRequest: js/3071 --- vm/mx.vm/suite.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index 23304a188343..cca02c588472 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -39,7 +39,7 @@ "name": "graal-nodejs", "subdir": True, "dynamic": True, - "version": "4cef57015938f2c58666df5d199221ec1f54edd7", + "version": "f08d6e3aff29e31bcc9bc324a44c592f98ecab3c", "urls" : [ {"url" : "https://github.com/graalvm/graaljs.git", "kind" : "git"}, {"url": "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind": "binary"}, @@ -49,7 +49,7 @@ "name": "graal-js", "subdir": True, "dynamic": True, - "version": "4cef57015938f2c58666df5d199221ec1f54edd7", + "version": "f08d6e3aff29e31bcc9bc324a44c592f98ecab3c", "urls": [ {"url": "https://github.com/graalvm/graaljs.git", "kind" : "git"}, {"url": "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind": "binary"}, From f01c5530ba6eaab89218dd9c43da99641f2bda12 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Thu, 29 Feb 2024 14:17:49 +0000 Subject: [PATCH 78/78] update to jvmci-23.0-b33 --- common.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common.json b/common.json index 378a46e97e33..1ff7f6a519a4 100644 --- a/common.json +++ b/common.json @@ -14,9 +14,9 @@ "labsjdk-ce-17": {"name": "labsjdk", "version": "ce-17.0.9+9-jvmci-23.0-b22", "platformspecific": true }, "labsjdk-ce-17Debug": {"name": "labsjdk", "version": "ce-17.0.9+9-jvmci-23.0-b22-debug", "platformspecific": true }, "labsjdk-ce-17-llvm": {"name": "labsjdk", "version": "ce-17.0.9+9-jvmci-23.0-b22-sulong", "platformspecific": true }, - "labsjdk-ee-17": {"name": "labsjdk", "version": "ee-17.0.11+5-jvmci-23.0-b32", "platformspecific": true }, - "labsjdk-ee-17Debug": {"name": "labsjdk", "version": "ee-17.0.11+5-jvmci-23.0-b32-debug", "platformspecific": true }, - "labsjdk-ee-17-llvm": {"name": "labsjdk", "version": "ee-17.0.11+5-jvmci-23.0-b32-sulong", "platformspecific": true }, + "labsjdk-ee-17": {"name": "labsjdk", "version": "ee-17.0.11+6-jvmci-23.0-b33", "platformspecific": true }, + "labsjdk-ee-17Debug": {"name": "labsjdk", "version": "ee-17.0.11+6-jvmci-23.0-b33-debug", "platformspecific": true }, + "labsjdk-ee-17-llvm": {"name": "labsjdk", "version": "ee-17.0.11+6-jvmci-23.0-b33-sulong", "platformspecific": true }, "oraclejdk19": {"name": "jpg-jdk", "version": "19", "build_id": "26", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, "labsjdk-ce-19": {"name": "labsjdk", "version": "ce-19.0.1+10-jvmci-23.0-b04", "platformspecific": true },