8198313: Wrap holder object for ClassLoaderData in a WeakHandle
Use WeakHandle for ClassLoaderData::_holder so that is_alive closure is not needed Reviewed-by: rehn, kbarrett
This commit is contained in:
parent
21f636f3cf
commit
d187884156
@ -72,7 +72,7 @@ ciInstanceKlass::ciInstanceKlass(Klass* k) :
|
||||
// by the GC but need to be strong roots if reachable from a current compilation.
|
||||
// InstanceKlass are created for both weak and strong metadata. Ensuring this metadata
|
||||
// alive covers the cases where there are weak roots without performance cost.
|
||||
oop holder = ik->klass_holder_phantom();
|
||||
oop holder = ik->holder_phantom();
|
||||
if (ik->is_anonymous()) {
|
||||
// Though ciInstanceKlass records class loader oop, it's not enough to keep
|
||||
// VM anonymous classes alive (loader == NULL). Klass holder should be used instead.
|
||||
|
@ -55,26 +55,22 @@
|
||||
#include "classfile/moduleEntry.hpp"
|
||||
#include "classfile/packageEntry.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logStream.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/metadataFactory.hpp"
|
||||
#include "memory/metaspaceShared.hpp"
|
||||
#include "memory/oopFactory.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "memory/universe.hpp"
|
||||
#include "oops/access.inline.hpp"
|
||||
#include "oops/objArrayOop.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "oops/weakHandle.inline.hpp"
|
||||
#include "runtime/atomic.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/javaCalls.hpp"
|
||||
#include "runtime/jniHandles.hpp"
|
||||
#include "runtime/mutex.hpp"
|
||||
#include "runtime/orderAccess.hpp"
|
||||
#include "runtime/safepoint.hpp"
|
||||
#include "runtime/safepointVerifiers.hpp"
|
||||
#include "runtime/synchronizer.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
@ -113,17 +109,21 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous) :
|
||||
// The null-class-loader should always be kept alive.
|
||||
_keep_alive((is_anonymous || h_class_loader.is_null()) ? 1 : 0),
|
||||
_metaspace(NULL), _unloading(false), _klasses(NULL),
|
||||
_modules(NULL), _packages(NULL),
|
||||
_modules(NULL), _packages(NULL), _unnamed_module(NULL), _dictionary(NULL),
|
||||
_claimed(0), _modified_oops(true), _accumulated_modified_oops(false),
|
||||
_jmethod_ids(NULL), _handles(), _deallocate_list(NULL),
|
||||
_next(NULL),
|
||||
_metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true,
|
||||
Monitor::_safepoint_check_never)) {
|
||||
|
||||
// A ClassLoaderData created solely for an anonymous class should never have a
|
||||
// ModuleEntryTable or PackageEntryTable created for it. The defining package
|
||||
// and module for an anonymous class will be found in its host class.
|
||||
if (!is_anonymous) {
|
||||
// The holder is initialized later for anonymous classes, and before calling anything
|
||||
// that call class_loader().
|
||||
initialize_holder(h_class_loader);
|
||||
|
||||
// A ClassLoaderData created solely for an anonymous class should never have a
|
||||
// ModuleEntryTable or PackageEntryTable created for it. The defining package
|
||||
// and module for an anonymous class will be found in its host class.
|
||||
_packages = new PackageEntryTable(PackageEntryTable::_packagetable_entry_size);
|
||||
if (h_class_loader.is_null()) {
|
||||
// Create unnamed module for boot loader
|
||||
@ -133,10 +133,6 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous) :
|
||||
_unnamed_module = ModuleEntry::create_unnamed_module(this);
|
||||
}
|
||||
_dictionary = create_dictionary();
|
||||
} else {
|
||||
_packages = NULL;
|
||||
_unnamed_module = NULL;
|
||||
_dictionary = NULL;
|
||||
}
|
||||
|
||||
NOT_PRODUCT(_dependency_count = 0); // number of class loader dependencies
|
||||
@ -510,6 +506,13 @@ InstanceKlass* ClassLoaderDataGraph::try_get_next_class() {
|
||||
}
|
||||
|
||||
|
||||
void ClassLoaderData::initialize_holder(Handle loader_or_mirror) {
|
||||
if (loader_or_mirror() != NULL) {
|
||||
assert(_holder.is_null(), "never replace holders");
|
||||
_holder = WeakHandle<vm_class_loader_data>::create(loader_or_mirror);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove a klass from the _klasses list for scratch_class during redefinition
|
||||
// or parsed class in the case of an error.
|
||||
void ClassLoaderData::remove_class(Klass* scratch_class) {
|
||||
@ -611,30 +614,23 @@ Dictionary* ClassLoaderData::create_dictionary() {
|
||||
}
|
||||
|
||||
// Tell the GC to keep this klass alive while iterating ClassLoaderDataGraph
|
||||
oop ClassLoaderData::holder_phantom() {
|
||||
oop ClassLoaderData::holder_phantom() const {
|
||||
// A klass that was previously considered dead can be looked up in the
|
||||
// CLD/SD, and its _java_mirror or _class_loader can be stored in a root
|
||||
// or a reachable object making it alive again. The SATB part of G1 needs
|
||||
// to get notified about this potential resurrection, otherwise the marking
|
||||
// might not find the object.
|
||||
if (!keep_alive()) {
|
||||
oop* o = is_anonymous() ? _klasses->java_mirror_handle().ptr_raw() : &_class_loader;
|
||||
return RootAccess<ON_PHANTOM_OOP_REF>::oop_load(o);
|
||||
if (!_holder.is_null()) { // NULL class_loader
|
||||
return _holder.resolve();
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Unloading support
|
||||
oop ClassLoaderData::keep_alive_object() const {
|
||||
assert_locked_or_safepoint(_metaspace_lock);
|
||||
assert(!keep_alive(), "Don't use with CLDs that are artificially kept alive");
|
||||
return is_anonymous() ? _klasses->java_mirror() : class_loader();
|
||||
}
|
||||
|
||||
bool ClassLoaderData::is_alive(BoolObjectClosure* is_alive_closure) const {
|
||||
bool alive = keep_alive() // null class loader and incomplete anonymous klasses.
|
||||
|| is_alive_closure->do_object_b(keep_alive_object());
|
||||
bool ClassLoaderData::is_alive() const {
|
||||
bool alive = keep_alive() // null class loader and incomplete anonymous klasses.
|
||||
|| (_holder.peek() != NULL); // not cleaned by weak reference processing
|
||||
|
||||
return alive;
|
||||
}
|
||||
@ -668,6 +664,9 @@ ClassLoaderData::~ClassLoaderData() {
|
||||
ClassLoaderDataGraph::dec_array_classes(cl.array_class_released());
|
||||
ClassLoaderDataGraph::dec_instance_classes(cl.instance_class_released());
|
||||
|
||||
// Release the WeakHandle
|
||||
_holder.release();
|
||||
|
||||
// Release C heap allocated hashtable for all the packages.
|
||||
if (_packages != NULL) {
|
||||
// Destroy the table itself
|
||||
@ -969,7 +968,6 @@ ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool is_anonymous) {
|
||||
|
||||
ClassLoaderData* cld = new ClassLoaderData(loader, is_anonymous);
|
||||
|
||||
|
||||
if (!is_anonymous) {
|
||||
// First, Atomically set it
|
||||
ClassLoaderData* old = java_lang_ClassLoader::cmpxchg_loader_data(cld, loader(), NULL);
|
||||
@ -1244,6 +1242,8 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure,
|
||||
ClassLoaderData* data = _head;
|
||||
ClassLoaderData* prev = NULL;
|
||||
bool seen_dead_loader = false;
|
||||
uint loaders_processed = 0;
|
||||
uint loaders_removed = 0;
|
||||
|
||||
// Mark metadata seen on the stack only so we can delete unneeded entries.
|
||||
// Only walk all metadata, including the expensive code cache walk, for Full GC
|
||||
@ -1260,7 +1260,7 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure,
|
||||
|
||||
data = _head;
|
||||
while (data != NULL) {
|
||||
if (data->is_alive(is_alive_closure)) {
|
||||
if (data->is_alive()) {
|
||||
// clean metaspace
|
||||
if (walk_all_metadata) {
|
||||
data->classes_do(InstanceKlass::purge_previous_versions);
|
||||
@ -1268,9 +1268,11 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure,
|
||||
data->free_deallocate_list();
|
||||
prev = data;
|
||||
data = data->next();
|
||||
loaders_processed++;
|
||||
continue;
|
||||
}
|
||||
seen_dead_loader = true;
|
||||
loaders_removed++;
|
||||
ClassLoaderData* dead = data;
|
||||
dead->unload();
|
||||
data = data->next();
|
||||
@ -1313,6 +1315,8 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure,
|
||||
post_class_unload_events();
|
||||
}
|
||||
|
||||
log_debug(class, loader, data)("do_unloading: loaders processed %u, loaders removed %u", loaders_processed, loaders_removed);
|
||||
|
||||
return seen_dead_loader;
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "memory/metaspace.hpp"
|
||||
#include "memory/metaspaceCounters.hpp"
|
||||
#include "oops/oopHandle.hpp"
|
||||
#include "oops/weakHandle.hpp"
|
||||
#include "runtime/mutex.hpp"
|
||||
#include "trace/traceMacros.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
@ -113,7 +114,7 @@ class ClassLoaderDataGraph : public AllStatic {
|
||||
static void packages_unloading_do(void f(PackageEntry*));
|
||||
static void loaded_classes_do(KlassClosure* klass_closure);
|
||||
static void classes_unloading_do(void f(Klass* const));
|
||||
static bool do_unloading(BoolObjectClosure* is_alive, bool clean_previous_versions);
|
||||
static bool do_unloading(BoolObjectClosure* is_alive_closure, bool clean_previous_versions);
|
||||
|
||||
// dictionary do
|
||||
// Iterate over all klasses in dictionary, but
|
||||
@ -219,8 +220,9 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
||||
|
||||
static ClassLoaderData * _the_null_class_loader_data;
|
||||
|
||||
oop _class_loader; // oop used to uniquely identify a class loader
|
||||
// class loader or a canonical class path
|
||||
WeakHandle<vm_class_loader_data> _holder; // The oop that determines lifetime of this class loader
|
||||
oop _class_loader; // The instance of java/lang/ClassLoader associated with
|
||||
// this ClassLoaderData
|
||||
|
||||
ClassLoaderMetaspace * volatile _metaspace; // Meta-space where meta-data defined by the
|
||||
// classes in the class loader are allocated.
|
||||
@ -286,7 +288,8 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
||||
|
||||
void unload();
|
||||
bool keep_alive() const { return _keep_alive > 0; }
|
||||
oop holder_phantom();
|
||||
|
||||
oop holder_phantom() const;
|
||||
void classes_do(void f(Klass*));
|
||||
void loaded_classes_do(KlassClosure* klass_closure);
|
||||
void classes_do(void f(InstanceKlass*));
|
||||
@ -308,7 +311,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
||||
bool claimed() const { return _claimed == 1; }
|
||||
bool claim();
|
||||
|
||||
bool is_alive(BoolObjectClosure* is_alive_closure) const;
|
||||
bool is_alive() const;
|
||||
|
||||
// Accessors
|
||||
ClassLoaderMetaspace* metaspace_or_null() const { return _metaspace; }
|
||||
@ -348,7 +351,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
||||
// method will allocate a Metaspace if needed.
|
||||
ClassLoaderMetaspace* metaspace_non_null();
|
||||
|
||||
oop class_loader() const { return _class_loader; }
|
||||
oop class_loader() const { return _class_loader; }
|
||||
|
||||
// The object the GC is using to keep this ClassLoaderData alive.
|
||||
oop keep_alive_object() const;
|
||||
@ -364,6 +367,8 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
||||
void inc_keep_alive();
|
||||
void dec_keep_alive();
|
||||
|
||||
void initialize_holder(Handle holder);
|
||||
|
||||
inline unsigned int identity_hash() const { return (unsigned int)(((intptr_t)this) >> 3); }
|
||||
|
||||
void oops_do(OopClosure* f, bool must_claim, bool clear_modified_oops = false);
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "code/codeCache.hpp"
|
||||
#include "compiler/compileBroker.hpp"
|
||||
#include "gc/shared/gcTraceTime.inline.hpp"
|
||||
#include "gc/shared/oopStorage.inline.hpp"
|
||||
#include "interpreter/bytecodeStream.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "logging/log.hpp"
|
||||
@ -117,6 +118,8 @@ InstanceKlass* volatile SystemDictionary::_abstract_ownable_synchronizer_klass =
|
||||
|
||||
const int defaultProtectionDomainCacheSize = 1009;
|
||||
|
||||
OopStorage* SystemDictionary::_vm_weak_oop_storage = NULL;
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Java-level SystemLoader and PlatformLoader
|
||||
@ -1012,7 +1015,9 @@ InstanceKlass* SystemDictionary::parse_stream(Symbol* class_name,
|
||||
CHECK_NULL);
|
||||
|
||||
if (host_klass != NULL && k != NULL) {
|
||||
// If it's anonymous, initialize it now, since nobody else will.
|
||||
// Anonymous classes must update ClassLoaderData holder (was host_klass loader)
|
||||
// so that they can be unloaded when the mirror is no longer referenced.
|
||||
k->class_loader_data()->initialize_holder(Handle(THREAD, k->java_mirror()));
|
||||
|
||||
{
|
||||
MutexLocker mu_r(Compile_lock, THREAD);
|
||||
@ -1032,6 +1037,8 @@ InstanceKlass* SystemDictionary::parse_stream(Symbol* class_name,
|
||||
if (cp_patches != NULL) {
|
||||
k->constants()->patch_resolved_references(cp_patches);
|
||||
}
|
||||
|
||||
// If it's anonymous, initialize it now, since nobody else will.
|
||||
k->eager_initialize(CHECK_NULL);
|
||||
|
||||
// notify jvmti
|
||||
@ -1848,6 +1855,10 @@ bool SystemDictionary::do_unloading(BoolObjectClosure* is_alive,
|
||||
GCTimer* gc_timer,
|
||||
bool do_cleaning) {
|
||||
|
||||
{
|
||||
GCTraceTime(Debug, gc, phases) t("SystemDictionary WeakHandle cleaning", gc_timer);
|
||||
vm_weak_oop_storage()->weak_oops_do(is_alive, &do_nothing_cl);
|
||||
}
|
||||
|
||||
bool unloading_occurred;
|
||||
{
|
||||
@ -1896,9 +1907,11 @@ void SystemDictionary::roots_oops_do(OopClosure* strong, OopClosure* weak) {
|
||||
// Only the protection domain oops contain references into the heap. Iterate
|
||||
// over all of them.
|
||||
_pd_cache_table->oops_do(strong);
|
||||
vm_weak_oop_storage()->oops_do(strong);
|
||||
} else {
|
||||
if (weak != NULL) {
|
||||
_pd_cache_table->oops_do(weak);
|
||||
vm_weak_oop_storage()->oops_do(weak);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1924,6 +1937,8 @@ void SystemDictionary::oops_do(OopClosure* f) {
|
||||
invoke_method_table()->oops_do(f);
|
||||
|
||||
ResolvedMethodTable::oops_do(f);
|
||||
|
||||
vm_weak_oop_storage()->oops_do(f);
|
||||
}
|
||||
|
||||
// CDS: scan and relocate all classes in the system dictionary.
|
||||
@ -3105,3 +3120,15 @@ const char* SystemDictionary::loader_name(const ClassLoaderData* loader_data) {
|
||||
return (loader_data->class_loader() == NULL ? "<bootloader>" :
|
||||
SystemDictionary::loader_name(loader_data->class_loader()));
|
||||
}
|
||||
|
||||
void SystemDictionary::initialize_oop_storage() {
|
||||
_vm_weak_oop_storage =
|
||||
new OopStorage("VM Weak Oop Handles",
|
||||
VMWeakAlloc_lock,
|
||||
VMWeakActive_lock);
|
||||
}
|
||||
|
||||
OopStorage* SystemDictionary::vm_weak_oop_storage() {
|
||||
assert(_vm_weak_oop_storage != NULL, "Uninitialized");
|
||||
return _vm_weak_oop_storage;
|
||||
}
|
||||
|
@ -84,6 +84,7 @@ class SymbolPropertyTable;
|
||||
class ProtectionDomainCacheTable;
|
||||
class ProtectionDomainCacheEntry;
|
||||
class GCTimer;
|
||||
class OopStorage;
|
||||
|
||||
// Certain classes are preloaded, such as java.lang.Object and java.lang.String.
|
||||
// They are all "well-known", in the sense that no class loader is allowed
|
||||
@ -637,6 +638,9 @@ public:
|
||||
// ProtectionDomain cache
|
||||
static ProtectionDomainCacheTable* _pd_cache_table;
|
||||
|
||||
// VM weak OopStorage object.
|
||||
static OopStorage* _vm_weak_oop_storage;
|
||||
|
||||
protected:
|
||||
static void validate_protection_domain(InstanceKlass* klass,
|
||||
Handle class_loader,
|
||||
@ -689,6 +693,9 @@ public:
|
||||
return !m->is_public() && m->method_holder() == SystemDictionary::Object_klass();
|
||||
}
|
||||
|
||||
static void initialize_oop_storage();
|
||||
static OopStorage* vm_weak_oop_storage();
|
||||
|
||||
protected:
|
||||
static InstanceKlass* find_shared_class(Symbol* class_name);
|
||||
|
||||
|
@ -689,6 +689,8 @@ jint universe_init() {
|
||||
return status;
|
||||
}
|
||||
|
||||
SystemDictionary::initialize_oop_storage();
|
||||
|
||||
Metaspace::global_initialize();
|
||||
|
||||
// Initialize performance counters for metaspaces
|
||||
|
@ -1901,7 +1901,7 @@ void InstanceKlass::clean_weak_instanceklass_links(BoolObjectClosure* is_alive)
|
||||
}
|
||||
|
||||
void InstanceKlass::clean_implementors_list(BoolObjectClosure* is_alive) {
|
||||
assert(class_loader_data()->is_alive(is_alive), "this klass should be live");
|
||||
assert(class_loader_data()->is_alive(), "this klass should be live");
|
||||
if (is_interface()) {
|
||||
if (ClassUnloading) {
|
||||
Klass* impl = implementor();
|
||||
@ -3407,14 +3407,8 @@ void JNIid::verify(Klass* holder) {
|
||||
}
|
||||
}
|
||||
|
||||
oop InstanceKlass::klass_holder_phantom() {
|
||||
oop* addr;
|
||||
if (is_anonymous()) {
|
||||
addr = _java_mirror.ptr_raw();
|
||||
} else {
|
||||
addr = &class_loader_data()->_class_loader;
|
||||
}
|
||||
return RootAccess<IN_CONCURRENT_ROOT | ON_PHANTOM_OOP_REF>::oop_load(addr);
|
||||
oop InstanceKlass::holder_phantom() const {
|
||||
return class_loader_data()->holder_phantom();
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
|
@ -646,10 +646,10 @@ class InstanceKlass: public Klass {
|
||||
return is_anonymous() ? java_mirror() : class_loader();
|
||||
}
|
||||
|
||||
// Load the klass_holder as a phantom. This is useful when a weak Klass
|
||||
// Load the klass's holder as a phantom. This is useful when a weak Klass
|
||||
// pointer has been "peeked" and then must be kept alive before it may
|
||||
// be used safely.
|
||||
oop klass_holder_phantom();
|
||||
oop holder_phantom() const;
|
||||
|
||||
bool is_contended() const {
|
||||
return (_misc_flags & _misc_is_contended) != 0;
|
||||
|
71
src/hotspot/share/oops/weakHandle.cpp
Normal file
71
src/hotspot/share/oops/weakHandle.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "gc/shared/oopStorage.hpp"
|
||||
#include "oops/access.inline.hpp"
|
||||
#include "oops/oop.hpp"
|
||||
#include "oops/weakHandle.inline.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
|
||||
template <> OopStorage* WeakHandle<vm_class_loader_data>::get_storage() {
|
||||
return SystemDictionary::vm_weak_oop_storage();
|
||||
}
|
||||
|
||||
template <WeakHandleType T>
|
||||
WeakHandle<T> WeakHandle<T>::create(Handle obj) {
|
||||
assert(obj() != NULL, "no need to create weak null oop");
|
||||
oop* oop_addr = get_storage()->allocate();
|
||||
if (oop_addr == NULL) {
|
||||
vm_exit_out_of_memory(sizeof(oop*), OOM_MALLOC_ERROR, "Unable to create new weak oop handle in OopStorage");
|
||||
}
|
||||
// Create WeakHandle with address returned and store oop into it.
|
||||
RootAccess<ON_PHANTOM_OOP_REF>::oop_store(oop_addr, obj());
|
||||
return WeakHandle(oop_addr);
|
||||
}
|
||||
|
||||
template <WeakHandleType T>
|
||||
void WeakHandle<T>::release() const {
|
||||
// Only release if the pointer to the object has been created.
|
||||
if (_obj != NULL) {
|
||||
// Clear the WeakHandle. For class loader data race, the handle may not have
|
||||
// been previously cleared by GC.
|
||||
RootAccess<ON_PHANTOM_OOP_REF>::oop_store(_obj, (oop)NULL);
|
||||
get_storage()->release(_obj);
|
||||
}
|
||||
}
|
||||
|
||||
template <WeakHandleType T>
|
||||
void WeakHandle<T>::print() const { print_on(tty); }
|
||||
|
||||
template <WeakHandleType T>
|
||||
void WeakHandle<T>::print_on(outputStream* st) const {
|
||||
st->print("WeakHandle: " PTR_FORMAT, p2i(peek()));
|
||||
}
|
||||
|
||||
// Provide instantiation.
|
||||
template class WeakHandle<vm_class_loader_data>;
|
||||
|
66
src/hotspot/share/oops/weakHandle.hpp
Normal file
66
src/hotspot/share/oops/weakHandle.hpp
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_OOPS_WEAKHANDLE_HPP
|
||||
#define SHARE_VM_OOPS_WEAKHANDLE_HPP
|
||||
|
||||
#include "oops/oop.hpp"
|
||||
#include "runtime/handles.hpp"
|
||||
|
||||
class outputStream;
|
||||
class OopStorage;
|
||||
|
||||
// A WeakHandle is a pointer to an oop that is stored in an OopStorage that is
|
||||
// processed weakly by GC. The runtime structures that point to the oop must
|
||||
// either peek or resolve the oop, the latter will keep the oop alive for
|
||||
// the GC cycle. The runtime structures that reference the oop must test
|
||||
// if the value is NULL. If it is NULL, it has been cleaned out by GC.
|
||||
// This is the vm version of jweak but has different GC lifetimes and policies,
|
||||
// depending on the type.
|
||||
|
||||
enum WeakHandleType { vm_class_loader_data, vm_string };
|
||||
|
||||
template <WeakHandleType T>
|
||||
class WeakHandle {
|
||||
public:
|
||||
|
||||
private:
|
||||
oop* _obj;
|
||||
|
||||
WeakHandle(oop* w) : _obj(w) {}
|
||||
static OopStorage* get_storage();
|
||||
public:
|
||||
WeakHandle() : _obj(NULL) {} // needed for init
|
||||
|
||||
static WeakHandle create(Handle obj);
|
||||
inline oop resolve() const;
|
||||
inline oop peek() const;
|
||||
void release() const;
|
||||
bool is_null() const { return _obj == NULL; }
|
||||
|
||||
void print() const;
|
||||
void print_on(outputStream* st) const;
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_OOPS_WEAKHANDLE_HPP
|
43
src/hotspot/share/oops/weakHandle.inline.hpp
Normal file
43
src/hotspot/share/oops/weakHandle.inline.hpp
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_OOPS_WEAKHANDLE_INLINE_HPP
|
||||
#define SHARE_VM_OOPS_WEAKHANDLE_INLINE_HPP
|
||||
|
||||
#include "oops/weakHandle.hpp"
|
||||
#include "oops/access.inline.hpp"
|
||||
|
||||
template <WeakHandleType T>
|
||||
oop WeakHandle<T>::resolve() const {
|
||||
assert(!is_null(), "Must be created");
|
||||
return RootAccess<ON_PHANTOM_OOP_REF>::oop_load(_obj);
|
||||
}
|
||||
|
||||
template <WeakHandleType T>
|
||||
oop WeakHandle<T>::peek() const {
|
||||
assert(!is_null(), "Must be created");
|
||||
return RootAccess<ON_PHANTOM_OOP_REF | AS_NO_KEEPALIVE>::oop_load(_obj);
|
||||
}
|
||||
|
||||
#endif // SHARE_VM_OOPS_WEAKHANDLE_INLINE_HPP
|
@ -48,6 +48,8 @@ Mutex* JNIGlobalActive_lock = NULL;
|
||||
Mutex* JNIWeakAlloc_lock = NULL;
|
||||
Mutex* JNIWeakActive_lock = NULL;
|
||||
Mutex* JNIHandleBlockFreeList_lock = NULL;
|
||||
Mutex* VMWeakAlloc_lock = NULL;
|
||||
Mutex* VMWeakActive_lock = NULL;
|
||||
Mutex* ResolvedMethodTable_lock = NULL;
|
||||
Mutex* JmethodIdCreation_lock = NULL;
|
||||
Mutex* JfieldIdCreation_lock = NULL;
|
||||
@ -260,6 +262,8 @@ void mutex_init() {
|
||||
def(JNIGlobalActive_lock , PaddedMutex , nonleaf-1, true, Monitor::_safepoint_check_never);
|
||||
def(JNIWeakAlloc_lock , PaddedMutex , nonleaf, true, Monitor::_safepoint_check_never);
|
||||
def(JNIWeakActive_lock , PaddedMutex , nonleaf-1, true, Monitor::_safepoint_check_never);
|
||||
def(VMWeakAlloc_lock , PaddedMutex , nonleaf, true, Monitor::_safepoint_check_never);
|
||||
def(VMWeakActive_lock , PaddedMutex , nonleaf-1, true, Monitor::_safepoint_check_never);
|
||||
def(JNICritical_lock , PaddedMonitor, nonleaf, true, Monitor::_safepoint_check_always); // used for JNI critical regions
|
||||
def(AdapterHandlerLibrary_lock , PaddedMutex , nonleaf, true, Monitor::_safepoint_check_always);
|
||||
|
||||
|
@ -41,6 +41,8 @@ extern Mutex* JNIGlobalActive_lock; // JNI global storage active li
|
||||
extern Mutex* JNIWeakAlloc_lock; // JNI weak storage allocate list lock
|
||||
extern Mutex* JNIWeakActive_lock; // JNI weak storage active list lock
|
||||
extern Mutex* JNIHandleBlockFreeList_lock; // a lock on the JNI handle block free list
|
||||
extern Mutex* VMWeakAlloc_lock; // VM Weak Handles storage allocate list lock
|
||||
extern Mutex* VMWeakActive_lock; // VM Weak Handles storage active list lock
|
||||
extern Mutex* ResolvedMethodTable_lock; // a lock on the ResolvedMethodTable updates
|
||||
extern Mutex* JmethodIdCreation_lock; // a lock on creating JNI method identifiers
|
||||
extern Mutex* JfieldIdCreation_lock; // a lock on creating JNI static field identifiers
|
||||
|
Loading…
Reference in New Issue
Block a user