Skip to content

Commit 82e0f67

Browse files
committed
[GR-62966] Prevent absent hashcode computation split across safepoint checks.
PullRequest: graal/20298
2 parents 690c6e9 + ef8f051 commit 82e0f67

File tree

4 files changed

+49
-21
lines changed

4 files changed

+49
-21
lines changed

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ObjectHeaderImpl.java

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -197,19 +197,14 @@ void setIdentityHashInField(Object o) {
197197
@Uninterruptible(reason = "Prevent a GC interfering with the object's identity hash state.", callerMustBe = true)
198198
@Override
199199
public void setIdentityHashFromAddress(Pointer ptr, Word currentHeader) {
200-
if (GraalDirectives.inIntrinsic()) {
201-
ReplacementsUtil.staticAssert(isIdentityHashFieldOptional(), "use only when hashcode fields are optional");
202-
} else {
203-
assert isIdentityHashFieldOptional() : "use only when hashcode fields are optional";
204-
assert !hasIdentityHashFromAddress(currentHeader) : "must not already have a hashcode";
205-
}
200+
assert isIdentityHashFieldOptional() : "use only when hashcode fields are optional";
201+
assert !hasIdentityHashFromAddress(currentHeader) : "must not already have a hashcode";
206202

207203
UnsignedWord fromAddressState = IDHASH_STATE_FROM_ADDRESS.shiftLeft(IDHASH_STATE_SHIFT);
208204
UnsignedWord newHeader = currentHeader.and(IDHASH_STATE_BITS.not()).or(fromAddressState);
209205
writeHeaderToObject(ptr.toObjectNonNull(), newHeader);
210-
if (!GraalDirectives.inIntrinsic()) {
211-
assert hasIdentityHashFromAddress(readHeaderFromObject(ptr));
212-
}
206+
207+
assert hasIdentityHashFromAddress(readHeaderFromPointer(ptr));
213208
}
214209

215210
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/identityhashcode/IdentityHashCodeSupport.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import com.oracle.svm.core.config.ConfigurationValues;
3434
import com.oracle.svm.core.config.ObjectLayout;
3535
import com.oracle.svm.core.heap.Heap;
36+
import com.oracle.svm.core.heap.ObjectHeader;
3637
import com.oracle.svm.core.hub.LayoutEncoding;
3738
import com.oracle.svm.core.snippets.SubstrateForeignCallTarget;
3839
import com.oracle.svm.core.threadlocal.FastThreadLocalFactory;
@@ -85,6 +86,34 @@ public static int generateIdentityHashCode(Object obj) {
8586
return newHashCode;
8687
}
8788

89+
@SubstrateForeignCallTarget(stubCallingConvention = false)
90+
@Uninterruptible(reason = "Prevent a GC interfering with the object's identity hash state.")
91+
public static int computeAbsentIdentityHashCode(Object obj) {
92+
/*
93+
* This code must not be inlined into the snippet because it could be used in an
94+
* interruptible method: the individual reads and writes of the object header and hash salt
95+
* could be independently spread across a safepoint check where a GC could happen, during
96+
* which addresses, header or salt can change. This could cause inconsistent hash values,
97+
* corrupted object headers (when modified by GC), or memory corruption and crashes (when
98+
* writing the object header to the object's previous location after is has been moved).
99+
*/
100+
ObjectHeader oh = Heap.getHeap().getObjectHeader();
101+
Word objPtr = Word.objectToUntrackedPointer(obj);
102+
Word header = ObjectHeader.readHeaderFromPointer(objPtr);
103+
if (oh.hasOptionalIdentityHashField(header)) {
104+
/*
105+
* Between the snippet and execution of this method, another thread could have set the
106+
* header bit and a GC could have triggered and added the field.
107+
*/
108+
int offset = LayoutEncoding.getIdentityHashOffset(obj);
109+
return ObjectAccess.readInt(obj, offset, IdentityHashCodeSupport.IDENTITY_HASHCODE_LOCATION);
110+
}
111+
if (!oh.hasIdentityHashFromAddress(header)) {
112+
oh.setIdentityHashFromAddress(objPtr, header);
113+
}
114+
return computeHashCodeFromAddress(obj);
115+
}
116+
88117
@Uninterruptible(reason = "Prevent a GC interfering with the object's identity hash state.")
89118
public static int computeHashCodeFromAddress(Object obj) {
90119
Word address = Word.objectToUntrackedPointer(obj);

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/identityhashcode/SubstrateIdentityHashCodeFeature.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,22 @@
2424
*/
2525
package com.oracle.svm.core.identityhashcode;
2626

27+
import com.oracle.svm.core.config.ConfigurationValues;
28+
import com.oracle.svm.core.config.ObjectLayout;
29+
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
2730
import com.oracle.svm.core.feature.InternalFeature;
2831
import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider;
29-
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
3032

3133
@AutomaticallyRegisteredFeature
3234
final class SubstrateIdentityHashCodeFeature implements InternalFeature {
3335

3436
@Override
3537
public void registerForeignCalls(SubstrateForeignCallsProvider foreignCalls) {
36-
foreignCalls.register(SubstrateIdentityHashCodeSnippets.GENERATE_IDENTITY_HASH_CODE);
38+
ObjectLayout ol = ConfigurationValues.getObjectLayout();
39+
if (ol.isIdentityHashFieldOptional()) {
40+
foreignCalls.register(SubstrateIdentityHashCodeSnippets.COMPUTE_ABSENT_IDENTITY_HASH_CODE);
41+
} else {
42+
foreignCalls.register(SubstrateIdentityHashCodeSnippets.GENERATE_IDENTITY_HASH_CODE);
43+
}
3744
}
3845
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/identityhashcode/SubstrateIdentityHashCodeSnippets.java

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626

2727
import static jdk.graal.compiler.core.common.spi.ForeignCallDescriptor.CallSideEffect.NO_SIDE_EFFECT;
2828
import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.LIKELY_PROBABILITY;
29-
import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY;
3029
import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY;
3130
import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.probability;
3231

@@ -53,6 +52,9 @@ final class SubstrateIdentityHashCodeSnippets extends IdentityHashCodeSnippets {
5352
static final SubstrateForeignCallDescriptor GENERATE_IDENTITY_HASH_CODE = SnippetRuntime.findForeignCall(
5453
IdentityHashCodeSupport.class, "generateIdentityHashCode", NO_SIDE_EFFECT, IdentityHashCodeSupport.IDENTITY_HASHCODE_LOCATION);
5554

55+
static final SubstrateForeignCallDescriptor COMPUTE_ABSENT_IDENTITY_HASH_CODE = SnippetRuntime.findForeignCall(
56+
IdentityHashCodeSupport.class, "computeAbsentIdentityHashCode", NO_SIDE_EFFECT);
57+
5658
static Templates createTemplates(OptionValues options, Providers providers) {
5759
return new Templates(new SubstrateIdentityHashCodeSnippets(), options, providers, IdentityHashCodeSupport.IDENTITY_HASHCODE_LOCATION);
5860
}
@@ -63,29 +65,24 @@ protected int computeIdentityHashCode(Object obj) {
6365
if (ol.isIdentityHashFieldOptional()) {
6466
int identityHashCode;
6567
ObjectHeader oh = Heap.getHeap().getObjectHeader();
66-
Word objPtr = Word.objectToUntrackedPointer(obj);
67-
Word header = ObjectHeader.readHeaderFromPointer(objPtr);
68+
Word header = ObjectHeader.readHeaderFromObject(obj);
6869
if (probability(LIKELY_PROBABILITY, oh.hasOptionalIdentityHashField(header))) {
6970
int offset = LayoutEncoding.getIdentityHashOffset(obj);
7071
identityHashCode = ObjectAccess.readInt(obj, offset, IdentityHashCodeSupport.IDENTITY_HASHCODE_LOCATION);
7172
} else {
72-
identityHashCode = IdentityHashCodeSupport.computeHashCodeFromAddress(obj);
73-
if (probability(NOT_FREQUENT_PROBABILITY, !oh.hasIdentityHashFromAddress(header))) {
74-
// This write leads to frame state issues that break scheduling if done earlier
75-
oh.setIdentityHashFromAddress(objPtr, header);
76-
}
73+
identityHashCode = foreignCall(COMPUTE_ABSENT_IDENTITY_HASH_CODE, obj);
7774
}
7875
return identityHashCode;
7976
}
8077

8178
int offset = LayoutEncoding.getIdentityHashOffset(obj);
8279
int identityHashCode = ObjectAccess.readInt(obj, offset, IdentityHashCodeSupport.IDENTITY_HASHCODE_LOCATION);
8380
if (probability(SLOW_PATH_PROBABILITY, identityHashCode == 0)) {
84-
identityHashCode = generateIdentityHashCode(GENERATE_IDENTITY_HASH_CODE, obj);
81+
identityHashCode = foreignCall(GENERATE_IDENTITY_HASH_CODE, obj);
8582
}
8683
return identityHashCode;
8784
}
8885

8986
@NodeIntrinsic(ForeignCallNode.class)
90-
private static native int generateIdentityHashCode(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object obj);
87+
private static native int foreignCall(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object obj);
9188
}

0 commit comments

Comments
 (0)