hotspot/src/share/vm/prims/unsafe.cpp
changeset 38211 fe30fdab0f62
parent 38060 954c9575f653
child 39260 10fcac2a233a
--- a/hotspot/src/share/vm/prims/unsafe.cpp	Fri May 06 13:00:21 2016 -0700
+++ b/hotspot/src/share/vm/prims/unsafe.cpp	Fri May 06 15:59:26 2016 -0700
@@ -131,38 +131,137 @@
 }
 
 
-///// Data in the Java heap.
+///// Data read/writes on the Java heap and in native (off-heap) memory
+
+/**
+ * Helper class for accessing memory.
+ *
+ * Normalizes values and wraps accesses in
+ * JavaThread::doing_unsafe_access() if needed.
+ */
+class MemoryAccess : StackObj {
+  JavaThread* _thread;
+  jobject _obj;
+  jlong _offset;
 
-#define truncate_jboolean(x) ((x) & 1)
-#define truncate_jbyte(x) (x)
-#define truncate_jshort(x) (x)
-#define truncate_jchar(x) (x)
-#define truncate_jint(x) (x)
-#define truncate_jlong(x) (x)
-#define truncate_jfloat(x) (x)
-#define truncate_jdouble(x) (x)
+  // Resolves and returns the address of the memory access
+  void* addr() {
+    return index_oop_from_field_offset_long(JNIHandles::resolve(_obj), _offset);
+  }
+
+  template <typename T>
+  T normalize(T x) {
+    return x;
+  }
 
-#define GET_FIELD(obj, offset, type_name, v) \
-  oop p = JNIHandles::resolve(obj); \
-  type_name v = *(type_name*)index_oop_from_field_offset_long(p, offset)
+  jboolean normalize(jboolean x) {
+    return x & 1;
+  }
+
+  /**
+   * Helper class to wrap memory accesses in JavaThread::doing_unsafe_access()
+   */
+  class GuardUnsafeAccess {
+    JavaThread* _thread;
+    bool _active;
 
-#define SET_FIELD(obj, offset, type_name, x) \
-  oop p = JNIHandles::resolve(obj); \
-  *(type_name*)index_oop_from_field_offset_long(p, offset) = truncate_##type_name(x)
+  public:
+    GuardUnsafeAccess(JavaThread* thread, jobject _obj) : _thread(thread) {
+      if (JNIHandles::resolve(_obj) == NULL) {
+        // native/off-heap access which may raise SIGBUS if accessing
+        // memory mapped file data in a region of the file which has
+        // been truncated and is now invalid
+        _thread->set_doing_unsafe_access(true);
+        _active = true;
+      } else {
+        _active = false;
+      }
+    }
+
+    ~GuardUnsafeAccess() {
+      if (_active) {
+        _thread->set_doing_unsafe_access(false);
+      }
+    }
+  };
 
-#define GET_FIELD_VOLATILE(obj, offset, type_name, v) \
-  oop p = JNIHandles::resolve(obj); \
-  if (support_IRIW_for_not_multiple_copy_atomic_cpu) { \
-    OrderAccess::fence(); \
-  } \
-  volatile type_name v = OrderAccess::load_acquire((volatile type_name*)index_oop_from_field_offset_long(p, offset));
+public:
+  MemoryAccess(JavaThread* thread, jobject obj, jlong offset)
+    : _thread(thread), _obj(obj), _offset(offset) {
+  }
+
+  template <typename T>
+  T get() {
+    GuardUnsafeAccess guard(_thread, _obj);
+
+    T* p = (T*)addr();
 
-#define SET_FIELD_VOLATILE(obj, offset, type_name, x) \
-  oop p = JNIHandles::resolve(obj); \
-  OrderAccess::release_store_fence((volatile type_name*)index_oop_from_field_offset_long(p, offset), truncate_##type_name(x));
+    T x = *p;
+
+    return x;
+  }
+
+  template <typename T>
+  void put(T x) {
+    GuardUnsafeAccess guard(_thread, _obj);
+
+    T* p = (T*)addr();
+
+    *p = normalize(x);
+  }
 
 
-// Get/SetObject must be special-cased, since it works with handles.
+  template <typename T>
+  T get_volatile() {
+    GuardUnsafeAccess guard(_thread, _obj);
+
+    T* p = (T*)addr();
+
+    if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
+      OrderAccess::fence();
+    }
+
+    T x = OrderAccess::load_acquire((volatile T*)p);
+
+    return x;
+  }
+
+  template <typename T>
+  void put_volatile(T x) {
+    GuardUnsafeAccess guard(_thread, _obj);
+
+    T* p = (T*)addr();
+
+    OrderAccess::release_store_fence((volatile T*)p, normalize(x));
+  }
+
+
+#ifndef SUPPORTS_NATIVE_CX8
+  jlong get_jlong_locked() {
+    GuardUnsafeAccess guard(_thread, _obj);
+
+    MutexLockerEx mu(UnsafeJlong_lock, Mutex::_no_safepoint_check_flag);
+
+    jlong* p = (jlong*)addr();
+
+    jlong x = Atomic::load(p);
+
+    return x;
+  }
+
+  void put_jlong_locked(jlong x) {
+    GuardUnsafeAccess guard(_thread, _obj);
+
+    MutexLockerEx mu(UnsafeJlong_lock, Mutex::_no_safepoint_check_flag);
+
+    jlong* p = (jlong*)addr();
+
+    Atomic::store(normalize(x),  p);
+  }
+#endif
+};
+
+// Get/PutObject must be special-cased, since it works with handles.
 
 // These functions allow a null base pointer with an arbitrary address.
 // But if the base pointer is non-null, the offset should make some sense.
