-
Bug
-
Resolution: Fixed
-
P4
-
repo-riscv-port
-
None
-
riscv
-
linux
On behalf of Xiaolin Zheng(yunyao.zxl@alibaba-inc.com)
A very simple program inherited from jcstress could reproduce this:
```
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
// run with:
// build/linux-riscv64-server-release/images/jdk/bin/java -ea -XX:-TieredCompilation -XX:CompileCommand=compileonly,jdk.internal.misc.Unsafe::compareAndSetByte TestCASByte
// assert will fail.
// if we add '-XX:+UnlockDiagnosticVMOptions -XX:DisableIntrinsic=_compareAndExchangeByte' this test will pass.
public class TestCASByte {
byte[] array = new byte[1];
static final VarHandle vh;
static {
try {
vh = MethodHandles.arrayElementVarHandle(byte[].class);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void test() {
for (int i = 0; i < 100_000; i++) { // To level 4
// clear
array[0] = 0;
byte res1 = (byte)vh.getAndSet(array, 0, (byte)-1);
byte res2 = (byte)vh.getAndSet(array, 0, (byte)2);
assert res1 == 0 && res2 == -1;
}
}
public static void main(String[] args) {
new TestCASByte().test();
}
}
```
In this case when we are getting the -1 value saved in memory, the shift is 0, the old is 0x00000000000000ff and the mask is 0x00000000000000ff at the end of cmpxchg_narrow_value. The final result is 0x00000000000000ff but it indeed should be 0xffffffffffffffff. In fact, I tried to use sra at first and found the problem was not gone, and then I found the shift is 0. The logic here is a bit delicate and the final result seems from and | or mask operations by only calculating the 8/16 bits regardless of high 56/48 bits. So the problem is that if the result is negative, we need to make a sign extension.
A very simple program inherited from jcstress could reproduce this:
```
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
// run with:
// build/linux-riscv64-server-release/images/jdk/bin/java -ea -XX:-TieredCompilation -XX:CompileCommand=compileonly,jdk.internal.misc.Unsafe::compareAndSetByte TestCASByte
// assert will fail.
// if we add '-XX:+UnlockDiagnosticVMOptions -XX:DisableIntrinsic=_compareAndExchangeByte' this test will pass.
public class TestCASByte {
byte[] array = new byte[1];
static final VarHandle vh;
static {
try {
vh = MethodHandles.arrayElementVarHandle(byte[].class);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void test() {
for (int i = 0; i < 100_000; i++) { // To level 4
// clear
array[0] = 0;
byte res1 = (byte)vh.getAndSet(array, 0, (byte)-1);
byte res2 = (byte)vh.getAndSet(array, 0, (byte)2);
assert res1 == 0 && res2 == -1;
}
}
public static void main(String[] args) {
new TestCASByte().test();
}
}
```
In this case when we are getting the -1 value saved in memory, the shift is 0, the old is 0x00000000000000ff and the mask is 0x00000000000000ff at the end of cmpxchg_narrow_value. The final result is 0x00000000000000ff but it indeed should be 0xffffffffffffffff. In fact, I tried to use sra at first and found the problem was not gone, and then I found the shift is 0. The logic here is a bit delicate and the final result seems from and | or mask operations by only calculating the 8/16 bits regardless of high 56/48 bits. So the problem is that if the result is negative, we need to make a sign extension.