8229027: Improve how JNIHandleBlock::oops_do distinguishes oops from non-oops
authoreosterlund
Fri, 09 Aug 2019 10:06:44 +0200
changeset 57698 9dc92e89243a
parent 57697 2e38a71e6038
child 57699 4aea554692aa
8229027: Improve how JNIHandleBlock::oops_do distinguishes oops from non-oops Reviewed-by: pliden, stuefe, dlong
src/hotspot/share/runtime/jniHandles.cpp
src/hotspot/share/runtime/jniHandles.hpp
--- a/src/hotspot/share/runtime/jniHandles.cpp	Fri Aug 09 03:51:20 2019 +0200
+++ b/src/hotspot/share/runtime/jniHandles.cpp	Fri Aug 09 10:06:44 2019 +0200
@@ -347,6 +347,24 @@
 JNIHandleBlock* JNIHandleBlock::_block_list           = NULL;
 #endif
 
+static inline bool is_tagged_free_list(uintptr_t value) {
+  return (value & 1u) != 0;
+}
+
+static inline uintptr_t tag_free_list(uintptr_t value) {
+  return value | 1u;
+}
+
+static inline uintptr_t untag_free_list(uintptr_t value) {
+  return value & ~(uintptr_t)1u;
+}
+
+// There is a freelist of handles running through the JNIHandleBlock
+// with a tagged next pointer, distinguishing these next pointers from
+// oops. The freelist handling currently relies on the size of oops
+// being the same as a native pointer. If this ever changes, then
+// this freelist handling must change too.
+STATIC_ASSERT(sizeof(oop) == sizeof(uintptr_t));
 
 #ifdef ASSERT
 void JNIHandleBlock::zap() {
@@ -355,7 +373,7 @@
   for (int index = 0; index < block_size_in_oops; index++) {
     // NOT using Access here; just bare clobbering to NULL, since the
     // block no longer contains valid oops.
-    _handles[index] = NULL;
+    _handles[index] = 0;
   }
 }
 #endif // ASSERT
@@ -459,11 +477,12 @@
       assert(current == current_chain || current->pop_frame_link() == NULL,
         "only blocks first in chain should have pop frame link set");
       for (int index = 0; index < current->_top; index++) {
-        oop* root = &(current->_handles)[index];
-        oop value = *root;
+        uintptr_t* addr = &(current->_handles)[index];
+        uintptr_t value = *addr;
         // traverse heap pointers only, not deleted handles or free list
         // pointers
-        if (value != NULL && Universe::heap()->is_in_reserved(value)) {
+        if (value != 0 && !is_tagged_free_list(value)) {
+          oop* root = (oop*)addr;
           f->do_oop(root);
         }
       }
@@ -509,15 +528,15 @@
 
   // Try last block
   if (_last->_top < block_size_in_oops) {
-    oop* handle = &(_last->_handles)[_last->_top++];
+    oop* handle = (oop*)&(_last->_handles)[_last->_top++];
     NativeAccess<IS_DEST_UNINITIALIZED>::oop_store(handle, obj);
     return (jobject) handle;
   }
 
   // Try free list
   if (_free_list != NULL) {
-    oop* handle = _free_list;
-    _free_list = (oop*) *_free_list;
+    oop* handle = (oop*)_free_list;
+    _free_list = (uintptr_t*) untag_free_list(*_free_list);
     NativeAccess<IS_DEST_UNINITIALIZED>::oop_store(handle, obj);
     return (jobject) handle;
   }
@@ -550,10 +569,10 @@
   int blocks = 0;
   for (JNIHandleBlock* current = this; current != NULL; current = current->_next) {
     for (int index = 0; index < current->_top; index++) {
-      oop* handle = &(current->_handles)[index];
-      if (*handle == NULL) {
+      uintptr_t* handle = &(current->_handles)[index];
+      if (*handle == 0) {
         // this handle was cleared out by a delete call, reuse it
-        *handle = (oop) _free_list;
+        *handle = _free_list == NULL ? 0 : tag_free_list((uintptr_t)_free_list);
         _free_list = handle;
         free++;
       }
--- a/src/hotspot/share/runtime/jniHandles.hpp	Fri Aug 09 03:51:20 2019 +0200
+++ b/src/hotspot/share/runtime/jniHandles.hpp	Fri Aug 09 10:06:44 2019 +0200
@@ -140,7 +140,7 @@
     block_size_in_oops  = 32                    // Number of handles per handle block
   };
 
-  oop             _handles[block_size_in_oops]; // The handles
+  uintptr_t       _handles[block_size_in_oops]; // The handles
   int             _top;                         // Index of next unused handle
   JNIHandleBlock* _next;                        // Link to next block
 
@@ -148,7 +148,7 @@
   // Having two types of blocks complicates the code and the space overhead in negligible.
   JNIHandleBlock* _last;                        // Last block in use
   JNIHandleBlock* _pop_frame_link;              // Block to restore on PopLocalFrame call
-  oop*            _free_list;                   // Handle free list
+  uintptr_t*      _free_list;                   // Handle free list
   int             _allocate_before_rebuild;     // Number of blocks to allocate before rebuilding free list
 
   // Check JNI, "planned capacity" for current frame (or push/ensure)