Skip to content

Commit 1cb5d89

Browse files
authored
Merge pull request #145 from bulasevich/GR-63266-2
[Backport] [Oracle GraalVM] [GR-63266] Backport to 23.1: Prevent absent hashcode computation split across safepoint checks.
2 parents 31dd718 + a989753 commit 1cb5d89

File tree

4 files changed

+51
-21
lines changed

4 files changed

+51
-21
lines changed

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

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -194,18 +194,14 @@ void setIdentityHashInField(Object o) {
194194
@Uninterruptible(reason = "Prevent a GC interfering with the object's identity hash state.", callerMustBe = true)
195195
@Override
196196
public void setIdentityHashFromAddress(Pointer ptr, Word currentHeader) {
197-
if (GraalDirectives.inIntrinsic()) {
198-
ReplacementsUtil.staticAssert(!hasFixedIdentityHashField(), "must always access field");
199-
} else {
200-
VMError.guarantee(!hasFixedIdentityHashField());
201-
assert !hasIdentityHashFromAddress(currentHeader);
202-
}
197+
VMError.guarantee(!hasFixedIdentityHashField());
198+
assert !hasIdentityHashFromAddress(currentHeader) : "must not already have a hashcode";
199+
203200
UnsignedWord fromAddressState = IDHASH_STATE_FROM_ADDRESS.shiftLeft(IDHASH_STATE_SHIFT);
204201
UnsignedWord newHeader = currentHeader.and(IDHASH_STATE_BITS.not()).or(fromAddressState);
205202
writeHeaderToObject(ptr.toObjectNonNull(), newHeader);
206-
if (!GraalDirectives.inIntrinsic()) {
207-
assert hasIdentityHashFromAddress(readHeaderFromObject(ptr));
208-
}
203+
204+
assert hasIdentityHashFromAddress(readHeaderFromPointer(ptr));
209205
}
210206

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

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
import com.oracle.svm.core.config.ConfigurationValues;
4141
import com.oracle.svm.core.config.ObjectLayout;
4242
import com.oracle.svm.core.heap.Heap;
43+
import com.oracle.svm.core.heap.ObjectHeader;
44+
import com.oracle.svm.core.hub.LayoutEncoding;
4345
import com.oracle.svm.core.snippets.SubstrateForeignCallTarget;
4446
import com.oracle.svm.core.threadlocal.FastThreadLocalFactory;
4547
import com.oracle.svm.core.threadlocal.FastThreadLocalObject;
@@ -83,6 +85,34 @@ public static int generateIdentityHashCode(Object obj) {
8385
return newHashCode;
8486
}
8587

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

2727
import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.LIKELY_PROBABILITY;
28-
import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY;
2928
import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY;
3029
import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
3130

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

54+
static final SubstrateForeignCallDescriptor COMPUTE_ABSENT_IDENTITY_HASH_CODE = SnippetRuntime.findForeignCall(
55+
IdentityHashCodeSupport.class, "computeAbsentIdentityHashCode", true);
56+
5557
static Templates createTemplates(OptionValues options, Providers providers) {
5658
return new Templates(new SubstrateIdentityHashCodeSnippets(), options, providers, IdentityHashCodeSupport.IDENTITY_HASHCODE_LOCATION);
5759
}
@@ -64,26 +66,21 @@ protected int computeIdentityHashCode(Object obj) {
6466
int offset = ol.getFixedIdentityHashOffset();
6567
identityHashCode = ObjectAccess.readInt(obj, offset, IdentityHashCodeSupport.IDENTITY_HASHCODE_LOCATION);
6668
if (probability(SLOW_PATH_PROBABILITY, identityHashCode == 0)) {
67-
identityHashCode = generateIdentityHashCode(GENERATE_IDENTITY_HASH_CODE, obj);
69+
identityHashCode = foreignCall(GENERATE_IDENTITY_HASH_CODE, obj);
6870
}
6971
return identityHashCode;
7072
}
7173
ObjectHeader oh = Heap.getHeap().getObjectHeader();
72-
Word objPtr = Word.objectToUntrackedPointer(obj);
73-
Word header = ObjectHeader.readHeaderFromPointer(objPtr);
74+
Word header = ObjectHeader.readHeaderFromObject(obj);
7475
if (probability(LIKELY_PROBABILITY, oh.hasOptionalIdentityHashField(header))) {
7576
int offset = LayoutEncoding.getOptionalIdentityHashOffset(obj);
7677
identityHashCode = ObjectAccess.readInt(obj, offset, IdentityHashCodeSupport.IDENTITY_HASHCODE_LOCATION);
7778
} else {
78-
identityHashCode = IdentityHashCodeSupport.computeHashCodeFromAddress(obj);
79-
if (probability(NOT_FREQUENT_PROBABILITY, !oh.hasIdentityHashFromAddress(header))) {
80-
// Note this write leads to frame state issues that break scheduling if done earlier
81-
oh.setIdentityHashFromAddress(objPtr, header);
82-
}
79+
identityHashCode = foreignCall(COMPUTE_ABSENT_IDENTITY_HASH_CODE, obj);
8380
}
8481
return identityHashCode;
8582
}
8683

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

0 commit comments

Comments
 (0)