--- old/src/hotspot/share/classfile/classLoaderData.cpp 2018-09-27 13:06:37.429427318 -0400 +++ new/src/hotspot/share/classfile/classLoaderData.cpp 2018-09-27 13:06:37.173427307 -0400 @@ -47,8 +47,8 @@ // the singleton class the_null_class_loader_data(). #include "precompiled.hpp" -#include "classfile/classLoaderData.hpp" #include "classfile/classLoaderData.inline.hpp" +#include "classfile/classLoaderDataGraph.inline.hpp" #include "classfile/dictionary.hpp" #include "classfile/javaClasses.hpp" #include "classfile/metadataOnStackMark.hpp" @@ -62,7 +62,6 @@ #include "memory/metadataFactory.hpp" #include "memory/metaspaceShared.hpp" #include "memory/resourceArea.hpp" -#include "memory/universe.hpp" #include "oops/access.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/oopHandle.inline.hpp" @@ -72,14 +71,10 @@ #include "runtime/mutex.hpp" #include "runtime/orderAccess.hpp" #include "runtime/safepoint.hpp" -#include "runtime/safepointVerifiers.hpp" #include "utilities/growableArray.hpp" #include "utilities/macros.hpp" #include "utilities/ostream.hpp" -volatile size_t ClassLoaderDataGraph::_num_array_classes = 0; -volatile size_t ClassLoaderDataGraph::_num_instance_classes = 0; - ClassLoaderData * ClassLoaderData::_the_null_class_loader_data = NULL; void ClassLoaderData::init_null_class_loader_data() { @@ -444,13 +439,6 @@ } } - -void ClassLoaderDataGraph::clear_claimed_marks() { - for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { - cld->clear_claimed(); - } -} - void ClassLoaderData::add_class(Klass* k, bool publicize /* true */) { { MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag); @@ -478,78 +466,6 @@ } } -// Class iterator used by the compiler. It gets some number of classes at -// a safepoint to decay invocation counters on the methods. -class ClassLoaderDataGraphKlassIteratorStatic { - ClassLoaderData* _current_loader_data; - Klass* _current_class_entry; - public: - - ClassLoaderDataGraphKlassIteratorStatic() : _current_loader_data(NULL), _current_class_entry(NULL) {} - - InstanceKlass* try_get_next_class() { - assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint"); - size_t max_classes = ClassLoaderDataGraph::num_instance_classes(); - assert(max_classes > 0, "should not be called with no instance classes"); - for (size_t i = 0; i < max_classes; ) { - - if (_current_class_entry != NULL) { - Klass* k = _current_class_entry; - _current_class_entry = _current_class_entry->next_link(); - - if (k->is_instance_klass()) { - InstanceKlass* ik = InstanceKlass::cast(k); - i++; // count all instance classes found - // Not yet loaded classes are counted in max_classes - // but only return loaded classes. - if (ik->is_loaded()) { - return ik; - } - } - } else { - // Go to next CLD - if (_current_loader_data != NULL) { - _current_loader_data = _current_loader_data->next(); - } - // Start at the beginning - if (_current_loader_data == NULL) { - _current_loader_data = ClassLoaderDataGraph::_head; - } - - _current_class_entry = _current_loader_data->klasses(); - } - } - // Should never be reached unless all instance classes have failed or are not fully loaded. - // Caller handles NULL. - return NULL; - } - - // If the current class for the static iterator is a class being unloaded or - // deallocated, adjust the current class. - void adjust_saved_class(ClassLoaderData* cld) { - if (_current_loader_data == cld) { - _current_loader_data = cld->next(); - if (_current_loader_data != NULL) { - _current_class_entry = _current_loader_data->klasses(); - } // else try_get_next_class will start at the head - } - } - - void adjust_saved_class(Klass* klass) { - if (_current_class_entry == klass) { - _current_class_entry = klass->next_link(); - } - } -}; - -static ClassLoaderDataGraphKlassIteratorStatic static_klass_iterator; - -InstanceKlass* ClassLoaderDataGraph::try_get_next_class() { - assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint"); - return static_klass_iterator.try_get_next_class(); -} - - void ClassLoaderData::initialize_holder(Handle loader_or_mirror) { if (loader_or_mirror() != NULL) { assert(_holder.is_null(), "never replace holders"); @@ -563,7 +479,7 @@ assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint"); // Adjust global class iterator. - static_klass_iterator.adjust_saved_class(scratch_class); + ClassLoaderDataGraph::adjust_saved_class(scratch_class); Klass* prev = NULL; for (Klass* k = _klasses; k != NULL; k = k->next_link()) { @@ -611,7 +527,7 @@ classes_do(InstanceKlass::unload_class); // Clean up global class iterator for compiler - static_klass_iterator.adjust_saved_class(this); + ClassLoaderDataGraph::adjust_saved_class(this); } ModuleEntryTable* ClassLoaderData::modules() { @@ -914,41 +830,6 @@ } } -void ClassLoaderDataGraph::clean_deallocate_lists(bool walk_previous_versions) { - assert(SafepointSynchronize::is_at_safepoint(), "must only be called at safepoint"); - uint loaders_processed = 0; - for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { - // is_alive check will be necessary for concurrent class unloading. - if (cld->is_alive()) { - // clean metaspace - if (walk_previous_versions) { - cld->classes_do(InstanceKlass::purge_previous_versions); - } - cld->free_deallocate_list(); - loaders_processed++; - } - } - log_debug(class, loader, data)("clean_deallocate_lists: loaders processed %u %s", - loaders_processed, walk_previous_versions ? "walk_previous_versions" : ""); -} - -void ClassLoaderDataGraph::walk_metadata_and_clean_metaspaces() { - assert(SafepointSynchronize::is_at_safepoint(), "must only be called at safepoint"); - - _should_clean_deallocate_lists = false; // assume everything gets cleaned - - // Mark metadata seen on the stack so we can delete unreferenced entries. - // Walk all metadata, including the expensive code cache walk, only for class redefinition. - // The MetadataOnStackMark walk during redefinition saves previous versions if it finds old methods - // on the stack or in the code cache, so we only have to repeat the full walk if - // they were found at that time. - // TODO: have redefinition clean old methods out of the code cache. They still exist in some places. - bool walk_all_metadata = InstanceKlass::has_previous_versions_and_reset(); - - MetadataOnStackMark md_on_stack(walk_all_metadata); - clean_deallocate_lists(walk_all_metadata); -} - // This is distinct from free_deallocate_list. For class loader data that are // unloading, this frees the C heap memory for items on the list, and unlinks // scratch or error classes so that unloading events aren't triggered for these @@ -1070,523 +951,3 @@ } return false; } - - -// GC root of class loader data created. -ClassLoaderData* ClassLoaderDataGraph::_head = NULL; -ClassLoaderData* ClassLoaderDataGraph::_unloading = NULL; -ClassLoaderData* ClassLoaderDataGraph::_saved_unloading = NULL; -ClassLoaderData* ClassLoaderDataGraph::_saved_head = NULL; - -bool ClassLoaderDataGraph::_should_purge = false; -bool ClassLoaderDataGraph::_should_clean_deallocate_lists = false; -bool ClassLoaderDataGraph::_safepoint_cleanup_needed = false; -bool ClassLoaderDataGraph::_metaspace_oom = false; - -// Add a new class loader data node to the list. Assign the newly created -// ClassLoaderData into the java/lang/ClassLoader object as a hidden field -ClassLoaderData* ClassLoaderDataGraph::add_to_graph(Handle loader, bool is_unsafe_anonymous) { - - assert_lock_strong(ClassLoaderDataGraph_lock); - - ClassLoaderData* cld; - - // First check if another thread beat us to creating the CLD and installing - // it into the loader while we were waiting for the lock. - if (!is_unsafe_anonymous && loader.not_null()) { - cld = java_lang_ClassLoader::loader_data_acquire(loader()); - if (cld != NULL) { - return cld; - } - } - - // We mustn't GC until we've installed the ClassLoaderData in the Graph since the CLD - // contains oops in _handles that must be walked. GC doesn't walk CLD from the - // loader oop in all collections, particularly young collections. - NoSafepointVerifier no_safepoints; - - cld = new ClassLoaderData(loader, is_unsafe_anonymous); - - // First install the new CLD to the Graph. - cld->set_next(_head); - _head = cld; - - // Next associate with the class_loader. - if (!is_unsafe_anonymous) { - // Use OrderAccess, since readers need to get the loader_data only after - // it's added to the Graph - java_lang_ClassLoader::release_set_loader_data(loader(), cld); - } - - // Lastly log, if requested - LogTarget(Trace, class, loader, data) lt; - if (lt.is_enabled()) { - ResourceMark rm; - LogStream ls(lt); - ls.print("create "); - cld->print_value_on(&ls); - ls.cr(); - } - return cld; -} - -ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool is_unsafe_anonymous) { - MutexLocker ml(ClassLoaderDataGraph_lock); - ClassLoaderData* loader_data = add_to_graph(loader, is_unsafe_anonymous); - return loader_data; -} - -void ClassLoaderDataGraph::cld_do(CLDClosure* cl) { - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->_next) { - cl->do_cld(cld); - } -} - -void ClassLoaderDataGraph::cld_unloading_do(CLDClosure* cl) { - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - // Only walk the head until any clds not purged from prior unloading - // (CMS doesn't purge right away). - for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) { - assert(cld->is_unloading(), "invariant"); - cl->do_cld(cld); - } -} - -void ClassLoaderDataGraph::roots_cld_do(CLDClosure* strong, CLDClosure* weak) { - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->_next) { - CLDClosure* closure = cld->keep_alive() ? strong : weak; - if (closure != NULL) { - closure->do_cld(cld); - } - } -} - -void ClassLoaderDataGraph::always_strong_cld_do(CLDClosure* cl) { - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - if (ClassUnloading) { - roots_cld_do(cl, NULL); - } else { - cld_do(cl); - } -} - -// Closure for locking and iterating through classes. -LockedClassesDo::LockedClassesDo(classes_do_func_t f) : _function(f) { - ClassLoaderDataGraph_lock->lock(); -} - -LockedClassesDo::LockedClassesDo() : _function(NULL) { - // callers provide their own do_klass - ClassLoaderDataGraph_lock->lock(); -} - -LockedClassesDo::~LockedClassesDo() { ClassLoaderDataGraph_lock->unlock(); } - - -// Iterating over the CLDG needs to be locked because -// unloading can remove entries concurrently soon. -class ClassLoaderDataGraphIterator : public StackObj { - ClassLoaderData* _next; - HandleMark _hm; // clean up handles when this is done. - Handle _holder; - Thread* _thread; - - void hold_next() { - if (_next != NULL) { - _holder = Handle(_thread, _next->holder_phantom()); - } - } -public: - ClassLoaderDataGraphIterator() : _next(ClassLoaderDataGraph::_head) { - _thread = Thread::current(); - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - hold_next(); - } - - bool repeat() const { - return _next != NULL; - } - - ClassLoaderData* get_next() { - ClassLoaderData* next = _next; - if (_next != NULL) { - _next = _next->next(); - hold_next(); - } - return next; - } -}; - -// 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) { - ClassLoaderDataGraphIterator iter; - while (iter.repeat()) { - ClassLoaderData* cld = iter.get_next(); - cld->classes_do(klass_closure); - } -} - -void ClassLoaderDataGraph::classes_do(void f(Klass* const)) { - ClassLoaderDataGraphIterator iter; - while (iter.repeat()) { - ClassLoaderData* cld = iter.get_next(); - cld->classes_do(f); - } -} - -void ClassLoaderDataGraph::methods_do(void f(Method*)) { - ClassLoaderDataGraphIterator iter; - while (iter.repeat()) { - ClassLoaderData* cld = iter.get_next(); - cld->methods_do(f); - } -} - -void ClassLoaderDataGraph::modules_do(void f(ModuleEntry*)) { - assert_locked_or_safepoint(Module_lock); - ClassLoaderDataGraphIterator iter; - while (iter.repeat()) { - ClassLoaderData* cld = iter.get_next(); - cld->modules_do(f); - } -} - -void ClassLoaderDataGraph::modules_unloading_do(void f(ModuleEntry*)) { - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - // Only walk the head until any clds not purged from prior unloading - // (CMS doesn't purge right away). - for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) { - assert(cld->is_unloading(), "invariant"); - cld->modules_do(f); - } -} - -void ClassLoaderDataGraph::packages_do(void f(PackageEntry*)) { - assert_locked_or_safepoint(Module_lock); - ClassLoaderDataGraphIterator iter; - while (iter.repeat()) { - ClassLoaderData* cld = iter.get_next(); - cld->packages_do(f); - } -} - -void ClassLoaderDataGraph::packages_unloading_do(void f(PackageEntry*)) { - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - // Only walk the head until any clds not purged from prior unloading - // (CMS doesn't purge right away). - for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) { - assert(cld->is_unloading(), "invariant"); - cld->packages_do(f); - } -} - -void ClassLoaderDataGraph::loaded_classes_do(KlassClosure* klass_closure) { - ClassLoaderDataGraphIterator iter; - while (iter.repeat()) { - ClassLoaderData* cld = iter.get_next(); - cld->loaded_classes_do(klass_closure); - } -} - -// This case can block but cannot do unloading (called from CDS) -void ClassLoaderDataGraph::unlocked_loaded_classes_do(KlassClosure* klass_closure) { - for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { - cld->loaded_classes_do(klass_closure); - } -} - - -void ClassLoaderDataGraph::classes_unloading_do(void f(Klass* const)) { - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - // Only walk the head until any clds not purged from prior unloading - // (CMS doesn't purge right away). - for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) { - assert(cld->is_unloading(), "invariant"); - cld->classes_do(f); - } -} - -#define FOR_ALL_DICTIONARY(X) ClassLoaderDataGraphIterator iter; \ - ClassLoaderData* X; \ - while ((X = iter.get_next()) != NULL) \ - if (X->dictionary() != NULL) - -// Walk classes in the loaded class dictionaries in various forms. -// Only walks the classes defined in this class loader. -void ClassLoaderDataGraph::dictionary_classes_do(void f(InstanceKlass*)) { - FOR_ALL_DICTIONARY(cld) { - cld->dictionary()->classes_do(f); - } -} - -// Only walks the classes defined in this class loader. -void ClassLoaderDataGraph::dictionary_classes_do(void f(InstanceKlass*, TRAPS), TRAPS) { - FOR_ALL_DICTIONARY(cld) { - cld->dictionary()->classes_do(f, CHECK); - } -} - -void ClassLoaderDataGraph::verify_dictionary() { - FOR_ALL_DICTIONARY(cld) { - cld->dictionary()->verify(); - } -} - -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(); - } -} - -void ClassLoaderDataGraph::print_dictionary_statistics(outputStream* st) { - FOR_ALL_DICTIONARY(cld) { - ResourceMark rm; - stringStream tempst; - tempst.print("System Dictionary for %s class loader", cld->loader_name_and_id()); - cld->dictionary()->print_table_statistics(st, tempst.as_string()); - } -} - -GrowableArray* ClassLoaderDataGraph::new_clds() { - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - assert(_head == NULL || _saved_head != NULL, "remember_new_clds(true) not called?"); - - GrowableArray* array = new GrowableArray(); - - // The CLDs in [_head, _saved_head] were all added during last call to remember_new_clds(true); - ClassLoaderData* curr = _head; - while (curr != _saved_head) { - if (!curr->claimed()) { - array->push(curr); - LogTarget(Debug, class, loader, data) lt; - if (lt.is_enabled()) { - LogStream ls(lt); - ls.print("found new CLD: "); - curr->print_value_on(&ls); - ls.cr(); - } - } - - curr = curr->_next; - } - - return array; -} - -#ifndef PRODUCT -bool ClassLoaderDataGraph::contains_loader_data(ClassLoaderData* loader_data) { - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - for (ClassLoaderData* data = _head; data != NULL; data = data->next()) { - if (loader_data == data) { - return true; - } - } - - return false; -} -#endif // PRODUCT - -// Move class loader data from main list to the unloaded list for unloading -// and deallocation later. -bool ClassLoaderDataGraph::do_unloading(bool do_cleaning) { - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - - // Indicate whether safepoint cleanup is needed. - _safepoint_cleanup_needed |= do_cleaning; - - ClassLoaderData* data = _head; - ClassLoaderData* prev = NULL; - bool seen_dead_loader = false; - uint loaders_processed = 0; - uint loaders_removed = 0; - - // Save previous _unloading pointer for CMS which may add to unloading list before - // purging and we don't want to rewalk the previously unloaded class loader data. - _saved_unloading = _unloading; - - data = _head; - while (data != NULL) { - if (data->is_alive()) { - prev = data; - data = data->next(); - loaders_processed++; - continue; - } - seen_dead_loader = true; - loaders_removed++; - ClassLoaderData* dead = data; - dead->unload(); - data = data->next(); - // Remove from loader list. - // This class loader data will no longer be found - // in the ClassLoaderDataGraph. - if (prev != NULL) { - prev->set_next(data); - } else { - assert(dead == _head, "sanity check"); - _head = data; - } - dead->set_next(_unloading); - _unloading = dead; - } - - log_debug(class, loader, data)("do_unloading: loaders processed %u, loaders removed %u", loaders_processed, loaders_removed); - - return seen_dead_loader; -} - -// There's at least one dead class loader. Purge refererences of healthy module -// reads lists and package export lists to modules belonging to dead loaders. -void ClassLoaderDataGraph::clean_module_and_package_info() { - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - - ClassLoaderData* data = _head; - while (data != NULL) { - // Remove entries in the dictionary of live class loader that have - // initiated loading classes in a dead class loader. - if (data->dictionary() != NULL) { - data->dictionary()->do_unloading(); - } - // Walk a ModuleEntry's reads, and a PackageEntry's exports - // lists to determine if there are modules on those lists that are now - // dead and should be removed. A module's life cycle is equivalent - // to its defining class loader's life cycle. Since a module is - // considered dead if its class loader is dead, these walks must - // occur after each class loader's aliveness is determined. - if (data->packages() != NULL) { - data->packages()->purge_all_package_exports(); - } - if (data->modules_defined()) { - data->modules()->purge_all_module_reads(); - } - data = data->next(); - } -} - -void ClassLoaderDataGraph::purge() { - assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!"); - ClassLoaderData* list = _unloading; - _unloading = NULL; - ClassLoaderData* next = list; - bool classes_unloaded = false; - while (next != NULL) { - ClassLoaderData* purge_me = next; - next = purge_me->next(); - delete purge_me; - classes_unloaded = true; - } - if (classes_unloaded) { - Metaspace::purge(); - set_metaspace_oom(false); - } -} - -int ClassLoaderDataGraph::resize_if_needed() { - assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!"); - int resized = 0; - if (Dictionary::does_any_dictionary_needs_resizing()) { - FOR_ALL_DICTIONARY(cld) { - if (cld->dictionary()->resize_if_needed()) { - resized++; - } - } - } - return resized; -} - -ClassLoaderDataGraphKlassIteratorAtomic::ClassLoaderDataGraphKlassIteratorAtomic() - : _next_klass(NULL) { - assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!"); - ClassLoaderData* cld = ClassLoaderDataGraph::_head; - Klass* klass = NULL; - - // Find the first klass in the CLDG. - while (cld != NULL) { - assert_locked_or_safepoint(cld->metaspace_lock()); - klass = cld->_klasses; - if (klass != NULL) { - _next_klass = klass; - return; - } - cld = cld->next(); - } -} - -Klass* ClassLoaderDataGraphKlassIteratorAtomic::next_klass_in_cldg(Klass* klass) { - Klass* next = klass->next_link(); - if (next != NULL) { - return next; - } - - // No more klasses in the current CLD. Time to find a new CLD. - ClassLoaderData* cld = klass->class_loader_data(); - assert_locked_or_safepoint(cld->metaspace_lock()); - while (next == NULL) { - cld = cld->next(); - if (cld == NULL) { - break; - } - next = cld->_klasses; - } - - return next; -} - -Klass* ClassLoaderDataGraphKlassIteratorAtomic::next_klass() { - Klass* head = _next_klass; - - while (head != NULL) { - Klass* next = next_klass_in_cldg(head); - - Klass* old_head = Atomic::cmpxchg(next, &_next_klass, head); - - if (old_head == head) { - return head; // Won the CAS. - } - - head = old_head; - } - - // Nothing more for the iterator to hand out. - assert(head == NULL, "head is " PTR_FORMAT ", expected not null:", p2i(head)); - return NULL; -} - -ClassLoaderDataGraphMetaspaceIterator::ClassLoaderDataGraphMetaspaceIterator() { - assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!"); - _data = ClassLoaderDataGraph::_head; -} - -ClassLoaderDataGraphMetaspaceIterator::~ClassLoaderDataGraphMetaspaceIterator() {} - -#ifndef PRODUCT -// callable from debugger -extern "C" int print_loader_data_graph() { - ResourceMark rm; - ClassLoaderDataGraph::print_on(tty); - return 0; -} - -void ClassLoaderDataGraph::verify() { - ClassLoaderDataGraphIterator iter; - while (iter.repeat()) { - ClassLoaderData* cld = iter.get_next(); - cld->verify(); - } -} - -void ClassLoaderDataGraph::print_on(outputStream * const out) { - ClassLoaderDataGraphIterator iter; - while (iter.repeat()) { - ClassLoaderData* cld = iter.get_next(); - cld->print_on(out); - } -} -#endif // PRODUCT --- old/src/hotspot/share/classfile/classLoaderData.hpp 2018-09-27 13:06:37.817427334 -0400 +++ new/src/hotspot/share/classfile/classLoaderData.hpp 2018-09-27 13:06:37.561427323 -0400 @@ -53,9 +53,8 @@ // ClassLoaderData are stored in the runtime representation of classes, // and provides iterators for root tracing and other GC operations. -class ClassLoaderData; +class ClassLoaderDataGraph; class JNIMethodBlock; -class Metadebug; class ModuleEntry; class PackageEntry; class ModuleEntryTable; @@ -63,136 +62,6 @@ class DictionaryEntry; class Dictionary; -// GC root for walking class loader data created - -class ClassLoaderDataGraph : public AllStatic { - friend class ClassLoaderData; - friend class ClassLoaderDataGraphMetaspaceIterator; - friend class ClassLoaderDataGraphKlassIteratorAtomic; - friend class ClassLoaderDataGraphKlassIteratorStatic; - friend class ClassLoaderDataGraphIterator; - friend class VMStructs; - private: - // All CLDs (except the null CLD) can be reached by walking _head->_next->... - static ClassLoaderData* _head; - static ClassLoaderData* _unloading; - // CMS support. - static ClassLoaderData* _saved_head; - static ClassLoaderData* _saved_unloading; - static bool _should_purge; - - // Set if there's anything to purge in the deallocate lists or previous versions - // during a safepoint after class unloading in a full GC. - static bool _should_clean_deallocate_lists; - static bool _safepoint_cleanup_needed; - - // OOM has been seen in metaspace allocation. Used to prevent some - // allocations until class unloading - static bool _metaspace_oom; - - static volatile size_t _num_instance_classes; - static volatile size_t _num_array_classes; - - static ClassLoaderData* add_to_graph(Handle class_loader, bool is_unsafe_anonymous); - static ClassLoaderData* add(Handle class_loader, bool is_unsafe_anonymous); - - public: - static ClassLoaderData* find_or_create(Handle class_loader); - static void clean_module_and_package_info(); - static void purge(); - static void clear_claimed_marks(); - // Iteration through CLDG inside a safepoint; GC support - static void cld_do(CLDClosure* cl); - static void cld_unloading_do(CLDClosure* cl); - static void roots_cld_do(CLDClosure* strong, CLDClosure* weak); - static void always_strong_cld_do(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 - // for redefinition. These classes are removed during the next class unloading. - // Walking the ClassLoaderDataGraph also includes unsafe anonymous classes. - 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(void f(ModuleEntry*)); - static void modules_unloading_do(void f(ModuleEntry*)); - static void packages_do(void f(PackageEntry*)); - static void packages_unloading_do(void f(PackageEntry*)); - static void loaded_classes_do(KlassClosure* klass_closure); - static void unlocked_loaded_classes_do(KlassClosure* klass_closure); - static void classes_unloading_do(void f(Klass* const)); - static bool do_unloading(bool do_cleaning); - - // Expose state to avoid logging overhead in safepoint cleanup tasks. - static inline bool should_clean_metaspaces_and_reset(); - static void set_should_clean_deallocate_lists() { _should_clean_deallocate_lists = true; } - static void clean_deallocate_lists(bool purge_previous_versions); - static void walk_metadata_and_clean_metaspaces(); - - // dictionary do - // Iterate over all klasses in dictionary, but - // just the classes from defining class loaders. - static void dictionary_classes_do(void f(InstanceKlass*)); - // Added for initialize_itable_for_klass to handle exceptions. - static void dictionary_classes_do(void f(InstanceKlass*, TRAPS), TRAPS); - - // VM_CounterDecay iteration support - static InstanceKlass* try_get_next_class(); - - static void verify_dictionary(); - static void print_dictionary(outputStream* st); - static void print_dictionary_statistics(outputStream* st); - - // CMS support. - static void remember_new_clds(bool remember) { _saved_head = (remember ? _head : NULL); } - static GrowableArray* new_clds(); - - static void set_should_purge(bool b) { _should_purge = b; } - static void purge_if_needed() { - // Only purge the CLDG for CMS if concurrent sweep is complete. - if (_should_purge) { - purge(); - // reset for next time. - set_should_purge(false); - } - } - - static int resize_if_needed(); - - static bool has_metaspace_oom() { return _metaspace_oom; } - static void set_metaspace_oom(bool value) { _metaspace_oom = value; } - - static void print_on(outputStream * const out) PRODUCT_RETURN; - static void print() { print_on(tty); } - static void verify(); - - // instance and array class counters - static inline size_t num_instance_classes(); - static inline size_t num_array_classes(); - static inline void inc_instance_classes(size_t count); - static inline void dec_instance_classes(size_t count); - static inline void inc_array_classes(size_t count); - static inline void dec_array_classes(size_t count); - -#ifndef PRODUCT - static bool contains_loader_data(ClassLoaderData* loader_data); -#endif -}; - -class LockedClassesDo : public KlassClosure { - typedef void (*classes_do_func_t)(Klass*); - classes_do_func_t _function; -public: - LockedClassesDo(); // For callers who provide their own do_klass - LockedClassesDo(classes_do_func_t function); - ~LockedClassesDo(); - - void do_klass(Klass* k) { - (*_function)(k); - } -}; - - // ClassLoaderData class class ClassLoaderData : public CHeapObj { @@ -448,31 +317,4 @@ JFR_ONLY(DEFINE_TRACE_ID_METHODS;) }; -// An iterator that distributes Klasses to parallel worker threads. -class ClassLoaderDataGraphKlassIteratorAtomic : public StackObj { - Klass* volatile _next_klass; - public: - ClassLoaderDataGraphKlassIteratorAtomic(); - Klass* next_klass(); - private: - static Klass* next_klass_in_cldg(Klass* klass); -}; - -class ClassLoaderDataGraphMetaspaceIterator : public StackObj { - ClassLoaderData* _data; - public: - ClassLoaderDataGraphMetaspaceIterator(); - ~ClassLoaderDataGraphMetaspaceIterator(); - bool repeat() { return _data != NULL; } - ClassLoaderMetaspace* get_next() { - assert(_data != NULL, "Should not be NULL in call to the iterator"); - ClassLoaderMetaspace* result = _data->metaspace_or_null(); - _data = _data->next(); - // This result might be NULL for class loaders without metaspace - // yet. It would be nice to return only non-null results but - // there is no guarantee that there will be a non-null result - // down the list so the caller is going to have to check. - return result; - } -}; #endif // SHARE_VM_CLASSFILE_CLASSLOADERDATA_HPP --- old/src/hotspot/share/classfile/classLoaderData.inline.hpp 2018-09-27 13:06:38.169427349 -0400 +++ new/src/hotspot/share/classfile/classLoaderData.inline.hpp 2018-09-27 13:06:37.921427338 -0400 @@ -55,54 +55,4 @@ return loader_data; } - -inline ClassLoaderData *ClassLoaderDataGraph::find_or_create(Handle loader) { - guarantee(loader() != NULL && oopDesc::is_oop(loader()), "Loader must be oop"); - // Gets the class loader data out of the java/lang/ClassLoader object, if non-null - // it's already in the loader_data, so no need to add - ClassLoaderData* loader_data= java_lang_ClassLoader::loader_data_acquire(loader()); - if (loader_data) { - return loader_data; - } - return ClassLoaderDataGraph::add(loader, false); -} - -size_t ClassLoaderDataGraph::num_instance_classes() { - return _num_instance_classes; -} - -size_t ClassLoaderDataGraph::num_array_classes() { - return _num_array_classes; -} - -void ClassLoaderDataGraph::inc_instance_classes(size_t count) { - Atomic::add(count, &_num_instance_classes); -} - -void ClassLoaderDataGraph::dec_instance_classes(size_t count) { - assert(count <= _num_instance_classes, "Sanity"); - Atomic::sub(count, &_num_instance_classes); -} - -void ClassLoaderDataGraph::inc_array_classes(size_t count) { - Atomic::add(count, &_num_array_classes); -} - -void ClassLoaderDataGraph::dec_array_classes(size_t count) { - assert(count <= _num_array_classes, "Sanity"); - Atomic::sub(count, &_num_array_classes); -} - -bool ClassLoaderDataGraph::should_clean_metaspaces_and_reset() { - // Only clean metaspaces after full GC. - bool do_cleaning = _safepoint_cleanup_needed; -#if INCLUDE_JVMTI - do_cleaning = do_cleaning && (_should_clean_deallocate_lists || InstanceKlass::has_previous_versions()); -#else - do_cleaning = do_cleaning && _should_clean_deallocate_lists; -#endif - _safepoint_cleanup_needed = false; // reset - return do_cleaning; -} - #endif // SHARE_VM_CLASSFILE_CLASSLOADERDATA_INLINE_HPP --- old/src/hotspot/share/classfile/classLoaderHierarchyDCmd.cpp 2018-09-27 13:06:38.521427363 -0400 +++ new/src/hotspot/share/classfile/classLoaderHierarchyDCmd.cpp 2018-09-27 13:06:38.269427353 -0400 @@ -26,6 +26,7 @@ #include "precompiled.hpp" #include "classfile/classLoaderData.inline.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/classLoaderHierarchyDCmd.hpp" #include "memory/allocation.hpp" #include "memory/resourceArea.hpp" --- old/src/hotspot/share/classfile/classLoaderStats.cpp 2018-09-27 13:06:38.869427378 -0400 +++ new/src/hotspot/share/classfile/classLoaderStats.cpp 2018-09-27 13:06:38.621427367 -0400 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/classLoaderData.inline.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/classLoaderStats.hpp" #include "oops/oop.inline.hpp" #include "utilities/globalDefinitions.hpp" --- old/src/hotspot/share/classfile/loaderConstraints.cpp 2018-09-27 13:06:39.189427391 -0400 +++ new/src/hotspot/share/classfile/loaderConstraints.cpp 2018-09-27 13:06:38.953427381 -0400 @@ -23,8 +23,9 @@ */ #include "precompiled.hpp" -#include "classfile/dictionary.hpp" #include "classfile/classLoaderData.inline.hpp" +#include "classfile/classLoaderDataGraph.hpp" +#include "classfile/dictionary.hpp" #include "classfile/loaderConstraints.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" --- old/src/hotspot/share/classfile/systemDictionary.cpp 2018-09-27 13:06:39.553427406 -0400 +++ new/src/hotspot/share/classfile/systemDictionary.cpp 2018-09-27 13:06:39.293427395 -0400 @@ -29,6 +29,7 @@ #include "classfile/classFileStream.hpp" #include "classfile/classLoader.hpp" #include "classfile/classLoaderData.inline.hpp" +#include "classfile/classLoaderDataGraph.inline.hpp" #include "classfile/classLoaderExt.hpp" #include "classfile/dictionary.hpp" #include "classfile/javaClasses.inline.hpp" --- old/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp 2018-09-27 13:06:39.941427423 -0400 +++ new/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp 2018-09-27 13:06:39.697427412 -0400 @@ -23,7 +23,7 @@ */ #include "precompiled.hpp" -#include "classfile/classLoaderData.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" --- old/src/hotspot/share/gc/g1/g1CollectedHeap.cpp 2018-09-27 13:06:40.441427443 -0400 +++ new/src/hotspot/share/gc/g1/g1CollectedHeap.cpp 2018-09-27 13:06:40.169427432 -0400 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/metadataOnStackMark.hpp" #include "classfile/stringTable.hpp" #include "code/codeCache.hpp" --- old/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp 2018-09-27 13:06:40.877427462 -0400 +++ new/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp 2018-09-27 13:06:40.609427450 -0400 @@ -23,7 +23,7 @@ */ #include "precompiled.hpp" -#include "classfile/metadataOnStackMark.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "code/codeCache.hpp" #include "gc/g1/g1BarrierSet.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" --- old/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp 2018-09-27 13:06:41.281427478 -0400 +++ new/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp 2018-09-27 13:06:41.025427468 -0400 @@ -23,7 +23,7 @@ */ #include "precompiled.hpp" -#include "classfile/classLoaderData.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "gc/g1/g1Analytics.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1ConcurrentMark.inline.hpp" --- old/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp 2018-09-27 13:06:41.645427494 -0400 +++ new/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp 2018-09-27 13:06:41.385427483 -0400 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "gc/g1/g1CollectedHeap.hpp" #include "gc/g1/g1ConcurrentMarkBitMap.inline.hpp" #include "gc/g1/g1FullCollector.hpp" --- old/src/hotspot/share/gc/g1/g1FullGCMarkTask.cpp 2018-09-27 13:06:42.017427509 -0400 +++ new/src/hotspot/share/gc/g1/g1FullGCMarkTask.cpp 2018-09-27 13:06:41.749427498 -0400 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "gc/g1/g1CollectedHeap.hpp" #include "gc/g1/g1FullCollector.hpp" #include "gc/g1/g1FullGCMarker.hpp" --- old/src/hotspot/share/gc/g1/g1RootProcessor.cpp 2018-09-27 13:06:42.389427525 -0400 +++ new/src/hotspot/share/gc/g1/g1RootProcessor.cpp 2018-09-27 13:06:42.129427514 -0400 @@ -23,8 +23,8 @@ */ #include "precompiled.hpp" - #include "aot/aotLoader.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" --- old/src/hotspot/share/gc/parallel/pcTasks.cpp 2018-09-27 13:06:42.745427540 -0400 +++ new/src/hotspot/share/gc/parallel/pcTasks.cpp 2018-09-27 13:06:42.489427529 -0400 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "aot/aotLoader.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" #include "gc/parallel/parallelScavengeHeap.hpp" --- old/src/hotspot/share/gc/parallel/psMarkSweep.cpp 2018-09-27 13:06:43.101427554 -0400 +++ new/src/hotspot/share/gc/parallel/psMarkSweep.cpp 2018-09-27 13:06:42.845427544 -0400 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "aot/aotLoader.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" --- old/src/hotspot/share/gc/parallel/psParallelCompact.cpp 2018-09-27 13:06:43.465427570 -0400 +++ new/src/hotspot/share/gc/parallel/psParallelCompact.cpp 2018-09-27 13:06:43.209427559 -0400 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "aot/aotLoader.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/javaClasses.inline.hpp" #include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" --- old/src/hotspot/share/gc/parallel/psTasks.cpp 2018-09-27 13:06:43.881427587 -0400 +++ new/src/hotspot/share/gc/parallel/psTasks.cpp 2018-09-27 13:06:43.613427576 -0400 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "aot/aotLoader.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" #include "gc/parallel/gcTaskManager.hpp" --- old/src/hotspot/share/gc/serial/genMarkSweep.cpp 2018-09-27 13:06:44.237427602 -0400 +++ new/src/hotspot/share/gc/serial/genMarkSweep.cpp 2018-09-27 13:06:43.981427591 -0400 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/javaClasses.hpp" #include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" --- old/src/hotspot/share/gc/shared/cardTableRS.cpp 2018-09-27 13:06:44.581427616 -0400 +++ new/src/hotspot/share/gc/shared/cardTableRS.cpp 2018-09-27 13:06:44.337427606 -0400 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "gc/shared/cardTableRS.hpp" #include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/genOopClosures.hpp" --- old/src/hotspot/share/gc/shared/genCollectedHeap.cpp 2018-09-27 13:06:44.937427631 -0400 +++ new/src/hotspot/share/gc/shared/genCollectedHeap.cpp 2018-09-27 13:06:44.681427620 -0400 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "aot/aotLoader.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/symbolTable.hpp" #include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" --- old/src/hotspot/share/gc/shared/parallelCleaning.hpp 2018-09-27 13:06:45.333427648 -0400 +++ new/src/hotspot/share/gc/shared/parallelCleaning.hpp 2018-09-27 13:06:45.057427636 -0400 @@ -25,6 +25,7 @@ #ifndef SHARE_VM_GC_SHARED_PARALLELCLEANING_HPP #define SHARE_VM_GC_SHARED_PARALLELCLEANING_HPP +#include "classfile/classLoaderDataGraph.inline.hpp" #include "gc/shared/oopStorageParState.hpp" #include "gc/shared/stringdedup/stringDedup.hpp" #include "gc/shared/workgroup.hpp" --- old/src/hotspot/share/gc/z/zRootsIterator.cpp 2018-09-27 13:06:45.697427663 -0400 +++ new/src/hotspot/share/gc/z/zRootsIterator.cpp 2018-09-27 13:06:45.433427652 -0400 @@ -22,7 +22,7 @@ */ #include "precompiled.hpp" -#include "classfile/classLoaderData.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" --- old/src/hotspot/share/jfr/leakprofiler/chains/rootSetClosure.cpp 2018-09-27 13:06:46.061427678 -0400 +++ new/src/hotspot/share/jfr/leakprofiler/chains/rootSetClosure.cpp 2018-09-27 13:06:45.797427667 -0400 @@ -24,7 +24,7 @@ #include "precompiled.hpp" #include "aot/aotLoader.hpp" -#include "classfile/classLoaderData.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" #include "gc/shared/strongRootsScope.hpp" --- old/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp 2018-09-27 13:06:46.421427693 -0400 +++ new/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp 2018-09-27 13:06:46.161427682 -0400 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "aot/aotLoader.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/stringTable.hpp" #include "gc/shared/strongRootsScope.hpp" #include "jfr/leakprofiler/utilities/unifiedOop.hpp" --- old/src/hotspot/share/jfr/leakprofiler/utilities/saveRestore.cpp 2018-09-27 13:06:46.781427708 -0400 +++ new/src/hotspot/share/jfr/leakprofiler/utilities/saveRestore.cpp 2018-09-27 13:06:46.525427697 -0400 @@ -23,7 +23,7 @@ */ #include "precompiled.hpp" -#include "classfile/classLoaderData.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "jfr/leakprofiler/utilities/saveRestore.hpp" #include "oops/oop.inline.hpp" --- old/src/hotspot/share/jfr/periodic/jfrModuleEvent.cpp 2018-09-27 13:06:47.137427723 -0400 +++ new/src/hotspot/share/jfr/periodic/jfrModuleEvent.cpp 2018-09-27 13:06:46.881427712 -0400 @@ -23,7 +23,8 @@ */ #include "precompiled.hpp" -#include "classfile/classLoaderData.hpp" +#include "classfile/classLoaderData.inline.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/moduleEntry.hpp" #include "classfile/packageEntry.hpp" #include "jfr/jfrEvents.hpp" --- old/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp 2018-09-27 13:06:47.501427738 -0400 +++ new/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp 2018-09-27 13:06:47.237427727 -0400 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "jvm.h" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/classLoaderStats.hpp" #include "classfile/javaClasses.hpp" #include "code/codeCache.hpp" --- old/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp 2018-09-27 13:06:47.853427753 -0400 +++ new/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp 2018-09-27 13:06:47.597427742 -0400 @@ -23,7 +23,7 @@ */ #include "precompiled.hpp" -#include "classfile/classLoaderData.inline.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/javaClasses.inline.hpp" #include "classfile/moduleEntry.hpp" #include "classfile/packageEntry.hpp" --- old/src/hotspot/share/memory/heapInspection.cpp 2018-09-27 13:06:48.213427768 -0400 +++ new/src/hotspot/share/memory/heapInspection.cpp 2018-09-27 13:06:47.957427757 -0400 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/classLoaderData.inline.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/moduleEntry.hpp" #include "classfile/systemDictionary.hpp" #include "gc/shared/collectedHeap.hpp" --- old/src/hotspot/share/memory/metaspace.cpp 2018-09-27 13:06:48.537427781 -0400 +++ new/src/hotspot/share/memory/metaspace.cpp 2018-09-27 13:06:48.301427772 -0400 @@ -23,8 +23,8 @@ */ #include "precompiled.hpp" - #include "aot/aotLoader.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "gc/shared/collectedHeap.hpp" #include "logging/log.hpp" #include "logging/logStream.hpp" --- old/src/hotspot/share/memory/metaspaceShared.cpp 2018-09-27 13:06:48.909427797 -0400 +++ new/src/hotspot/share/memory/metaspaceShared.cpp 2018-09-27 13:06:48.641427786 -0400 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "jvm.h" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/classListParser.hpp" #include "classfile/classLoaderExt.hpp" #include "classfile/dictionary.hpp" --- old/src/hotspot/share/memory/universe.cpp 2018-09-27 13:06:49.301427813 -0400 +++ new/src/hotspot/share/memory/universe.cpp 2018-09-27 13:06:49.041427802 -0400 @@ -25,7 +25,7 @@ #include "precompiled.hpp" #include "aot/aotLoader.hpp" #include "classfile/classLoader.hpp" -#include "classfile/classLoaderData.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/javaClasses.hpp" #include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" --- old/src/hotspot/share/oops/klassVtable.cpp 2018-09-27 13:06:49.685427829 -0400 +++ new/src/hotspot/share/oops/klassVtable.cpp 2018-09-27 13:06:49.417427818 -0400 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "jvm.h" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/javaClasses.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" --- old/src/hotspot/share/oops/method.cpp 2018-09-27 13:06:50.073427845 -0400 +++ new/src/hotspot/share/oops/method.cpp 2018-09-27 13:06:49.805427834 -0400 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/metadataOnStackMark.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" --- old/src/hotspot/share/prims/jvmtiEnvBase.cpp 2018-09-27 13:06:50.469427862 -0400 +++ new/src/hotspot/share/prims/jvmtiEnvBase.cpp 2018-09-27 13:06:50.209427851 -0400 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/systemDictionary.hpp" #include "jvmtifiles/jvmtiEnv.hpp" #include "memory/resourceArea.hpp" --- old/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp 2018-09-27 13:06:50.853427878 -0400 +++ new/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp 2018-09-27 13:06:50.585427867 -0400 @@ -23,8 +23,8 @@ */ #include "precompiled.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/dictionary.hpp" -#include "classfile/classLoaderData.inline.hpp" #include "classfile/systemDictionary.hpp" #include "gc/shared/collectedHeap.hpp" #include "memory/universe.hpp" --- old/src/hotspot/share/prims/jvmtiRedefineClasses.cpp 2018-09-27 13:06:51.213427893 -0400 +++ new/src/hotspot/share/prims/jvmtiRedefineClasses.cpp 2018-09-27 13:06:50.953427882 -0400 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "aot/aotLoader.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/classFileStream.hpp" #include "classfile/metadataOnStackMark.hpp" #include "classfile/systemDictionary.hpp" --- old/src/hotspot/share/prims/jvmtiTagMap.cpp 2018-09-27 13:06:51.649427911 -0400 +++ new/src/hotspot/share/prims/jvmtiTagMap.cpp 2018-09-27 13:06:51.381427900 -0400 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/javaClasses.inline.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" --- old/src/hotspot/share/prims/whitebox.cpp 2018-09-27 13:06:52.057427928 -0400 +++ new/src/hotspot/share/prims/whitebox.cpp 2018-09-27 13:06:51.785427917 -0400 @@ -26,7 +26,7 @@ #include -#include "classfile/classLoaderData.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/modules.hpp" #include "classfile/protectionDomainCache.hpp" #include "classfile/stringTable.hpp" --- old/src/hotspot/share/runtime/biasedLocking.cpp 2018-09-27 13:06:52.457427945 -0400 +++ new/src/hotspot/share/runtime/biasedLocking.cpp 2018-09-27 13:06:52.189427934 -0400 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "jfr/jfrEvents.hpp" #include "jfr/support/jfrThreadId.hpp" #include "logging/log.hpp" --- old/src/hotspot/share/runtime/compilationPolicy.cpp 2018-09-27 13:06:52.833427961 -0400 +++ new/src/hotspot/share/runtime/compilationPolicy.cpp 2018-09-27 13:06:52.569427950 -0400 @@ -23,7 +23,7 @@ */ #include "precompiled.hpp" -#include "classfile/classLoaderData.inline.hpp" +#include "classfile/classLoaderDataGraph.inline.hpp" #include "code/compiledIC.hpp" #include "code/nmethod.hpp" #include "code/scopeDesc.hpp" --- old/src/hotspot/share/runtime/java.cpp 2018-09-27 13:06:53.205427976 -0400 +++ new/src/hotspot/share/runtime/java.cpp 2018-09-27 13:06:52.941427965 -0400 @@ -26,6 +26,7 @@ #include "jvm.h" #include "aot/aotLoader.hpp" #include "classfile/classLoader.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" --- old/src/hotspot/share/runtime/memprofiler.cpp 2018-09-27 13:06:53.573427992 -0400 +++ new/src/hotspot/share/runtime/memprofiler.cpp 2018-09-27 13:06:53.309427981 -0400 @@ -23,7 +23,7 @@ */ #include "precompiled.hpp" -#include "classfile/classLoaderData.inline.hpp" +#include "classfile/classLoaderDataGraph.inline.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" #include "gc/shared/collectedHeap.inline.hpp" --- old/src/hotspot/share/runtime/safepoint.cpp 2018-09-27 13:06:53.937428007 -0400 +++ new/src/hotspot/share/runtime/safepoint.cpp 2018-09-27 13:06:53.677427996 -0400 @@ -23,7 +23,7 @@ */ #include "precompiled.hpp" -#include "classfile/classLoaderData.inline.hpp" +#include "classfile/classLoaderDataGraph.inline.hpp" #include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" --- old/src/hotspot/share/runtime/vmStructs.cpp 2018-09-27 13:06:54.321428023 -0400 +++ new/src/hotspot/share/runtime/vmStructs.cpp 2018-09-27 13:06:54.053428012 -0400 @@ -29,6 +29,7 @@ #include "ci/ciObjArrayKlass.hpp" #include "ci/ciSymbol.hpp" #include "classfile/compactHashtable.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/dictionary.hpp" #include "classfile/javaClasses.hpp" #include "classfile/stringTable.hpp" --- old/src/hotspot/share/services/heapDumper.cpp 2018-09-27 13:06:54.749428041 -0400 +++ new/src/hotspot/share/services/heapDumper.cpp 2018-09-27 13:06:54.481428029 -0400 @@ -24,6 +24,8 @@ #include "precompiled.hpp" #include "jvm.h" +#include "classfile/classLoaderData.inline.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" --- old/src/hotspot/share/services/memBaseline.cpp 2018-09-27 13:06:55.137428057 -0400 +++ new/src/hotspot/share/services/memBaseline.cpp 2018-09-27 13:06:54.881428046 -0400 @@ -23,7 +23,7 @@ */ #include "precompiled.hpp" -#include "classfile/classLoaderData.inline.hpp" +#include "classfile/classLoaderDataGraph.inline.hpp" #include "memory/allocation.hpp" #include "runtime/safepoint.hpp" #include "runtime/thread.inline.hpp" --- /dev/null 2018-09-21 07:49:39.980007338 -0400 +++ new/src/hotspot/share/classfile/classLoaderDataGraph.cpp 2018-09-27 13:06:55.245428061 -0400 @@ -0,0 +1,688 @@ +/* + * 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/classLoaderDataGraph.inline.hpp" +#include "classfile/dictionary.hpp" +#include "classfile/javaClasses.hpp" +#include "classfile/metadataOnStackMark.hpp" +#include "classfile/moduleEntry.hpp" +#include "classfile/packageEntry.hpp" +#include "classfile/symbolTable.hpp" +#include "classfile/systemDictionary.hpp" +#include "logging/log.hpp" +#include "logging/logStream.hpp" +#include "memory/allocation.inline.hpp" +#include "memory/metaspaceShared.hpp" +#include "memory/resourceArea.hpp" +#include "runtime/atomic.hpp" +#include "runtime/handles.inline.hpp" +#include "runtime/mutex.hpp" +#include "runtime/safepoint.hpp" +#include "runtime/safepointVerifiers.hpp" +#include "utilities/growableArray.hpp" +#include "utilities/macros.hpp" +#include "utilities/ostream.hpp" + +volatile size_t ClassLoaderDataGraph::_num_array_classes = 0; +volatile size_t ClassLoaderDataGraph::_num_instance_classes = 0; + +void ClassLoaderDataGraph::clear_claimed_marks() { + for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { + cld->clear_claimed(); + } +} + +// Class iterator used by the compiler. It gets some number of classes at +// a safepoint to decay invocation counters on the methods. +class ClassLoaderDataGraphKlassIteratorStatic { + ClassLoaderData* _current_loader_data; + Klass* _current_class_entry; + public: + + ClassLoaderDataGraphKlassIteratorStatic() : _current_loader_data(NULL), _current_class_entry(NULL) {} + + InstanceKlass* try_get_next_class() { + assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint"); + size_t max_classes = ClassLoaderDataGraph::num_instance_classes(); + assert(max_classes > 0, "should not be called with no instance classes"); + for (size_t i = 0; i < max_classes; ) { + + if (_current_class_entry != NULL) { + Klass* k = _current_class_entry; + _current_class_entry = _current_class_entry->next_link(); + + if (k->is_instance_klass()) { + InstanceKlass* ik = InstanceKlass::cast(k); + i++; // count all instance classes found + // Not yet loaded classes are counted in max_classes + // but only return loaded classes. + if (ik->is_loaded()) { + return ik; + } + } + } else { + // Go to next CLD + if (_current_loader_data != NULL) { + _current_loader_data = _current_loader_data->next(); + } + // Start at the beginning + if (_current_loader_data == NULL) { + _current_loader_data = ClassLoaderDataGraph::_head; + } + + _current_class_entry = _current_loader_data->klasses(); + } + } + // Should never be reached unless all instance classes have failed or are not fully loaded. + // Caller handles NULL. + return NULL; + } + + // If the current class for the static iterator is a class being unloaded or + // deallocated, adjust the current class. + void adjust_saved_class(ClassLoaderData* cld) { + if (_current_loader_data == cld) { + _current_loader_data = cld->next(); + if (_current_loader_data != NULL) { + _current_class_entry = _current_loader_data->klasses(); + } // else try_get_next_class will start at the head + } + } + + void adjust_saved_class(Klass* klass) { + if (_current_class_entry == klass) { + _current_class_entry = klass->next_link(); + } + } +}; + +static ClassLoaderDataGraphKlassIteratorStatic static_klass_iterator; + +InstanceKlass* ClassLoaderDataGraph::try_get_next_class() { + assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint"); + return static_klass_iterator.try_get_next_class(); +} + +void ClassLoaderDataGraph::adjust_saved_class(ClassLoaderData* cld) { + return static_klass_iterator.adjust_saved_class(cld); +} + +void ClassLoaderDataGraph::adjust_saved_class(Klass* klass) { + return static_klass_iterator.adjust_saved_class(klass); +} + +void ClassLoaderDataGraph::clean_deallocate_lists(bool walk_previous_versions) { + assert(SafepointSynchronize::is_at_safepoint(), "must only be called at safepoint"); + uint loaders_processed = 0; + for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { + // is_alive check will be necessary for concurrent class unloading. + if (cld->is_alive()) { + // clean metaspace + if (walk_previous_versions) { + cld->classes_do(InstanceKlass::purge_previous_versions); + } + cld->free_deallocate_list(); + loaders_processed++; + } + } + log_debug(class, loader, data)("clean_deallocate_lists: loaders processed %u %s", + loaders_processed, walk_previous_versions ? "walk_previous_versions" : ""); +} + +void ClassLoaderDataGraph::walk_metadata_and_clean_metaspaces() { + assert(SafepointSynchronize::is_at_safepoint(), "must only be called at safepoint"); + + _should_clean_deallocate_lists = false; // assume everything gets cleaned + + // Mark metadata seen on the stack so we can delete unreferenced entries. + // Walk all metadata, including the expensive code cache walk, only for class redefinition. + // The MetadataOnStackMark walk during redefinition saves previous versions if it finds old methods + // on the stack or in the code cache, so we only have to repeat the full walk if + // they were found at that time. + // TODO: have redefinition clean old methods out of the code cache. They still exist in some places. + bool walk_all_metadata = InstanceKlass::has_previous_versions_and_reset(); + + MetadataOnStackMark md_on_stack(walk_all_metadata); + clean_deallocate_lists(walk_all_metadata); +} + +// GC root of class loader data created. +ClassLoaderData* ClassLoaderDataGraph::_head = NULL; +ClassLoaderData* ClassLoaderDataGraph::_unloading = NULL; +ClassLoaderData* ClassLoaderDataGraph::_saved_unloading = NULL; +ClassLoaderData* ClassLoaderDataGraph::_saved_head = NULL; + +bool ClassLoaderDataGraph::_should_purge = false; +bool ClassLoaderDataGraph::_should_clean_deallocate_lists = false; +bool ClassLoaderDataGraph::_safepoint_cleanup_needed = false; +bool ClassLoaderDataGraph::_metaspace_oom = false; + +// Add a new class loader data node to the list. Assign the newly created +// ClassLoaderData into the java/lang/ClassLoader object as a hidden field +ClassLoaderData* ClassLoaderDataGraph::add_to_graph(Handle loader, bool is_unsafe_anonymous) { + + assert_lock_strong(ClassLoaderDataGraph_lock); + + ClassLoaderData* cld; + + // First check if another thread beat us to creating the CLD and installing + // it into the loader while we were waiting for the lock. + if (!is_unsafe_anonymous && loader.not_null()) { + cld = java_lang_ClassLoader::loader_data_acquire(loader()); + if (cld != NULL) { + return cld; + } + } + + // We mustn't GC until we've installed the ClassLoaderData in the Graph since the CLD + // contains oops in _handles that must be walked. GC doesn't walk CLD from the + // loader oop in all collections, particularly young collections. + NoSafepointVerifier no_safepoints; + + cld = new ClassLoaderData(loader, is_unsafe_anonymous); + + // First install the new CLD to the Graph. + cld->set_next(_head); + _head = cld; + + // Next associate with the class_loader. + if (!is_unsafe_anonymous) { + // Use OrderAccess, since readers need to get the loader_data only after + // it's added to the Graph + java_lang_ClassLoader::release_set_loader_data(loader(), cld); + } + + // Lastly log, if requested + LogTarget(Trace, class, loader, data) lt; + if (lt.is_enabled()) { + ResourceMark rm; + LogStream ls(lt); + ls.print("create "); + cld->print_value_on(&ls); + ls.cr(); + } + return cld; +} + +ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool is_unsafe_anonymous) { + MutexLocker ml(ClassLoaderDataGraph_lock); + ClassLoaderData* loader_data = add_to_graph(loader, is_unsafe_anonymous); + return loader_data; +} + +void ClassLoaderDataGraph::cld_do(CLDClosure* cl) { + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->_next) { + cl->do_cld(cld); + } +} + +void ClassLoaderDataGraph::cld_unloading_do(CLDClosure* cl) { + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + // Only walk the head until any clds not purged from prior unloading + // (CMS doesn't purge right away). + for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) { + assert(cld->is_unloading(), "invariant"); + cl->do_cld(cld); + } +} + +void ClassLoaderDataGraph::roots_cld_do(CLDClosure* strong, CLDClosure* weak) { + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->_next) { + CLDClosure* closure = cld->keep_alive() ? strong : weak; + if (closure != NULL) { + closure->do_cld(cld); + } + } +} + +void ClassLoaderDataGraph::always_strong_cld_do(CLDClosure* cl) { + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + if (ClassUnloading) { + roots_cld_do(cl, NULL); + } else { + cld_do(cl); + } +} + +// Closure for locking and iterating through classes. +LockedClassesDo::LockedClassesDo(classes_do_func_t f) : _function(f) { + ClassLoaderDataGraph_lock->lock(); +} + +LockedClassesDo::LockedClassesDo() : _function(NULL) { + // callers provide their own do_klass + ClassLoaderDataGraph_lock->lock(); +} + +LockedClassesDo::~LockedClassesDo() { ClassLoaderDataGraph_lock->unlock(); } + + +// Iterating over the CLDG needs to be locked because +// unloading can remove entries concurrently soon. +class ClassLoaderDataGraphIterator : public StackObj { + ClassLoaderData* _next; + HandleMark _hm; // clean up handles when this is done. + Handle _holder; + Thread* _thread; + + void hold_next() { + if (_next != NULL) { + _holder = Handle(_thread, _next->holder_phantom()); + } + } +public: + ClassLoaderDataGraphIterator() : _next(ClassLoaderDataGraph::_head) { + _thread = Thread::current(); + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + hold_next(); + } + + bool repeat() const { + return _next != NULL; + } + + ClassLoaderData* get_next() { + ClassLoaderData* next = _next; + if (_next != NULL) { + _next = _next->next(); + hold_next(); + } + return next; + } +}; + +// 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) { + ClassLoaderDataGraphIterator iter; + while (iter.repeat()) { + ClassLoaderData* cld = iter.get_next(); + cld->classes_do(klass_closure); + } +} + +void ClassLoaderDataGraph::classes_do(void f(Klass* const)) { + ClassLoaderDataGraphIterator iter; + while (iter.repeat()) { + ClassLoaderData* cld = iter.get_next(); + cld->classes_do(f); + } +} + +void ClassLoaderDataGraph::methods_do(void f(Method*)) { + ClassLoaderDataGraphIterator iter; + while (iter.repeat()) { + ClassLoaderData* cld = iter.get_next(); + cld->methods_do(f); + } +} + +void ClassLoaderDataGraph::modules_do(void f(ModuleEntry*)) { + assert_locked_or_safepoint(Module_lock); + ClassLoaderDataGraphIterator iter; + while (iter.repeat()) { + ClassLoaderData* cld = iter.get_next(); + cld->modules_do(f); + } +} + +void ClassLoaderDataGraph::modules_unloading_do(void f(ModuleEntry*)) { + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + // Only walk the head until any clds not purged from prior unloading + // (CMS doesn't purge right away). + for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) { + assert(cld->is_unloading(), "invariant"); + cld->modules_do(f); + } +} + +void ClassLoaderDataGraph::packages_do(void f(PackageEntry*)) { + assert_locked_or_safepoint(Module_lock); + ClassLoaderDataGraphIterator iter; + while (iter.repeat()) { + ClassLoaderData* cld = iter.get_next(); + cld->packages_do(f); + } +} + +void ClassLoaderDataGraph::packages_unloading_do(void f(PackageEntry*)) { + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + // Only walk the head until any clds not purged from prior unloading + // (CMS doesn't purge right away). + for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) { + assert(cld->is_unloading(), "invariant"); + cld->packages_do(f); + } +} + +void ClassLoaderDataGraph::loaded_classes_do(KlassClosure* klass_closure) { + ClassLoaderDataGraphIterator iter; + while (iter.repeat()) { + ClassLoaderData* cld = iter.get_next(); + cld->loaded_classes_do(klass_closure); + } +} + +// This case can block but cannot do unloading (called from CDS) +void ClassLoaderDataGraph::unlocked_loaded_classes_do(KlassClosure* klass_closure) { + for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { + cld->loaded_classes_do(klass_closure); + } +} + + +void ClassLoaderDataGraph::classes_unloading_do(void f(Klass* const)) { + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + // Only walk the head until any clds not purged from prior unloading + // (CMS doesn't purge right away). + for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) { + assert(cld->is_unloading(), "invariant"); + cld->classes_do(f); + } +} + +#define FOR_ALL_DICTIONARY(X) ClassLoaderDataGraphIterator iter; \ + ClassLoaderData* X; \ + while ((X = iter.get_next()) != NULL) \ + if (X->dictionary() != NULL) + +// Walk classes in the loaded class dictionaries in various forms. +// Only walks the classes defined in this class loader. +void ClassLoaderDataGraph::dictionary_classes_do(void f(InstanceKlass*)) { + FOR_ALL_DICTIONARY(cld) { + cld->dictionary()->classes_do(f); + } +} + +// Only walks the classes defined in this class loader. +void ClassLoaderDataGraph::dictionary_classes_do(void f(InstanceKlass*, TRAPS), TRAPS) { + FOR_ALL_DICTIONARY(cld) { + cld->dictionary()->classes_do(f, CHECK); + } +} + +void ClassLoaderDataGraph::verify_dictionary() { + FOR_ALL_DICTIONARY(cld) { + cld->dictionary()->verify(); + } +} + +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(); + } +} + +void ClassLoaderDataGraph::print_dictionary_statistics(outputStream* st) { + FOR_ALL_DICTIONARY(cld) { + ResourceMark rm; + stringStream tempst; + tempst.print("System Dictionary for %s class loader", cld->loader_name_and_id()); + cld->dictionary()->print_table_statistics(st, tempst.as_string()); + } +} + +GrowableArray* ClassLoaderDataGraph::new_clds() { + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + assert(_head == NULL || _saved_head != NULL, "remember_new_clds(true) not called?"); + + GrowableArray* array = new GrowableArray(); + + // The CLDs in [_head, _saved_head] were all added during last call to remember_new_clds(true); + ClassLoaderData* curr = _head; + while (curr != _saved_head) { + if (!curr->claimed()) { + array->push(curr); + LogTarget(Debug, class, loader, data) lt; + if (lt.is_enabled()) { + LogStream ls(lt); + ls.print("found new CLD: "); + curr->print_value_on(&ls); + ls.cr(); + } + } + + curr = curr->_next; + } + + return array; +} + +#ifndef PRODUCT +bool ClassLoaderDataGraph::contains_loader_data(ClassLoaderData* loader_data) { + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + for (ClassLoaderData* data = _head; data != NULL; data = data->next()) { + if (loader_data == data) { + return true; + } + } + + return false; +} +#endif // PRODUCT + +// Move class loader data from main list to the unloaded list for unloading +// and deallocation later. +bool ClassLoaderDataGraph::do_unloading(bool do_cleaning) { + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + + // Indicate whether safepoint cleanup is needed. + _safepoint_cleanup_needed |= do_cleaning; + + ClassLoaderData* data = _head; + ClassLoaderData* prev = NULL; + bool seen_dead_loader = false; + uint loaders_processed = 0; + uint loaders_removed = 0; + + // Save previous _unloading pointer for CMS which may add to unloading list before + // purging and we don't want to rewalk the previously unloaded class loader data. + _saved_unloading = _unloading; + + data = _head; + while (data != NULL) { + if (data->is_alive()) { + prev = data; + data = data->next(); + loaders_processed++; + continue; + } + seen_dead_loader = true; + loaders_removed++; + ClassLoaderData* dead = data; + dead->unload(); + data = data->next(); + // Remove from loader list. + // This class loader data will no longer be found + // in the ClassLoaderDataGraph. + if (prev != NULL) { + prev->set_next(data); + } else { + assert(dead == _head, "sanity check"); + _head = data; + } + dead->set_next(_unloading); + _unloading = dead; + } + + log_debug(class, loader, data)("do_unloading: loaders processed %u, loaders removed %u", loaders_processed, loaders_removed); + + return seen_dead_loader; +} + +// There's at least one dead class loader. Purge refererences of healthy module +// reads lists and package export lists to modules belonging to dead loaders. +void ClassLoaderDataGraph::clean_module_and_package_info() { + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + + ClassLoaderData* data = _head; + while (data != NULL) { + // Remove entries in the dictionary of live class loader that have + // initiated loading classes in a dead class loader. + if (data->dictionary() != NULL) { + data->dictionary()->do_unloading(); + } + // Walk a ModuleEntry's reads, and a PackageEntry's exports + // lists to determine if there are modules on those lists that are now + // dead and should be removed. A module's life cycle is equivalent + // to its defining class loader's life cycle. Since a module is + // considered dead if its class loader is dead, these walks must + // occur after each class loader's aliveness is determined. + if (data->packages() != NULL) { + data->packages()->purge_all_package_exports(); + } + if (data->modules_defined()) { + data->modules()->purge_all_module_reads(); + } + data = data->next(); + } +} + +void ClassLoaderDataGraph::purge() { + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!"); + ClassLoaderData* list = _unloading; + _unloading = NULL; + ClassLoaderData* next = list; + bool classes_unloaded = false; + while (next != NULL) { + ClassLoaderData* purge_me = next; + next = purge_me->next(); + delete purge_me; + classes_unloaded = true; + } + if (classes_unloaded) { + Metaspace::purge(); + set_metaspace_oom(false); + } +} + +int ClassLoaderDataGraph::resize_if_needed() { + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!"); + int resized = 0; + if (Dictionary::does_any_dictionary_needs_resizing()) { + FOR_ALL_DICTIONARY(cld) { + if (cld->dictionary()->resize_if_needed()) { + resized++; + } + } + } + return resized; +} + +ClassLoaderDataGraphKlassIteratorAtomic::ClassLoaderDataGraphKlassIteratorAtomic() + : _next_klass(NULL) { + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!"); + ClassLoaderData* cld = ClassLoaderDataGraph::_head; + Klass* klass = NULL; + + // Find the first klass in the CLDG. + while (cld != NULL) { + assert_locked_or_safepoint(cld->metaspace_lock()); + klass = cld->_klasses; + if (klass != NULL) { + _next_klass = klass; + return; + } + cld = cld->next(); + } +} + +Klass* ClassLoaderDataGraphKlassIteratorAtomic::next_klass_in_cldg(Klass* klass) { + Klass* next = klass->next_link(); + if (next != NULL) { + return next; + } + + // No more klasses in the current CLD. Time to find a new CLD. + ClassLoaderData* cld = klass->class_loader_data(); + assert_locked_or_safepoint(cld->metaspace_lock()); + while (next == NULL) { + cld = cld->next(); + if (cld == NULL) { + break; + } + next = cld->_klasses; + } + + return next; +} + +Klass* ClassLoaderDataGraphKlassIteratorAtomic::next_klass() { + Klass* head = _next_klass; + + while (head != NULL) { + Klass* next = next_klass_in_cldg(head); + + Klass* old_head = Atomic::cmpxchg(next, &_next_klass, head); + + if (old_head == head) { + return head; // Won the CAS. + } + + head = old_head; + } + + // Nothing more for the iterator to hand out. + assert(head == NULL, "head is " PTR_FORMAT ", expected not null:", p2i(head)); + return NULL; +} + +ClassLoaderDataGraphMetaspaceIterator::ClassLoaderDataGraphMetaspaceIterator() { + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!"); + _data = ClassLoaderDataGraph::_head; +} + +ClassLoaderDataGraphMetaspaceIterator::~ClassLoaderDataGraphMetaspaceIterator() {} + +#ifndef PRODUCT +// callable from debugger +extern "C" int print_loader_data_graph() { + ResourceMark rm; + ClassLoaderDataGraph::print_on(tty); + return 0; +} + +void ClassLoaderDataGraph::verify() { + ClassLoaderDataGraphIterator iter; + while (iter.repeat()) { + ClassLoaderData* cld = iter.get_next(); + cld->verify(); + } +} + +void ClassLoaderDataGraph::print_on(outputStream * const out) { + ClassLoaderDataGraphIterator iter; + while (iter.repeat()) { + ClassLoaderData* cld = iter.get_next(); + cld->print_on(out); + } +} +#endif // PRODUCT --- /dev/null 2018-09-21 07:49:39.980007338 -0400 +++ new/src/hotspot/share/classfile/classLoaderDataGraph.hpp 2018-09-27 13:06:55.629428077 -0400 @@ -0,0 +1,193 @@ +/* + * 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_CLASSFILE_CLASSLOADERDATAGRAPH_HPP +#define SHARE_VM_CLASSFILE_CLASSLOADERDATAGRAPH_HPP + +#include "classfile/classLoaderData.hpp" +#include "memory/allocation.hpp" +#include "memory/memRegion.hpp" +#include "memory/metaspace.hpp" +#include "utilities/growableArray.hpp" +#include "utilities/macros.hpp" + +// GC root for walking class loader data created + +class ClassLoaderDataGraph : public AllStatic { + friend class ClassLoaderData; + friend class ClassLoaderDataGraphMetaspaceIterator; + friend class ClassLoaderDataGraphKlassIteratorAtomic; + friend class ClassLoaderDataGraphKlassIteratorStatic; + friend class ClassLoaderDataGraphIterator; + friend class VMStructs; + private: + // All CLDs (except the null CLD) can be reached by walking _head->_next->... + static ClassLoaderData* _head; + static ClassLoaderData* _unloading; + // CMS support. + static ClassLoaderData* _saved_head; + static ClassLoaderData* _saved_unloading; + static bool _should_purge; + + // Set if there's anything to purge in the deallocate lists or previous versions + // during a safepoint after class unloading in a full GC. + static bool _should_clean_deallocate_lists; + static bool _safepoint_cleanup_needed; + + // OOM has been seen in metaspace allocation. Used to prevent some + // allocations until class unloading + static bool _metaspace_oom; + + static volatile size_t _num_instance_classes; + static volatile size_t _num_array_classes; + + static ClassLoaderData* add_to_graph(Handle class_loader, bool is_unsafe_anonymous); + static ClassLoaderData* add(Handle class_loader, bool is_unsafe_anonymous); + + public: + static ClassLoaderData* find_or_create(Handle class_loader); + static void clean_module_and_package_info(); + static void purge(); + static void clear_claimed_marks(); + // Iteration through CLDG inside a safepoint; GC support + static void cld_do(CLDClosure* cl); + static void cld_unloading_do(CLDClosure* cl); + static void roots_cld_do(CLDClosure* strong, CLDClosure* weak); + static void always_strong_cld_do(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 + // for redefinition. These classes are removed during the next class unloading. + // Walking the ClassLoaderDataGraph also includes unsafe anonymous classes. + 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(void f(ModuleEntry*)); + static void modules_unloading_do(void f(ModuleEntry*)); + static void packages_do(void f(PackageEntry*)); + static void packages_unloading_do(void f(PackageEntry*)); + static void loaded_classes_do(KlassClosure* klass_closure); + static void unlocked_loaded_classes_do(KlassClosure* klass_closure); + static void classes_unloading_do(void f(Klass* const)); + static bool do_unloading(bool do_cleaning); + + // Expose state to avoid logging overhead in safepoint cleanup tasks. + static inline bool should_clean_metaspaces_and_reset(); + static void set_should_clean_deallocate_lists() { _should_clean_deallocate_lists = true; } + static void clean_deallocate_lists(bool purge_previous_versions); + static void walk_metadata_and_clean_metaspaces(); + + // dictionary do + // Iterate over all klasses in dictionary, but + // just the classes from defining class loaders. + static void dictionary_classes_do(void f(InstanceKlass*)); + // Added for initialize_itable_for_klass to handle exceptions. + static void dictionary_classes_do(void f(InstanceKlass*, TRAPS), TRAPS); + + // VM_CounterDecay iteration support + static InstanceKlass* try_get_next_class(); + static void adjust_saved_class(ClassLoaderData* cld); + static void adjust_saved_class(Klass* klass); + + static void verify_dictionary(); + static void print_dictionary(outputStream* st); + static void print_dictionary_statistics(outputStream* st); + + // CMS support. + static void remember_new_clds(bool remember) { _saved_head = (remember ? _head : NULL); } + static GrowableArray* new_clds(); + + static void set_should_purge(bool b) { _should_purge = b; } + static void purge_if_needed() { + // Only purge the CLDG for CMS if concurrent sweep is complete. + if (_should_purge) { + purge(); + // reset for next time. + set_should_purge(false); + } + } + + static int resize_if_needed(); + + static bool has_metaspace_oom() { return _metaspace_oom; } + static void set_metaspace_oom(bool value) { _metaspace_oom = value; } + + static void print_on(outputStream * const out) PRODUCT_RETURN; + static void print() { print_on(tty); } + static void verify(); + + // instance and array class counters + static inline size_t num_instance_classes(); + static inline size_t num_array_classes(); + static inline void inc_instance_classes(size_t count); + static inline void dec_instance_classes(size_t count); + static inline void inc_array_classes(size_t count); + static inline void dec_array_classes(size_t count); + +#ifndef PRODUCT + static bool contains_loader_data(ClassLoaderData* loader_data); +#endif +}; + +class LockedClassesDo : public KlassClosure { + typedef void (*classes_do_func_t)(Klass*); + classes_do_func_t _function; +public: + LockedClassesDo(); // For callers who provide their own do_klass + LockedClassesDo(classes_do_func_t function); + ~LockedClassesDo(); + + void do_klass(Klass* k) { + (*_function)(k); + } +}; + +// An iterator that distributes Klasses to parallel worker threads. +class ClassLoaderDataGraphKlassIteratorAtomic : public StackObj { + Klass* volatile _next_klass; + public: + ClassLoaderDataGraphKlassIteratorAtomic(); + Klass* next_klass(); + private: + static Klass* next_klass_in_cldg(Klass* klass); +}; + +class ClassLoaderDataGraphMetaspaceIterator : public StackObj { + ClassLoaderData* _data; + public: + ClassLoaderDataGraphMetaspaceIterator(); + ~ClassLoaderDataGraphMetaspaceIterator(); + bool repeat() { return _data != NULL; } + ClassLoaderMetaspace* get_next() { + assert(_data != NULL, "Should not be NULL in call to the iterator"); + ClassLoaderMetaspace* result = _data->metaspace_or_null(); + _data = _data->next(); + // This result might be NULL for class loaders without metaspace + // yet. It would be nice to return only non-null results but + // there is no guarantee that there will be a non-null result + // down the list so the caller is going to have to check. + return result; + } +}; +#endif // SHARE_VM_CLASSFILE_CLASSLOADERDATAGRAPH_HPP --- /dev/null 2018-09-21 07:49:39.980007338 -0400 +++ new/src/hotspot/share/classfile/classLoaderDataGraph.inline.hpp 2018-09-27 13:06:56.009428093 -0400 @@ -0,0 +1,82 @@ +/* + * 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_CLASSFILE_CLASSLOADERDATAGRAPH_INLINE_HPP +#define SHARE_VM_CLASSFILE_CLASSLOADERDATAGRAPH_INLINE_HPP + +#include "classfile/classLoaderDataGraph.hpp" +#include "classfile/javaClasses.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/atomic.hpp" + +inline ClassLoaderData *ClassLoaderDataGraph::find_or_create(Handle loader) { + guarantee(loader() != NULL && oopDesc::is_oop(loader()), "Loader must be oop"); + // Gets the class loader data out of the java/lang/ClassLoader object, if non-null + // it's already in the loader_data, so no need to add + ClassLoaderData* loader_data = java_lang_ClassLoader::loader_data_acquire(loader()); + if (loader_data) { + return loader_data; + } + return ClassLoaderDataGraph::add(loader, false); +} + +size_t ClassLoaderDataGraph::num_instance_classes() { + return _num_instance_classes; +} + +size_t ClassLoaderDataGraph::num_array_classes() { + return _num_array_classes; +} + +void ClassLoaderDataGraph::inc_instance_classes(size_t count) { + Atomic::add(count, &_num_instance_classes); +} + +void ClassLoaderDataGraph::dec_instance_classes(size_t count) { + assert(count <= _num_instance_classes, "Sanity"); + Atomic::sub(count, &_num_instance_classes); +} + +void ClassLoaderDataGraph::inc_array_classes(size_t count) { + Atomic::add(count, &_num_array_classes); +} + +void ClassLoaderDataGraph::dec_array_classes(size_t count) { + assert(count <= _num_array_classes, "Sanity"); + Atomic::sub(count, &_num_array_classes); +} + +bool ClassLoaderDataGraph::should_clean_metaspaces_and_reset() { + // Only clean metaspaces after full GC. + bool do_cleaning = _safepoint_cleanup_needed; +#if INCLUDE_JVMTI + do_cleaning = do_cleaning && (_should_clean_deallocate_lists || InstanceKlass::has_previous_versions()); +#else + do_cleaning = do_cleaning && _should_clean_deallocate_lists; +#endif + _safepoint_cleanup_needed = false; // reset + return do_cleaning; +} + +#endif // SHARE_VM_CLASSFILE_CLASSLOADERDATAGRAPH_INLINE_HPP