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.
|
// 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.
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
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* 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);
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user