8209645: Split ClassLoaderData and ClassLoaderDataGraph into separate files
Reviewed-by: iklam, stuefe
This commit is contained in:
parent
3a0b2d59ad
commit
7ef28cb2bc
@ -47,11 +47,10 @@
|
|||||||
// the singleton class the_null_class_loader_data().
|
// the singleton class the_null_class_loader_data().
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "classfile/classLoaderData.hpp"
|
|
||||||
#include "classfile/classLoaderData.inline.hpp"
|
#include "classfile/classLoaderData.inline.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.inline.hpp"
|
||||||
#include "classfile/dictionary.hpp"
|
#include "classfile/dictionary.hpp"
|
||||||
#include "classfile/javaClasses.hpp"
|
#include "classfile/javaClasses.hpp"
|
||||||
#include "classfile/metadataOnStackMark.hpp"
|
|
||||||
#include "classfile/moduleEntry.hpp"
|
#include "classfile/moduleEntry.hpp"
|
||||||
#include "classfile/packageEntry.hpp"
|
#include "classfile/packageEntry.hpp"
|
||||||
#include "classfile/symbolTable.hpp"
|
#include "classfile/symbolTable.hpp"
|
||||||
@ -60,9 +59,7 @@
|
|||||||
#include "logging/logStream.hpp"
|
#include "logging/logStream.hpp"
|
||||||
#include "memory/allocation.inline.hpp"
|
#include "memory/allocation.inline.hpp"
|
||||||
#include "memory/metadataFactory.hpp"
|
#include "memory/metadataFactory.hpp"
|
||||||
#include "memory/metaspaceShared.hpp"
|
|
||||||
#include "memory/resourceArea.hpp"
|
#include "memory/resourceArea.hpp"
|
||||||
#include "memory/universe.hpp"
|
|
||||||
#include "oops/access.inline.hpp"
|
#include "oops/access.inline.hpp"
|
||||||
#include "oops/oop.inline.hpp"
|
#include "oops/oop.inline.hpp"
|
||||||
#include "oops/oopHandle.inline.hpp"
|
#include "oops/oopHandle.inline.hpp"
|
||||||
@ -72,14 +69,10 @@
|
|||||||
#include "runtime/mutex.hpp"
|
#include "runtime/mutex.hpp"
|
||||||
#include "runtime/orderAccess.hpp"
|
#include "runtime/orderAccess.hpp"
|
||||||
#include "runtime/safepoint.hpp"
|
#include "runtime/safepoint.hpp"
|
||||||
#include "runtime/safepointVerifiers.hpp"
|
|
||||||
#include "utilities/growableArray.hpp"
|
#include "utilities/growableArray.hpp"
|
||||||
#include "utilities/macros.hpp"
|
#include "utilities/macros.hpp"
|
||||||
#include "utilities/ostream.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;
|
ClassLoaderData * ClassLoaderData::_the_null_class_loader_data = NULL;
|
||||||
|
|
||||||
void ClassLoaderData::init_null_class_loader_data() {
|
void ClassLoaderData::init_null_class_loader_data() {
|
||||||
@ -444,13 +437,6 @@ void ClassLoaderData::record_dependency(const Klass* k) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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 */) {
|
void ClassLoaderData::add_class(Klass* k, bool publicize /* true */) {
|
||||||
{
|
{
|
||||||
MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
|
MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
|
||||||
@ -478,78 +464,6 @@ void ClassLoaderData::add_class(Klass* k, bool publicize /* true */) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) {
|
void ClassLoaderData::initialize_holder(Handle loader_or_mirror) {
|
||||||
if (loader_or_mirror() != NULL) {
|
if (loader_or_mirror() != NULL) {
|
||||||
assert(_holder.is_null(), "never replace holders");
|
assert(_holder.is_null(), "never replace holders");
|
||||||
@ -563,7 +477,7 @@ void ClassLoaderData::remove_class(Klass* scratch_class) {
|
|||||||
assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
|
assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
|
||||||
|
|
||||||
// Adjust global class iterator.
|
// Adjust global class iterator.
|
||||||
static_klass_iterator.adjust_saved_class(scratch_class);
|
ClassLoaderDataGraph::adjust_saved_class(scratch_class);
|
||||||
|
|
||||||
Klass* prev = NULL;
|
Klass* prev = NULL;
|
||||||
for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
|
for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
|
||||||
@ -611,7 +525,7 @@ void ClassLoaderData::unload() {
|
|||||||
classes_do(InstanceKlass::unload_class);
|
classes_do(InstanceKlass::unload_class);
|
||||||
|
|
||||||
// Clean up global class iterator for compiler
|
// Clean up global class iterator for compiler
|
||||||
static_klass_iterator.adjust_saved_class(this);
|
ClassLoaderDataGraph::adjust_saved_class(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
ModuleEntryTable* ClassLoaderData::modules() {
|
ModuleEntryTable* ClassLoaderData::modules() {
|
||||||
@ -914,41 +828,6 @@ void ClassLoaderData::free_deallocate_list() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// 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
|
// 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
|
// scratch or error classes so that unloading events aren't triggered for these
|
||||||
@ -1070,523 +949,3 @@ bool ClassLoaderData::contains_klass(Klass* klass) {
|
|||||||
}
|
}
|
||||||
return false;
|
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<ClassLoaderData*>* ClassLoaderDataGraph::new_clds() {
|
|
||||||
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
|
||||||
assert(_head == NULL || _saved_head != NULL, "remember_new_clds(true) not called?");
|
|
||||||
|
|
||||||
GrowableArray<ClassLoaderData*>* array = new GrowableArray<ClassLoaderData*>();
|
|
||||||
|
|
||||||
// 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
|
|
||||||
|
@ -53,9 +53,8 @@
|
|||||||
// ClassLoaderData are stored in the runtime representation of classes,
|
// ClassLoaderData are stored in the runtime representation of classes,
|
||||||
// and provides iterators for root tracing and other GC operations.
|
// and provides iterators for root tracing and other GC operations.
|
||||||
|
|
||||||
class ClassLoaderData;
|
class ClassLoaderDataGraph;
|
||||||
class JNIMethodBlock;
|
class JNIMethodBlock;
|
||||||
class Metadebug;
|
|
||||||
class ModuleEntry;
|
class ModuleEntry;
|
||||||
class PackageEntry;
|
class PackageEntry;
|
||||||
class ModuleEntryTable;
|
class ModuleEntryTable;
|
||||||
@ -63,136 +62,6 @@ class PackageEntryTable;
|
|||||||
class DictionaryEntry;
|
class DictionaryEntry;
|
||||||
class Dictionary;
|
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<ClassLoaderData*>* 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
|
// ClassLoaderData class
|
||||||
|
|
||||||
class ClassLoaderData : public CHeapObj<mtClass> {
|
class ClassLoaderData : public CHeapObj<mtClass> {
|
||||||
@ -448,31 +317,4 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
|||||||
JFR_ONLY(DEFINE_TRACE_ID_METHODS;)
|
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
|
#endif // SHARE_VM_CLASSFILE_CLASSLOADERDATA_HPP
|
||||||
|
@ -55,54 +55,4 @@ inline ClassLoaderData* ClassLoaderData::class_loader_data(oop loader) {
|
|||||||
return loader_data;
|
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
|
#endif // SHARE_VM_CLASSFILE_CLASSLOADERDATA_INLINE_HPP
|
||||||
|
697
src/hotspot/share/classfile/classLoaderDataGraph.cpp
Normal file
697
src/hotspot/share/classfile/classLoaderDataGraph.cpp
Normal file
@ -0,0 +1,697 @@
|
|||||||
|
/*
|
||||||
|
* 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 "logging/log.hpp"
|
||||||
|
#include "logging/logStream.hpp"
|
||||||
|
#include "memory/allocation.inline.hpp"
|
||||||
|
#include "memory/metaspace.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<ClassLoaderData*>* ClassLoaderDataGraph::new_clds() {
|
||||||
|
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
||||||
|
assert(_head == NULL || _saved_head != NULL, "remember_new_clds(true) not called?");
|
||||||
|
|
||||||
|
GrowableArray<ClassLoaderData*>* array = new GrowableArray<ClassLoaderData*>();
|
||||||
|
|
||||||
|
// 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() {}
|
||||||
|
|
||||||
|
ClassLoaderMetaspace* ClassLoaderDataGraphMetaspaceIterator::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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
|
182
src/hotspot/share/classfile/classLoaderDataGraph.hpp
Normal file
182
src/hotspot/share/classfile/classLoaderDataGraph.hpp
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
* 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 "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<ClassLoaderData*>* 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();
|
||||||
|
};
|
||||||
|
#endif // SHARE_VM_CLASSFILE_CLASSLOADERDATAGRAPH_HPP
|
82
src/hotspot/share/classfile/classLoaderDataGraph.inline.hpp
Normal file
82
src/hotspot/share/classfile/classLoaderDataGraph.inline.hpp
Normal file
@ -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
|
@ -26,6 +26,7 @@
|
|||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
|
|
||||||
#include "classfile/classLoaderData.inline.hpp"
|
#include "classfile/classLoaderData.inline.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/classLoaderHierarchyDCmd.hpp"
|
#include "classfile/classLoaderHierarchyDCmd.hpp"
|
||||||
#include "memory/allocation.hpp"
|
#include "memory/allocation.hpp"
|
||||||
#include "memory/resourceArea.hpp"
|
#include "memory/resourceArea.hpp"
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "classfile/classLoaderData.inline.hpp"
|
#include "classfile/classLoaderData.inline.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/classLoaderStats.hpp"
|
#include "classfile/classLoaderStats.hpp"
|
||||||
#include "oops/oop.inline.hpp"
|
#include "oops/oop.inline.hpp"
|
||||||
#include "utilities/globalDefinitions.hpp"
|
#include "utilities/globalDefinitions.hpp"
|
||||||
|
@ -23,8 +23,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "classfile/dictionary.hpp"
|
|
||||||
#include "classfile/classLoaderData.inline.hpp"
|
#include "classfile/classLoaderData.inline.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
|
#include "classfile/dictionary.hpp"
|
||||||
#include "classfile/loaderConstraints.hpp"
|
#include "classfile/loaderConstraints.hpp"
|
||||||
#include "logging/log.hpp"
|
#include "logging/log.hpp"
|
||||||
#include "memory/resourceArea.hpp"
|
#include "memory/resourceArea.hpp"
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "classfile/classFileStream.hpp"
|
#include "classfile/classFileStream.hpp"
|
||||||
#include "classfile/classLoader.hpp"
|
#include "classfile/classLoader.hpp"
|
||||||
#include "classfile/classLoaderData.inline.hpp"
|
#include "classfile/classLoaderData.inline.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.inline.hpp"
|
||||||
#include "classfile/classLoaderExt.hpp"
|
#include "classfile/classLoaderExt.hpp"
|
||||||
#include "classfile/dictionary.hpp"
|
#include "classfile/dictionary.hpp"
|
||||||
#include "classfile/javaClasses.inline.hpp"
|
#include "classfile/javaClasses.inline.hpp"
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "classfile/classLoaderData.hpp"
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/stringTable.hpp"
|
#include "classfile/stringTable.hpp"
|
||||||
#include "classfile/symbolTable.hpp"
|
#include "classfile/symbolTable.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/metadataOnStackMark.hpp"
|
#include "classfile/metadataOnStackMark.hpp"
|
||||||
#include "classfile/stringTable.hpp"
|
#include "classfile/stringTable.hpp"
|
||||||
#include "code/codeCache.hpp"
|
#include "code/codeCache.hpp"
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "classfile/metadataOnStackMark.hpp"
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "code/codeCache.hpp"
|
#include "code/codeCache.hpp"
|
||||||
#include "gc/g1/g1BarrierSet.hpp"
|
#include "gc/g1/g1BarrierSet.hpp"
|
||||||
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "classfile/classLoaderData.hpp"
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "gc/g1/g1Analytics.hpp"
|
#include "gc/g1/g1Analytics.hpp"
|
||||||
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
||||||
#include "gc/g1/g1ConcurrentMark.inline.hpp"
|
#include "gc/g1/g1ConcurrentMark.inline.hpp"
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "gc/g1/g1CollectedHeap.hpp"
|
#include "gc/g1/g1CollectedHeap.hpp"
|
||||||
#include "gc/g1/g1ConcurrentMarkBitMap.inline.hpp"
|
#include "gc/g1/g1ConcurrentMarkBitMap.inline.hpp"
|
||||||
#include "gc/g1/g1FullCollector.hpp"
|
#include "gc/g1/g1FullCollector.hpp"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -23,6 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "gc/g1/g1CollectedHeap.hpp"
|
#include "gc/g1/g1CollectedHeap.hpp"
|
||||||
#include "gc/g1/g1FullCollector.hpp"
|
#include "gc/g1/g1FullCollector.hpp"
|
||||||
#include "gc/g1/g1FullGCMarker.hpp"
|
#include "gc/g1/g1FullGCMarker.hpp"
|
||||||
|
@ -23,8 +23,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
|
|
||||||
#include "aot/aotLoader.hpp"
|
#include "aot/aotLoader.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/stringTable.hpp"
|
#include "classfile/stringTable.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
#include "code/codeCache.hpp"
|
#include "code/codeCache.hpp"
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "aot/aotLoader.hpp"
|
#include "aot/aotLoader.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
#include "code/codeCache.hpp"
|
#include "code/codeCache.hpp"
|
||||||
#include "gc/parallel/parallelScavengeHeap.hpp"
|
#include "gc/parallel/parallelScavengeHeap.hpp"
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "aot/aotLoader.hpp"
|
#include "aot/aotLoader.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/stringTable.hpp"
|
#include "classfile/stringTable.hpp"
|
||||||
#include "classfile/symbolTable.hpp"
|
#include "classfile/symbolTable.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "aot/aotLoader.hpp"
|
#include "aot/aotLoader.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/javaClasses.inline.hpp"
|
#include "classfile/javaClasses.inline.hpp"
|
||||||
#include "classfile/stringTable.hpp"
|
#include "classfile/stringTable.hpp"
|
||||||
#include "classfile/symbolTable.hpp"
|
#include "classfile/symbolTable.hpp"
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "aot/aotLoader.hpp"
|
#include "aot/aotLoader.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
#include "code/codeCache.hpp"
|
#include "code/codeCache.hpp"
|
||||||
#include "gc/parallel/gcTaskManager.hpp"
|
#include "gc/parallel/gcTaskManager.hpp"
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/javaClasses.hpp"
|
#include "classfile/javaClasses.hpp"
|
||||||
#include "classfile/stringTable.hpp"
|
#include "classfile/stringTable.hpp"
|
||||||
#include "classfile/symbolTable.hpp"
|
#include "classfile/symbolTable.hpp"
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "gc/shared/cardTableRS.hpp"
|
#include "gc/shared/cardTableRS.hpp"
|
||||||
#include "gc/shared/genCollectedHeap.hpp"
|
#include "gc/shared/genCollectedHeap.hpp"
|
||||||
#include "gc/shared/genOopClosures.hpp"
|
#include "gc/shared/genOopClosures.hpp"
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "aot/aotLoader.hpp"
|
#include "aot/aotLoader.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/symbolTable.hpp"
|
#include "classfile/symbolTable.hpp"
|
||||||
#include "classfile/stringTable.hpp"
|
#include "classfile/stringTable.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#ifndef SHARE_VM_GC_SHARED_PARALLELCLEANING_HPP
|
#ifndef SHARE_VM_GC_SHARED_PARALLELCLEANING_HPP
|
||||||
#define 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/oopStorageParState.hpp"
|
||||||
#include "gc/shared/stringdedup/stringDedup.hpp"
|
#include "gc/shared/stringdedup/stringDedup.hpp"
|
||||||
#include "gc/shared/workgroup.hpp"
|
#include "gc/shared/workgroup.hpp"
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "classfile/classLoaderData.hpp"
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/stringTable.hpp"
|
#include "classfile/stringTable.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
#include "code/codeCache.hpp"
|
#include "code/codeCache.hpp"
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "aot/aotLoader.hpp"
|
#include "aot/aotLoader.hpp"
|
||||||
#include "classfile/classLoaderData.hpp"
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/stringTable.hpp"
|
#include "classfile/stringTable.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
#include "gc/shared/strongRootsScope.hpp"
|
#include "gc/shared/strongRootsScope.hpp"
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "aot/aotLoader.hpp"
|
#include "aot/aotLoader.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/stringTable.hpp"
|
#include "classfile/stringTable.hpp"
|
||||||
#include "gc/shared/strongRootsScope.hpp"
|
#include "gc/shared/strongRootsScope.hpp"
|
||||||
#include "jfr/leakprofiler/utilities/unifiedOop.hpp"
|
#include "jfr/leakprofiler/utilities/unifiedOop.hpp"
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "classfile/classLoaderData.hpp"
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "jfr/leakprofiler/utilities/saveRestore.hpp"
|
#include "jfr/leakprofiler/utilities/saveRestore.hpp"
|
||||||
#include "oops/oop.inline.hpp"
|
#include "oops/oop.inline.hpp"
|
||||||
|
|
||||||
|
@ -23,7 +23,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "classfile/classLoaderData.hpp"
|
#include "classfile/classLoaderData.inline.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/moduleEntry.hpp"
|
#include "classfile/moduleEntry.hpp"
|
||||||
#include "classfile/packageEntry.hpp"
|
#include "classfile/packageEntry.hpp"
|
||||||
#include "jfr/jfrEvents.hpp"
|
#include "jfr/jfrEvents.hpp"
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "jvm.h"
|
#include "jvm.h"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/classLoaderStats.hpp"
|
#include "classfile/classLoaderStats.hpp"
|
||||||
#include "classfile/javaClasses.hpp"
|
#include "classfile/javaClasses.hpp"
|
||||||
#include "code/codeCache.hpp"
|
#include "code/codeCache.hpp"
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "classfile/classLoaderData.inline.hpp"
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/javaClasses.inline.hpp"
|
#include "classfile/javaClasses.inline.hpp"
|
||||||
#include "classfile/moduleEntry.hpp"
|
#include "classfile/moduleEntry.hpp"
|
||||||
#include "classfile/packageEntry.hpp"
|
#include "classfile/packageEntry.hpp"
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "classfile/classLoaderData.inline.hpp"
|
#include "classfile/classLoaderData.inline.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/moduleEntry.hpp"
|
#include "classfile/moduleEntry.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
#include "gc/shared/collectedHeap.hpp"
|
#include "gc/shared/collectedHeap.hpp"
|
||||||
|
@ -23,8 +23,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
|
|
||||||
#include "aot/aotLoader.hpp"
|
#include "aot/aotLoader.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "gc/shared/collectedHeap.hpp"
|
#include "gc/shared/collectedHeap.hpp"
|
||||||
#include "logging/log.hpp"
|
#include "logging/log.hpp"
|
||||||
#include "logging/logStream.hpp"
|
#include "logging/logStream.hpp"
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "jvm.h"
|
#include "jvm.h"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/classListParser.hpp"
|
#include "classfile/classListParser.hpp"
|
||||||
#include "classfile/classLoaderExt.hpp"
|
#include "classfile/classLoaderExt.hpp"
|
||||||
#include "classfile/dictionary.hpp"
|
#include "classfile/dictionary.hpp"
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "aot/aotLoader.hpp"
|
#include "aot/aotLoader.hpp"
|
||||||
#include "classfile/classLoader.hpp"
|
#include "classfile/classLoader.hpp"
|
||||||
#include "classfile/classLoaderData.hpp"
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/javaClasses.hpp"
|
#include "classfile/javaClasses.hpp"
|
||||||
#include "classfile/stringTable.hpp"
|
#include "classfile/stringTable.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "jvm.h"
|
#include "jvm.h"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/javaClasses.hpp"
|
#include "classfile/javaClasses.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
#include "classfile/vmSymbols.hpp"
|
#include "classfile/vmSymbols.hpp"
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/metadataOnStackMark.hpp"
|
#include "classfile/metadataOnStackMark.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
#include "code/codeCache.hpp"
|
#include "code/codeCache.hpp"
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
#include "jvmtifiles/jvmtiEnv.hpp"
|
#include "jvmtifiles/jvmtiEnv.hpp"
|
||||||
#include "memory/resourceArea.hpp"
|
#include "memory/resourceArea.hpp"
|
||||||
|
@ -23,8 +23,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/dictionary.hpp"
|
#include "classfile/dictionary.hpp"
|
||||||
#include "classfile/classLoaderData.inline.hpp"
|
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
#include "gc/shared/collectedHeap.hpp"
|
#include "gc/shared/collectedHeap.hpp"
|
||||||
#include "memory/universe.hpp"
|
#include "memory/universe.hpp"
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "aot/aotLoader.hpp"
|
#include "aot/aotLoader.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/classFileStream.hpp"
|
#include "classfile/classFileStream.hpp"
|
||||||
#include "classfile/metadataOnStackMark.hpp"
|
#include "classfile/metadataOnStackMark.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/javaClasses.inline.hpp"
|
#include "classfile/javaClasses.inline.hpp"
|
||||||
#include "classfile/symbolTable.hpp"
|
#include "classfile/symbolTable.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
#include "classfile/classLoaderData.hpp"
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/modules.hpp"
|
#include "classfile/modules.hpp"
|
||||||
#include "classfile/protectionDomainCache.hpp"
|
#include "classfile/protectionDomainCache.hpp"
|
||||||
#include "classfile/stringTable.hpp"
|
#include "classfile/stringTable.hpp"
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "jfr/jfrEvents.hpp"
|
#include "jfr/jfrEvents.hpp"
|
||||||
#include "jfr/support/jfrThreadId.hpp"
|
#include "jfr/support/jfrThreadId.hpp"
|
||||||
#include "logging/log.hpp"
|
#include "logging/log.hpp"
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "classfile/classLoaderData.inline.hpp"
|
#include "classfile/classLoaderDataGraph.inline.hpp"
|
||||||
#include "code/compiledIC.hpp"
|
#include "code/compiledIC.hpp"
|
||||||
#include "code/nmethod.hpp"
|
#include "code/nmethod.hpp"
|
||||||
#include "code/scopeDesc.hpp"
|
#include "code/scopeDesc.hpp"
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "jvm.h"
|
#include "jvm.h"
|
||||||
#include "aot/aotLoader.hpp"
|
#include "aot/aotLoader.hpp"
|
||||||
#include "classfile/classLoader.hpp"
|
#include "classfile/classLoader.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/stringTable.hpp"
|
#include "classfile/stringTable.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
#include "code/codeCache.hpp"
|
#include "code/codeCache.hpp"
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "classfile/classLoaderData.inline.hpp"
|
#include "classfile/classLoaderDataGraph.inline.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
#include "code/codeCache.hpp"
|
#include "code/codeCache.hpp"
|
||||||
#include "gc/shared/collectedHeap.inline.hpp"
|
#include "gc/shared/collectedHeap.inline.hpp"
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "classfile/classLoaderData.inline.hpp"
|
#include "classfile/classLoaderDataGraph.inline.hpp"
|
||||||
#include "classfile/stringTable.hpp"
|
#include "classfile/stringTable.hpp"
|
||||||
#include "classfile/symbolTable.hpp"
|
#include "classfile/symbolTable.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "ci/ciObjArrayKlass.hpp"
|
#include "ci/ciObjArrayKlass.hpp"
|
||||||
#include "ci/ciSymbol.hpp"
|
#include "ci/ciSymbol.hpp"
|
||||||
#include "classfile/compactHashtable.hpp"
|
#include "classfile/compactHashtable.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/dictionary.hpp"
|
#include "classfile/dictionary.hpp"
|
||||||
#include "classfile/javaClasses.hpp"
|
#include "classfile/javaClasses.hpp"
|
||||||
#include "classfile/stringTable.hpp"
|
#include "classfile/stringTable.hpp"
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "jvm.h"
|
#include "jvm.h"
|
||||||
|
#include "classfile/classLoaderData.inline.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/symbolTable.hpp"
|
#include "classfile/symbolTable.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
#include "classfile/vmSymbols.hpp"
|
#include "classfile/vmSymbols.hpp"
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
|
|
||||||
#include "classfile/classLoaderData.inline.hpp"
|
#include "classfile/classLoaderDataGraph.inline.hpp"
|
||||||
#include "memory/allocation.hpp"
|
#include "memory/allocation.hpp"
|
||||||
#include "runtime/safepoint.hpp"
|
#include "runtime/safepoint.hpp"
|
||||||
#include "runtime/thread.inline.hpp"
|
#include "runtime/thread.inline.hpp"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user