|
25 | 25 |
|
26 | 26 | package jdk.internal.misc; |
27 | 27 |
|
28 | | -import jdk.internal.value.ValueClass; |
29 | 28 | import jdk.internal.vm.annotation.AOTRuntimeSetup; |
30 | 29 | import jdk.internal.vm.annotation.AOTSafeClassInitializer; |
31 | 30 | import jdk.internal.vm.annotation.ForceInline; |
@@ -1711,15 +1710,8 @@ public final <V> boolean compareAndSetFlatValue(Object o, long offset, |
1711 | 1710 | Class<?> valueType, |
1712 | 1711 | V expected, |
1713 | 1712 | V x) { |
1714 | | - while (true) { |
1715 | | - Object witness = getFlatValueVolatile(o, offset, layout, valueType); |
1716 | | - if (witness != expected) { |
1717 | | - return false; |
1718 | | - } |
1719 | | - if (compareAndSetFlatValueAsBytes(o, offset, layout, valueType, witness, x)) { |
1720 | | - return true; |
1721 | | - } |
1722 | | - } |
| 1713 | + Object[] array = newSpecialArray(valueType, 2, layout); |
| 1714 | + return compareAndSetFlatValueAsBytes(array, o, offset, layout, valueType, expected, x); |
1723 | 1715 | } |
1724 | 1716 |
|
1725 | 1717 | @IntrinsicCandidate |
@@ -1753,15 +1745,9 @@ public final <V> Object compareAndExchangeFlatValue(Object o, long offset, |
1753 | 1745 | Class<?> valueType, |
1754 | 1746 | V expected, |
1755 | 1747 | V x) { |
1756 | | - while (true) { |
1757 | | - Object witness = getFlatValueVolatile(o, offset, layout, valueType); |
1758 | | - if (witness != expected) { |
1759 | | - return witness; |
1760 | | - } |
1761 | | - if (compareAndSetFlatValueAsBytes(o, offset, layout, valueType, witness, x)) { |
1762 | | - return witness; |
1763 | | - } |
1764 | | - } |
| 1748 | + Object[] array = newSpecialArray(valueType, 2, layout); |
| 1749 | + compareAndSetFlatValueAsBytes(array, o, offset, layout, valueType, expected, x); |
| 1750 | + return array[0]; |
1765 | 1751 | } |
1766 | 1752 |
|
1767 | 1753 | @IntrinsicCandidate |
@@ -2877,38 +2863,75 @@ public final void putDoubleOpaque(Object o, long offset, double x) { |
2877 | 2863 | } |
2878 | 2864 |
|
2879 | 2865 | @ForceInline |
2880 | | - private boolean compareAndSetFlatValueAsBytes(Object o, long offset, int layout, Class<?> valueType, Object expected, Object x) { |
2881 | | - // We turn the payload of an atomic value into a numeric value (of suitable type) |
2882 | | - // by storing the value into an array element (of matching layout) and by reading |
2883 | | - // back the array element as an integral value. After which we can implement the CAS |
2884 | | - // as a plain numeric CAS. Note: this only works if the payload contains no oops |
2885 | | - // (see VarHandles::isAtomicFlat). |
2886 | | - Object[] expectedArray = newSpecialArray(valueType, 1, layout); |
2887 | | - Object xArray = newSpecialArray(valueType, 1, layout); |
2888 | | - long base = arrayInstanceBaseOffset(expectedArray); |
2889 | | - int scale = arrayInstanceIndexScale(expectedArray); |
2890 | | - putFlatValue(expectedArray, base, layout, valueType, expected); |
2891 | | - putFlatValue(xArray, base, layout, valueType, x); |
| 2866 | + private boolean compareAndSetFlatValueAsBytes(Object[] array, Object o, long offset, int layout, Class<?> valueType, Object expected, Object x) { |
| 2867 | + // We can convert between a value object and a binary value (of suitable size) using array elements. |
| 2868 | + // This only works if the payload contains no oops (see VarHandles::isAtomicFlat). |
| 2869 | + // Thus, we can implement the CAS with a plain numeric CAS. |
| 2870 | + |
| 2871 | + // array[0]: witness (put as binary, get as object), at base |
| 2872 | + // array[1]: x (put as object, get as binary), at base + scale |
| 2873 | + // When witness == expected, the witness binary may be different from the expected binary. |
| 2874 | + // This happens when compiler does not zero unused positions in the witness. |
| 2875 | + // So we must obtain the witness binary and use it as expected binary for the numeric CAS. |
| 2876 | + long base = arrayInstanceBaseOffset(array); |
| 2877 | + int scale = arrayInstanceIndexScale(array); |
| 2878 | + putFlatValue(array, base + scale, layout, valueType, x); // put x as object |
2892 | 2879 | switch (scale) { |
2893 | 2880 | case 1: { |
2894 | | - byte expectedByte = getByte(expectedArray, base); |
2895 | | - byte xByte = getByte(xArray, base); |
2896 | | - return compareAndSetByte(o, offset, expectedByte, xByte); |
| 2881 | + do { |
| 2882 | + byte witnessByte = getByteVolatile(o, offset); |
| 2883 | + putByte(array, base, witnessByte); // put witness as binary |
| 2884 | + Object witness = getFlatValue(array, base, layout, valueType); // get witness as object |
| 2885 | + if (witness != expected) { |
| 2886 | + return false; |
| 2887 | + } |
| 2888 | + byte xByte = getByte(array, base + scale); // get x as binary |
| 2889 | + if (compareAndSetByte(o, offset, witnessByte, xByte)) { |
| 2890 | + return true; |
| 2891 | + } |
| 2892 | + } while (true); |
2897 | 2893 | } |
2898 | 2894 | case 2: { |
2899 | | - short expectedShort = getShort(expectedArray, base); |
2900 | | - short xShort = getShort(xArray, base); |
2901 | | - return compareAndSetShort(o, offset, expectedShort, xShort); |
| 2895 | + do { |
| 2896 | + short witnessShort = getShortVolatile(o, offset); |
| 2897 | + putShort(array, base, witnessShort); // put witness as binary |
| 2898 | + Object witness = getFlatValue(array, base, layout, valueType); // get witness as object |
| 2899 | + if (witness != expected) { |
| 2900 | + return false; |
| 2901 | + } |
| 2902 | + short xShort = getShort(array, base + scale); // get x as binary |
| 2903 | + if (compareAndSetShort(o, offset, witnessShort, xShort)) { |
| 2904 | + return true; |
| 2905 | + } |
| 2906 | + } while (true); |
2902 | 2907 | } |
2903 | 2908 | case 4: { |
2904 | | - int expectedInt = getInt(expectedArray, base); |
2905 | | - int xInt = getInt(xArray, base); |
2906 | | - return compareAndSetInt(o, offset, expectedInt, xInt); |
| 2909 | + do { |
| 2910 | + int witnessInt = getIntVolatile(o, offset); |
| 2911 | + putInt(array, base, witnessInt); // put witness as binary |
| 2912 | + Object witness = getFlatValue(array, base, layout, valueType); // get witness as object |
| 2913 | + if (witness != expected) { |
| 2914 | + return false; |
| 2915 | + } |
| 2916 | + int xInt = getInt(array, base + scale); // get x as binary |
| 2917 | + if (compareAndSetInt(o, offset, witnessInt, xInt)) { |
| 2918 | + return true; |
| 2919 | + } |
| 2920 | + } while (true); |
2907 | 2921 | } |
2908 | 2922 | case 8: { |
2909 | | - long expectedLong = getLong(expectedArray, base); |
2910 | | - long xLong = getLong(xArray, base); |
2911 | | - return compareAndSetLong(o, offset, expectedLong, xLong); |
| 2923 | + do { |
| 2924 | + long witnessLong = getLongVolatile(o, offset); |
| 2925 | + putLong(array, base, witnessLong); // put witness as binary |
| 2926 | + Object witness = getFlatValue(array, base, layout, valueType); |
| 2927 | + if (witness != expected) { |
| 2928 | + return false; |
| 2929 | + } |
| 2930 | + long xLong = getLong(array, base + scale); // get x as binary |
| 2931 | + if (compareAndSetLong(o, offset, witnessLong, xLong)) { |
| 2932 | + return true; |
| 2933 | + } |
| 2934 | + } while (true); |
2912 | 2935 | } |
2913 | 2936 | default: { |
2914 | 2937 | throw new UnsupportedOperationException(); |
|
0 commit comments