Fwd: Unsafe and jit bug
Roman Kennke
rkennke at redhat.com
Thu Mar 14 18:03:49 UTC 2019
I believe I made a mistake in the list admin interface and accidentally
dropped this email. Forwarding it manually.
Roman
-------- Weitergeleitete Nachricht --------
Betreff: Unsafe and jit bug
Datum: Thu, 14 Mar 2019 20:18:59 +0300
Von: Владислав Таболин <tabolin at yandex.ru>
An: shenandoah-dev at openjdk.java.net
Hi. Looking for shenandoah project for a long time, tried every new
version, but still can't use it in out production. There is some sort of
jit inlining bug when using Unsafe.get* methods which we are heavily
using in production.
I wroute a simpe test wich fails with shenandoah and runs smooth with
every other option:
1) openjdk + any other gc = OK
2) openjdk + shenandoah + -XX:TieredStopAtLevel=1 = OK
The problem (imho) is in insructions reordering at method
NativIntArray.swap():
package test;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
import sun.misc.Unsafe;
public class Test {
private static final int TEST_ARRAY_SIZE = 1000000;
private static final long SEED = 0xDEADBEEFBEEFDEADL;
private static final Unsafe UNSAFE = getUnsafe();
private static Unsafe getUnsafe() {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);
return unsafe;
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws Exception {
System.out.println("Test start");
for (int i = 0; i < 100; i++) {
test2();
System.out.println(i + " iter passed");
}
}
private static void test2() throws Exception {
final ArrayList<Integer> reference = new ArrayList<>();
NativeIntArray arr = new NativeIntArray(TEST_ARRAY_SIZE);
Random rnd = new Random(SEED);
System.out.println("Filling arrays");
for (int i = 0; i < TEST_ARRAY_SIZE; i++) {
int value = rnd.nextInt();
reference.add(value);
arr.set(i, value);
}
System.out.println("Testing random arrays");
for (int i = 0; i < TEST_ARRAY_SIZE; i++) {
final int value = arr.get(i);
final int refValue = reference.get(i);
if (value != refValue) {
throw new Exception("Native array value doesn't matches "
+ "reference: " + value + " <> " + refValue);
}
}
for (int i = 1; i < TEST_ARRAY_SIZE; i++) {
Collections.swap(reference, i - 1, i);
arr.swap(i - 1, i);
}
System.out.println("Testing sorted");
for (int i = 0; i < TEST_ARRAY_SIZE; i++) {
final int value = arr.get(i);
final int refValue = reference.get(i);
if (value != refValue) {
throw new Exception("Native array value doesn't matches "
+ "reference: " + value + " <> " + refValue);
}
}
}
private static final class NativeIntArray {
private final Memory mem;
private volatile int fence;
public NativeIntArray(final int size) {
mem = new Memory(size << 2);
}
public int get(final int index) {
return mem.getInt(index);
}
public void set(final int index, final int value) {
mem.setInt(index, value);
}
// The BUG is HERE :)
public void swap(final int a, final int b) {
int tmp = mem.getInt(a);
//Uncommenting the following line eliminates the problem
//int fence = this.fence;
mem.setInt(a, mem.getInt(b));
mem.setInt(b, tmp);
}
}
private static final class Memory {
private final long addr;
Memory(final int size) {
addr = UNSAFE.allocateMemory(size);
}
public int getInt(final int index) {
return UNSAFE.getInt(addr + (index << 2));
}
public void setInt(final int index, final int value) {
UNSAFE.putInt(addr + (index << 2), value);
}
}
}
Could anyone take a professional look a this code please?
Thanks a lot!
More information about the shenandoah-dev
mailing list