Skip to content

Commit f22ab63

Browse files
mur47x111gilles-duboscq
authored andcommitted
[GR-45962] Backport: Use markWord::lock_mask_in_place in identity hash code fast path after JDK 18.
PullRequest: graal/14672
2 parents 8a6ccfa + 0844fa8 commit f22ab63

File tree

6 files changed

+62
-26
lines changed

6 files changed

+62
-26
lines changed

compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ public final int logMinObjAlignment() {
223223
public final int markOffset = getFieldOffset("oopDesc::_mark", Integer.class, markWord);
224224
public final int hubOffset = getFieldOffset("oopDesc::_metadata._klass", Integer.class, "Klass*");
225225

226-
public final int prototypeMarkWordOffset = getFieldOffset("Klass::_prototype_header", Integer.class, markWord, -1, JDK < 18);
226+
public final Integer prototypeMarkWordOffset = getFieldOffset("Klass::_prototype_header", Integer.class, markWord, null, JDK < 18);
227227
public final int superCheckOffsetOffset = getFieldOffset("Klass::_super_check_offset", Integer.class, "juint");
228228
public final int secondarySuperCacheOffset = getFieldOffset("Klass::_secondary_super_cache", Integer.class, "Klass*");
229229
public final int secondarySupersOffset = getFieldOffset("Klass::_secondary_supers", Integer.class, "Array<Klass*>*");
@@ -404,13 +404,28 @@ public int threadLastJavaFpOffset() {
404404
public final int frameInterpreterFrameSenderSpOffset = getConstant("frame::interpreter_frame_sender_sp_offset", Integer.class, 0, osArch.equals("amd64"));
405405
public final int frameInterpreterFrameLastSpOffset = getConstant("frame::interpreter_frame_last_sp_offset", Integer.class, 0, osArch.equals("amd64"));
406406

407-
public final int biasedLockMaskInPlace = getConstant(markWordField("biased_lock_mask_in_place"), Integer.class, -1, JDK < 18);
407+
private final Integer biasedLockMaskInPlace = getConstant(markWordField("biased_lock_mask_in_place"), Integer.class, null, JDK < 18);
408+
private final Integer lockMaskInPlace = getConstant(markWordField("lock_mask_in_place"), Integer.class, null, JDK == 20 && jvmciGE(JVMCI_23_0_b12));
409+
410+
public int getLockMaskInPlace() {
411+
if (JDK >= 18) {
412+
if (lockMaskInPlace != null) {
413+
return lockMaskInPlace;
414+
} else {
415+
// This presumes markWord::unlocked_value is non-zero.
416+
return 0;
417+
}
418+
} else {
419+
return biasedLockMaskInPlace;
420+
}
421+
}
422+
408423
public final int ageMaskInPlace = getConstant(markWordField("age_mask_in_place"), Integer.class);
409-
public final int epochMaskInPlace = getConstant(markWordField("epoch_mask_in_place"), Integer.class, -1, JDK < 18);
424+
public final Integer epochMaskInPlace = getConstant(markWordField("epoch_mask_in_place"), Integer.class, null, JDK < 18);
410425

411426
public final int unlockedMask = getConstant(markWordField("unlocked_value"), Integer.class);
412427
public final int monitorMask = getConstant(markWordField("monitor_value"), Integer.class);
413-
public final int biasedLockPattern = getConstant(markWordField("biased_lock_pattern"), Integer.class, -1, JDK < 18);
428+
public final Integer biasedLockPattern = getConstant(markWordField("biased_lock_pattern"), Integer.class, null, JDK < 18);
414429

415430
// This field has no type in vmStructs.cpp
416431
public final int objectMonitorOwner = getFieldOffset("ObjectMonitor::_owner", Integer.class, null);

compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigAccess.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,13 +126,15 @@ protected static String getProperty(String name) {
126126
protected static final Version JVMCI_23_0_b06 = new Version(23, 0, 6);
127127
protected static final Version JVMCI_23_0_b07 = new Version(23, 0, 7);
128128
protected static final Version JVMCI_23_0_b10 = new Version(23, 0, 10);
129+
protected static final Version JVMCI_23_0_b12 = new Version(23, 0, 12);
129130

130131
public static boolean jvmciGE(Version v) {
131132
return JVMCI && !JVMCI_VERSION.isLessThan(v);
132133
}
133134

134-
static final int JDK = Runtime.version().feature();
135+
public static final int JDK = Runtime.version().feature();
135136
static final int JDK_UPDATE = Runtime.version().update();
137+
static final int JDK_BUILD = Runtime.version().build().orElse(0);
136138
public static final boolean IS_OPENJDK = getProperty("java.vm.name", "").startsWith("OpenJDK");
137139
public static final Version JVMCI_VERSION;
138140
public static final boolean JVMCI;

compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotHashCodeSnippets.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,29 +26,47 @@
2626

2727
import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
2828
import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.IDENTITY_HASHCODE;
29-
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.biasedLockMaskInPlace;
3029
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.identityHashCode;
3130
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.identityHashCodeShift;
3231
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadWordFromObject;
32+
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.lockMaskInPlace;
3333
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.markOffset;
3434
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.uninitializedIdentityHashCodeValue;
3535
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.unlockedMask;
3636
import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FAST_PATH_PROBABILITY;
3737
import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
3838

39+
import org.graalvm.compiler.lir.StubPort;
3940
import org.graalvm.compiler.replacements.IdentityHashCodeSnippets;
4041
import org.graalvm.compiler.word.Word;
4142
import org.graalvm.word.WordFactory;
4243

44+
// @formatter:off
45+
@StubPort(path = "src/hotspot/share/opto/library_call.cpp",
46+
lineStart = 4311,
47+
lineEnd = 4435,
48+
commit = "540c706bbcbb809ae1304aac4f2a16a5e83cb458",
49+
sha1 = "bbf28398bfdef37afbb856160110d010c60e87e7")
50+
// @formatter:on
4351
public class HotSpotHashCodeSnippets extends IdentityHashCodeSnippets {
4452

4553
@Override
4654
protected int computeIdentityHashCode(final Object x) {
4755
Word mark = loadWordFromObject(x, markOffset(INJECTED_VMCONFIG));
4856

49-
// this code is independent from biased locking (although it does not look that way)
50-
final Word biasedLock = mark.and(biasedLockMaskInPlace(INJECTED_VMCONFIG));
51-
if (probability(FAST_PATH_PROBABILITY, biasedLock.equal(WordFactory.unsigned(unlockedMask(INJECTED_VMCONFIG))))) {
57+
// When the object is unlocked, HotSpot reuses upper bits (e.g., [38:8] in 64-bits VM) of
58+
// the mark word in object header for caching identity hash code. The same bits are part of
59+
// the thread pointer in the case of biased locking, pointer to the displaced mark in a
60+
// thread's stack in the case of stack locking, or pointer to the monitor object in the case
61+
// of inflated lock.
62+
//
63+
// To test if an object is unlocked, we simply need to compare the lock bits against the
64+
// constant unlocked value. The lock bits are the least significant 3 bits prior to Java 18
65+
// (1 bit for biased locking and 2 bits for stack locking or heavy locking), and 2 bits
66+
// afterwards due to elimination of the biased locking. The unlocked values are 001 and 01
67+
// respectively. See src/hotspot/share/oops/markWord.hpp for more details.
68+
final Word lockBits = mark.and(lockMaskInPlace(INJECTED_VMCONFIG));
69+
if (probability(FAST_PATH_PROBABILITY, lockBits.equal(WordFactory.unsigned(unlockedMask(INJECTED_VMCONFIG))))) {
5270
int hash = (int) mark.unsignedShiftRight(identityHashCodeShift(INJECTED_VMCONFIG)).rawValue();
5371
if (probability(FAST_PATH_PROBABILITY, hash != uninitializedIdentityHashCodeValue(INJECTED_VMCONFIG))) {
5472
return hash;

compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -511,18 +511,13 @@ public static int objectMonitorSuccOffset(@InjectedParameter GraalHotSpotVMConfi
511511
}
512512

513513
/**
514-
* Mask for a biasable, locked or unlocked mark word.
515-
*
516-
* <pre>
517-
* +----------------------------------+-+-+
518-
* | 1|1|1|
519-
* +----------------------------------+-+-+
520-
* </pre>
521-
*
514+
* Mask for a biasable, locked or unlocked mark word. It is the least significant 3 bits prior
515+
* to Java 18 (1 bit for biased locking and 2 bits for stack locking or heavy locking), and 2
516+
* bits afterwards due to elimination of the biased locking.
522517
*/
523518
@Fold
524-
public static int biasedLockMaskInPlace(@InjectedParameter GraalHotSpotVMConfig config) {
525-
return config.biasedLockMaskInPlace;
519+
public static int lockMaskInPlace(@InjectedParameter GraalHotSpotVMConfig config) {
520+
return config.getLockMaskInPlace();
526521
}
527522

528523
@Fold

compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/MonitorSnippets.java

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

2727
import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_OPTIONVALUES;
2828
import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
29+
import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfigAccess.JDK;
2930
import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallDescriptor.Reexecutability.NOT_REEXECUTABLE;
3031
import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallDescriptor.Transition.SAFEPOINT;
3132
import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallDescriptor.Transition.STACK_INSPECTABLE_LEAF;
@@ -44,7 +45,6 @@
4445
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.OBJECT_MONITOR_SUCC_LOCATION;
4546
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.PROTOTYPE_MARK_WORD_LOCATION;
4647
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.ageMaskInPlace;
47-
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.biasedLockMaskInPlace;
4848
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.biasedLockPattern;
4949
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.diagnoseSyncOnValueBasedClasses;
5050
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.epochMaskInPlace;
@@ -53,6 +53,7 @@
5353
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.klassAccessFlagsOffset;
5454
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadWordFromObject;
5555
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.lockDisplacedMarkOffset;
56+
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.lockMaskInPlace;
5657
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.markOffset;
5758
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.monitorMask;
5859
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.objectMonitorCxqOffset;
@@ -274,7 +275,7 @@ public static void monitorenter(Object object, KlassPointer hub, @ConstantParame
274275
}
275276
}
276277

277-
if (useBiasedLocking(INJECTED_VMCONFIG)) {
278+
if (probability(NOT_LIKELY_PROBABILITY, JDK < 18) && useBiasedLocking(INJECTED_VMCONFIG)) {
278279
if (tryEnterBiased(object, hub, lock, mark, thread, trace, counters)) {
279280
return;
280281
}
@@ -347,7 +348,7 @@ private static boolean tryEnterBiased(Object object, KlassPointer hub, Word lock
347348
// whether the epoch is still valid.
348349
// Note that the runtime guarantees sufficient alignment of JavaThread
349350
// pointers to allow age to be placed into low bits.
350-
final Word biasableLockBits = mark.and(biasedLockMaskInPlace(INJECTED_VMCONFIG));
351+
final Word biasableLockBits = mark.and(lockMaskInPlace(INJECTED_VMCONFIG));
351352

352353
// Check whether the bias pattern is present in the object's mark word
353354
// and the bias owner and the epoch are both still current.
@@ -376,7 +377,7 @@ private static boolean tryEnterBiased(Object object, KlassPointer hub, Word lock
376377
// If the low three bits in the xor result aren't clear, that means
377378
// the prototype header is no longer biasable and we have to revoke
378379
// the bias on this object.
379-
if (probability(FREQUENT_PROBABILITY, tmp.and(biasedLockMaskInPlace(INJECTED_VMCONFIG)).equal(0))) {
380+
if (probability(FREQUENT_PROBABILITY, tmp.and(lockMaskInPlace(INJECTED_VMCONFIG)).equal(0))) {
380381
// Biasing is still enabled for object's type. See whether the
381382
// epoch of the current bias is still valid, meaning that the epoch
382383
// bits of the mark word are equal to the epoch bits of the
@@ -393,7 +394,7 @@ private static boolean tryEnterBiased(Object object, KlassPointer hub, Word lock
393394
// fails we will go in to the runtime to revoke the object's bias.
394395
// Note that we first construct the presumed unbiased header so we
395396
// don't accidentally blow away another thread's valid bias.
396-
Word unbiasedMark = mark.and(biasedLockMaskInPlace(INJECTED_VMCONFIG) | ageMaskInPlace(INJECTED_VMCONFIG) | epochMaskInPlace(INJECTED_VMCONFIG));
397+
Word unbiasedMark = mark.and(lockMaskInPlace(INJECTED_VMCONFIG) | ageMaskInPlace(INJECTED_VMCONFIG) | epochMaskInPlace(INJECTED_VMCONFIG));
397398
Word biasedMark = unbiasedMark.or(thread);
398399
trace(trace, " unbiasedMark: 0x%016lx\n", unbiasedMark);
399400
trace(trace, " biasedMark: 0x%016lx\n", biasedMark);
@@ -533,7 +534,7 @@ public static void monitorexit(Object object, @ConstantParameter int lockDepth,
533534
@ConstantParameter Counters counters) {
534535
Word thread = registerAsWord(threadRegister);
535536
trace(trace, " object: 0x%016lx\n", Word.objectToTrackedPointer(object));
536-
if (useBiasedLocking(INJECTED_VMCONFIG)) {
537+
if (probability(NOT_LIKELY_PROBABILITY, JDK < 18) && useBiasedLocking(INJECTED_VMCONFIG)) {
537538
// Check for biased locking unlock case, which is a no-op
538539
// Note: we do not have to check the thread ID for two reasons.
539540
// First, the interpreter checks for IllegalMonitorStateException at
@@ -542,7 +543,7 @@ public static void monitorexit(Object object, @ConstantParameter int lockDepth,
542543
// the bias bit would be clear.
543544
final Word mark = loadWordFromObject(object, markOffset(INJECTED_VMCONFIG));
544545
trace(trace, " mark: 0x%016lx\n", mark);
545-
if (probability(FREQUENT_PROBABILITY, mark.and(biasedLockMaskInPlace(INJECTED_VMCONFIG)).equal(WordFactory.unsigned(biasedLockPattern(INJECTED_VMCONFIG))))) {
546+
if (probability(FREQUENT_PROBABILITY, mark.and(lockMaskInPlace(INJECTED_VMCONFIG)).equal(WordFactory.unsigned(biasedLockPattern(INJECTED_VMCONFIG))))) {
546547
endLockScope();
547548
decCounter();
548549
traceObject(trace, "-lock{bias}", object, false);

compiler/src/org.graalvm.micro.benchmarks/src/micro/benchmarks/HashBenchmark.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,9 @@ public int hash(ThreadState state) {
4747
}
4848
return value;
4949
}
50+
51+
@Benchmark
52+
public int identityHashCode(ThreadState state) {
53+
return System.identityHashCode(state.characters);
54+
}
5055
}

0 commit comments

Comments
 (0)