Skip to content

Commit

Permalink
8326820: Metadata artificially kept alive
Browse files Browse the repository at this point in the history
Reviewed-by: stefank
Backport-of: 5909d54
  • Loading branch information
xmas92 committed Jul 1, 2024
1 parent e78c682 commit e5fbc63
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 49 deletions.
83 changes: 42 additions & 41 deletions src/hotspot/share/classfile/classLoaderDataGraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,22 +241,23 @@ LockedClassesDo::~LockedClassesDo() {


// Iterating over the CLDG needs to be locked because
// unloading can remove entries concurrently soon.
template <bool keep_alive = true>
class ClassLoaderDataGraphIteratorBase : public StackObj {
// unloading can remove entries concurrently.
// This iterator does not keep the CLD alive.
// Any CLD OopHandles (modules, mirrors, resolved refs)
// resolved must be treated as no keepalive. And requires
// that its CLD's holder is kept alive if they escape the
// caller's safepoint or ClassLoaderDataGraph_lock
// critical section.
class ClassLoaderDataGraph::ClassLoaderDataGraphIterator : public StackObj {
ClassLoaderData* _next;
Thread* _thread;
HandleMark _hm; // clean up handles when this is done.
NoSafepointVerifier _nsv; // No safepoints allowed in this scope
// unless verifying at a safepoint.

public:
ClassLoaderDataGraphIteratorBase() : _next(ClassLoaderDataGraph::_head), _thread(Thread::current()), _hm(_thread) {
if (keep_alive) {
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
} else {
assert_at_safepoint();
}
ClassLoaderDataGraphIterator() : _next(ClassLoaderDataGraph::_head), _thread(Thread::current()), _hm(_thread) {
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
}

ClassLoaderData* get_next() {
Expand All @@ -266,10 +267,6 @@ class ClassLoaderDataGraphIteratorBase : public StackObj {
cld = cld->next();
}
if (cld != nullptr) {
if (keep_alive) {
// Keep cld that is being returned alive.
Handle(_thread, cld->holder());
}
_next = cld->next();
} else {
_next = nullptr;
Expand All @@ -278,23 +275,13 @@ class ClassLoaderDataGraphIteratorBase : public StackObj {
}
};

using ClassLoaderDataGraphIterator = ClassLoaderDataGraphIteratorBase<true /* keep_alive */>;
using ClassLoaderDataGraphIteratorNoKeepAlive = ClassLoaderDataGraphIteratorBase<false /* keep_alive */>;

void ClassLoaderDataGraph::loaded_cld_do(CLDClosure* cl) {
ClassLoaderDataGraphIterator iter;
while (ClassLoaderData* cld = iter.get_next()) {
cl->do_cld(cld);
}
}

void ClassLoaderDataGraph::loaded_cld_do_no_keepalive(CLDClosure* cl) {
ClassLoaderDataGraphIteratorNoKeepAlive iter;
while (ClassLoaderData* cld = iter.get_next()) {
cl->do_cld(cld);
}
}

// These functions assume that the caller has locked the ClassLoaderDataGraph_lock
// if they are not calling the function from a safepoint.
void ClassLoaderDataGraph::classes_do(KlassClosure* klass_closure) {
Expand All @@ -318,6 +305,16 @@ void ClassLoaderDataGraph::methods_do(void f(Method*)) {
}
}

void ClassLoaderDataGraph::modules_do_keepalive(void f(ModuleEntry*)) {
assert_locked_or_safepoint(Module_lock);
ClassLoaderDataGraphIterator iter;
while (ClassLoaderData* cld = iter.get_next()) {
// Keep the holder alive.
(void)cld->holder();
cld->modules_do(f);
}
}

void ClassLoaderDataGraph::modules_do(void f(ModuleEntry*)) {
assert_locked_or_safepoint(Module_lock);
ClassLoaderDataGraphIterator iter;
Expand All @@ -334,9 +331,11 @@ void ClassLoaderDataGraph::packages_do(void f(PackageEntry*)) {
}
}

void ClassLoaderDataGraph::loaded_classes_do(KlassClosure* klass_closure) {
void ClassLoaderDataGraph::loaded_classes_do_keepalive(KlassClosure* klass_closure) {
ClassLoaderDataGraphIterator iter;
while (ClassLoaderData* cld = iter.get_next()) {
// Keep the holder alive.
(void)cld->holder();
cld->loaded_classes_do(klass_closure);
}
}
Expand All @@ -346,34 +345,36 @@ void ClassLoaderDataGraph::classes_unloading_do(void f(Klass* const)) {
}

void ClassLoaderDataGraph::verify_dictionary() {
ClassLoaderDataGraphIteratorNoKeepAlive iter;
ClassLoaderDataGraphIterator iter;
while (ClassLoaderData* cld = iter.get_next()) {
if (cld->dictionary() != nullptr) {
cld->dictionary()->verify();
}
}
}

#define FOR_ALL_DICTIONARY(X) ClassLoaderDataGraphIterator iter; \
while (ClassLoaderData* X = iter.get_next()) \
if (X->dictionary() != nullptr)

void ClassLoaderDataGraph::print_dictionary(outputStream* st) {
FOR_ALL_DICTIONARY(cld) {
st->print("Dictionary for ");
cld->print_value_on(st);
st->cr();
cld->dictionary()->print_on(st);
st->cr();
ClassLoaderDataGraphIterator iter;
while (ClassLoaderData *cld = iter.get_next()) {
if (cld->dictionary() != nullptr) {
st->print("Dictionary for ");
cld->print_value_on(st);
st->cr();
cld->dictionary()->print_on(st);
st->cr();
}
}
}

void ClassLoaderDataGraph::print_table_statistics(outputStream* st) {
FOR_ALL_DICTIONARY(cld) {
ResourceMark rm; // loader_name_and_id
stringStream tempst;
tempst.print("System Dictionary for %s class loader", cld->loader_name_and_id());
cld->dictionary()->print_table_statistics(st, tempst.freeze());
ClassLoaderDataGraphIterator iter;
while (ClassLoaderData *cld = iter.get_next()) {
if (cld->dictionary() != nullptr) {
ResourceMark rm; // loader_name_and_id
stringStream tempst;
tempst.print("System Dictionary for %s class loader", cld->loader_name_and_id());
cld->dictionary()->print_table_statistics(st, tempst.freeze());
}
}
}

Expand Down Expand Up @@ -550,7 +551,7 @@ Klass* ClassLoaderDataGraphKlassIteratorAtomic::next_klass() {
}

void ClassLoaderDataGraph::verify() {
ClassLoaderDataGraphIteratorNoKeepAlive iter;
ClassLoaderDataGraphIterator iter;
while (ClassLoaderData* cld = iter.get_next()) {
cld->verify();
}
Expand Down
13 changes: 9 additions & 4 deletions src/hotspot/share/classfile/classLoaderDataGraph.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ class ClassLoaderDataGraph : public AllStatic {
friend class ClassLoaderDataGraphMetaspaceIterator;
friend class ClassLoaderDataGraphKlassIteratorAtomic;
friend class ClassLoaderDataGraphKlassIteratorStatic;
template <bool keep_alive>
friend class ClassLoaderDataGraphIteratorBase;
friend class VMStructs;
private:
class ClassLoaderDataGraphIterator;

// All CLDs (except unlinked CLDs) can be reached by walking _head->_next->...
static ClassLoaderData* volatile _head;

Expand Down Expand Up @@ -71,8 +71,12 @@ class ClassLoaderDataGraph : public AllStatic {
static void roots_cld_do(CLDClosure* strong, CLDClosure* weak);
static void always_strong_cld_do(CLDClosure* cl);
// Iteration through CLDG not by GC.
// All the do suffixed functions do not keep the CLD alive. Any CLD OopHandles
// (modules, mirrors, resolved refs) resolved must be treated as no keepalive.
// And requires that its CLD's holder is kept alive if they escape the
// caller's safepoint or ClassLoaderDataGraph_lock critical section.
// The do_keepalive suffixed functions will keep all CLDs alive.
static void loaded_cld_do(CLDClosure* cl);
static void loaded_cld_do_no_keepalive(CLDClosure* cl);
// klass do
// Walking classes through the ClassLoaderDataGraph include array classes. It also includes
// classes that are allocated but not loaded, classes that have errors, and scratch classes
Expand All @@ -81,9 +85,10 @@ class ClassLoaderDataGraph : public AllStatic {
static void classes_do(KlassClosure* klass_closure);
static void classes_do(void f(Klass* const));
static void methods_do(void f(Method*));
static void modules_do_keepalive(void f(ModuleEntry*));
static void modules_do(void f(ModuleEntry*));
static void packages_do(void f(PackageEntry*));
static void loaded_classes_do(KlassClosure* klass_closure);
static void loaded_classes_do_keepalive(KlassClosure* klass_closure);
static void classes_unloading_do(void f(Klass* const));
static bool do_unloading();

Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/classfile/classLoaderStats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ void ClassLoaderStatsClosure::addEmptyParents(oop cl) {

void ClassLoaderStatsVMOperation::doit() {
ClassLoaderStatsClosure clsc (_out);
ClassLoaderDataGraph::loaded_cld_do_no_keepalive(&clsc);
ClassLoaderDataGraph::loaded_cld_do(&clsc);
clsc.print();
}

Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/classfile/systemDictionary.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ class SystemDictionary : AllStatic {

static void classes_do(MetaspaceClosure* it);
// Iterate over all methods in all klasses

// Will not keep metadata alive. See ClassLoaderDataGraph::methods_do.
static void methods_do(void f(Method*));

// Garbage collection support
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/prims/jvmtiEnvBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2339,7 +2339,7 @@ JvmtiModuleClosure::get_all_modules(JvmtiEnv* env, jint* module_count_ptr, jobje
}

// Iterate over all the modules loaded to the system.
ClassLoaderDataGraph::modules_do(&do_module);
ClassLoaderDataGraph::modules_do_keepalive(&do_module);

jint len = _tbl->length();
guarantee(len > 0, "at least one module must be present");
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ JvmtiGetLoadedClasses::getLoadedClasses(JvmtiEnv *env, jint* classCountPtr, jcla
// Iterate through all classes in ClassLoaderDataGraph
// and collect them using the LoadedClassesClosure
MutexLocker mcld(ClassLoaderDataGraph_lock);
ClassLoaderDataGraph::loaded_classes_do(&closure);
ClassLoaderDataGraph::loaded_classes_do_keepalive(&closure);
}

return closure.get_result(env, classCountPtr, classesPtr);
Expand Down

1 comment on commit e5fbc63

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.