1 /*
   2  * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #include "precompiled.hpp"
  26 #include "gc/shared/oopStorage.inline.hpp"
  27 #include "gc/shared/oopStorageSet.hpp"
  28 #include "logging/log.hpp"
  29 #include "memory/iterator.hpp"
  30 #include "memory/universe.hpp"
  31 #include "oops/access.inline.hpp"
  32 #include "oops/oop.inline.hpp"
  33 #include "runtime/handles.inline.hpp"
  34 #include "runtime/jniHandles.inline.hpp"
  35 #include "runtime/mutexLocker.hpp"
  36 #include "runtime/thread.inline.hpp"
  37 #include "utilities/align.hpp"
  38 #include "utilities/debug.hpp"
  39 
  40 static OopStorage* global_handles() {
  41   return OopStorageSet::jni_global();
  42 }
  43 
  44 static OopStorage* weak_global_handles() {
  45   return OopStorageSet::jni_weak();
  46 }
  47 
  48 // Serviceability agent support.
  49 OopStorage* JNIHandles::_global_handles = NULL;
  50 OopStorage* JNIHandles::_weak_global_handles = NULL;
  51 
  52 void jni_handles_init() {
  53   JNIHandles::_global_handles = global_handles();
  54   JNIHandles::_weak_global_handles = weak_global_handles();
  55 }
  56 
  57 
  58 jobject JNIHandles::make_local(oop obj) {
  59   if (obj == NULL) {
  60     return NULL;                // ignore null handles
  61   } else {
  62     Thread* thread = Thread::current();
  63     assert(oopDesc::is_oop(obj), "not an oop");
  64     assert(!current_thread_in_native(), "must not be in native");
  65     return thread->active_handles()->allocate_handle(obj);
  66   }
  67 }
  68 
  69 
  70 // optimized versions
  71 
  72 jobject JNIHandles::make_local(Thread* thread, oop obj) {
  73   if (obj == NULL) {
  74     return NULL;                // ignore null handles
  75   } else {
  76     assert(oopDesc::is_oop(obj), "not an oop");
  77     assert(thread->is_Java_thread(), "not a Java thread");
  78     assert(!current_thread_in_native(), "must not be in native");
  79     return thread->active_handles()->allocate_handle(obj);
  80   }
  81 }
  82 
  83 
  84 jobject JNIHandles::make_local(JNIEnv* env, oop obj) {
  85   if (obj == NULL) {
  86     return NULL;                // ignore null handles
  87   } else {
  88     JavaThread* thread = JavaThread::thread_from_jni_environment(env);
  89     assert(oopDesc::is_oop(obj), "not an oop");
  90     assert(!current_thread_in_native(), "must not be in native");
  91     return thread->active_handles()->allocate_handle(obj);
  92   }
  93 }
  94 
  95 
  96 static void report_handle_allocation_failure(AllocFailType alloc_failmode,
  97                                              const char* handle_kind) {
  98   if (alloc_failmode == AllocFailStrategy::EXIT_OOM) {
  99     // Fake size value, since we don't know the min allocation size here.
 100     vm_exit_out_of_memory(sizeof(oop), OOM_MALLOC_ERROR,
 101                           "Cannot create %s JNI handle", handle_kind);
 102   } else {
 103     assert(alloc_failmode == AllocFailStrategy::RETURN_NULL, "invariant");
 104   }
 105 }
 106 
 107 jobject JNIHandles::make_global(Handle obj, AllocFailType alloc_failmode) {
 108   assert(!Universe::heap()->is_gc_active(), "can't extend the root set during GC");
 109   assert(!current_thread_in_native(), "must not be in native");
 110   jobject res = NULL;
 111   if (!obj.is_null()) {
 112     // ignore null handles
 113     assert(oopDesc::is_oop(obj()), "not an oop");
 114     oop* ptr = global_handles()->allocate();
 115     // Return NULL on allocation failure.
 116     if (ptr != NULL) {
 117       assert(*ptr == NULL, "invariant");
 118       NativeAccess<>::oop_store(ptr, obj());
 119       res = reinterpret_cast<jobject>(ptr);
 120     } else {
 121       report_handle_allocation_failure(alloc_failmode, "global");
 122     }
 123   }
 124 
 125   return res;
 126 }
 127 
 128 
 129 jobject JNIHandles::make_weak_global(Handle obj, AllocFailType alloc_failmode) {
 130   assert(!Universe::heap()->is_gc_active(), "can't extend the root set during GC");
 131   assert(!current_thread_in_native(), "must not be in native");
 132   jobject res = NULL;
 133   if (!obj.is_null()) {
 134     // ignore null handles
 135     assert(oopDesc::is_oop(obj()), "not an oop");
 136     oop* ptr = weak_global_handles()->allocate();
 137     // Return NULL on allocation failure.
 138     if (ptr != NULL) {
 139       assert(*ptr == NULL, "invariant");
 140       NativeAccess<ON_PHANTOM_OOP_REF>::oop_store(ptr, obj());
 141       char* tptr = reinterpret_cast<char*>(ptr) + weak_tag_value;
 142       res = reinterpret_cast<jobject>(tptr);
 143     } else {
 144       report_handle_allocation_failure(alloc_failmode, "weak global");
 145     }
 146   }
 147   return res;
 148 }
 149 
 150 // Resolve some erroneous cases to NULL, rather than treating them as
 151 // possibly unchecked errors.  In particular, deleted handles are
 152 // treated as NULL (though a deleted and later reallocated handle
 153 // isn't detected).
 154 oop JNIHandles::resolve_external_guard(jobject handle) {
 155   oop result = NULL;
 156   if (handle != NULL) {
 157     result = resolve_impl<DECORATORS_NONE, true /* external_guard */>(handle);
 158   }
 159   return result;
 160 }
 161 
 162 bool JNIHandles::is_global_weak_cleared(jweak handle) {
 163   assert(handle != NULL, "precondition");
 164   assert(is_jweak(handle), "not a weak handle");
 165   oop* oop_ptr = jweak_ptr(handle);
 166   oop value = NativeAccess<ON_PHANTOM_OOP_REF | AS_NO_KEEPALIVE>::oop_load(oop_ptr);
 167   return value == NULL;
 168 }
 169 
 170 void JNIHandles::destroy_global(jobject handle) {
 171   if (handle != NULL) {
 172     assert(!is_jweak(handle), "wrong method for detroying jweak");
 173     oop* oop_ptr = jobject_ptr(handle);
 174     NativeAccess<>::oop_store(oop_ptr, (oop)NULL);
 175     global_handles()->release(oop_ptr);
 176   }
 177 }
 178 
 179 
 180 void JNIHandles::destroy_weak_global(jobject handle) {
 181   if (handle != NULL) {
 182     assert(is_jweak(handle), "JNI handle not jweak");
 183     oop* oop_ptr = jweak_ptr(handle);
 184     NativeAccess<ON_PHANTOM_OOP_REF>::oop_store(oop_ptr, (oop)NULL);
 185     weak_global_handles()->release(oop_ptr);
 186   }
 187 }
 188 
 189 
 190 void JNIHandles::oops_do(OopClosure* f) {
 191   global_handles()->oops_do(f);
 192 }
 193 
 194 
 195 void JNIHandles::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f) {
 196   weak_global_handles()->weak_oops_do(is_alive, f);
 197 }
 198 
 199 
 200 void JNIHandles::weak_oops_do(OopClosure* f) {
 201   weak_global_handles()->weak_oops_do(f);
 202 }
 203 
 204 
 205 inline bool is_storage_handle(const OopStorage* storage, const oop* ptr) {
 206   return storage->allocation_status(ptr) == OopStorage::ALLOCATED_ENTRY;
 207 }
 208 
 209 
 210 jobjectRefType JNIHandles::handle_type(Thread* thread, jobject handle) {
 211   assert(handle != NULL, "precondition");
 212   jobjectRefType result = JNIInvalidRefType;
 213   if (is_jweak(handle)) {
 214     if (is_storage_handle(weak_global_handles(), jweak_ptr(handle))) {
 215       result = JNIWeakGlobalRefType;
 216     }
 217   } else {
 218     switch (global_handles()->allocation_status(jobject_ptr(handle))) {
 219     case OopStorage::ALLOCATED_ENTRY:
 220       result = JNIGlobalRefType;
 221       break;
 222 
 223     case OopStorage::UNALLOCATED_ENTRY:
 224       break;                    // Invalid global handle
 225 
 226     case OopStorage::INVALID_ENTRY:
 227       // Not in global storage.  Might be a local handle.
 228       if (is_local_handle(thread, handle) ||
 229           (thread->is_Java_thread() &&
 230            is_frame_handle((JavaThread*)thread, handle))) {
 231         result = JNILocalRefType;
 232       }
 233       break;
 234 
 235     default:
 236       ShouldNotReachHere();
 237     }
 238   }
 239   return result;
 240 }
 241 
 242 
 243 bool JNIHandles::is_local_handle(Thread* thread, jobject handle) {
 244   assert(handle != NULL, "precondition");
 245   JNIHandleBlock* block = thread->active_handles();
 246 
 247   // Look back past possible native calls to jni_PushLocalFrame.
 248   while (block != NULL) {
 249     if (block->chain_contains(handle)) {
 250       return true;
 251     }
 252     block = block->pop_frame_link();
 253   }
 254   return false;
 255 }
 256 
 257 
 258 // Determine if the handle is somewhere in the current thread's stack.
 259 // We easily can't isolate any particular stack frame the handle might
 260 // come from, so we'll check the whole stack.
 261 
 262 bool JNIHandles::is_frame_handle(JavaThread* thr, jobject handle) {
 263   assert(handle != NULL, "precondition");
 264   // If there is no java frame, then this must be top level code, such
 265   // as the java command executable, in which case, this type of handle
 266   // is not permitted.
 267   return (thr->has_last_Java_frame() &&
 268           thr->is_in_stack_range_incl((address)handle, (address)thr->last_Java_sp()));
 269 }
 270 
 271 
 272 bool JNIHandles::is_global_handle(jobject handle) {
 273   assert(handle != NULL, "precondition");
 274   return !is_jweak(handle) && is_storage_handle(global_handles(), jobject_ptr(handle));
 275 }
 276 
 277 
 278 bool JNIHandles::is_weak_global_handle(jobject handle) {
 279   assert(handle != NULL, "precondition");
 280   return is_jweak(handle) && is_storage_handle(weak_global_handles(), jweak_ptr(handle));
 281 }
 282 
 283 size_t JNIHandles::global_handle_memory_usage() {
 284   return global_handles()->total_memory_usage();
 285 }
 286 
 287 size_t JNIHandles::weak_global_handle_memory_usage() {
 288   return weak_global_handles()->total_memory_usage();
 289 }
 290 
 291 
 292 // We assume this is called at a safepoint: no lock is needed.
 293 void JNIHandles::print_on(outputStream* st) {
 294   assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
 295 
 296   st->print_cr("JNI global refs: " SIZE_FORMAT ", weak refs: " SIZE_FORMAT,
 297                global_handles()->allocation_count(),
 298                weak_global_handles()->allocation_count());
 299   st->cr();
 300   st->flush();
 301 }
 302 
 303 void JNIHandles::print() { print_on(tty); }
 304 
 305 class VerifyJNIHandles: public OopClosure {
 306 public:
 307   virtual void do_oop(oop* root) {
 308     guarantee(oopDesc::is_oop_or_null(RawAccess<>::oop_load(root)), "Invalid oop");
 309   }
 310   virtual void do_oop(narrowOop* root) { ShouldNotReachHere(); }
 311 };
 312 
 313 void JNIHandles::verify() {
 314   VerifyJNIHandles verify_handle;
 315 
 316   oops_do(&verify_handle);
 317   weak_oops_do(&verify_handle);
 318 }
 319 
 320 // This method is implemented here to avoid circular includes between
 321 // jniHandles.hpp and thread.hpp.
 322 bool JNIHandles::current_thread_in_native() {
 323   Thread* thread = Thread::current();
 324   return (thread->is_Java_thread() &&
 325           JavaThread::current()->thread_state() == _thread_in_native);
 326 }
 327 
 328 
 329 int             JNIHandleBlock::_blocks_allocated     = 0;
 330 JNIHandleBlock* JNIHandleBlock::_block_free_list      = NULL;
 331 #ifndef PRODUCT
 332 JNIHandleBlock* JNIHandleBlock::_block_list           = NULL;
 333 #endif
 334 
 335 static inline bool is_tagged_free_list(uintptr_t value) {
 336   return (value & 1u) != 0;
 337 }
 338 
 339 static inline uintptr_t tag_free_list(uintptr_t value) {
 340   return value | 1u;
 341 }
 342 
 343 static inline uintptr_t untag_free_list(uintptr_t value) {
 344   return value & ~(uintptr_t)1u;
 345 }
 346 
 347 // There is a freelist of handles running through the JNIHandleBlock
 348 // with a tagged next pointer, distinguishing these next pointers from
 349 // oops. The freelist handling currently relies on the size of oops
 350 // being the same as a native pointer. If this ever changes, then
 351 // this freelist handling must change too.
 352 STATIC_ASSERT(sizeof(oop) == sizeof(uintptr_t));
 353 
 354 #ifdef ASSERT
 355 void JNIHandleBlock::zap() {
 356   // Zap block values
 357   _top = 0;
 358   for (int index = 0; index < block_size_in_oops; index++) {
 359     // NOT using Access here; just bare clobbering to NULL, since the
 360     // block no longer contains valid oops.
 361     _handles[index] = 0;
 362   }
 363 }
 364 #endif // ASSERT
 365 
 366 JNIHandleBlock* JNIHandleBlock::allocate_block(Thread* thread)  {
 367   assert(thread == NULL || thread == Thread::current(), "sanity check");
 368   JNIHandleBlock* block;
 369   // Check the thread-local free list for a block so we don't
 370   // have to acquire a mutex.
 371   if (thread != NULL && thread->free_handle_block() != NULL) {
 372     block = thread->free_handle_block();
 373     thread->set_free_handle_block(block->_next);
 374   }
 375   else {
 376     // locking with safepoint checking introduces a potential deadlock:
 377     // - we would hold JNIHandleBlockFreeList_lock and then Threads_lock
 378     // - another would hold Threads_lock (jni_AttachCurrentThread) and then
 379     //   JNIHandleBlockFreeList_lock (JNIHandleBlock::allocate_block)
 380     MutexLocker ml(JNIHandleBlockFreeList_lock,
 381                    Mutex::_no_safepoint_check_flag);
 382     if (_block_free_list == NULL) {
 383       // Allocate new block
 384       block = new JNIHandleBlock();
 385       _blocks_allocated++;
 386       block->zap();
 387       #ifndef PRODUCT
 388       // Link new block to list of all allocated blocks
 389       block->_block_list_link = _block_list;
 390       _block_list = block;
 391       #endif
 392     } else {
 393       // Get block from free list
 394       block = _block_free_list;
 395       _block_free_list = _block_free_list->_next;
 396     }
 397   }
 398   block->_top = 0;
 399   block->_next = NULL;
 400   block->_pop_frame_link = NULL;
 401   block->_planned_capacity = block_size_in_oops;
 402   // _last, _free_list & _allocate_before_rebuild initialized in allocate_handle
 403   debug_only(block->_last = NULL);
 404   debug_only(block->_free_list = NULL);
 405   debug_only(block->_allocate_before_rebuild = -1);
 406   return block;
 407 }
 408 
 409 
 410 void JNIHandleBlock::release_block(JNIHandleBlock* block, Thread* thread) {
 411   assert(thread == NULL || thread == Thread::current(), "sanity check");
 412   JNIHandleBlock* pop_frame_link = block->pop_frame_link();
 413   // Put returned block at the beginning of the thread-local free list.
 414   // Note that if thread == NULL, we use it as an implicit argument that
 415   // we _don't_ want the block to be kept on the free_handle_block.
 416   // See for instance JavaThread::exit().
 417   if (thread != NULL ) {
 418     block->zap();
 419     JNIHandleBlock* freelist = thread->free_handle_block();
 420     block->_pop_frame_link = NULL;
 421     thread->set_free_handle_block(block);
 422 
 423     // Add original freelist to end of chain
 424     if ( freelist != NULL ) {
 425       while ( block->_next != NULL ) block = block->_next;
 426       block->_next = freelist;
 427     }
 428     block = NULL;
 429   }
 430   if (block != NULL) {
 431     // Return blocks to free list
 432     // locking with safepoint checking introduces a potential deadlock:
 433     // - we would hold JNIHandleBlockFreeList_lock and then Threads_lock
 434     // - another would hold Threads_lock (jni_AttachCurrentThread) and then
 435     //   JNIHandleBlockFreeList_lock (JNIHandleBlock::allocate_block)
 436     MutexLocker ml(JNIHandleBlockFreeList_lock,
 437                    Mutex::_no_safepoint_check_flag);
 438     while (block != NULL) {
 439       block->zap();
 440       JNIHandleBlock* next = block->_next;
 441       block->_next = _block_free_list;
 442       _block_free_list = block;
 443       block = next;
 444     }
 445   }
 446   if (pop_frame_link != NULL) {
 447     // As a sanity check we release blocks pointed to by the pop_frame_link.
 448     // This should never happen (only if PopLocalFrame is not called the
 449     // correct number of times).
 450     release_block(pop_frame_link, thread);
 451   }
 452 }
 453 
 454 
 455 void JNIHandleBlock::oops_do(OopClosure* f) {
 456   JNIHandleBlock* current_chain = this;
 457   // Iterate over chain of blocks, followed by chains linked through the
 458   // pop frame links.
 459   while (current_chain != NULL) {
 460     for (JNIHandleBlock* current = current_chain; current != NULL;
 461          current = current->_next) {
 462       assert(current == current_chain || current->pop_frame_link() == NULL,
 463         "only blocks first in chain should have pop frame link set");
 464       for (int index = 0; index < current->_top; index++) {
 465         uintptr_t* addr = &(current->_handles)[index];
 466         uintptr_t value = *addr;
 467         // traverse heap pointers only, not deleted handles or free list
 468         // pointers
 469         if (value != 0 && !is_tagged_free_list(value)) {
 470           oop* root = (oop*)addr;
 471           f->do_oop(root);
 472         }
 473       }
 474       // the next handle block is valid only if current block is full
 475       if (current->_top < block_size_in_oops) {
 476         break;
 477       }
 478     }
 479     current_chain = current_chain->pop_frame_link();
 480   }
 481 }
 482 
 483 
 484 jobject JNIHandleBlock::allocate_handle(oop obj) {
 485   assert(Universe::heap()->is_in(obj), "sanity check");
 486   if (_top == 0) {
 487     // This is the first allocation or the initial block got zapped when
 488     // entering a native function. If we have any following blocks they are
 489     // not valid anymore.
 490     for (JNIHandleBlock* current = _next; current != NULL;
 491          current = current->_next) {
 492       assert(current->_last == NULL, "only first block should have _last set");
 493       assert(current->_free_list == NULL,
 494              "only first block should have _free_list set");
 495       if (current->_top == 0) {
 496         // All blocks after the first clear trailing block are already cleared.
 497 #ifdef ASSERT
 498         for (current = current->_next; current != NULL; current = current->_next) {
 499           assert(current->_top == 0, "trailing blocks must already be cleared");
 500         }
 501 #endif
 502         break;
 503       }
 504       current->_top = 0;
 505       current->zap();
 506     }
 507     // Clear initial block
 508     _free_list = NULL;
 509     _allocate_before_rebuild = 0;
 510     _last = this;
 511     zap();
 512   }
 513 
 514   // Try last block
 515   if (_last->_top < block_size_in_oops) {
 516     oop* handle = (oop*)&(_last->_handles)[_last->_top++];
 517     NativeAccess<IS_DEST_UNINITIALIZED>::oop_store(handle, obj);
 518     return (jobject) handle;
 519   }
 520 
 521   // Try free list
 522   if (_free_list != NULL) {
 523     oop* handle = (oop*)_free_list;
 524     _free_list = (uintptr_t*) untag_free_list(*_free_list);
 525     NativeAccess<IS_DEST_UNINITIALIZED>::oop_store(handle, obj);
 526     return (jobject) handle;
 527   }
 528   // Check if unused block follow last
 529   if (_last->_next != NULL) {
 530     // update last and retry
 531     _last = _last->_next;
 532     return allocate_handle(obj);
 533   }
 534 
 535   // No space available, we have to rebuild free list or expand
 536   if (_allocate_before_rebuild == 0) {
 537       rebuild_free_list();        // updates _allocate_before_rebuild counter
 538   } else {
 539     // Append new block
 540     Thread* thread = Thread::current();
 541     Handle obj_handle(thread, obj);
 542     // This can block, so we need to preserve obj across call.
 543     _last->_next = JNIHandleBlock::allocate_block(thread);
 544     _last = _last->_next;
 545     _allocate_before_rebuild--;
 546     obj = obj_handle();
 547   }
 548   return allocate_handle(obj);  // retry
 549 }
 550 
 551 void JNIHandleBlock::rebuild_free_list() {
 552   assert(_allocate_before_rebuild == 0 && _free_list == NULL, "just checking");
 553   int free = 0;
 554   int blocks = 0;
 555   for (JNIHandleBlock* current = this; current != NULL; current = current->_next) {
 556     for (int index = 0; index < current->_top; index++) {
 557       uintptr_t* handle = &(current->_handles)[index];
 558       if (*handle == 0) {
 559         // this handle was cleared out by a delete call, reuse it
 560         *handle = _free_list == NULL ? 0 : tag_free_list((uintptr_t)_free_list);
 561         _free_list = handle;
 562         free++;
 563       }
 564     }
 565     // we should not rebuild free list if there are unused handles at the end
 566     assert(current->_top == block_size_in_oops, "just checking");
 567     blocks++;
 568   }
 569   // Heuristic: if more than half of the handles are free we rebuild next time
 570   // as well, otherwise we append a corresponding number of new blocks before
 571   // attempting a free list rebuild again.
 572   int total = blocks * block_size_in_oops;
 573   int extra = total - 2*free;
 574   if (extra > 0) {
 575     // Not as many free handles as we would like - compute number of new blocks to append
 576     _allocate_before_rebuild = (extra + block_size_in_oops - 1) / block_size_in_oops;
 577   }
 578 }
 579 
 580 
 581 bool JNIHandleBlock::contains(jobject handle) const {
 582   return ((jobject)&_handles[0] <= handle && handle<(jobject)&_handles[_top]);
 583 }
 584 
 585 
 586 bool JNIHandleBlock::chain_contains(jobject handle) const {
 587   for (JNIHandleBlock* current = (JNIHandleBlock*) this; current != NULL; current = current->_next) {
 588     if (current->contains(handle)) {
 589       return true;
 590     }
 591   }
 592   return false;
 593 }
 594 
 595 
 596 size_t JNIHandleBlock::length() const {
 597   size_t result = 1;
 598   for (JNIHandleBlock* current = _next; current != NULL; current = current->_next) {
 599     result++;
 600   }
 601   return result;
 602 }
 603 
 604 class CountJNIHandleClosure: public OopClosure {
 605 private:
 606   int _count;
 607 public:
 608   CountJNIHandleClosure(): _count(0) {}
 609   virtual void do_oop(oop* ooph) { _count++; }
 610   virtual void do_oop(narrowOop* unused) { ShouldNotReachHere(); }
 611   int count() { return _count; }
 612 };
 613 
 614 const size_t JNIHandleBlock::get_number_of_live_handles() {
 615   CountJNIHandleClosure counter;
 616   oops_do(&counter);
 617   return counter.count();
 618 }
 619 
 620 // This method is not thread-safe, i.e., must be called while holding a lock on the
 621 // structure.
 622 size_t JNIHandleBlock::memory_usage() const {
 623   return length() * sizeof(JNIHandleBlock);
 624 }
 625 
 626 
 627 #ifndef PRODUCT
 628 
 629 bool JNIHandles::is_local_handle(jobject handle) {
 630   return JNIHandleBlock::any_contains(handle);
 631 }
 632 
 633 bool JNIHandleBlock::any_contains(jobject handle) {
 634   assert(handle != NULL, "precondition");
 635   for (JNIHandleBlock* current = _block_list; current != NULL; current = current->_block_list_link) {
 636     if (current->contains(handle)) {
 637       return true;
 638     }
 639   }
 640   return false;
 641 }
 642 
 643 void JNIHandleBlock::print_statistics() {
 644   int used_blocks = 0;
 645   int free_blocks = 0;
 646   int used_handles = 0;
 647   int free_handles = 0;
 648   JNIHandleBlock* block = _block_list;
 649   while (block != NULL) {
 650     if (block->_top > 0) {
 651       used_blocks++;
 652     } else {
 653       free_blocks++;
 654     }
 655     used_handles += block->_top;
 656     free_handles += (block_size_in_oops - block->_top);
 657     block = block->_block_list_link;
 658   }
 659   tty->print_cr("JNIHandleBlocks statistics");
 660   tty->print_cr("- blocks allocated: %d", used_blocks + free_blocks);
 661   tty->print_cr("- blocks in use:    %d", used_blocks);
 662   tty->print_cr("- blocks free:      %d", free_blocks);
 663   tty->print_cr("- handles in use:   %d", used_handles);
 664   tty->print_cr("- handles free:     %d", free_handles);
 665 }
 666 
 667 #endif