8197844: JVMTI GetLoadedClasses should use the Access API
Make sure the holder of a class loader is accessed during iteration of CLDG Reviewed-by: eosterlund, rkennke
This commit is contained in:
parent
c944c3aba7
commit
b15a3ff611
@ -610,6 +610,21 @@ Dictionary* ClassLoaderData::create_dictionary() {
|
|||||||
return new Dictionary(this, size, resizable);
|
return new Dictionary(this, size, resizable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tell the GC to keep this klass alive while iterating ClassLoaderDataGraph
|
||||||
|
oop ClassLoaderData::holder_phantom() {
|
||||||
|
// 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);
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Unloading support
|
// Unloading support
|
||||||
oop ClassLoaderData::keep_alive_object() const {
|
oop ClassLoaderData::keep_alive_object() const {
|
||||||
assert_locked_or_safepoint(_metaspace_lock);
|
assert_locked_or_safepoint(_metaspace_lock);
|
||||||
@ -1048,26 +1063,34 @@ void ClassLoaderDataGraph::always_strong_cld_do(CLDClosure* cl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ClassLoaderDataGraph::classes_do(KlassClosure* klass_closure) {
|
void ClassLoaderDataGraph::classes_do(KlassClosure* klass_closure) {
|
||||||
|
Thread* thread = Thread::current();
|
||||||
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
|
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
|
||||||
|
Handle holder(thread, cld->holder_phantom());
|
||||||
cld->classes_do(klass_closure);
|
cld->classes_do(klass_closure);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClassLoaderDataGraph::classes_do(void f(Klass* const)) {
|
void ClassLoaderDataGraph::classes_do(void f(Klass* const)) {
|
||||||
|
Thread* thread = Thread::current();
|
||||||
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
|
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
|
||||||
|
Handle holder(thread, cld->holder_phantom());
|
||||||
cld->classes_do(f);
|
cld->classes_do(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClassLoaderDataGraph::methods_do(void f(Method*)) {
|
void ClassLoaderDataGraph::methods_do(void f(Method*)) {
|
||||||
|
Thread* thread = Thread::current();
|
||||||
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
|
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
|
||||||
|
Handle holder(thread, cld->holder_phantom());
|
||||||
cld->methods_do(f);
|
cld->methods_do(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClassLoaderDataGraph::modules_do(void f(ModuleEntry*)) {
|
void ClassLoaderDataGraph::modules_do(void f(ModuleEntry*)) {
|
||||||
assert_locked_or_safepoint(Module_lock);
|
assert_locked_or_safepoint(Module_lock);
|
||||||
|
Thread* thread = Thread::current();
|
||||||
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
|
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
|
||||||
|
Handle holder(thread, cld->holder_phantom());
|
||||||
cld->modules_do(f);
|
cld->modules_do(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1084,7 +1107,9 @@ void ClassLoaderDataGraph::modules_unloading_do(void f(ModuleEntry*)) {
|
|||||||
|
|
||||||
void ClassLoaderDataGraph::packages_do(void f(PackageEntry*)) {
|
void ClassLoaderDataGraph::packages_do(void f(PackageEntry*)) {
|
||||||
assert_locked_or_safepoint(Module_lock);
|
assert_locked_or_safepoint(Module_lock);
|
||||||
|
Thread* thread = Thread::current();
|
||||||
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
|
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
|
||||||
|
Handle holder(thread, cld->holder_phantom());
|
||||||
cld->packages_do(f);
|
cld->packages_do(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1100,7 +1125,9 @@ void ClassLoaderDataGraph::packages_unloading_do(void f(PackageEntry*)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ClassLoaderDataGraph::loaded_classes_do(KlassClosure* klass_closure) {
|
void ClassLoaderDataGraph::loaded_classes_do(KlassClosure* klass_closure) {
|
||||||
|
Thread* thread = Thread::current();
|
||||||
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
|
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
|
||||||
|
Handle holder(thread, cld->holder_phantom());
|
||||||
cld->loaded_classes_do(klass_closure);
|
cld->loaded_classes_do(klass_closure);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1121,21 +1148,27 @@ void ClassLoaderDataGraph::classes_unloading_do(void f(Klass* const)) {
|
|||||||
// Walk classes in the loaded class dictionaries in various forms.
|
// Walk classes in the loaded class dictionaries in various forms.
|
||||||
// Only walks the classes defined in this class loader.
|
// Only walks the classes defined in this class loader.
|
||||||
void ClassLoaderDataGraph::dictionary_classes_do(void f(InstanceKlass*)) {
|
void ClassLoaderDataGraph::dictionary_classes_do(void f(InstanceKlass*)) {
|
||||||
|
Thread* thread = Thread::current();
|
||||||
FOR_ALL_DICTIONARY(cld) {
|
FOR_ALL_DICTIONARY(cld) {
|
||||||
|
Handle holder(thread, cld->holder_phantom());
|
||||||
cld->dictionary()->classes_do(f);
|
cld->dictionary()->classes_do(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only walks the classes defined in this class loader.
|
// Only walks the classes defined in this class loader.
|
||||||
void ClassLoaderDataGraph::dictionary_classes_do(void f(InstanceKlass*, TRAPS), TRAPS) {
|
void ClassLoaderDataGraph::dictionary_classes_do(void f(InstanceKlass*, TRAPS), TRAPS) {
|
||||||
|
Thread* thread = Thread::current();
|
||||||
FOR_ALL_DICTIONARY(cld) {
|
FOR_ALL_DICTIONARY(cld) {
|
||||||
|
Handle holder(thread, cld->holder_phantom());
|
||||||
cld->dictionary()->classes_do(f, CHECK);
|
cld->dictionary()->classes_do(f, CHECK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Walks all entries in the dictionary including entries initiated by this class loader.
|
// Walks all entries in the dictionary including entries initiated by this class loader.
|
||||||
void ClassLoaderDataGraph::dictionary_all_entries_do(void f(InstanceKlass*, ClassLoaderData*)) {
|
void ClassLoaderDataGraph::dictionary_all_entries_do(void f(InstanceKlass*, ClassLoaderData*)) {
|
||||||
|
Thread* thread = Thread::current();
|
||||||
FOR_ALL_DICTIONARY(cld) {
|
FOR_ALL_DICTIONARY(cld) {
|
||||||
|
Handle holder(thread, cld->holder_phantom());
|
||||||
cld->dictionary()->all_entries_do(f);
|
cld->dictionary()->all_entries_do(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -288,6 +288,7 @@ 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();
|
||||||
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*));
|
||||||
|
@ -30,10 +30,6 @@
|
|||||||
#include "runtime/jniHandles.inline.hpp"
|
#include "runtime/jniHandles.inline.hpp"
|
||||||
#include "runtime/thread.hpp"
|
#include "runtime/thread.hpp"
|
||||||
#include "utilities/stack.inline.hpp"
|
#include "utilities/stack.inline.hpp"
|
||||||
#if INCLUDE_ALL_GCS
|
|
||||||
#include "gc/g1/g1BarrierSet.hpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// The closure for GetLoadedClasses
|
// The closure for GetLoadedClasses
|
||||||
class LoadedClassesClosure : public KlassClosure {
|
class LoadedClassesClosure : public KlassClosure {
|
||||||
@ -42,20 +38,6 @@ private:
|
|||||||
JvmtiEnv* _env;
|
JvmtiEnv* _env;
|
||||||
Thread* _cur_thread;
|
Thread* _cur_thread;
|
||||||
|
|
||||||
// Tell the GC to keep this klass alive
|
|
||||||
static void ensure_klass_alive(oop o) {
|
|
||||||
// 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 INCLUDE_ALL_GCS
|
|
||||||
if (UseG1GC && o != NULL) {
|
|
||||||
G1BarrierSet::enqueue(o);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LoadedClassesClosure(Thread* thread, JvmtiEnv* env) : _cur_thread(thread), _env(env) {
|
LoadedClassesClosure(Thread* thread, JvmtiEnv* env) : _cur_thread(thread), _env(env) {
|
||||||
assert(_cur_thread == Thread::current(), "must be current thread");
|
assert(_cur_thread == Thread::current(), "must be current thread");
|
||||||
@ -64,7 +46,6 @@ public:
|
|||||||
void do_klass(Klass* k) {
|
void do_klass(Klass* k) {
|
||||||
// Collect all jclasses
|
// Collect all jclasses
|
||||||
_classStack.push((jclass) _env->jni_reference(Handle(_cur_thread, k->java_mirror())));
|
_classStack.push((jclass) _env->jni_reference(Handle(_cur_thread, k->java_mirror())));
|
||||||
ensure_klass_alive(k->java_mirror());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int extract(jclass* result_list) {
|
int extract(jclass* result_list) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user