@@ -208,7 +307,7 @@
   return ret;
 } UNSAFE_END
 
-UNSAFE_ENTRY(void, Unsafe_SetObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject x_h)) {
+UNSAFE_ENTRY(void, Unsafe_PutObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject x_h)) {
   oop x = JNIHandles::resolve(x_h);
   oop p = JNIHandles::resolve(obj);
 
@@ -236,7 +335,7 @@
   return JNIHandles::make_local(env, v);
 } UNSAFE_END
 
-UNSAFE_ENTRY(void, Unsafe_SetObjectVolatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject x_h)) {
+UNSAFE_ENTRY(void, Unsafe_PutObjectVolatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject x_h)) {
   oop x = JNIHandles::resolve(x_h);
   oop p = JNIHandles::resolve(obj);
   void* addr = index_oop_from_field_offset_long(p, offset);
@@ -301,25 +400,17 @@
 
 UNSAFE_ENTRY(jlong, Unsafe_GetLongVolatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) {
   if (VM_Version::supports_cx8()) {
-    GET_FIELD_VOLATILE(obj, offset, jlong, v);
-    return v;
+    return MemoryAccess(thread, obj, offset).get_volatile<jlong>();
   } else {
-    Handle p (THREAD, JNIHandles::resolve(obj));
-    jlong* addr = (jlong*)(index_oop_from_field_offset_long(p(), offset));
-    MutexLockerEx mu(UnsafeJlong_lock, Mutex::_no_safepoint_check_flag);
-    jlong value = Atomic::load(addr);
-    return value;
+    return MemoryAccess(thread, obj, offset).get_jlong_locked();
   }
 } UNSAFE_END
 
-UNSAFE_ENTRY(void, Unsafe_SetLongVolatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jlong x)) {
+UNSAFE_ENTRY(void, Unsafe_PutLongVolatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jlong x)) {
   if (VM_Version::supports_cx8()) {
-    SET_FIELD_VOLATILE(obj, offset, jlong, x);
+    MemoryAccess(thread, obj, offset).put_volatile<jlong>(x);
   } else {
-    Handle p (THREAD, JNIHandles::resolve(obj));
-    jlong* addr = (jlong*)(index_oop_from_field_offset_long(p(), offset));
-    MutexLockerEx mu(UnsafeJlong_lock, Mutex::_no_safepoint_check_flag);
-    Atomic::store(x, addr);
+    MemoryAccess(thread, obj, offset).put_jlong_locked(x);
   }
 } UNSAFE_END
 
