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