Skip to content

Commit cc8444a

Browse files
[GR-71261] [GR-71478] Fold reads from stable arrays.
PullRequest: graal/22578
2 parents ff0e899 + 38db208 commit cc8444a

File tree

12 files changed

+265
-83
lines changed

12 files changed

+265
-83
lines changed

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/common/type/PrimitiveStamp.java

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424
*/
2525
package jdk.graal.compiler.core.common.type;
2626

27-
import jdk.graal.compiler.debug.GraalError;
28-
2927
import jdk.vm.ci.meta.Constant;
3028
import jdk.vm.ci.meta.JavaConstant;
3129
import jdk.vm.ci.meta.MemoryAccessProvider;
@@ -62,12 +60,6 @@ public static int getBits(Stamp stamp) {
6260
}
6361
}
6462

65-
private static boolean isAligned(long displacement, int numBits) {
66-
GraalError.guarantee((numBits & 7) == 0, "numBits not a multiple of 8: %d", numBits);
67-
int numBytes = numBits / 8;
68-
return displacement % numBytes == 0;
69-
}
70-
7163
@Override
7264
public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) {
7365
return readJavaConstant(provider, base, displacement, getBits());
@@ -77,10 +69,6 @@ public Constant readConstant(MemoryAccessProvider provider, Constant base, long
7769
* @param accessBits the number of bits to read from memory (must be 8, 16, 32 or 64)
7870
*/
7971
protected JavaConstant readJavaConstant(MemoryAccessProvider provider, Constant base, long displacement, int accessBits) {
80-
if (!isAligned(displacement, accessBits)) {
81-
// Avoid crash when performing unaligned reads (JDK-8275645)
82-
return null;
83-
}
8472
try {
8573
return provider.readPrimitiveConstant(getStackKind(), base, displacement, accessBits);
8674
} catch (IllegalArgumentException e) {

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapConstant.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ public ConstantData getConstantData() {
149149
return constantData;
150150
}
151151

152+
/** Only relevant for object data, as snapshotting doesn't happen eagerly there. */
152153
public void ensureReaderInstalled() {
153154
if (constantData.hostedValuesReader != null) {
154155
constantData.hostedValuesReader.ensureDone();

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoDecoder.java

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
*/
2525
package com.oracle.svm.core.code;
2626

27+
import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE;
2728
import static com.oracle.svm.core.code.CodeInfoDecoder.FrameInfoState.NO_SUCCESSOR_INDEX_MARKER;
2829

2930
import java.util.Arrays;
@@ -505,6 +506,7 @@ private static ValueInfo[] decodeValues(ValueInfoAllocator valueInfoAllocator, C
505506
valueInfo.kind = extractKind(flags);
506507
valueInfo.isCompressedReference = extractIsCompressedReference(flags);
507508
valueInfo.isEliminatedMonitor = extractIsEliminatedMonitor(flags);
509+
valueInfo.isAutoBoxedPrimitive = extractIsAutoBoxedPrimitive(flags);
508510
}
509511
if (valueType.hasData) {
510512
long valueInfoData = readBuffer.getSV();
@@ -574,44 +576,56 @@ public static void logReadableBci(Log log, long encodedBci) {
574576
protected static final int KIND_SHIFT = TYPE_SHIFT + TYPE_BITS;
575577
protected static final int KIND_MASK_IN_PLACE = ((1 << KIND_BITS) - 1) << KIND_SHIFT;
576578

577-
/**
578-
* Value not used by {@link JavaKind} as a marker for eliminated monitors. The kind of a monitor
579-
* is always {@link JavaKind#Object}.
580-
*/
581-
protected static final int IS_ELIMINATED_MONITOR_KIND_VALUE = 15;
579+
/* Repurpose unused {@link JavaKind} ordinal values as markers for special object values. */
580+
protected static final int AUTOBOXED_PRIMITIVE_KIND_INDEX = 14;
581+
protected static final int ELIMINATED_MONITOR_KIND_INDEX = 15;
582582

583583
protected static final int IS_COMPRESSED_REFERENCE_BITS = 1;
584584
protected static final int IS_COMPRESSED_REFERENCE_SHIFT = KIND_SHIFT + KIND_BITS;
585585
protected static final int IS_COMPRESSED_REFERENCE_MASK_IN_PLACE = ((1 << IS_COMPRESSED_REFERENCE_BITS) - 1) << IS_COMPRESSED_REFERENCE_SHIFT;
586586

587-
protected static final JavaKind[] KIND_VALUES;
588-
589-
static {
590-
KIND_VALUES = Arrays.copyOf(JavaKind.values(), IS_ELIMINATED_MONITOR_KIND_VALUE + 1);
591-
assert KIND_VALUES[IS_ELIMINATED_MONITOR_KIND_VALUE] == null;
592-
KIND_VALUES[IS_ELIMINATED_MONITOR_KIND_VALUE] = JavaKind.Object;
593-
}
587+
protected static final JavaKind[] KIND_VALUES = createJavaKindArray();
594588

595589
/* Allow allocation-free access to ValueType values */
596590
private static final ValueType[] ValueTypeValues = ValueType.values();
597591

598-
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
592+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
599593
private static ValueType extractType(int flags) {
600594
return ValueTypeValues[(flags & TYPE_MASK_IN_PLACE) >> TYPE_SHIFT];
601595
}
602596

603-
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
597+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
604598
private static JavaKind extractKind(int flags) {
605-
return KIND_VALUES[(flags & KIND_MASK_IN_PLACE) >> KIND_SHIFT];
599+
return KIND_VALUES[extractKindIndex(flags)];
606600
}
607601

608-
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
602+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
609603
private static boolean extractIsCompressedReference(int flags) {
610604
return (flags & IS_COMPRESSED_REFERENCE_MASK_IN_PLACE) != 0;
611605
}
612606

613-
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
607+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
614608
private static boolean extractIsEliminatedMonitor(int flags) {
615-
return ((flags & KIND_MASK_IN_PLACE) >> KIND_SHIFT) == IS_ELIMINATED_MONITOR_KIND_VALUE;
609+
return extractKindIndex(flags) == ELIMINATED_MONITOR_KIND_INDEX;
610+
}
611+
612+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
613+
private static boolean extractIsAutoBoxedPrimitive(int flags) {
614+
return extractKindIndex(flags) == AUTOBOXED_PRIMITIVE_KIND_INDEX;
615+
}
616+
617+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
618+
private static int extractKindIndex(int flags) {
619+
return (flags & KIND_MASK_IN_PLACE) >> KIND_SHIFT;
620+
}
621+
622+
private static JavaKind[] createJavaKindArray() {
623+
JavaKind[] result = Arrays.copyOf(JavaKind.values(), ELIMINATED_MONITOR_KIND_INDEX + 1);
624+
assert result[AUTOBOXED_PRIMITIVE_KIND_INDEX] == null;
625+
assert result[ELIMINATED_MONITOR_KIND_INDEX] == null;
626+
627+
result[AUTOBOXED_PRIMITIVE_KIND_INDEX] = JavaKind.Object;
628+
result[ELIMINATED_MONITOR_KIND_INDEX] = JavaKind.Object;
629+
return result;
616630
}
617631
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoEncoder.java

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,7 @@ private ValueInfo makeValueInfo(FrameData data, JavaKind kind, JavaValue v, bool
700700
} else if (ValueUtil.isVirtualObject(value)) {
701701
VirtualObject virtualObject = (VirtualObject) value;
702702
result.type = ValueType.VirtualObject;
703+
result.isAutoBoxedPrimitive = virtualObject.isAutoBox();
703704
result.data = virtualObject.getId();
704705
makeVirtualObject(data, virtualObject, isDeoptEntry);
705706
} else {
@@ -979,7 +980,7 @@ private void encodeValues(ValueInfo[] valueInfos, UnsafeArrayTypeWriter encoding
979980
}
980981
}
981982

982-
encodingBuffer.putU1(encodeFlags(valueInfo.type, valueInfo.kind, valueInfo.isCompressedReference, valueInfo.isEliminatedMonitor));
983+
encodingBuffer.putU1(encodeFlags(valueInfo));
983984
if (valueInfo.type.hasData) {
984985
encodingBuffer.putSV(valueInfo.data);
985986
}
@@ -994,13 +995,24 @@ protected static long encodePrimitiveConstant(JavaConstant constant) {
994995
};
995996
}
996997

997-
private static int encodeFlags(ValueType type, JavaKind kind, boolean isCompressedReference, boolean isEliminatedMonitor) {
998-
int kindIndex = isEliminatedMonitor ? FrameInfoDecoder.IS_ELIMINATED_MONITOR_KIND_VALUE : kind.ordinal();
999-
assert FrameInfoDecoder.KIND_VALUES[kindIndex] == kind : kind;
998+
private static int encodeFlags(ValueInfo valueInfo) {
999+
int encodedType = valueInfo.getType().ordinal() << FrameInfoDecoder.TYPE_SHIFT;
1000+
int encodedJavaKind = convertJavaKindToInt(valueInfo) << FrameInfoDecoder.KIND_SHIFT;
1001+
int isCompressedReference = (valueInfo.isCompressedReference() ? 1 : 0) << FrameInfoDecoder.IS_COMPRESSED_REFERENCE_SHIFT;
1002+
return encodedType | encodedJavaKind | isCompressedReference;
1003+
}
10001004

1001-
return (type.ordinal() << FrameInfoDecoder.TYPE_SHIFT) |
1002-
(kindIndex << FrameInfoDecoder.KIND_SHIFT) |
1003-
((isCompressedReference ? 1 : 0) << FrameInfoDecoder.IS_COMPRESSED_REFERENCE_SHIFT);
1005+
private static int convertJavaKindToInt(ValueInfo valueInfo) {
1006+
if (valueInfo.isEliminatedMonitor()) {
1007+
assert valueInfo.getKind() == JavaKind.Object;
1008+
assert !valueInfo.isAutoBoxedPrimitive();
1009+
return FrameInfoDecoder.ELIMINATED_MONITOR_KIND_INDEX;
1010+
} else if (valueInfo.isAutoBoxedPrimitive()) {
1011+
assert valueInfo.getKind() == JavaKind.Object;
1012+
return FrameInfoDecoder.AUTOBOXED_PRIMITIVE_KIND_INDEX;
1013+
} else {
1014+
return valueInfo.getKind().ordinal();
1015+
}
10041016
}
10051017

10061018
/**
@@ -1110,6 +1122,7 @@ private static void verifyValues(ValueInfo[] expectedValues, ValueInfo[] actualV
11101122
assert expectedValue.kind.equals(actualValue.kind) : actualValue;
11111123
assert expectedValue.isCompressedReference == actualValue.isCompressedReference : actualValue;
11121124
assert expectedValue.isEliminatedMonitor == actualValue.isEliminatedMonitor : actualValue;
1125+
assert expectedValue.isAutoBoxedPrimitive == actualValue.isAutoBoxedPrimitive : actualValue;
11131126
assert expectedValue.data == actualValue.data : actualValue;
11141127
verifyConstant(expectedValue.value, actualValue.value);
11151128
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoQueryResult.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ public static final class ValueInfo {
110110
protected JavaKind kind;
111111
protected boolean isCompressedReference; // for JavaKind.Object
112112
protected boolean isEliminatedMonitor;
113+
protected boolean isAutoBoxedPrimitive;
113114
protected long data;
114115
protected JavaConstant value;
115116

@@ -144,6 +145,14 @@ public boolean isEliminatedMonitor() {
144145
return isEliminatedMonitor;
145146
}
146147

148+
/**
149+
* Returns true if this is an automatically boxed primitive (i.e., a method like
150+
* {@link Integer#valueOf} should be used to produce the value).
151+
*/
152+
public boolean isAutoBoxedPrimitive() {
153+
return isAutoBoxedPrimitive;
154+
}
155+
147156
/**
148157
* Returns additional data for the value, according to the specification in
149158
* {@link ValueType}.
@@ -172,6 +181,7 @@ public ValueInfo copyForElement(JavaKind javaKind, int offset) {
172181
copy.kind = javaKind;
173182
copy.isCompressedReference = isCompressedReference;
174183
copy.isEliminatedMonitor = isEliminatedMonitor;
184+
copy.isAutoBoxedPrimitive = isAutoBoxedPrimitive;
175185
copy.data = data + offset;
176186
copy.value = value;
177187
return copy;

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/DeoptState.java

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838

3939
import com.oracle.svm.core.ReservedRegisters;
4040
import com.oracle.svm.core.code.FrameInfoQueryResult;
41+
import com.oracle.svm.core.code.FrameInfoQueryResult.ValueType;
4142
import com.oracle.svm.core.config.ConfigurationValues;
4243
import com.oracle.svm.core.config.ObjectLayout;
4344
import com.oracle.svm.core.heap.ReferenceAccess;
@@ -118,7 +119,7 @@ protected JavaConstant readValue(FrameInfoQueryResult.ValueInfo valueInfo, Frame
118119
}
119120

120121
case VirtualObject:
121-
Object obj = materializeObject(TypeConversion.asS4(valueInfo.getData()), sourceFrame);
122+
Object obj = materializeObject(valueInfo, sourceFrame);
122123
return SubstrateObjectConstant.forObject(obj, valueInfo.isCompressedReference());
123124
case Illegal:
124125
return JavaConstant.forIllegal();
@@ -135,52 +136,75 @@ private static PrimitiveConstant createWordConstant(WordBase word) {
135136
return JavaConstant.forIntegerKind(ConfigurationValues.getWordKind(), word.rawValue());
136137
}
137138

138-
/**
139-
* Materializes a virtual object.
140-
*
141-
* @param virtualObjectId the id of the virtual object to materialize
142-
* @return the materialized object
143-
*/
144-
private Object materializeObject(int virtualObjectId, FrameInfoQueryResult sourceFrame) {
139+
private Object materializeObject(FrameInfoQueryResult.ValueInfo valueInfo, FrameInfoQueryResult sourceFrame) {
140+
assert valueInfo.getType() == ValueType.VirtualObject;
145141
if (materializedObjects == null) {
146142
materializedObjects = new Object[sourceFrame.getVirtualObjects().length];
147143
}
148144
if (materializedObjects.length != sourceFrame.getVirtualObjects().length) {
149145
throw fatalDeoptimizationError(String.format("MaterializedObjects length (%s) does not match sourceFrame", materializedObjects.length), sourceFrame);
150146
}
151147

148+
/* Check if the object was already materialized earlier. */
149+
int virtualObjectId = TypeConversion.asS4(valueInfo.getData());
152150
Object obj = materializedObjects[virtualObjectId];
153151
if (obj != null) {
154152
return obj;
155153
}
154+
155+
/* Materialize the object. */
156+
return materializeObject0(valueInfo, virtualObjectId, sourceFrame);
157+
}
158+
159+
private Object materializeObject0(FrameInfoQueryResult.ValueInfo valueInfo, int virtualObjectId, FrameInfoQueryResult sourceFrame) {
156160
DeoptimizationCounters.counters().virtualObjectsCount.inc();
157161

158162
FrameInfoQueryResult.ValueInfo[] encodings = sourceFrame.getVirtualObjects()[virtualObjectId];
159-
DynamicHub hub = (DynamicHub) SubstrateObjectConstant.asObject(readValue(encodings[0], sourceFrame));
160163
ObjectLayout objectLayout = ConfigurationValues.getObjectLayout();
161164

162-
int curIdx;
165+
/* The first encoded value is always the hub. */
166+
DynamicHub hub = (DynamicHub) SubstrateObjectConstant.asObject(readValue(encodings[0], sourceFrame));
167+
assert hub != null;
168+
int curIdx = 1;
169+
170+
Object obj;
163171
UnsignedWord curOffset;
164172
int layoutEncoding = hub.getLayoutEncoding();
165173
if (LayoutEncoding.isArray(layoutEncoding)) {
166174
/* For arrays, the second encoded value is the array length. */
167175
int length = readValue(encodings[1], sourceFrame).asInt();
176+
curIdx++;
177+
178+
/* Allocate an array and zero it. The data will be filled in below. */
168179
obj = Array.newInstance(DynamicHub.toClass(hub.getComponentHub()), length);
169180
curOffset = LayoutEncoding.getArrayBaseOffset(hub.getLayoutEncoding());
170-
curIdx = 2;
171181
} else {
172182
if (!LayoutEncoding.isPureInstance(layoutEncoding)) {
173183
throw fatalDeoptimizationError("Non-pure instance layout encoding: " + layoutEncoding, sourceFrame);
174184
}
175-
try {
176-
obj = Unsafe.getUnsafe().allocateInstance(DynamicHub.toClass(hub));
177-
} catch (InstantiationException ex) {
178-
throw fatalDeoptimizationError("Instantiation exception: " + ex, sourceFrame);
185+
186+
if (valueInfo.isAutoBoxedPrimitive()) {
187+
/*
188+
* For boxed primitives, we need to return a cached object if there is one. Note
189+
* that the encodings array may contain multiple entries for layouting reasons but
190+
* only the last one is relevant.
191+
*/
192+
obj = readValue(encodings[encodings.length - 1], sourceFrame).asBoxedPrimitive();
193+
assert obj.getClass() == DynamicHub.toClass(hub);
194+
materializedObjects[virtualObjectId] = obj;
195+
return obj;
196+
} else {
197+
/* Allocate an instance and zero it. The data will be filled in below. */
198+
try {
199+
obj = Unsafe.getUnsafe().allocateInstance(DynamicHub.toClass(hub));
200+
} catch (InstantiationException ex) {
201+
throw fatalDeoptimizationError("Instantiation exception: " + ex, sourceFrame);
202+
}
179203
}
180204
curOffset = Word.unsigned(objectLayout.getFirstFieldOffset());
181-
curIdx = 1;
182205
}
183206

207+
/* Store the reference before filling the object. This breaks cycles in the object graph. */
184208
materializedObjects[virtualObjectId] = obj;
185209
Deoptimizer.maybeTestGC();
186210

@@ -195,6 +219,7 @@ private Object materializeObject(int virtualObjectId, FrameInfoQueryResult sourc
195219
}
196220
}
197221

222+
/* Fill the object with data (except if we exited early). */
198223
while (curIdx < encodings.length) {
199224
FrameInfoQueryResult.ValueInfo value = encodings[curIdx];
200225
JavaKind kind = value.getKind();
@@ -203,7 +228,6 @@ private Object materializeObject(int virtualObjectId, FrameInfoQueryResult sourc
203228
curOffset = curOffset.add(objectLayout.sizeInBytes(kind));
204229
curIdx++;
205230
}
206-
207231
return obj;
208232
}
209233

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/deopt/Deoptimizer.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1469,7 +1469,7 @@ private VirtualFrame constructTargetFrame(CodeInfoQueryResult targetInfo, FrameI
14691469
case Constant:
14701470
/*
14711471
* The target value was constant propagated. Check that source and target
1472-
* performed the same constant propagation
1472+
* agree on the value.
14731473
*/
14741474
verifyConstant(targetFrame, targetValue, con);
14751475
DeoptimizationCounters.counters().constantValueCount.inc();
@@ -1503,15 +1503,15 @@ private void relockObject(JavaConstant valueConstant) {
15031503
}
15041504

15051505
private void verifyConstant(FrameInfoQueryResult targetFrame, ValueInfo targetValue, JavaConstant source) {
1506-
boolean equal;
15071506
JavaConstant target = deoptState.readValue(targetValue, targetFrame);
15081507
if (source.getJavaKind() == JavaKind.Object && target.getJavaKind() == JavaKind.Object) {
1509-
// Differences in compression are irrelevant, compare only object identities
1510-
equal = (SubstrateObjectConstant.asObject(target) == SubstrateObjectConstant.asObject(source));
1511-
} else {
1512-
equal = source.equals(target);
1513-
}
1514-
if (!equal) {
1508+
/* Differences in compression are irrelevant, compare only object identities. */
1509+
Object t = SubstrateObjectConstant.asObject(target);
1510+
Object s = SubstrateObjectConstant.asObject(source);
1511+
if (t != s) {
1512+
throw fatalDeoptimizationError(String.format("Constants do not match.%nSource: %s%nTarget: %s", s, t), targetFrame);
1513+
}
1514+
} else if (!source.equals(target)) {
15151515
throw fatalDeoptimizationError(String.format("Constants do not match.%nSource: %s%nTarget: %s", source, target), targetFrame);
15161516
}
15171517
}
@@ -1523,7 +1523,7 @@ private void verifyConstant(FrameInfoQueryResult targetFrame, ValueInfo targetVa
15231523
* @param offsetInObj The offset of the instance field or array element
15241524
* @param constant The value to write
15251525
*/
1526-
protected static void writeValueInMaterializedObj(Object materializedObj, UnsignedWord offsetInObj, JavaConstant constant, FrameInfoQueryResult frameInfo) {
1526+
static void writeValueInMaterializedObj(Object materializedObj, UnsignedWord offsetInObj, JavaConstant constant, FrameInfoQueryResult frameInfo) {
15271527
if (offsetInObj.equal(0)) {
15281528
throw fatalDeoptimizationError("offsetInObj is 0. Materialized value would overwrite hub.", frameInfo);
15291529
}

0 commit comments

Comments
 (0)