RFR 8158039 VarHandle float/double field/array access shouldsupport CAS/set/add atomics
timo.kinnunen at gmail.com
timo.kinnunen at gmail.com
Thu Jun 2 18:19:50 UTC 2016
Hi,
Regarding x86, I can induce an infinite loop in getAndAddFloat on my computer if I simulate getFloatVolatile with the following implementation:
static float getFloatVolatile(Object o, long offset) {
return -0.0f + Float.intBitsToFloat(((int[]) o)[(int) offset]);
}
Note the added sum with -0.0f. This simulates the case where storing or subsequently reading a local variable changes the NaN value. With this implementation the first (largest) NaN to hang is 0xffbfffff.
Some other curiosities:
Adding -0.0 leaves all non-NaN floats with identical raw bits, including the negative zero. This isn’t the case if positive zero is used.
When positive zero was used every non-NaN except negative zero remained same.
This method changes 8,388,606 of the NaNs and leaves 8,388,608 the same.
--
Have a nice day,
Timo
Sent from Mail for Windows 10
From: Paul Sandoz
Sent: Thursday, June 2, 2016 17:26
To: Vladimir Ivanov
Cc: jdk9-dev; hotspot-dev developers
Subject: Re: RFR 8158039 VarHandle float/double field/array access shouldsupport CAS/set/add atomics
> On 2 Jun 2016, at 14:55, Vladimir Ivanov <vladimir.x.ivanov at oracle.com> wrote:
>
> Paul,
>
> Leaving practicality aspect of float/double API aside...
>
>> I am concerned that the CAS loops could in some cases loop without termination:
>
> Can you elaborate? I don't see how it is possible with the proposed patch.
>
The key aspect is in the JavaDoc snippet in my previous email.
> On Float.intBitsToFloat:
>
> * <p>Note that this method may not be able to return a
> * {@code float} NaN with exactly same bit pattern as the
> * {@code int} argument. IEEE 754 distinguishes between two
> * kinds of NaNs, quiet NaNs and <i>signaling NaNs</i>. The
> * differences between the two kinds of NaN are generally not
> * visible in Java. Arithmetic operations on signaling NaNs turn
> * them into quiet NaNs with a different, but often similar, bit
> * pattern. However, on some processors merely copying a
> * signaling NaN also performs that conversion. In particular,
> * copying a signaling NaN to return it to the calling method may
> * perform this conversion. So {@code intBitsToFloat} may
> * not be able to return a {@code float} with a signaling NaN
> * bit pattern. Consequently, for some {@code int} values,
> * {@code floatToRawIntBits(intBitsToFloat(start))} may
> * <i>not</i> equal {@code start}. Moreover, which
> * particular bit patterns represent signaling NaNs is platform
> * dependent; although all NaN bit patterns, quiet or signaling,
> * must be in the NaN range identified above.
>
I dunno if it can happen on x86 [*], but from reading the above I presume it could theoretically happen on some other hardware (what exactly i do not know).
Note that the loaded float value is passed to the weakCompareAndSwapFloatVolatile method as an argument. IIUC that might trigger the conversion from a signalling NaN to a quiet NaN, subtly changing the bits of the expected value that was loaded.
Paul.
[*] Here is a simple program to induce a different on x86 (at least on my machine). To induce that i am adding 0.0f to the float value.
public class AllTheNaNs {
public static void main(String[] args) {
for (long bits = 0x7f800001; bits <= 0x7fffffff; bits++) {
testBits((int) bits);
}
for (long bits = 0xff800001; bits <= 0xffffffff; bits++) {
testBits((int) bits);
}
}
static void testBits(int vbits) {
float v = Float.intBitsToFloat(vbits);
assert Float.isNaN(v);
float vv = id(v);
assert Float.isNaN(vv);
int vvbits = Float.floatToRawIntBits(vv);
if (vvbits != vbits) {
System.out.println(Integer.toHexString(vbits) + " " +
Integer.toHexString(vvbits) + " " +
Float.valueOf(v).equals(Float.valueOf(vv)) + " " +
Float.compare(v, vv));
}
}
static float id(float f) {
return f + 0.0f;
}
}
> Unless getFloatVolatile() or weakCompareAndSwapFloatVolatile() change the original value, it should not happen. And both functions preserve float value bits intact:
>
> + @ForceInline
> + public final boolean weakCompareAndSwapFloatVolatile(Object o, long offset,
> + float expected,
> + float x) {
> + return weakCompareAndSwapIntVolatile(o, offset,
> + Float.floatToRawIntBits(expected),
> + Float.floatToRawIntBits(x));
> + }
>
> Float.floatToRawIntBits() makes it safe, but with Float.intBitsToFloat() used infinite looping can happen for NaNs.
>
> Best regards,
> Vladimir Ivanov
>
More information about the jdk9-dev
mailing list