@@ -337,15 +428,14 @@
   return UseUnalignedAccesses;
 } UNSAFE_END
 
-#define DEFINE_GETSETOOP(java_type, Type)        \
+#define DEFINE_GETSETOOP(java_type, Type) \
  \
 UNSAFE_ENTRY(java_type, Unsafe_Get##Type(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) { \
-  GET_FIELD(obj, offset, java_type, v); \
-  return v; \
+  return MemoryAccess(thread, obj, offset).get<java_type>(); \
 } UNSAFE_END \
  \
-UNSAFE_ENTRY(void, Unsafe_Set##Type(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, java_type x)) { \
-  SET_FIELD(obj, offset, java_type, x); \
+UNSAFE_ENTRY(void, Unsafe_Put##Type(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, java_type x)) { \
+  MemoryAccess(thread, obj, offset).put<java_type>(x); \
 } UNSAFE_END \
  \
 // END DEFINE_GETSETOOP.
@@ -364,12 +454,11 @@
 #define DEFINE_GETSETOOP_VOLATILE(java_type, Type) \
  \
 UNSAFE_ENTRY(java_type, Unsafe_Get##Type##Volatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) { \
-  GET_FIELD_VOLATILE(obj, offset, java_type, v); \
-  return v; \
+  return MemoryAccess(thread, obj, offset).get_volatile<java_type>(); \
 } UNSAFE_END \
  \
-UNSAFE_ENTRY(void, Unsafe_Set##Type##Volatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, java_type x)) { \
-  SET_FIELD_VOLATILE(obj, offset, java_type, x); \
+UNSAFE_ENTRY(void, Unsafe_Put##Type##Volatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, java_type x)) { \
+  MemoryAccess(thread, obj, offset).put_volatile<java_type>(x); \
 } UNSAFE_END \
  \
 // END DEFINE_GETSETOOP_VOLATILE.
@@ -400,98 +489,6 @@
   OrderAccess::fence();
 } UNSAFE_END
 
-////// Data in the C heap.
-
-// Note:  These do not throw NullPointerException for bad pointers.
-// They just crash.  Only a oop base pointer can generate a NullPointerException.
-//
-#define DEFINE_GETSETNATIVE(java_type, Type, native_type) \
- \
-UNSAFE_ENTRY(java_type, Unsafe_GetNative##Type(JNIEnv *env, jobject unsafe, jlong addr)) { \
-  void* p = addr_from_java(addr); \
-  JavaThread* t = JavaThread::current(); \
-  t->set_doing_unsafe_access(true); \
-  java_type x = *(volatile native_type*)p; \
-  t->set_doing_unsafe_access(false); \
-  return x; \
-} UNSAFE_END \
- \
-UNSAFE_ENTRY(void, Unsafe_SetNative##Type(JNIEnv *env, jobject unsafe, jlong addr, java_type x)) { \
-  JavaThread* t = JavaThread::current(); \
-  t->set_doing_unsafe_access(true); \
-  void* p = addr_from_java(addr); \
-  *(volatile native_type*)p = x; \
-  t->set_doing_unsafe_access(false); \
-} UNSAFE_END \
- \
-// END DEFINE_GETSETNATIVE.
-
-DEFINE_GETSETNATIVE(jbyte, Byte, signed char)
-DEFINE_GETSETNATIVE(jshort, Short, signed short);
-DEFINE_GETSETNATIVE(jchar, Char, unsigned short);
-DEFINE_GETSETNATIVE(jint, Int, jint);
-// no long -- handled specially
-DEFINE_GETSETNATIVE(jfloat, Float, float);
-DEFINE_GETSETNATIVE(jdouble, Double, double);
-
-#undef DEFINE_GETSETNATIVE
-
-UNSAFE_ENTRY(jlong, Unsafe_GetNativeLong(JNIEnv *env, jobject unsafe, jlong addr)) {
-  JavaThread* t = JavaThread::current();
-  // We do it this way to avoid problems with access to heap using 64
-  // bit loads, as jlong in heap could be not 64-bit aligned, and on
-  // some CPUs (SPARC) it leads to SIGBUS.
-  t->set_doing_unsafe_access(true);
-  void* p = addr_from_java(addr);
-  jlong x;
-
-  if (is_ptr_aligned(p, sizeof(jlong)) == 0) {
-    // jlong is aligned, do a volatile access
-    x = *(volatile jlong*)p;
-  } else {
-    jlong_accessor acc;
-    acc.words[0] = ((volatile jint*)p)[0];
-    acc.words[1] = ((volatile jint*)p)[1];
-    x = acc.long_value;
-  }
-
-  t->set_doing_unsafe_access(false);
-
-  return x;
-} UNSAFE_END
-
-UNSAFE_ENTRY(void, Unsafe_SetNativeLong(JNIEnv *env, jobject unsafe, jlong addr, jlong x)) {
-  JavaThread* t = JavaThread::current();
-  // see comment for Unsafe_GetNativeLong
-  t->set_doing_unsafe_access(true);
-  void* p = addr_from_java(addr);
-
-  if (is_ptr_aligned(p, sizeof(jlong))) {
-    // jlong is aligned, do a volatile access
-    *(volatile jlong*)p = x;
-  } else {
-    jlong_accessor acc;
-    acc.long_value = x;
-    ((volatile jint*)p)[0] = acc.words[0];
-    ((volatile jint*)p)[1] = acc.words[1];
-  }
-
-  t->set_doing_unsafe_access(false);
-} UNSAFE_END
-
-
-UNSAFE_LEAF(jlong, Unsafe_GetNativeAddress(JNIEnv *env, jobject unsafe, jlong addr)) {
-  void* p = addr_from_java(addr);
-
-  return addr_to_java(*(void**)p);
-} UNSAFE_END
-
-UNSAFE_LEAF(void, Unsafe_SetNativeAddress(JNIEnv *env, jobject unsafe, jlong addr, jlong x)) {
-  void* p = addr_from_java(addr);
-  *(void**)p = addr_from_java(x);
-} UNSAFE_END
-
-
 ////// Allocation requests
 
 UNSAFE_ENTRY(jobject, Unsafe_AllocateInstance(JNIEnv *env, jobject unsafe, jclass cls)) {
@@ -980,8 +977,8 @@
 } UNSAFE_END
 
 UNSAFE_ENTRY(jlong, Unsafe_CompareAndExchangeLong(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jlong e, jlong x)) {
-  Handle p (THREAD, JNIHandles::resolve(obj));
-  jlong* addr = (jlong*)(index_oop_from_field_offset_long(p(), offset));
+  Handle p(THREAD, JNIHandles::resolve(obj));
+  jlong* addr = (jlong*)index_oop_from_field_offset_long(p(), offset);
 
 #ifdef SUPPORTS_NATIVE_CX8
   return (jlong)(Atomic::cmpxchg(x, addr, e));
@@ -1017,7 +1014,7 @@
 
 UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x)) {
   oop p = JNIHandles::resolve(obj);
-  jint* addr = (jint *) index_oop_from_field_offset_long(p, offset);
+  jint* addr = (jint *)index_oop_from_field_offset_long(p, offset);
 
   return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
 } UNSAFE_END
