8229027: Improve how JNIHandleBlock::oops_do distinguishes oops from non-oops
Reviewed-by: pliden, stuefe, dlong
--- 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)