diff --git a/src/java.base/share/classes/java/lang/invoke/VarHandle.java b/src/java.base/share/classes/java/lang/invoke/VarHandle.java index 37f048b384..11563d557b 100644 --- a/src/java.base/share/classes/java/lang/invoke/VarHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/VarHandle.java @@ -23,9 +23,16 @@ * questions. */ +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2024, 2024 All Rights Reserved + * =========================================================================== + */ + package java.lang.invoke; import jdk.internal.HotSpotIntrinsicCandidate; +import jdk.internal.misc.Unsafe; import jdk.internal.util.Preconditions; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.Stable; @@ -1964,11 +1971,22 @@ static class TypesAndInvokers { new MethodHandle[AccessMode.values().length]; } + private static final long TYPES_AND_INVOKERS_OFFSET; + + static { + TYPES_AND_INVOKERS_OFFSET = UNSAFE.objectFieldOffset(VarHandle.class, "typesAndInvokers"); + } + @ForceInline private final TypesAndInvokers getTypesAndInvokers() { TypesAndInvokers tis = typesAndInvokers; if (tis == null) { - tis = typesAndInvokers = new TypesAndInvokers(); + tis = new TypesAndInvokers(); + Object other = UNSAFE.compareAndExchangeObject(this, TYPES_AND_INVOKERS_OFFSET, null, tis); + if (other != null) { + // Lost the race, so use what was set by winning thread. + tis = (TypesAndInvokers) other; + } } return tis; } @@ -1978,7 +1996,13 @@ final MethodHandle getMethodHandle(int mode) { TypesAndInvokers tis = getTypesAndInvokers(); MethodHandle mh = tis.methodHandle_table[mode]; if (mh == null) { - mh = tis.methodHandle_table[mode] = getMethodHandleUncached(mode); + mh = getMethodHandleUncached(mode); + long offset = Unsafe.ARRAY_OBJECT_BASE_OFFSET + (Unsafe.ARRAY_OBJECT_INDEX_SCALE * mode); + Object other = UNSAFE.compareAndExchangeObject(tis.methodHandle_table, offset, null, mh); + if (other != null) { + // We lost the race. Use the winning thread's handle instead. + mh = (MethodHandle) other; + } } return mh; }