@@ -1143,20 +1140,16 @@
 
 #define DECLARE_GETPUTOOP(Type, Desc) \
     {CC "get" #Type,      CC "(" OBJ "J)" #Desc,       FN_PTR(Unsafe_Get##Type)}, \
-    {CC "put" #Type,      CC "(" OBJ "J" #Desc ")V",   FN_PTR(Unsafe_Set##Type)}, \
+    {CC "put" #Type,      CC "(" OBJ "J" #Desc ")V",   FN_PTR(Unsafe_Put##Type)}, \
     {CC "get" #Type "Volatile",      CC "(" OBJ "J)" #Desc,       FN_PTR(Unsafe_Get##Type##Volatile)}, \
-    {CC "put" #Type "Volatile",      CC "(" OBJ "J" #Desc ")V",   FN_PTR(Unsafe_Set##Type##Volatile)}
+    {CC "put" #Type "Volatile",      CC "(" OBJ "J" #Desc ")V",   FN_PTR(Unsafe_Put##Type##Volatile)}
 
 
-#define DECLARE_GETPUTNATIVE(Byte, B) \
-    {CC "get" #Byte,         CC "(" ADR ")" #B,       FN_PTR(Unsafe_GetNative##Byte)}, \
-    {CC "put" #Byte,         CC "(" ADR#B ")V",       FN_PTR(Unsafe_SetNative##Byte)}
-
 static JNINativeMethod jdk_internal_misc_Unsafe_methods[] = {
     {CC "getObject",        CC "(" OBJ "J)" OBJ "",   FN_PTR(Unsafe_GetObject)},
-    {CC "putObject",        CC "(" OBJ "J" OBJ ")V",  FN_PTR(Unsafe_SetObject)},
+    {CC "putObject",        CC "(" OBJ "J" OBJ ")V",  FN_PTR(Unsafe_PutObject)},
     {CC "getObjectVolatile",CC "(" OBJ "J)" OBJ "",   FN_PTR(Unsafe_GetObjectVolatile)},
-    {CC "putObjectVolatile",CC "(" OBJ "J" OBJ ")V",  FN_PTR(Unsafe_SetObjectVolatile)},
+    {CC "putObjectVolatile",CC "(" OBJ "J" OBJ ")V",  FN_PTR(Unsafe_PutObjectVolatile)},
 
     {CC "getUncompressedObject", CC "(" ADR ")" OBJ,  FN_PTR(Unsafe_GetUncompressedObject)},
     {CC "getJavaMirror",         CC "(" ADR ")" CLS,  FN_PTR(Unsafe_GetJavaMirror)},
@@ -1171,17 +1164,6 @@
     DECLARE_GETPUTOOP(Float, F),
     DECLARE_GETPUTOOP(Double, D),
 
-    DECLARE_GETPUTNATIVE(Byte, B),
-    DECLARE_GETPUTNATIVE(Short, S),
-    DECLARE_GETPUTNATIVE(Char, C),
-    DECLARE_GETPUTNATIVE(Int, I),
-    DECLARE_GETPUTNATIVE(Long, J),
-    DECLARE_GETPUTNATIVE(Float, F),
-    DECLARE_GETPUTNATIVE(Double, D),
-
-    {CC "getAddress",         CC "(" ADR ")" ADR,        FN_PTR(Unsafe_GetNativeAddress)},
-    {CC "putAddress",         CC "(" ADR "" ADR ")V",    FN_PTR(Unsafe_SetNativeAddress)},
-
     {CC "allocateMemory0",    CC "(J)" ADR,              FN_PTR(Unsafe_AllocateMemory0)},
     {CC "reallocateMemory0",  CC "(" ADR "J)" ADR,       FN_PTR(Unsafe_ReallocateMemory0)},
     {CC "freeMemory0",        CC "(" ADR ")V",           FN_PTR(Unsafe_FreeMemory0)},
@@ -1239,7 +1221,6 @@
 #undef DAC_Args
 
 #undef DECLARE_GETPUTOOP
-#undef DECLARE_GETPUTNATIVE
 
 
 // This function is exported, used by NativeLookup.