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