Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6653795

C2 intrinsic for Unsafe.getAddress performs pointer sign extension on 32-bit systems

XMLWordPrintable

    • b08
    • generic
    • generic

        We've recently encountered a problem with the c2 compiler in hotspot 1.7/1.6 when
        the method "public native long getAddress(long address)" of class "sun.misc.Unsafe"
        gets inlined as an intrinsic call on 32-bit platforms.
        The API documentation of "sun.misc.Unsafe.getAddress" states that "it fetches a native
        pointer from a given memory address" and that "if the native pointer is less than 64
        bits wide, it is extended as an unsigned number to a Java long".
        Unfortunately, the intrinsic version of this method in hotspot 1.7/1.6 extends the
        native pointer as a signed number to a Java long, thus resulting in a discrepancy
        between interpreted execution and compiled execution.
        Let's consider the following example:
          import sun.misc.Unsafe;
          public class UnsafeGetAddressTest {
              public static void main(String[] args) {
                  Unsafe unsafe = Unsafe.getUnsafe();
                  long address = unsafe.allocateMemory(unsafe.addressSize());
                  unsafe.putAddress(address, 0x0000000080000000L);
                  // from sun.misc.Unsafe.getAddress' documentation:
                  // "If the native pointer is less than 64 bits wide, it is
                  // extended as an unsigned number to a Java long."
                  result = unsafe.getAddress(address);
                  System.out.printf("1: was 0x%x, expected 0x%x\n", result,
                          0x0000000080000000L);
                  for (int i = 0; i < 1000000; i++) {
                      result = unsafe.getAddress(address);
                  }
                  System.out.printf("2: was 0x%x, expected 0x%x\n", result,
                          0x0000000080000000L);
              }
              static volatile long result;
          }
        and one execution of the example in interpreted-mode:
           $ /tmp/jdk1.7.0/bin/java -Xint -showversion -Xbootclasspath/a:UnsafeGetAddressTest.jar -XX:+PrintCompilation UnsafeGetAddressTest
          java version "1.7.0-ea"
          Java(TM) SE Runtime Environment (build 1.7.0-ea-b24)
          Java HotSpot(TM) Server VM (build 12.0-b01, interpreted mode)
           1: was 0x80000000, expected 0x80000000
          2: was 0x80000000, expected 0x80000000
         and one execution in mixed-mode:
           $ /tmp/jdk1.7.0/bin/java -Xmixed -server -showversion -Xbootclasspath/a:UnsafeGetAddressTest.jar -XX:+PrintCompilation UnsafeGetAddressTest
          java version "1.7.0-ea"
          Java(TM) SE Runtime Environment (build 1.7.0-ea-b24)
          Java HotSpot(TM) Server VM (build 12.0-b01, mixed mode)
           1: was 0x80000000, expected 0x80000000
          --- n sun.misc.Unsafe::getAddress
            1% UnsafeGetAddressTest::main @ 65 (113 bytes)
          2: was 0xffffffff80000000, expected 0x80000000
         The mixed-mode execution shows that the native pointer 0x80000000 gets extended as
        a signed number to the Java long 0xffffffff80000000L after the method has been
        on-stack-replaced. The interpreted execution always returns 0x80000000L.
        The problem arises from the deletion of opto's CastP2LNode class and the new usage
        of CastP2XNode and ConvX2L in "hotspot/src/share/vm/opto/library_call.cpp" in method
        "LibraryCallKit::inline_unsafe_access" which is not equivalent to the old implementation.

              poonam Poonam Bajaj Parhar
              jrose John Rose
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

                Created:
                Updated:
                Resolved:
                Imported:
                Indexed: