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:
Coleen Phillimore 2018-04-10 10:06:42 -04:00
parent 21f636f3cf
commit d187884156
13 changed files with 273 additions and 48 deletions

View File

@ -72,7 +72,7 @@ ciInstanceKlass::ciInstanceKlass(Klass* k) :
// by the GC but need to be strong roots if reachable from a current compilation. // 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 // InstanceKlass are created for both weak and strong metadata. Ensuring this metadata
// alive covers the cases where there are weak roots without performance cost. // 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()) { if (ik->is_anonymous()) {
// Though ciInstanceKlass records class loader oop, it's not enough to keep // Though ciInstanceKlass records class loader oop, it's not enough to keep
// VM anonymous classes alive (loader == NULL). Klass holder should be used instead. // VM anonymous classes alive (loader == NULL). Klass holder should be used instead.

View File

@ -55,26 +55,22 @@
#include "classfile/moduleEntry.hpp" #include "classfile/moduleEntry.hpp"
#include "classfile/packageEntry.hpp" #include "classfile/packageEntry.hpp"
#include "classfile/systemDictionary.hpp" #include "classfile/systemDictionary.hpp"
#include "code/codeCache.hpp"
#include "logging/log.hpp" #include "logging/log.hpp"
#include "logging/logStream.hpp" #include "logging/logStream.hpp"
#include "memory/allocation.inline.hpp" #include "memory/allocation.inline.hpp"
#include "memory/metadataFactory.hpp" #include "memory/metadataFactory.hpp"
#include "memory/metaspaceShared.hpp" #include "memory/metaspaceShared.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp" #include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "oops/access.inline.hpp" #include "oops/access.inline.hpp"
#include "oops/objArrayOop.inline.hpp"
#include "oops/oop.inline.hpp" #include "oops/oop.inline.hpp"
#include "oops/weakHandle.inline.hpp"
#include "runtime/atomic.hpp" #include "runtime/atomic.hpp"
#include "runtime/handles.inline.hpp" #include "runtime/handles.inline.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/jniHandles.hpp"
#include "runtime/mutex.hpp" #include "runtime/mutex.hpp"
#include "runtime/orderAccess.hpp" #include "runtime/orderAccess.hpp"
#include "runtime/safepoint.hpp" #include "runtime/safepoint.hpp"
#include "runtime/safepointVerifiers.hpp" #include "runtime/safepointVerifiers.hpp"
#include "runtime/synchronizer.hpp"
#include "utilities/growableArray.hpp" #include "utilities/growableArray.hpp"
#include "utilities/macros.hpp" #include "utilities/macros.hpp"
#include "utilities/ostream.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. // The null-class-loader should always be kept alive.
_keep_alive((is_anonymous || h_class_loader.is_null()) ? 1 : 0), _keep_alive((is_anonymous || h_class_loader.is_null()) ? 1 : 0),
_metaspace(NULL), _unloading(false), _klasses(NULL), _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), _claimed(0), _modified_oops(true), _accumulated_modified_oops(false),
_jmethod_ids(NULL), _handles(), _deallocate_list(NULL), _jmethod_ids(NULL), _handles(), _deallocate_list(NULL),
_next(NULL), _next(NULL),
_metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true, _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true,
Monitor::_safepoint_check_never)) { 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) { 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); _packages = new PackageEntryTable(PackageEntryTable::_packagetable_entry_size);
if (h_class_loader.is_null()) { if (h_class_loader.is_null()) {
// Create unnamed module for boot loader // 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); _unnamed_module = ModuleEntry::create_unnamed_module(this);
} }
_dictionary = create_dictionary(); _dictionary = create_dictionary();
} else {
_packages = NULL;
_unnamed_module = NULL;
_dictionary = NULL;
} }
NOT_PRODUCT(_dependency_count = 0); // number of class loader dependencies 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 // Remove a klass from the _klasses list for scratch_class during redefinition
// or parsed class in the case of an error. // or parsed class in the case of an error.
void ClassLoaderData::remove_class(Klass* scratch_class) { 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 // 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 // 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 // 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 // or a reachable object making it alive again. The SATB part of G1 needs
// to get notified about this potential resurrection, otherwise the marking // to get notified about this potential resurrection, otherwise the marking
// might not find the object. // might not find the object.
if (!keep_alive()) { if (!_holder.is_null()) { // NULL class_loader
oop* o = is_anonymous() ? _klasses->java_mirror_handle().ptr_raw() : &_class_loader; return _holder.resolve();
return RootAccess<ON_PHANTOM_OOP_REF>::oop_load(o);
} else { } else {
return NULL; return NULL;
} }
} }
// Unloading support // Unloading support
oop ClassLoaderData::keep_alive_object() const { bool ClassLoaderData::is_alive() const {
assert_locked_or_safepoint(_metaspace_lock); bool alive = keep_alive() // null class loader and incomplete anonymous klasses.
assert(!keep_alive(), "Don't use with CLDs that are artificially kept alive"); || (_holder.peek() != NULL); // not cleaned by weak reference processing
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());
return alive; return alive;
} }
@ -668,6 +664,9 @@ ClassLoaderData::~ClassLoaderData() {
ClassLoaderDataGraph::dec_array_classes(cl.array_class_released()); ClassLoaderDataGraph::dec_array_classes(cl.array_class_released());
ClassLoaderDataGraph::dec_instance_classes(cl.instance_class_released()); ClassLoaderDataGraph::dec_instance_classes(cl.instance_class_released());
// Release the WeakHandle
_holder.release();
// Release C heap allocated hashtable for all the packages. // Release C heap allocated hashtable for all the packages.
if (_packages != NULL) { if (_packages != NULL) {
// Destroy the table itself // Destroy the table itself
@ -969,7 +968,6 @@ ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool is_anonymous) {
ClassLoaderData* cld = new ClassLoaderData(loader, is_anonymous); ClassLoaderData* cld = new ClassLoaderData(loader, is_anonymous);
if (!is_anonymous) { if (!is_anonymous) {
// First, Atomically set it // First, Atomically set it
ClassLoaderData* old = java_lang_ClassLoader::cmpxchg_loader_data(cld, loader(), NULL); 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* data = _head;
ClassLoaderData* prev = NULL; ClassLoaderData* prev = NULL;
bool seen_dead_loader = false; 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. // 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 // 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; data = _head;
while (data != NULL) { while (data != NULL) {
if (data->is_alive(is_alive_closure)) { if (data->is_alive()) {
// clean metaspace // clean metaspace
if (walk_all_metadata) { if (walk_all_metadata) {
data->classes_do(InstanceKlass::purge_previous_versions); data->classes_do(InstanceKlass::purge_previous_versions);
@ -1268,9 +1268,11 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure,
data->free_deallocate_list(); data->free_deallocate_list();
prev = data; prev = data;
data = data->next(); data = data->next();
loaders_processed++;
continue; continue;
} }
seen_dead_loader = true; seen_dead_loader = true;
loaders_removed++;
ClassLoaderData* dead = data; ClassLoaderData* dead = data;
dead->unload(); dead->unload();
data = data->next(); data = data->next();
@ -1313,6 +1315,8 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure,
post_class_unload_events(); 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; return seen_dead_loader;
} }

View File

@ -30,6 +30,7 @@
#include "memory/metaspace.hpp" #include "memory/metaspace.hpp"
#include "memory/metaspaceCounters.hpp" #include "memory/metaspaceCounters.hpp"
#include "oops/oopHandle.hpp" #include "oops/oopHandle.hpp"
#include "oops/weakHandle.hpp"
#include "runtime/mutex.hpp" #include "runtime/mutex.hpp"
#include "trace/traceMacros.hpp" #include "trace/traceMacros.hpp"
#include "utilities/growableArray.hpp" #include "utilities/growableArray.hpp"
@ -113,7 +114,7 @@ class ClassLoaderDataGraph : public AllStatic {
static void packages_unloading_do(void f(PackageEntry*)); static void packages_unloading_do(void f(PackageEntry*));
static void loaded_classes_do(KlassClosure* klass_closure); static void loaded_classes_do(KlassClosure* klass_closure);
static void classes_unloading_do(void f(Klass* const)); 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 // dictionary do
// Iterate over all klasses in dictionary, but // Iterate over all klasses in dictionary, but
@ -219,8 +220,9 @@ class ClassLoaderData : public CHeapObj<mtClass> {
static ClassLoaderData * _the_null_class_loader_data; static ClassLoaderData * _the_null_class_loader_data;
oop _class_loader; // oop used to uniquely identify a class loader WeakHandle<vm_class_loader_data> _holder; // The oop that determines lifetime of this class loader
// class loader or a canonical class path oop _class_loader; // The instance of java/lang/ClassLoader associated with
// this ClassLoaderData
ClassLoaderMetaspace * volatile _metaspace; // Meta-space where meta-data defined by the ClassLoaderMetaspace * volatile _metaspace; // Meta-space where meta-data defined by the
// classes in the class loader are allocated. // classes in the class loader are allocated.
@ -286,7 +288,8 @@ class ClassLoaderData : public CHeapObj<mtClass> {
void unload(); void unload();
bool keep_alive() const { return _keep_alive > 0; } bool keep_alive() const { return _keep_alive > 0; }
oop holder_phantom();
oop holder_phantom() const;
void classes_do(void f(Klass*)); void classes_do(void f(Klass*));
void loaded_classes_do(KlassClosure* klass_closure); void loaded_classes_do(KlassClosure* klass_closure);
void classes_do(void f(InstanceKlass*)); void classes_do(void f(InstanceKlass*));
@ -308,7 +311,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
bool claimed() const { return _claimed == 1; } bool claimed() const { return _claimed == 1; }
bool claim(); bool claim();
bool is_alive(BoolObjectClosure* is_alive_closure) const; bool is_alive() const;
// Accessors // Accessors
ClassLoaderMetaspace* metaspace_or_null() const { return _metaspace; } ClassLoaderMetaspace* metaspace_or_null() const { return _metaspace; }
@ -348,7 +351,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
// method will allocate a Metaspace if needed. // method will allocate a Metaspace if needed.
ClassLoaderMetaspace* metaspace_non_null(); 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. // The object the GC is using to keep this ClassLoaderData alive.
oop keep_alive_object() const; oop keep_alive_object() const;
@ -364,6 +367,8 @@ class ClassLoaderData : public CHeapObj<mtClass> {
void inc_keep_alive(); void inc_keep_alive();
void dec_keep_alive(); void dec_keep_alive();
void initialize_holder(Handle holder);
inline unsigned int identity_hash() const { return (unsigned int)(((intptr_t)this) >> 3); } 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); void oops_do(OopClosure* f, bool must_claim, bool clear_modified_oops = false);

View File

@ -44,6 +44,7 @@
#include "code/codeCache.hpp" #include "code/codeCache.hpp"
#include "compiler/compileBroker.hpp" #include "compiler/compileBroker.hpp"
#include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/gcTraceTime.inline.hpp"
#include "gc/shared/oopStorage.inline.hpp"
#include "interpreter/bytecodeStream.hpp" #include "interpreter/bytecodeStream.hpp"
#include "interpreter/interpreter.hpp" #include "interpreter/interpreter.hpp"
#include "logging/log.hpp" #include "logging/log.hpp"
@ -117,6 +118,8 @@ InstanceKlass* volatile SystemDictionary::_abstract_ownable_synchronizer_klass =
const int defaultProtectionDomainCacheSize = 1009; const int defaultProtectionDomainCacheSize = 1009;
OopStorage* SystemDictionary::_vm_weak_oop_storage = NULL;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Java-level SystemLoader and PlatformLoader // Java-level SystemLoader and PlatformLoader
@ -1012,7 +1015,9 @@ InstanceKlass* SystemDictionary::parse_stream(Symbol* class_name,
CHECK_NULL); CHECK_NULL);
if (host_klass != NULL && k != 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); MutexLocker mu_r(Compile_lock, THREAD);
@ -1032,6 +1037,8 @@ InstanceKlass* SystemDictionary::parse_stream(Symbol* class_name,
if (cp_patches != NULL) { if (cp_patches != NULL) {
k->constants()->patch_resolved_references(cp_patches); k->constants()->patch_resolved_references(cp_patches);
} }
// If it's anonymous, initialize it now, since nobody else will.
k->eager_initialize(CHECK_NULL); k->eager_initialize(CHECK_NULL);
// notify jvmti // notify jvmti
@ -1848,6 +1855,10 @@ bool SystemDictionary::do_unloading(BoolObjectClosure* is_alive,
GCTimer* gc_timer, GCTimer* gc_timer,
bool do_cleaning) { 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; 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 // Only the protection domain oops contain references into the heap. Iterate
// over all of them. // over all of them.
_pd_cache_table->oops_do(strong); _pd_cache_table->oops_do(strong);
vm_weak_oop_storage()->oops_do(strong);
} else { } else {
if (weak != NULL) { if (weak != NULL) {
_pd_cache_table->oops_do(weak); _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); invoke_method_table()->oops_do(f);
ResolvedMethodTable::oops_do(f); ResolvedMethodTable::oops_do(f);
vm_weak_oop_storage()->oops_do(f);
} }
// CDS: scan and relocate all classes in the system dictionary. // 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>" : return (loader_data->class_loader() == NULL ? "<bootloader>" :
SystemDictionary::loader_name(loader_data->class_loader())); 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;
}

View File

@ -84,6 +84,7 @@ class SymbolPropertyTable;
class ProtectionDomainCacheTable; class ProtectionDomainCacheTable;
class ProtectionDomainCacheEntry; class ProtectionDomainCacheEntry;
class GCTimer; class GCTimer;
class OopStorage;
// Certain classes are preloaded, such as java.lang.Object and java.lang.String. // 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 // They are all "well-known", in the sense that no class loader is allowed
@ -637,6 +638,9 @@ public:
// ProtectionDomain cache // ProtectionDomain cache
static ProtectionDomainCacheTable* _pd_cache_table; static ProtectionDomainCacheTable* _pd_cache_table;
// VM weak OopStorage object.
static OopStorage* _vm_weak_oop_storage;
protected: protected:
static void validate_protection_domain(InstanceKlass* klass, static void validate_protection_domain(InstanceKlass* klass,
Handle class_loader, Handle class_loader,
@ -689,6 +693,9 @@ public:
return !m->is_public() && m->method_holder() == SystemDictionary::Object_klass(); return !m->is_public() && m->method_holder() == SystemDictionary::Object_klass();
} }
static void initialize_oop_storage();
static OopStorage* vm_weak_oop_storage();
protected: protected:
static InstanceKlass* find_shared_class(Symbol* class_name); static InstanceKlass* find_shared_class(Symbol* class_name);

View File

@ -689,6 +689,8 @@ jint universe_init() {
return status; return status;
} }
SystemDictionary::initialize_oop_storage();
Metaspace::global_initialize(); Metaspace::global_initialize();
// Initialize performance counters for metaspaces // Initialize performance counters for metaspaces

View File

@ -1901,7 +1901,7 @@ void InstanceKlass::clean_weak_instanceklass_links(BoolObjectClosure* is_alive)
} }
void InstanceKlass::clean_implementors_list(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 (is_interface()) {
if (ClassUnloading) { if (ClassUnloading) {
Klass* impl = implementor(); Klass* impl = implementor();
@ -3407,14 +3407,8 @@ void JNIid::verify(Klass* holder) {
} }
} }
oop InstanceKlass::klass_holder_phantom() { oop InstanceKlass::holder_phantom() const {
oop* addr; return class_loader_data()->holder_phantom();
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);
} }
#ifdef ASSERT #ifdef ASSERT

View File

@ -646,10 +646,10 @@ class InstanceKlass: public Klass {
return is_anonymous() ? java_mirror() : class_loader(); 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 // pointer has been "peeked" and then must be kept alive before it may
// be used safely. // be used safely.
oop klass_holder_phantom(); oop holder_phantom() const;
bool is_contended() const { bool is_contended() const {
return (_misc_flags & _misc_is_contended) != 0; return (_misc_flags & _misc_is_contended) != 0;

View 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>;

View 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

View 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

View File

@ -48,6 +48,8 @@ Mutex* JNIGlobalActive_lock = NULL;
Mutex* JNIWeakAlloc_lock = NULL; Mutex* JNIWeakAlloc_lock = NULL;
Mutex* JNIWeakActive_lock = NULL; Mutex* JNIWeakActive_lock = NULL;
Mutex* JNIHandleBlockFreeList_lock = NULL; Mutex* JNIHandleBlockFreeList_lock = NULL;
Mutex* VMWeakAlloc_lock = NULL;
Mutex* VMWeakActive_lock = NULL;
Mutex* ResolvedMethodTable_lock = NULL; Mutex* ResolvedMethodTable_lock = NULL;
Mutex* JmethodIdCreation_lock = NULL; Mutex* JmethodIdCreation_lock = NULL;
Mutex* JfieldIdCreation_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(JNIGlobalActive_lock , PaddedMutex , nonleaf-1, true, Monitor::_safepoint_check_never);
def(JNIWeakAlloc_lock , PaddedMutex , nonleaf, 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(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(JNICritical_lock , PaddedMonitor, nonleaf, true, Monitor::_safepoint_check_always); // used for JNI critical regions
def(AdapterHandlerLibrary_lock , PaddedMutex , nonleaf, true, Monitor::_safepoint_check_always); def(AdapterHandlerLibrary_lock , PaddedMutex , nonleaf, true, Monitor::_safepoint_check_always);

View File

@ -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* JNIWeakAlloc_lock; // JNI weak storage allocate list lock
extern Mutex* JNIWeakActive_lock; // JNI weak storage active 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* 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* ResolvedMethodTable_lock; // a lock on the ResolvedMethodTable updates
extern Mutex* JmethodIdCreation_lock; // a lock on creating JNI method identifiers extern Mutex* JmethodIdCreation_lock; // a lock on creating JNI method identifiers
extern Mutex* JfieldIdCreation_lock; // a lock on creating JNI static field identifiers extern Mutex* JfieldIdCreation_lock; // a lock on creating JNI static field identifiers