Path: blob/master/src/hotspot/share/runtime/jniHandles.cpp
40951 views
/*1* Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "gc/shared/collectedHeap.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"3940OopStorage* JNIHandles::global_handles() {41return _global_handles;42}4344OopStorage* JNIHandles::weak_global_handles() {45return _weak_global_handles;46}4748// Serviceability agent support.49OopStorage* JNIHandles::_global_handles = NULL;50OopStorage* JNIHandles::_weak_global_handles = NULL;5152void jni_handles_init() {53JNIHandles::_global_handles = OopStorageSet::create_strong("JNI Global", mtInternal);54JNIHandles::_weak_global_handles = OopStorageSet::create_weak("JNI Weak", mtInternal);55}5657jobject JNIHandles::make_local(oop obj) {58return make_local(Thread::current(), obj);59}6061// Used by NewLocalRef which requires NULL on out-of-memory62jobject JNIHandles::make_local(Thread* thread, oop obj, AllocFailType alloc_failmode) {63if (obj == NULL) {64return NULL; // ignore null handles65} else {66assert(oopDesc::is_oop(obj), "not an oop");67assert(thread->is_Java_thread(), "not a Java thread");68assert(!current_thread_in_native(), "must not be in native");69return thread->active_handles()->allocate_handle(obj, alloc_failmode);70}71}7273static void report_handle_allocation_failure(AllocFailType alloc_failmode,74const char* handle_kind) {75if (alloc_failmode == AllocFailStrategy::EXIT_OOM) {76// Fake size value, since we don't know the min allocation size here.77vm_exit_out_of_memory(sizeof(oop), OOM_MALLOC_ERROR,78"Cannot create %s JNI handle", handle_kind);79} else {80assert(alloc_failmode == AllocFailStrategy::RETURN_NULL, "invariant");81}82}8384jobject JNIHandles::make_global(Handle obj, AllocFailType alloc_failmode) {85assert(!Universe::heap()->is_gc_active(), "can't extend the root set during GC");86assert(!current_thread_in_native(), "must not be in native");87jobject res = NULL;88if (!obj.is_null()) {89// ignore null handles90assert(oopDesc::is_oop(obj()), "not an oop");91oop* ptr = global_handles()->allocate();92// Return NULL on allocation failure.93if (ptr != NULL) {94assert(*ptr == NULL, "invariant");95NativeAccess<>::oop_store(ptr, obj());96res = reinterpret_cast<jobject>(ptr);97} else {98report_handle_allocation_failure(alloc_failmode, "global");99}100}101102return res;103}104105jobject JNIHandles::make_weak_global(Handle obj, AllocFailType alloc_failmode) {106assert(!Universe::heap()->is_gc_active(), "can't extend the root set during GC");107assert(!current_thread_in_native(), "must not be in native");108jobject res = NULL;109if (!obj.is_null()) {110// ignore null handles111assert(oopDesc::is_oop(obj()), "not an oop");112oop* ptr = weak_global_handles()->allocate();113// Return NULL on allocation failure.114if (ptr != NULL) {115assert(*ptr == NULL, "invariant");116NativeAccess<ON_PHANTOM_OOP_REF>::oop_store(ptr, obj());117char* tptr = reinterpret_cast<char*>(ptr) + weak_tag_value;118res = reinterpret_cast<jobject>(tptr);119} else {120report_handle_allocation_failure(alloc_failmode, "weak global");121}122}123return res;124}125126// Resolve some erroneous cases to NULL, rather than treating them as127// possibly unchecked errors. In particular, deleted handles are128// treated as NULL (though a deleted and later reallocated handle129// isn't detected).130oop JNIHandles::resolve_external_guard(jobject handle) {131oop result = NULL;132if (handle != NULL) {133result = resolve_impl<DECORATORS_NONE, true /* external_guard */>(handle);134}135return result;136}137138bool JNIHandles::is_global_weak_cleared(jweak handle) {139assert(handle != NULL, "precondition");140assert(is_jweak(handle), "not a weak handle");141oop* oop_ptr = jweak_ptr(handle);142oop value = NativeAccess<ON_PHANTOM_OOP_REF | AS_NO_KEEPALIVE>::oop_load(oop_ptr);143return value == NULL;144}145146void JNIHandles::destroy_global(jobject handle) {147if (handle != NULL) {148assert(!is_jweak(handle), "wrong method for detroying jweak");149oop* oop_ptr = jobject_ptr(handle);150NativeAccess<>::oop_store(oop_ptr, (oop)NULL);151global_handles()->release(oop_ptr);152}153}154155156void JNIHandles::destroy_weak_global(jobject handle) {157if (handle != NULL) {158assert(is_jweak(handle), "JNI handle not jweak");159oop* oop_ptr = jweak_ptr(handle);160NativeAccess<ON_PHANTOM_OOP_REF>::oop_store(oop_ptr, (oop)NULL);161weak_global_handles()->release(oop_ptr);162}163}164165166void JNIHandles::oops_do(OopClosure* f) {167global_handles()->oops_do(f);168}169170171void JNIHandles::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f) {172weak_global_handles()->weak_oops_do(is_alive, f);173}174175176void JNIHandles::weak_oops_do(OopClosure* f) {177weak_global_handles()->weak_oops_do(f);178}179180bool JNIHandles::is_global_storage(const OopStorage* storage) {181return _global_handles == storage;182}183184inline bool is_storage_handle(const OopStorage* storage, const oop* ptr) {185return storage->allocation_status(ptr) == OopStorage::ALLOCATED_ENTRY;186}187188189jobjectRefType JNIHandles::handle_type(Thread* thread, jobject handle) {190assert(handle != NULL, "precondition");191jobjectRefType result = JNIInvalidRefType;192if (is_jweak(handle)) {193if (is_storage_handle(weak_global_handles(), jweak_ptr(handle))) {194result = JNIWeakGlobalRefType;195}196} else {197switch (global_handles()->allocation_status(jobject_ptr(handle))) {198case OopStorage::ALLOCATED_ENTRY:199result = JNIGlobalRefType;200break;201202case OopStorage::UNALLOCATED_ENTRY:203break; // Invalid global handle204205case OopStorage::INVALID_ENTRY:206// Not in global storage. Might be a local handle.207if (is_local_handle(thread, handle) ||208(thread->is_Java_thread() &&209is_frame_handle(thread->as_Java_thread(), handle))) {210result = JNILocalRefType;211}212break;213214default:215ShouldNotReachHere();216}217}218return result;219}220221222bool JNIHandles::is_local_handle(Thread* thread, jobject handle) {223assert(handle != NULL, "precondition");224JNIHandleBlock* block = thread->active_handles();225226// Look back past possible native calls to jni_PushLocalFrame.227while (block != NULL) {228if (block->chain_contains(handle)) {229return true;230}231block = block->pop_frame_link();232}233return false;234}235236237// Determine if the handle is somewhere in the current thread's stack.238// We easily can't isolate any particular stack frame the handle might239// come from, so we'll check the whole stack.240241bool JNIHandles::is_frame_handle(JavaThread* thr, jobject handle) {242assert(handle != NULL, "precondition");243// If there is no java frame, then this must be top level code, such244// as the java command executable, in which case, this type of handle245// is not permitted.246return (thr->has_last_Java_frame() &&247thr->is_in_stack_range_incl((address)handle, (address)thr->last_Java_sp()));248}249250251bool JNIHandles::is_global_handle(jobject handle) {252assert(handle != NULL, "precondition");253return !is_jweak(handle) && is_storage_handle(global_handles(), jobject_ptr(handle));254}255256257bool JNIHandles::is_weak_global_handle(jobject handle) {258assert(handle != NULL, "precondition");259return is_jweak(handle) && is_storage_handle(weak_global_handles(), jweak_ptr(handle));260}261262size_t JNIHandles::global_handle_memory_usage() {263return global_handles()->total_memory_usage();264}265266size_t JNIHandles::weak_global_handle_memory_usage() {267return weak_global_handles()->total_memory_usage();268}269270271// We assume this is called at a safepoint: no lock is needed.272void JNIHandles::print_on(outputStream* st) {273assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");274275st->print_cr("JNI global refs: " SIZE_FORMAT ", weak refs: " SIZE_FORMAT,276global_handles()->allocation_count(),277weak_global_handles()->allocation_count());278st->cr();279st->flush();280}281282void JNIHandles::print() { print_on(tty); }283284class VerifyJNIHandles: public OopClosure {285public:286virtual void do_oop(oop* root) {287guarantee(oopDesc::is_oop_or_null(RawAccess<>::oop_load(root)), "Invalid oop");288}289virtual void do_oop(narrowOop* root) { ShouldNotReachHere(); }290};291292void JNIHandles::verify() {293VerifyJNIHandles verify_handle;294295oops_do(&verify_handle);296weak_oops_do(&verify_handle);297}298299// This method is implemented here to avoid circular includes between300// jniHandles.hpp and thread.hpp.301bool JNIHandles::current_thread_in_native() {302Thread* thread = Thread::current();303return (thread->is_Java_thread() &&304thread->as_Java_thread()->thread_state() == _thread_in_native);305}306307308int JNIHandleBlock::_blocks_allocated = 0;309JNIHandleBlock* JNIHandleBlock::_block_free_list = NULL;310#ifndef PRODUCT311JNIHandleBlock* JNIHandleBlock::_block_list = NULL;312#endif313314static inline bool is_tagged_free_list(uintptr_t value) {315return (value & 1u) != 0;316}317318static inline uintptr_t tag_free_list(uintptr_t value) {319return value | 1u;320}321322static inline uintptr_t untag_free_list(uintptr_t value) {323return value & ~(uintptr_t)1u;324}325326// There is a freelist of handles running through the JNIHandleBlock327// with a tagged next pointer, distinguishing these next pointers from328// oops. The freelist handling currently relies on the size of oops329// being the same as a native pointer. If this ever changes, then330// this freelist handling must change too.331STATIC_ASSERT(sizeof(oop) == sizeof(uintptr_t));332333#ifdef ASSERT334void JNIHandleBlock::zap() {335// Zap block values336_top = 0;337for (int index = 0; index < block_size_in_oops; index++) {338// NOT using Access here; just bare clobbering to NULL, since the339// block no longer contains valid oops.340_handles[index] = 0;341}342}343#endif // ASSERT344345JNIHandleBlock* JNIHandleBlock::allocate_block(Thread* thread, AllocFailType alloc_failmode) {346assert(thread == NULL || thread == Thread::current(), "sanity check");347JNIHandleBlock* block;348// Check the thread-local free list for a block so we don't349// have to acquire a mutex.350if (thread != NULL && thread->free_handle_block() != NULL) {351block = thread->free_handle_block();352thread->set_free_handle_block(block->_next);353}354else {355// locking with safepoint checking introduces a potential deadlock:356// - we would hold JNIHandleBlockFreeList_lock and then Threads_lock357// - another would hold Threads_lock (jni_AttachCurrentThread) and then358// JNIHandleBlockFreeList_lock (JNIHandleBlock::allocate_block)359MutexLocker ml(JNIHandleBlockFreeList_lock,360Mutex::_no_safepoint_check_flag);361if (_block_free_list == NULL) {362// Allocate new block363if (alloc_failmode == AllocFailStrategy::RETURN_NULL) {364block = new (std::nothrow) JNIHandleBlock();365if (block == NULL) {366return NULL;367}368} else {369block = new JNIHandleBlock();370}371_blocks_allocated++;372block->zap();373#ifndef PRODUCT374// Link new block to list of all allocated blocks375block->_block_list_link = _block_list;376_block_list = block;377#endif378} else {379// Get block from free list380block = _block_free_list;381_block_free_list = _block_free_list->_next;382}383}384block->_top = 0;385block->_next = NULL;386block->_pop_frame_link = NULL;387block->_planned_capacity = block_size_in_oops;388// _last, _free_list & _allocate_before_rebuild initialized in allocate_handle389debug_only(block->_last = NULL);390debug_only(block->_free_list = NULL);391debug_only(block->_allocate_before_rebuild = -1);392return block;393}394395396void JNIHandleBlock::release_block(JNIHandleBlock* block, Thread* thread) {397assert(thread == NULL || thread == Thread::current(), "sanity check");398JNIHandleBlock* pop_frame_link = block->pop_frame_link();399// Put returned block at the beginning of the thread-local free list.400// Note that if thread == NULL, we use it as an implicit argument that401// we _don't_ want the block to be kept on the free_handle_block.402// See for instance JavaThread::exit().403if (thread != NULL ) {404block->zap();405JNIHandleBlock* freelist = thread->free_handle_block();406block->_pop_frame_link = NULL;407thread->set_free_handle_block(block);408409// Add original freelist to end of chain410if ( freelist != NULL ) {411while ( block->_next != NULL ) block = block->_next;412block->_next = freelist;413}414block = NULL;415}416if (block != NULL) {417// Return blocks to free list418// locking with safepoint checking introduces a potential deadlock:419// - we would hold JNIHandleBlockFreeList_lock and then Threads_lock420// - another would hold Threads_lock (jni_AttachCurrentThread) and then421// JNIHandleBlockFreeList_lock (JNIHandleBlock::allocate_block)422MutexLocker ml(JNIHandleBlockFreeList_lock,423Mutex::_no_safepoint_check_flag);424while (block != NULL) {425block->zap();426JNIHandleBlock* next = block->_next;427block->_next = _block_free_list;428_block_free_list = block;429block = next;430}431}432if (pop_frame_link != NULL) {433// As a sanity check we release blocks pointed to by the pop_frame_link.434// This should never happen (only if PopLocalFrame is not called the435// correct number of times).436release_block(pop_frame_link, thread);437}438}439440441void JNIHandleBlock::oops_do(OopClosure* f) {442JNIHandleBlock* current_chain = this;443// Iterate over chain of blocks, followed by chains linked through the444// pop frame links.445while (current_chain != NULL) {446for (JNIHandleBlock* current = current_chain; current != NULL;447current = current->_next) {448assert(current == current_chain || current->pop_frame_link() == NULL,449"only blocks first in chain should have pop frame link set");450for (int index = 0; index < current->_top; index++) {451uintptr_t* addr = &(current->_handles)[index];452uintptr_t value = *addr;453// traverse heap pointers only, not deleted handles or free list454// pointers455if (value != 0 && !is_tagged_free_list(value)) {456oop* root = (oop*)addr;457f->do_oop(root);458}459}460// the next handle block is valid only if current block is full461if (current->_top < block_size_in_oops) {462break;463}464}465current_chain = current_chain->pop_frame_link();466}467}468469470jobject JNIHandleBlock::allocate_handle(oop obj, AllocFailType alloc_failmode) {471assert(Universe::heap()->is_in(obj), "sanity check");472if (_top == 0) {473// This is the first allocation or the initial block got zapped when474// entering a native function. If we have any following blocks they are475// not valid anymore.476for (JNIHandleBlock* current = _next; current != NULL;477current = current->_next) {478assert(current->_last == NULL, "only first block should have _last set");479assert(current->_free_list == NULL,480"only first block should have _free_list set");481if (current->_top == 0) {482// All blocks after the first clear trailing block are already cleared.483#ifdef ASSERT484for (current = current->_next; current != NULL; current = current->_next) {485assert(current->_top == 0, "trailing blocks must already be cleared");486}487#endif488break;489}490current->_top = 0;491current->zap();492}493// Clear initial block494_free_list = NULL;495_allocate_before_rebuild = 0;496_last = this;497zap();498}499500// Try last block501if (_last->_top < block_size_in_oops) {502oop* handle = (oop*)&(_last->_handles)[_last->_top++];503NativeAccess<IS_DEST_UNINITIALIZED>::oop_store(handle, obj);504return (jobject) handle;505}506507// Try free list508if (_free_list != NULL) {509oop* handle = (oop*)_free_list;510_free_list = (uintptr_t*) untag_free_list(*_free_list);511NativeAccess<IS_DEST_UNINITIALIZED>::oop_store(handle, obj);512return (jobject) handle;513}514// Check if unused block follow last515if (_last->_next != NULL) {516// update last and retry517_last = _last->_next;518return allocate_handle(obj, alloc_failmode);519}520521// No space available, we have to rebuild free list or expand522if (_allocate_before_rebuild == 0) {523rebuild_free_list(); // updates _allocate_before_rebuild counter524} else {525// Append new block526Thread* thread = Thread::current();527Handle obj_handle(thread, obj);528// This can block, so we need to preserve obj across call.529_last->_next = JNIHandleBlock::allocate_block(thread, alloc_failmode);530if (_last->_next == NULL) {531return NULL;532}533_last = _last->_next;534_allocate_before_rebuild--;535obj = obj_handle();536}537return allocate_handle(obj, alloc_failmode); // retry538}539540void JNIHandleBlock::rebuild_free_list() {541assert(_allocate_before_rebuild == 0 && _free_list == NULL, "just checking");542int free = 0;543int blocks = 0;544for (JNIHandleBlock* current = this; current != NULL; current = current->_next) {545for (int index = 0; index < current->_top; index++) {546uintptr_t* handle = &(current->_handles)[index];547if (*handle == 0) {548// this handle was cleared out by a delete call, reuse it549*handle = _free_list == NULL ? 0 : tag_free_list((uintptr_t)_free_list);550_free_list = handle;551free++;552}553}554// we should not rebuild free list if there are unused handles at the end555assert(current->_top == block_size_in_oops, "just checking");556blocks++;557}558// Heuristic: if more than half of the handles are free we rebuild next time559// as well, otherwise we append a corresponding number of new blocks before560// attempting a free list rebuild again.561int total = blocks * block_size_in_oops;562int extra = total - 2*free;563if (extra > 0) {564// Not as many free handles as we would like - compute number of new blocks to append565_allocate_before_rebuild = (extra + block_size_in_oops - 1) / block_size_in_oops;566}567}568569570bool JNIHandleBlock::contains(jobject handle) const {571return ((jobject)&_handles[0] <= handle && handle<(jobject)&_handles[_top]);572}573574575bool JNIHandleBlock::chain_contains(jobject handle) const {576for (JNIHandleBlock* current = (JNIHandleBlock*) this; current != NULL; current = current->_next) {577if (current->contains(handle)) {578return true;579}580}581return false;582}583584585size_t JNIHandleBlock::length() const {586size_t result = 1;587for (JNIHandleBlock* current = _next; current != NULL; current = current->_next) {588result++;589}590return result;591}592593class CountJNIHandleClosure: public OopClosure {594private:595int _count;596public:597CountJNIHandleClosure(): _count(0) {}598virtual void do_oop(oop* ooph) { _count++; }599virtual void do_oop(narrowOop* unused) { ShouldNotReachHere(); }600int count() { return _count; }601};602603const size_t JNIHandleBlock::get_number_of_live_handles() {604CountJNIHandleClosure counter;605oops_do(&counter);606return counter.count();607}608609// This method is not thread-safe, i.e., must be called while holding a lock on the610// structure.611size_t JNIHandleBlock::memory_usage() const {612return length() * sizeof(JNIHandleBlock);613}614615616#ifndef PRODUCT617618bool JNIHandles::is_local_handle(jobject handle) {619return JNIHandleBlock::any_contains(handle);620}621622bool JNIHandleBlock::any_contains(jobject handle) {623assert(handle != NULL, "precondition");624for (JNIHandleBlock* current = _block_list; current != NULL; current = current->_block_list_link) {625if (current->contains(handle)) {626return true;627}628}629return false;630}631632void JNIHandleBlock::print_statistics() {633int used_blocks = 0;634int free_blocks = 0;635int used_handles = 0;636int free_handles = 0;637JNIHandleBlock* block = _block_list;638while (block != NULL) {639if (block->_top > 0) {640used_blocks++;641} else {642free_blocks++;643}644used_handles += block->_top;645free_handles += (block_size_in_oops - block->_top);646block = block->_block_list_link;647}648tty->print_cr("JNIHandleBlocks statistics");649tty->print_cr("- blocks allocated: %d", used_blocks + free_blocks);650tty->print_cr("- blocks in use: %d", used_blocks);651tty->print_cr("- blocks free: %d", free_blocks);652tty->print_cr("- handles in use: %d", used_handles);653tty->print_cr("- handles free: %d", free_handles);654}655656#endif657658659