JDK-6653795 : C2 intrinsic for Unsafe.getAddress performs pointer sign extension on 32-bit systems
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 6
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2008-01-22
  • Updated: 2014-10-15
  • Resolved: 2014-03-24
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6 JDK 7 JDK 8 JDK 9
6u81Fixed 7u55Fixed 8u20Fixed 9 b08Fixed
Description
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.

Comments
SQE OK to take customer's escalation to PSU14_03
18-04-2014

Not critical for JDK6 (issue has been around since at least 2008). Given the restrictions on which bugs to fix in 7u60, we probably shouldn't fix there either (P3, not a regression). Putting on tbd_minor
04-12-2013

We should see if the suggested fix is still relevant, and if it needs to be taken to JDK7 and later
29-11-2013

EVALUATION See the Discription.
07-11-2008

SUGGESTED FIX diff --git a/src/share/vm/opto/graphKit.cpp b/src/share/vm/opto/graphKit.cpp --- a/src/share/vm/opto/graphKit.cpp +++ b/src/share/vm/opto/graphKit.cpp @@ -1016,9 +1016,19 @@ Node* GraphKit::ConvI2L(Node* offset) { // short-circuit a common case jint offset_con = find_int_con(offset, Type::OffsetBot); if (offset_con != Type::OffsetBot) { - return longcon((long) offset_con); + return longcon((jlong) offset_con); } return _gvn.transform( new (C, 2) ConvI2LNode(offset)); +} +Node* GraphKit::ConvI2UL(Node* offset) { + juint offset_con = (juint) find_int_con(offset, Type::OffsetBot); + if (offset_con != (juint) Type::OffsetBot) { + return longcon((julong) offset_con); + } + Node* conv = _gvn.transform( new (C, 2) ConvI2LNode(offset)); + juint mask_con = (juint) -1; + Node* mask = _gvn.transform( ConLNode::make(C, (julong) mask_con) ); + return _gvn.transform( new (C, 2) AndLNode(conv, mask) ); } Node* GraphKit::ConvL2I(Node* offset) { // short-circuit a common case diff --git a/src/share/vm/opto/graphKit.hpp b/src/share/vm/opto/graphKit.hpp --- a/src/share/vm/opto/graphKit.hpp +++ b/src/share/vm/opto/graphKit.hpp @@ -269,6 +269,7 @@ class GraphKit : public Phase { // Convert between int and long, and size_t. // (See macros ConvI2X, etc., in type.hpp for ConvI2X, etc.) Node* ConvI2L(Node* offset); + Node* ConvI2UL(Node* offset); Node* ConvL2I(Node* offset); // Find out the klass of an object. Node* load_object_klass(Node* object); diff --git a/src/share/vm/opto/library_call.cpp b/src/share/vm/opto/library_call.cpp --- a/src/share/vm/opto/library_call.cpp +++ b/src/share/vm/opto/library_call.cpp @@ -1922,7 +1922,7 @@ bool LibraryCallKit::inline_unsafe_acces case T_ADDRESS: // Cast to an int type. p = _gvn.transform( new (C, 2) CastP2XNode(NULL,p) ); - p = ConvX2L(p); + p = ConvX2UL(p); push_pair(p); break; case T_DOUBLE: diff --git a/src/share/vm/opto/type.hpp b/src/share/vm/opto/type.hpp --- a/src/share/vm/opto/type.hpp +++ b/src/share/vm/opto/type.hpp @@ -1081,7 +1081,7 @@ inline bool Type::is_floatingpoint() con #define ConvI2X(x) ConvI2L(x) #define ConvL2X(x) (x) #define ConvX2I(x) ConvL2I(x) -#define ConvX2L(x) (x) +#define ConvX2UL(x) (x) #else @@ -1119,6 +1119,6 @@ inline bool Type::is_floatingpoint() con #define ConvI2X(x) (x) #define ConvL2X(x) ConvL2I(x) #define ConvX2I(x) (x) -#define ConvX2L(x) ConvI2L(x) - -#endif +#define ConvX2UL(x) ConvI2UL(x) + +#endif
22-01-2008