< prev index next >

src/hotspot/share/classfile/classLoaderData.cpp

Print this page

        

*** 45,55 **** // // The bootstrap loader (represented by NULL) also has a ClassLoaderData, // the singleton class the_null_class_loader_data(). #include "precompiled.hpp" - #include "classfile/classLoaderData.hpp" #include "classfile/classLoaderData.inline.hpp" #include "classfile/dictionary.hpp" #include "classfile/javaClasses.hpp" #include "classfile/metadataOnStackMark.hpp" #include "classfile/moduleEntry.hpp" --- 45,54 ----
*** 57,68 **** #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" #include "gc/shared/gcLocker.hpp" #include "logging/log.hpp" #include "logging/logStream.hpp" #include "memory/metadataFactory.hpp" - #include "memory/metaspaceShared.hpp" #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.hpp" --- 56,67 ---- #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" #include "gc/shared/gcLocker.hpp" #include "logging/log.hpp" #include "logging/logStream.hpp" + #include "memory/metaspace.hpp" #include "memory/metadataFactory.hpp" #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.hpp"
*** 70,140 **** #include "runtime/jniHandles.hpp" #include "runtime/mutex.hpp" #include "runtime/orderAccess.hpp" #include "runtime/safepoint.hpp" #include "runtime/synchronizer.hpp" - #include "utilities/growableArray.hpp" - #include "utilities/macros.hpp" #include "utilities/ostream.hpp" #if INCLUDE_ALL_GCS #include "gc/g1/g1SATBCardTableModRefBS.hpp" #endif // INCLUDE_ALL_GCS #if INCLUDE_TRACE #include "trace/tracing.hpp" #endif ! ClassLoaderData * ClassLoaderData::_the_null_class_loader_data = NULL; ! ! ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Dependencies dependencies) : ! _class_loader(h_class_loader()), ! _is_anonymous(is_anonymous), ! // An anonymous class loader data doesn't have anything to keep ! // it from being unloaded during parsing of the anonymous class. ! // The null-class-loader should always be kept alive. ! _keep_alive((is_anonymous || h_class_loader.is_null()) ? 1 : 0), ! _metaspace(NULL), _unloading(false), _klasses(NULL), ! _modules(NULL), _packages(NULL), ! _claimed(0), _modified_oops(true), _accumulated_modified_oops(false), ! _jmethod_ids(NULL), _handles(), _deallocate_list(NULL), ! _next(NULL), _dependencies(dependencies), ! _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true, ! Monitor::_safepoint_check_never)) { ! // A ClassLoaderData created solely for an anonymous class should never have a ! // ModuleEntryTable or PackageEntryTable created for it. The defining package ! // and module for an anonymous class will be found in its host class. ! if (!is_anonymous) { ! _packages = new PackageEntryTable(PackageEntryTable::_packagetable_entry_size); ! if (h_class_loader.is_null()) { ! // Create unnamed module for boot loader ! _unnamed_module = ModuleEntry::create_boot_unnamed_module(this); ! } else { ! // Create unnamed module for all other loaders ! _unnamed_module = ModuleEntry::create_unnamed_module(this); } ! } else { ! _unnamed_module = NULL; } ! if (!is_anonymous) { ! _dictionary = create_dictionary(); ! } else { ! _dictionary = NULL; ! } ! TRACE_INIT_ID(this); } ! void ClassLoaderData::init_dependencies(TRAPS) { ! assert(!Universe::is_fully_initialized(), "should only be called when initializing"); ! assert(is_the_null_class_loader_data(), "should only call this for the null class loader"); ! _dependencies.init(CHECK); } ! void ClassLoaderData::Dependencies::init(TRAPS) { ! // Create empty dependencies array to add to. CMS requires this to be ! // an oop so that it can track additions via card marks. We think. ! _list_head = oopFactory::new_objectArray(2, CHECK); } ClassLoaderData::ChunkedHandleList::~ChunkedHandleList() { Chunk* c = _head; while (c != NULL) { --- 69,156 ---- #include "runtime/jniHandles.hpp" #include "runtime/mutex.hpp" #include "runtime/orderAccess.hpp" #include "runtime/safepoint.hpp" #include "runtime/synchronizer.hpp" #include "utilities/ostream.hpp" #if INCLUDE_ALL_GCS #include "gc/g1/g1SATBCardTableModRefBS.hpp" #endif // INCLUDE_ALL_GCS #if INCLUDE_TRACE #include "trace/tracing.hpp" + #include "utilities/ticks.hpp" #endif ! void ClassLoaderData::Dependencies::init(TRAPS) { ! // Create empty dependencies array to add to. CMS requires this to be ! // an oop so that it can track additions via card marks. We think. ! _list_head = oopFactory::new_objectArray(2, CHECK); ! } ! void ClassLoaderData::Dependencies::add(Handle dependency, TRAPS) { ! // Check first if this dependency is already in the list. ! // Save a pointer to the last to add to under the lock. ! objArrayOop ok = _list_head; ! objArrayOop last = NULL; ! while (ok != NULL) { ! last = ok; ! if (ok->obj_at(0) == dependency()) { ! // Don't need to add it ! return; } ! ok = (objArrayOop)ok->obj_at(1); } ! // Must handle over GC points ! assert(last != NULL, "dependencies should be initialized"); ! objArrayHandle last_handle(THREAD, last); ! ! // Create a new dependency node with fields for (class_loader or mirror, next) ! objArrayOop deps = oopFactory::new_objectArray(2, CHECK); ! deps->obj_at_put(0, dependency()); ! ! // Must handle over GC points ! objArrayHandle new_dependency(THREAD, deps); ! ! // Add the dependency under lock ! locked_add(last_handle, new_dependency, THREAD); } ! void ClassLoaderData::Dependencies::locked_add(objArrayHandle last_handle, ! objArrayHandle new_dependency, ! Thread* THREAD) { ! ! // Have to lock and put the new dependency on the end of the dependency ! // array so the card mark for CMS sees that this dependency is new. ! // Can probably do this lock free with some effort. ! ObjectLocker ol(Handle(THREAD, _list_head), THREAD); ! ! oop loader_or_mirror = new_dependency->obj_at(0); ! ! // Since the dependencies are only added, add to the end. ! objArrayOop end = last_handle(); ! objArrayOop last = NULL; ! while (end != NULL) { ! last = end; ! // check again if another thread added it to the end. ! if (end->obj_at(0) == loader_or_mirror) { ! // Don't need to add it ! return; ! } ! end = (objArrayOop)end->obj_at(1); ! } ! assert(last != NULL, "dependencies should be initialized"); ! // fill in the first element with the oop in new_dependency. ! if (last->obj_at(0) == NULL) { ! last->obj_at_put(0, new_dependency->obj_at(0)); ! } else { ! last->obj_at_put(1, new_dependency()); ! } } ! void ClassLoaderData::Dependencies::oops_do(OopClosure* f) { ! f->do_oop((oop*)&_list_head); } ClassLoaderData::ChunkedHandleList::~ChunkedHandleList() { Chunk* c = _head; while (c != NULL) {
*** 153,170 **** *handle = o; OrderAccess::release_store(&_head->_size, _head->_size + 1); return handle; } - inline void ClassLoaderData::ChunkedHandleList::oops_do_chunk(OopClosure* f, Chunk* c, const juint size) { - for (juint i = 0; i < size; i++) { - if (c->_data[i] != NULL) { - f->do_oop(&c->_data[i]); - } - } - } - void ClassLoaderData::ChunkedHandleList::oops_do(OopClosure* f) { Chunk* head = OrderAccess::load_acquire(&_head); if (head != NULL) { // Must be careful when reading size of head oops_do_chunk(f, head, OrderAccess::load_acquire(&head->_size)); --- 169,178 ----
*** 172,187 **** oops_do_chunk(f, c, c->_size); } } } #ifdef ASSERT class VerifyContainsOopClosure : public OopClosure { oop* _target; bool _found; ! public: VerifyContainsOopClosure(oop* target) : _target(target), _found(false) {} void do_oop(oop* p) { if (p == _target) { _found = true; --- 180,203 ---- oops_do_chunk(f, c, c->_size); } } } + inline void ClassLoaderData::ChunkedHandleList::oops_do_chunk(OopClosure* f, Chunk* c, const juint size) { + for (juint i = 0; i < size; i++) { + if (c->_data[i] != NULL) { + f->do_oop(&c->_data[i]); + } + } + } + #ifdef ASSERT class VerifyContainsOopClosure : public OopClosure { oop* _target; bool _found; ! public: VerifyContainsOopClosure(oop* target) : _target(target), _found(false) {} void do_oop(oop* p) { if (p == _target) { _found = true;
*** 203,474 **** oops_do(&cl); return cl.found(); } #endif // ASSERT ! bool ClassLoaderData::claim() { ! if (_claimed == 1) { ! return false; ! } ! return (int) Atomic::cmpxchg(1, &_claimed, 0) == 0; ! } ! // Anonymous classes have their own ClassLoaderData that is marked to keep alive ! // while the class is being parsed, and if the class appears on the module fixup list. ! // Due to the uniqueness that no other class shares the anonymous class' name or ! // ClassLoaderData, no other non-GC thread has knowledge of the anonymous class while ! // it is being defined, therefore _keep_alive is not volatile or atomic. ! void ClassLoaderData::inc_keep_alive() { ! if (is_anonymous()) { ! assert(_keep_alive >= 0, "Invalid keep alive increment count"); ! _keep_alive++; } ! } ! ! void ClassLoaderData::dec_keep_alive() { ! if (is_anonymous()) { ! assert(_keep_alive > 0, "Invalid keep alive decrement count"); ! _keep_alive--; } } ! void ClassLoaderData::oops_do(OopClosure* f, bool must_claim, bool clear_mod_oops) { ! if (must_claim && !claim()) { ! return; ! } ! ! // Only clear modified_oops after the ClassLoaderData is claimed. ! if (clear_mod_oops) { ! clear_modified_oops(); ! } ! f->do_oop(&_class_loader); ! _dependencies.oops_do(f); ! _handles.oops_do(f); } ! void ClassLoaderData::Dependencies::oops_do(OopClosure* f) { ! f->do_oop((oop*)&_list_head); ! } ! void ClassLoaderData::classes_do(KlassClosure* klass_closure) { ! // Lock-free access requires load_acquire ! for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) { ! klass_closure->do_klass(k); ! assert(k != k->next_link(), "no loops!"); } ! } ! ! void ClassLoaderData::classes_do(void f(Klass * const)) { ! // Lock-free access requires load_acquire ! for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) { ! f(k); ! assert(k != k->next_link(), "no loops!"); } - } ! void ClassLoaderData::methods_do(void f(Method*)) { ! // Lock-free access requires load_acquire ! for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) { ! if (k->is_instance_klass() && InstanceKlass::cast(k)->is_loaded()) { ! InstanceKlass::cast(k)->methods_do(f); ! } } } ! void ClassLoaderData::loaded_classes_do(KlassClosure* klass_closure) { ! // Lock-free access requires load_acquire ! for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) { ! // Do not filter ArrayKlass oops here... ! if (k->is_array_klass() || (k->is_instance_klass() && InstanceKlass::cast(k)->is_loaded())) { ! klass_closure->do_klass(k); ! } ! } ! } ! void ClassLoaderData::classes_do(void f(InstanceKlass*)) { ! // Lock-free access requires load_acquire ! for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) { ! if (k->is_instance_klass()) { ! f(InstanceKlass::cast(k)); ! } ! assert(k != k->next_link(), "no loops!"); } - } ! void ClassLoaderData::modules_do(void f(ModuleEntry*)) { ! assert_locked_or_safepoint(Module_lock); ! if (_unnamed_module != NULL) { ! f(_unnamed_module); ! } if (_modules != NULL) { ! for (int i = 0; i < _modules->table_size(); i++) { ! for (ModuleEntry* entry = _modules->bucket(i); ! entry != NULL; ! entry = entry->next()) { ! f(entry); ! } ! } } - } ! void ClassLoaderData::packages_do(void f(PackageEntry*)) { ! assert_locked_or_safepoint(Module_lock); ! if (_packages != NULL) { ! for (int i = 0; i < _packages->table_size(); i++) { ! for (PackageEntry* entry = _packages->bucket(i); ! entry != NULL; ! entry = entry->next()) { ! f(entry); ! } ! } } - } ! void ClassLoaderData::record_dependency(const Klass* k, TRAPS) { ! assert(k != NULL, "invariant"); ! ! ClassLoaderData * const from_cld = this; ! ClassLoaderData * const to_cld = k->class_loader_data(); ! ! // Dependency to the null class loader data doesn't need to be recorded ! // because the null class loader data never goes away. ! if (to_cld->is_the_null_class_loader_data()) { ! return; } ! oop to; ! if (to_cld->is_anonymous()) { ! // Anonymous class dependencies are through the mirror. ! to = k->java_mirror(); ! } else { ! to = to_cld->class_loader(); ! ! // If from_cld is anonymous, even if it's class_loader is a parent of 'to' ! // we still have to add it. The class_loader won't keep from_cld alive. ! if (!from_cld->is_anonymous()) { ! // Check that this dependency isn't from the same or parent class_loader ! oop from = from_cld->class_loader(); ! ! oop curr = from; ! while (curr != NULL) { ! if (curr == to) { ! return; // this class loader is in the parent list, no need to add it. ! } ! curr = java_lang_ClassLoader::parent(curr); ! } } } ! // It's a dependency we won't find through GC, add it. This is relatively rare ! // Must handle over GC point. ! Handle dependency(THREAD, to); ! from_cld->_dependencies.add(dependency, CHECK); ! ! // Added a potentially young gen oop to the ClassLoaderData ! record_modified_oops(); ! } ! ! ! void ClassLoaderData::Dependencies::add(Handle dependency, TRAPS) { ! // Check first if this dependency is already in the list. ! // Save a pointer to the last to add to under the lock. ! objArrayOop ok = _list_head; ! objArrayOop last = NULL; ! while (ok != NULL) { ! last = ok; ! if (ok->obj_at(0) == dependency()) { ! // Don't need to add it ! return; ! } ! ok = (objArrayOop)ok->obj_at(1); } - - // Must handle over GC points - assert (last != NULL, "dependencies should be initialized"); - objArrayHandle last_handle(THREAD, last); - - // Create a new dependency node with fields for (class_loader or mirror, next) - objArrayOop deps = oopFactory::new_objectArray(2, CHECK); - deps->obj_at_put(0, dependency()); - - // Must handle over GC points - objArrayHandle new_dependency(THREAD, deps); - - // Add the dependency under lock - locked_add(last_handle, new_dependency, THREAD); } ! void ClassLoaderData::Dependencies::locked_add(objArrayHandle last_handle, ! objArrayHandle new_dependency, ! Thread* THREAD) { ! ! // Have to lock and put the new dependency on the end of the dependency ! // array so the card mark for CMS sees that this dependency is new. ! // Can probably do this lock free with some effort. ! ObjectLocker ol(Handle(THREAD, _list_head), THREAD); ! ! oop loader_or_mirror = new_dependency->obj_at(0); ! // Since the dependencies are only added, add to the end. ! objArrayOop end = last_handle(); ! objArrayOop last = NULL; ! while (end != NULL) { ! last = end; ! // check again if another thread added it to the end. ! if (end->obj_at(0) == loader_or_mirror) { ! // Don't need to add it return; } ! end = (objArrayOop)end->obj_at(1); } - assert (last != NULL, "dependencies should be initialized"); - // fill in the first element with the oop in new_dependency. - if (last->obj_at(0) == NULL) { - last->obj_at_put(0, new_dependency->obj_at(0)); } else { ! last->obj_at_put(1, new_dependency()); } - } - - void ClassLoaderDataGraph::clear_claimed_marks() { - for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { - cld->clear_claimed(); } } ! void ClassLoaderData::add_class(Klass* k, bool publicize /* true */) { ! { ! MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag); ! Klass* old_value = _klasses; ! k->set_next_link(old_value); ! // Link the new item into the list, making sure the linked class is stable ! // since the list can be walked without a lock ! OrderAccess::release_store(&_klasses, k); } - - if (publicize && k->class_loader_data() != NULL) { - ResourceMark rm; - log_trace(class, loader, data)("Adding k: " PTR_FORMAT " %s to CLD: " - PTR_FORMAT " loader: " PTR_FORMAT " %s", - p2i(k), - k->external_name(), - p2i(k->class_loader_data()), - p2i((void *)k->class_loader()), - loader_name()); } } // 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"); int max_classes = InstanceKlass::number_of_instance_classes(); assert(max_classes > 0, "should not be called with no instance classes"); --- 219,431 ---- oops_do(&cl); return cl.found(); } #endif // ASSERT ! static const int _boot_loader_dictionary_size = 1009; ! static const int _default_loader_dictionary_size = 107; ! static Dictionary* create_dictionary(ClassLoaderData* cld) { ! assert(cld != NULL, "invariant"); ! assert(!cld->is_anonymous(), "anonymous class loader data do not have a dictionary"); ! int size; ! bool resizable = false; ! if (ClassLoaderData::the_null_class_loader_data() == NULL) { ! size = _boot_loader_dictionary_size; ! resizable = true; ! } else if (cld->class_loader()->is_a(SystemDictionary::reflect_DelegatingClassLoader_klass())) { ! size = 1; // there's only one class in relection class loader and no initiated classes ! } else if (cld->is_system_class_loader_data()) { ! size = _boot_loader_dictionary_size; ! resizable = true; ! } else { ! size = _default_loader_dictionary_size; ! resizable = true; } ! if (!DynamicallyResizeSystemDictionaries || DumpSharedSpaces || UseSharedSpaces) { ! resizable = false; } + return new Dictionary(cld, size, resizable); } ! ClassLoaderData * ClassLoaderData::_the_null_class_loader_data = NULL; ! void ClassLoaderData::init_null_class_loader_data() { ! assert(_the_null_class_loader_data == NULL, "cannot initialize twice"); ! assert(ClassLoaderDataGraph::_head == NULL, "cannot initialize twice"); ! ! // We explicitly initialize the Dependencies object at a later phase in the initialization ! _the_null_class_loader_data = new ClassLoaderData(Handle(), false, Dependencies()); ! ClassLoaderDataGraph::_head = _the_null_class_loader_data; ! assert(_the_null_class_loader_data->is_the_null_class_loader_data(), "Must be"); } ! ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Dependencies dependencies) : ! _class_loader(h_class_loader()), ! _is_anonymous(is_anonymous), ! // An anonymous class loader data doesn't have anything to keep ! // it from being unloaded during parsing of the anonymous class. ! // The null-class-loader should always be kept alive. ! _keep_alive((is_anonymous || h_class_loader.is_null()) ? 1 : 0), ! _metaspace(NULL), _unloading(false), _klasses(NULL), ! _modules(NULL), _packages(NULL), ! _claimed(0), _modified_oops(true), _accumulated_modified_oops(false), ! _jmethod_ids(NULL), _handles(), _deallocate_list(NULL), ! _next(NULL), _dependencies(dependencies), ! _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true, ! Monitor::_safepoint_check_never)) { ! // A ClassLoaderData created solely for an anonymous class should never have a ! // ModuleEntryTable or PackageEntryTable created for it. The defining package ! // and module for an anonymous class will be found in its host class. ! if (!is_anonymous) { ! _packages = new PackageEntryTable(PackageEntryTable::_packagetable_entry_size); ! if (h_class_loader.is_null()) { ! // Create unnamed module for boot loader ! _unnamed_module = ModuleEntry::create_boot_unnamed_module(this); ! } else { ! // Create unnamed module for all other loaders ! _unnamed_module = ModuleEntry::create_unnamed_module(this); } ! } else { ! _unnamed_module = NULL; } ! if (!is_anonymous) { ! _dictionary = create_dictionary(this); ! } else { ! _dictionary = NULL; } + TRACE_INIT_ID(this); } ! ClassLoaderData::~ClassLoaderData() { ! // Release C heap structures for all the classes. ! classes_do(InstanceKlass::release_C_heap_structures); ! // Release C heap allocated hashtable for all the packages. ! if (_packages != NULL) { ! // Destroy the table itself ! delete _packages; ! _packages = NULL; } ! // Release C heap allocated hashtable for all the modules. if (_modules != NULL) { ! // Destroy the table itself ! delete _modules; ! _modules = NULL; } ! // Release C heap allocated hashtable for the dictionary ! if (_dictionary != NULL) { ! // Destroy the table itself ! delete _dictionary; ! _dictionary = NULL; } ! if (_unnamed_module != NULL) { ! _unnamed_module->delete_unnamed_module(); ! _unnamed_module = NULL; } ! // release the metaspace ! Metaspace *m = _metaspace; ! if (m != NULL) { ! _metaspace = NULL; ! delete m; } + // Clear all the JNI handles for methods + // These aren't deallocated and are going to look like a leak, but that's + // needed because we can't really get rid of jmethodIDs because we don't + // know when native code is going to stop using them. The spec says that + // they're "invalid" but existing programs likely rely on their being + // NULL after class unloading. + if (_jmethod_ids != NULL) { + Method::clear_jmethod_ids(this); } + // Delete lock + delete _metaspace_lock; ! // Delete free list ! if (_deallocate_list != NULL) { ! delete _deallocate_list; } } ! void ClassLoaderData::init_dependencies(TRAPS) { ! assert(!Universe::is_fully_initialized(), "should only be called when initializing"); ! assert(is_the_null_class_loader_data(), "should only call this for the null class loader"); ! _dependencies.init(CHECK); ! } ! // Deallocate free metadata on the free list. How useful the PermGen was! ! void ClassLoaderData::free_deallocate_list() { ! // Don't need lock, at safepoint ! assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint"); ! assert(!is_unloading(), "only called for ClassLoaderData that are not unloading"); ! if (_deallocate_list == NULL) { return; } ! // Go backwards because this removes entries that are freed. ! for (int i = _deallocate_list->length() - 1; i >= 0; i--) { ! Metadata* m = _deallocate_list->at(i); ! if (!m->on_stack()) { ! _deallocate_list->remove_at(i); ! // There are only three types of metadata that we deallocate directly. ! // Cast them so they can be used by the template function. ! if (m->is_method()) { ! MetadataFactory::free_metadata(this, (Method*)m); ! } else if (m->is_constantPool()) { ! MetadataFactory::free_metadata(this, (ConstantPool*)m); ! } else if (m->is_klass()) { ! MetadataFactory::free_metadata(this, (InstanceKlass*)m); ! } else { ! ShouldNotReachHere(); } } else { ! // Metadata is alive. ! // If scratch_class is on stack then it shouldn't be on this list! ! assert(!m->is_klass() || !((InstanceKlass*)m)->is_scratch_class(), ! "scratch classes on this list should be dead"); ! // Also should assert that other metadata on the list was found in handles. } } } ! // This is distinct from free_deallocate_list. For class loader data that are ! // unloading, this frees the C heap memory for constant pools on the list. If there ! // were C heap memory allocated for methods, it would free that too. The C heap memory ! // for InstanceKlasses on this list is freed in the ClassLoaderData destructor. ! void ClassLoaderData::unload_deallocate_list() { ! // Don't need lock, at safepoint ! assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint"); ! assert(is_unloading(), "only called for ClassLoaderData that are unloading"); ! if (_deallocate_list == NULL) { ! return; ! } ! // Go backwards because this removes entries that are freed. ! for (int i = _deallocate_list->length() - 1; i >= 0; i--) { ! Metadata* m = _deallocate_list->at(i); ! assert(!m->on_stack(), "wouldn't be unloading if this were so"); ! _deallocate_list->remove_at(i); ! // Only constant pool entries have C heap memory to free. ! if (m->is_constantPool()) { ! ((ConstantPool*)m)->release_C_heap_structures(); } } } // Class iterator used by the compiler. It gets some number of classes at // a safepoint to decay invocation counters on the methods. class ClassLoaderDataGraphKlassIteratorStatic { + friend class ClassLoaderData; + friend class ClassLoaderDataGraph; + private: ClassLoaderData* _current_loader_data; Klass* _current_class_entry; InstanceKlass* try_get_next_class() { assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint"); int max_classes = InstanceKlass::number_of_instance_classes(); assert(max_classes > 0, "should not be called with no instance classes");
*** 519,562 **** 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() { - return static_klass_iterator.try_get_next_class(); - } - - - // Remove a klass from the _klasses list for scratch_class during redefinition - // or parsed class in the case of an error. - void ClassLoaderData::remove_class(Klass* scratch_class) { - assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint"); - - // Adjust global class iterator. - static_klass_iterator.adjust_saved_class(scratch_class); - - Klass* prev = NULL; - for (Klass* k = _klasses; k != NULL; k = k->next_link()) { - if (k == scratch_class) { - if (prev == NULL) { - _klasses = k->next_link(); - } else { - Klass* next = k->next_link(); - prev->set_next_link(next); - } - return; - } - prev = k; - assert(k != k->next_link(), "no loops!"); - } - ShouldNotReachHere(); // should have found this class!! - } - void ClassLoaderData::unload() { _unloading = true; // Tell serviceability tools these classes are unloading classes_do(InstanceKlass::notify_unload_class); --- 476,492 ---- void adjust_saved_class(Klass* klass) { if (_current_class_entry == klass) { _current_class_entry = klass->next_link(); } } + + public: + ClassLoaderDataGraphKlassIteratorStatic() : _current_loader_data(NULL), _current_class_entry(NULL) {} }; static ClassLoaderDataGraphKlassIteratorStatic static_klass_iterator; void ClassLoaderData::unload() { _unloading = true; // Tell serviceability tools these classes are unloading classes_do(InstanceKlass::notify_unload_class);
*** 580,719 **** // Clean up global class iterator for compiler static_klass_iterator.adjust_saved_class(this); } ! ModuleEntryTable* ClassLoaderData::modules() { ! // Lazily create the module entry table at first request. ! // Lock-free access requires load_acquire. ! ModuleEntryTable* modules = OrderAccess::load_acquire(&_modules); ! if (modules == NULL) { ! MutexLocker m1(Module_lock); ! // Check if _modules got allocated while we were waiting for this lock. ! if ((modules = _modules) == NULL) { ! modules = new ModuleEntryTable(ModuleEntryTable::_moduletable_entry_size); ! { ! MutexLockerEx m1(metaspace_lock(), Mutex::_no_safepoint_check_flag); ! // Ensure _modules is stable, since it is examined without a lock ! OrderAccess::release_store(&_modules, modules); } } } - return modules; } ! const int _boot_loader_dictionary_size = 1009; ! const int _default_loader_dictionary_size = 107; ! ! Dictionary* ClassLoaderData::create_dictionary() { ! assert(!is_anonymous(), "anonymous class loader data do not have a dictionary"); ! int size; ! bool resizable = false; ! if (_the_null_class_loader_data == NULL) { ! size = _boot_loader_dictionary_size; ! resizable = true; ! } else if (class_loader()->is_a(SystemDictionary::reflect_DelegatingClassLoader_klass())) { ! size = 1; // there's only one class in relection class loader and no initiated classes ! } else if (is_system_class_loader_data()) { ! size = _boot_loader_dictionary_size; ! resizable = true; ! } else { ! size = _default_loader_dictionary_size; ! resizable = true; } - if (!DynamicallyResizeSystemDictionaries || DumpSharedSpaces || UseSharedSpaces) { - resizable = false; } - return new Dictionary(this, size, resizable); } ! // Unloading support ! oop ClassLoaderData::keep_alive_object() const { ! assert_locked_or_safepoint(_metaspace_lock); ! assert(!keep_alive(), "Don't use with CLDs that are artificially kept alive"); ! return is_anonymous() ? _klasses->java_mirror() : class_loader(); } ! bool ClassLoaderData::is_alive(BoolObjectClosure* is_alive_closure) const { ! bool alive = keep_alive() // null class loader and incomplete anonymous klasses. ! || is_alive_closure->do_object_b(keep_alive_object()); ! ! return alive; } ! ClassLoaderData::~ClassLoaderData() { ! // Release C heap structures for all the classes. ! classes_do(InstanceKlass::release_C_heap_structures); ! ! // Release C heap allocated hashtable for all the packages. if (_packages != NULL) { ! // Destroy the table itself ! delete _packages; ! _packages = NULL; } - - // Release C heap allocated hashtable for all the modules. - if (_modules != NULL) { - // Destroy the table itself - delete _modules; - _modules = NULL; } - - // Release C heap allocated hashtable for the dictionary - if (_dictionary != NULL) { - // Destroy the table itself - delete _dictionary; - _dictionary = NULL; } ! if (_unnamed_module != NULL) { ! _unnamed_module->delete_unnamed_module(); ! _unnamed_module = NULL; } ! // release the metaspace ! Metaspace *m = _metaspace; ! if (m != NULL) { ! _metaspace = NULL; ! delete m; ! } ! // Clear all the JNI handles for methods ! // These aren't deallocated and are going to look like a leak, but that's ! // needed because we can't really get rid of jmethodIDs because we don't ! // know when native code is going to stop using them. The spec says that ! // they're "invalid" but existing programs likely rely on their being ! // NULL after class unloading. ! if (_jmethod_ids != NULL) { ! Method::clear_jmethod_ids(this); } - // Delete lock - delete _metaspace_lock; ! // Delete free list ! if (_deallocate_list != NULL) { ! delete _deallocate_list; ! } } ! // Returns true if this class loader data is for the system class loader. ! bool ClassLoaderData::is_system_class_loader_data() const { ! return SystemDictionary::is_system_class_loader(class_loader()); } ! // Returns true if this class loader data is for the platform class loader. ! bool ClassLoaderData::is_platform_class_loader_data() const { ! return SystemDictionary::is_platform_class_loader(class_loader()); } ! // Returns true if this class loader data is one of the 3 builtin ! // (boot, application/system or platform) class loaders. Note, the ! // builtin loaders are not freed by a GC. ! bool ClassLoaderData::is_builtin_class_loader_data() const { ! return (is_the_null_class_loader_data() || ! SystemDictionary::is_system_class_loader(class_loader()) || ! SystemDictionary::is_platform_class_loader(class_loader())); } Metaspace* ClassLoaderData::metaspace_non_null() { // If the metaspace has not been allocated, create a new one. Might want // to create smaller arena for Reflection class loaders also. --- 510,645 ---- // Clean up global class iterator for compiler static_klass_iterator.adjust_saved_class(this); } ! void ClassLoaderData::classes_do(KlassClosure* klass_closure) { ! // Lock-free access requires load_acquire ! for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) { ! klass_closure->do_klass(k); ! assert(k != k->next_link(), "no loops!"); ! } ! } ! void ClassLoaderData::classes_do(void f(Klass * const)) { ! // Lock-free access requires load_acquire ! for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) { ! f(k); ! assert(k != k->next_link(), "no loops!"); } + } + + void ClassLoaderData::classes_do(void f(InstanceKlass*)) { + // Lock-free access requires load_acquire + for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) { + if (k->is_instance_klass()) { + f(InstanceKlass::cast(k)); } + assert(k != k->next_link(), "no loops!"); } } ! void ClassLoaderData::loaded_classes_do(KlassClosure* klass_closure) { ! // Lock-free access requires load_acquire ! for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) { ! // Do not filter ArrayKlass oops here... ! if (k->is_array_klass() || (k->is_instance_klass() && InstanceKlass::cast(k)->is_loaded())) { ! klass_closure->do_klass(k); } } } ! void ClassLoaderData::methods_do(void f(Method*)) { ! // Lock-free access requires load_acquire ! for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) { ! if (k->is_instance_klass() && InstanceKlass::cast(k)->is_loaded()) { ! InstanceKlass::cast(k)->methods_do(f); ! } ! } } ! void ClassLoaderData::modules_do(void f(ModuleEntry*)) { ! assert_locked_or_safepoint(Module_lock); ! if (_unnamed_module != NULL) { ! f(_unnamed_module); ! } ! if (_modules != NULL) { ! for (int i = 0; i < _modules->table_size(); i++) { ! for (ModuleEntry* entry = _modules->bucket(i); ! entry != NULL; ! entry = entry->next()) { ! f(entry); ! } ! } ! } } ! void ClassLoaderData::packages_do(void f(PackageEntry*)) { ! assert_locked_or_safepoint(Module_lock); if (_packages != NULL) { ! for (int i = 0; i < _packages->table_size(); i++) { ! for (PackageEntry* entry = _packages->bucket(i); ! entry != NULL; ! entry = entry->next()) { ! f(entry); } } } + } ! void ClassLoaderData::oops_do(OopClosure* f, bool must_claim, bool clear_mod_oops) { ! if (must_claim && !claim()) { ! return; } ! // Only clear modified_oops after the ClassLoaderData is claimed. ! if (clear_mod_oops) { ! clear_modified_oops(); } ! f->do_oop(&_class_loader); ! _dependencies.oops_do(f); ! _handles.oops_do(f); } ! // Unloading support ! oop ClassLoaderData::keep_alive_object() const { ! assert_locked_or_safepoint(_metaspace_lock); ! assert(!keep_alive(), "Don't use with CLDs that are artificially kept alive"); ! return is_anonymous() ? _klasses->java_mirror() : class_loader(); } ! bool ClassLoaderData::is_alive(BoolObjectClosure* is_alive_closure) const { ! return keep_alive() // null class loader and incomplete anonymous klasses. ! || is_alive_closure->do_object_b(keep_alive_object()); } ! // Anonymous classes have their own ClassLoaderData that is marked to keep alive ! // while the class is being parsed, and if the class appears on the module fixup list. ! // Due to the uniqueness that no other class shares the anonymous class' name or ! // ClassLoaderData, no other non-GC thread has knowledge of the anonymous class while ! // it is being defined, therefore _keep_alive is not volatile or atomic. ! void ClassLoaderData::inc_keep_alive() { ! if (is_anonymous()) { ! assert(_keep_alive >= 0, "Invalid keep alive increment count"); ! _keep_alive++; ! } ! } ! ! void ClassLoaderData::dec_keep_alive() { ! if (is_anonymous()) { ! assert(_keep_alive > 0, "Invalid keep alive decrement count"); ! _keep_alive--; ! } ! } ! ! bool ClassLoaderData::claim() { ! if (_claimed == 1) { ! return false; ! } ! ! return (int)Atomic::cmpxchg(1, &_claimed, 0) == 0; } Metaspace* ClassLoaderData::metaspace_non_null() { // If the metaspace has not been allocated, create a new one. Might want // to create smaller arena for Reflection class loaders also.
*** 724,734 **** if (metaspace == NULL) { MutexLockerEx ml(_metaspace_lock, Mutex::_no_safepoint_check_flag); // Check if _metaspace got allocated while we were waiting for this lock. if ((metaspace = _metaspace) == NULL) { if (this == the_null_class_loader_data()) { ! assert (class_loader() == NULL, "Must be"); metaspace = new Metaspace(_metaspace_lock, Metaspace::BootMetaspaceType); } else if (is_anonymous()) { if (class_loader() != NULL) { log_trace(class, loader, data)("is_anonymous: %s", class_loader()->klass()->internal_name()); } --- 650,660 ---- if (metaspace == NULL) { MutexLockerEx ml(_metaspace_lock, Mutex::_no_safepoint_check_flag); // Check if _metaspace got allocated while we were waiting for this lock. if ((metaspace = _metaspace) == NULL) { if (this == the_null_class_loader_data()) { ! assert(class_loader() == NULL, "Must be"); metaspace = new Metaspace(_metaspace_lock, Metaspace::BootMetaspaceType); } else if (is_anonymous()) { if (class_loader() != NULL) { log_trace(class, loader, data)("is_anonymous: %s", class_loader()->klass()->internal_name()); }
*** 746,755 **** --- 672,725 ---- } } return metaspace; } + // Returns true if this class loader data is for the system class loader. + bool ClassLoaderData::is_system_class_loader_data() const { + return SystemDictionary::is_system_class_loader(class_loader()); + } + + // Returns true if this class loader data is for the platform class loader. + bool ClassLoaderData::is_platform_class_loader_data() const { + return SystemDictionary::is_platform_class_loader(class_loader()); + } + + // Returns true if this class loader data is one of the 3 builtin + // (boot, application/system or platform) class loaders. Note, the + // builtin loaders are not freed by a GC. + bool ClassLoaderData::is_builtin_class_loader_data() const { + return (is_the_null_class_loader_data() || + SystemDictionary::is_system_class_loader(class_loader()) || + SystemDictionary::is_platform_class_loader(class_loader())); + } + + const char* ClassLoaderData::loader_name() { + // Handles null class loader + return SystemDictionary::loader_name(class_loader()); + } + + ModuleEntryTable* ClassLoaderData::modules() { + // Lazily create the module entry table at first request. + // Lock-free access requires load_acquire. + ModuleEntryTable* modules = OrderAccess::load_acquire(&_modules); + if (modules == NULL) { + MutexLocker m1(Module_lock); + // Check if _modules got allocated while we were waiting for this lock. + if ((modules = _modules) == NULL) { + modules = new ModuleEntryTable(ModuleEntryTable::_moduletable_entry_size); + + { + MutexLockerEx m1(metaspace_lock(), Mutex::_no_safepoint_check_flag); + // Ensure _modules is stable, since it is examined without a lock + OrderAccess::release_store(&_modules, modules); + } + } + } + return modules; + } + OopHandle ClassLoaderData::add_handle(Handle h) { MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag); record_modified_oops(); return OopHandle(_handles.add(h())); }
*** 781,870 **** } else { dest = _handles.add(h()); } } ! // Add this metadata pointer to be freed when it's safe. This is only during ! // class unloading because Handles might point to this metadata field. ! void ClassLoaderData::add_to_deallocate_list(Metadata* m) { ! // Metadata in shared region isn't deleted. ! if (!m->is_shared()) { MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag); ! if (_deallocate_list == NULL) { ! _deallocate_list = new (ResourceObj::C_HEAP, mtClass) GrowableArray<Metadata*>(100, true); } ! _deallocate_list->append_if_missing(m); } } ! // Deallocate free metadata on the free list. How useful the PermGen was! ! void ClassLoaderData::free_deallocate_list() { ! // Don't need lock, at safepoint assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint"); ! assert(!is_unloading(), "only called for ClassLoaderData that are not unloading"); ! if (_deallocate_list == NULL) { ! return; ! } ! // Go backwards because this removes entries that are freed. ! for (int i = _deallocate_list->length() - 1; i >= 0; i--) { ! Metadata* m = _deallocate_list->at(i); ! if (!m->on_stack()) { ! _deallocate_list->remove_at(i); ! // There are only three types of metadata that we deallocate directly. ! // Cast them so they can be used by the template function. ! if (m->is_method()) { ! MetadataFactory::free_metadata(this, (Method*)m); ! } else if (m->is_constantPool()) { ! MetadataFactory::free_metadata(this, (ConstantPool*)m); ! } else if (m->is_klass()) { ! MetadataFactory::free_metadata(this, (InstanceKlass*)m); } else { ! ShouldNotReachHere(); } ! } else { ! // Metadata is alive. ! // If scratch_class is on stack then it shouldn't be on this list! ! assert(!m->is_klass() || !((InstanceKlass*)m)->is_scratch_class(), ! "scratch classes on this list should be dead"); ! // Also should assert that other metadata on the list was found in handles. } } } ! // This is distinct from free_deallocate_list. For class loader data that are ! // unloading, this frees the C heap memory for constant pools on the list. If there ! // were C heap memory allocated for methods, it would free that too. The C heap memory ! // for InstanceKlasses on this list is freed in the ClassLoaderData destructor. ! void ClassLoaderData::unload_deallocate_list() { ! // Don't need lock, at safepoint ! assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint"); ! assert(is_unloading(), "only called for ClassLoaderData that are unloading"); ! if (_deallocate_list == NULL) { return; } ! // Go backwards because this removes entries that are freed. ! for (int i = _deallocate_list->length() - 1; i >= 0; i--) { ! Metadata* m = _deallocate_list->at(i); ! assert (!m->on_stack(), "wouldn't be unloading if this were so"); ! _deallocate_list->remove_at(i); ! // Only constant pool entries have C heap memory to free. ! if (m->is_constantPool()) { ! ((ConstantPool*)m)->release_C_heap_structures(); } } - } ! // These anonymous class loaders are to contain classes used for JSR292 ! ClassLoaderData* ClassLoaderData::anonymous_class_loader_data(oop loader, TRAPS) { ! // Add a new class loader data to the graph. ! Handle lh(THREAD, loader); ! return ClassLoaderDataGraph::add(lh, true, THREAD); } ! const char* ClassLoaderData::loader_name() { ! // Handles null class loader ! return SystemDictionary::loader_name(class_loader()); } #ifndef PRODUCT // Define to dump klasses #undef CLD_DUMP_KLASSES --- 751,870 ---- } else { dest = _handles.add(h()); } } ! void ClassLoaderData::add_class(Klass* k, bool publicize /* true */) { ! { MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag); ! Klass* old_value = _klasses; ! k->set_next_link(old_value); ! // Link the new item into the list, making sure the linked class is stable ! // since the list can be walked without a lock ! OrderAccess::release_store(&_klasses, k); } ! ! if (publicize && k->class_loader_data() != NULL) { ! ResourceMark rm; ! log_trace(class, loader, data)("Adding k: " PTR_FORMAT " %s to CLD: " ! PTR_FORMAT " loader: " PTR_FORMAT " %s", ! p2i(k), ! k->external_name(), ! p2i(k->class_loader_data()), ! p2i((void *)k->class_loader()), ! loader_name()); } } ! // Remove a klass from the _klasses list for scratch_class during redefinition ! // or parsed class in the case of an error. ! void ClassLoaderData::remove_class(Klass* scratch_class) { assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint"); ! ! // Adjust global class iterator. ! static_klass_iterator.adjust_saved_class(scratch_class); ! ! Klass* prev = NULL; ! for (Klass* k = _klasses; k != NULL; k = k->next_link()) { ! if (k == scratch_class) { ! if (prev == NULL) { ! _klasses = k->next_link(); } else { ! Klass* next = k->next_link(); ! prev->set_next_link(next); } ! return; } + prev = k; + assert(k != k->next_link(), "no loops!"); } + ShouldNotReachHere(); // should have found this class!! } ! bool ClassLoaderData::contains_klass(Klass* klass) { ! // Lock-free access requires load_acquire ! for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) { ! if (k == klass) return true; ! } ! return false; ! } ! ! void ClassLoaderData::record_dependency(const Klass* k, TRAPS) { ! assert(k != NULL, "invariant"); ! ! ClassLoaderData * const from_cld = this; ! ClassLoaderData * const to_cld = k->class_loader_data(); ! ! // Dependency to the null class loader data doesn't need to be recorded ! // because the null class loader data never goes away. ! if (to_cld->is_the_null_class_loader_data()) { return; } ! ! oop to; ! if (to_cld->is_anonymous()) { ! // Anonymous class dependencies are through the mirror. ! to = k->java_mirror(); ! } else { ! to = to_cld->class_loader(); ! ! // If from_cld is anonymous, even if it's class_loader is a parent of 'to' ! // we still have to add it. The class_loader won't keep from_cld alive. ! if (!from_cld->is_anonymous()) { ! // Check that this dependency isn't from the same or parent class_loader ! oop from = from_cld->class_loader(); ! ! oop curr = from; ! while (curr != NULL) { ! if (curr == to) { ! return; // this class loader is in the parent list, no need to add it. ! } ! curr = java_lang_ClassLoader::parent(curr); ! } } } ! // It's a dependency we won't find through GC, add it. This is relatively rare ! // Must handle over GC point. ! Handle dependency(THREAD, to); ! from_cld->_dependencies.add(dependency, CHECK); ! ! // Added a potentially young gen oop to the ClassLoaderData ! record_modified_oops(); } ! // Add this metadata pointer to be freed when it's safe. This is only during ! // class unloading because Handles might point to this metadata field. ! void ClassLoaderData::add_to_deallocate_list(Metadata* m) { ! // Metadata in shared region isn't deleted. ! if (!m->is_shared()) { ! MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag); ! if (_deallocate_list == NULL) { ! _deallocate_list = new (ResourceObj::C_HEAP, mtClass) GrowableArray<Metadata*>(100, true); ! } ! _deallocate_list->append_if_missing(m); ! } } #ifndef PRODUCT // Define to dump klasses #undef CLD_DUMP_KLASSES
*** 897,907 **** if (_jmethod_ids != NULL) { Method::print_jmethod_ids(this, out); } out->print_cr("}"); } - #endif // PRODUCT void ClassLoaderData::verify() { assert_locked_or_safepoint(_metaspace_lock); oop cl = class_loader(); --- 897,906 ----
*** 918,933 **** k->verify(); assert(k != k->next_link(), "no loops!"); } } ! bool ClassLoaderData::contains_klass(Klass* klass) { ! // Lock-free access requires load_acquire ! for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) { ! if (k == klass) return true; } - return false; } // GC root of class loader data created. ClassLoaderData* ClassLoaderDataGraph::_head = NULL; --- 917,944 ---- k->verify(); assert(k != k->next_link(), "no loops!"); } } ! #endif // !PRODUCT ! ! void ClassLoaderData::print_value_on(outputStream* out) const { ! if (class_loader() == NULL) { ! out->print("NULL class loader"); ! } else { ! out->print("class loader " INTPTR_FORMAT " ", p2i(this)); ! class_loader()->print_value_on(out); ! } ! } ! ! void ClassLoaderData::print_on(outputStream* out) const { ! if (class_loader() == NULL) { ! out->print("NULL class loader"); ! } else { ! out->print("class loader " INTPTR_FORMAT " ", p2i(this)); ! class_loader()->print_on(out); } } // GC root of class loader data created. ClassLoaderData* ClassLoaderDataGraph::_head = NULL;
*** 936,945 **** --- 947,985 ---- ClassLoaderData* ClassLoaderDataGraph::_saved_head = NULL; bool ClassLoaderDataGraph::_should_purge = false; bool ClassLoaderDataGraph::_metaspace_oom = false; + static void print_creation(outputStream* out, Handle loader, ClassLoaderData* cld, TRAPS) { + Handle string; + if (loader.not_null()) { + // Include the result of loader.toString() in the output. This allows + // the user of the log to identify the class loader instance. + JavaValue result(T_OBJECT); + Klass* spec_klass = SystemDictionary::ClassLoader_klass(); + JavaCalls::call_virtual(&result, + loader, + spec_klass, + vmSymbols::toString_name(), + vmSymbols::void_string_signature(), + CHECK); + assert(result.get_type() == T_OBJECT, "just checking"); + string = Handle(THREAD, (oop)result.get_jobject()); + } + + ResourceMark rm; + out->print("create class loader data " INTPTR_FORMAT, p2i(cld)); + out->print(" for instance " INTPTR_FORMAT " of %s", p2i((void *)cld->class_loader()), + cld->loader_name()); + + if (string.not_null()) { + out->print(": "); + java_lang_String::print(string(), out); + } + out->cr(); + } + // 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(Handle loader, bool is_anonymous, TRAPS) { // We need to allocate all the oops for the ClassLoaderData before allocating the // actual ClassLoaderData object.
*** 982,1021 **** } next = exchanged; } while (true); } - void ClassLoaderDataGraph::print_creation(outputStream* out, Handle loader, ClassLoaderData* cld, TRAPS) { - Handle string; - if (loader.not_null()) { - // Include the result of loader.toString() in the output. This allows - // the user of the log to identify the class loader instance. - JavaValue result(T_OBJECT); - Klass* spec_klass = SystemDictionary::ClassLoader_klass(); - JavaCalls::call_virtual(&result, - loader, - spec_klass, - vmSymbols::toString_name(), - vmSymbols::void_string_signature(), - CHECK); - assert(result.get_type() == T_OBJECT, "just checking"); - string = Handle(THREAD, (oop)result.get_jobject()); - } - - ResourceMark rm; - out->print("create class loader data " INTPTR_FORMAT, p2i(cld)); - out->print(" for instance " INTPTR_FORMAT " of %s", p2i((void *)cld->class_loader()), - cld->loader_name()); - - if (string.not_null()) { - out->print(": "); - java_lang_String::print(string(), out); - } - out->cr(); - } - - void ClassLoaderDataGraph::oops_do(OopClosure* f, bool must_claim) { for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { cld->oops_do(f, must_claim); } } --- 1022,1031 ----
*** 1224,1245 **** } } return false; } ! #ifndef PRODUCT ! bool ClassLoaderDataGraph::contains_loader_data(ClassLoaderData* loader_data) { ! 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(BoolObjectClosure* is_alive_closure, bool clean_previous_versions) { --- 1234,1267 ---- } } return false; } ! #if INCLUDE_TRACE ! static Ticks class_unload_time; ! static void post_class_unload_event(Klass* const k) { ! assert(k != NULL, "invariant"); ! EventClassUnload event(UNTIMED); ! event.set_endtime(class_unload_time); ! event.set_unloadedClass(k); ! event.set_definingClassLoader(k->class_loader_data()); ! event.commit(); ! } ! #endif // INCLUDE_TRACE ! ! static void post_class_unload_events() { ! #if INCLUDE_TRACE ! assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!"); ! if (Tracing::enabled()) { ! if (Tracing::is_event_enabled(TraceClassUnloadEvent)) { ! class_unload_time = Ticks::now(); ! ClassLoaderDataGraph::classes_unloading_do(&post_class_unload_event); } + Tracing::on_unloading_classes(); } ! #endif // INCLUDE_TRACE } // Move class loader data from main list to the unloaded list for unloading // and deallocation later. bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure, bool clean_previous_versions) {
*** 1335,1344 **** --- 1357,1372 ---- Metaspace::purge(); set_metaspace_oom(false); } } + void ClassLoaderDataGraph::clear_claimed_marks() { + for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { + cld->clear_claimed(); + } + } + 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) {
*** 1348,1371 **** } } return resized; } ! void ClassLoaderDataGraph::post_class_unload_events() { ! #if INCLUDE_TRACE ! assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!"); ! if (Tracing::enabled()) { ! if (Tracing::is_event_enabled(TraceClassUnloadEvent)) { ! assert(_unloading != NULL, "need class loader data unload list!"); ! _class_unload_time = Ticks::now(); ! classes_unloading_do(&class_unload_event); } ! Tracing::on_unloading_classes(); } ! #endif } ClassLoaderDataGraphKlassIteratorAtomic::ClassLoaderDataGraphKlassIteratorAtomic() : _next_klass(NULL) { ClassLoaderData* cld = ClassLoaderDataGraph::_head; Klass* klass = NULL; --- 1376,1420 ---- } } return resized; } ! InstanceKlass* ClassLoaderDataGraph::try_get_next_class() { ! return static_klass_iterator.try_get_next_class(); ! } ! ! #ifndef PRODUCT ! void ClassLoaderDataGraph::verify() { ! for (ClassLoaderData* data = _head; data != NULL; data = data->next()) { ! data->verify(); } ! } ! ! void ClassLoaderDataGraph::dump_on(outputStream * const out) { ! for (ClassLoaderData* data = _head; data != NULL; data = data->next()) { ! data->dump(out); } ! MetaspaceAux::dump(out); ! } ! ! bool ClassLoaderDataGraph::contains_loader_data(ClassLoaderData* loader_data) { ! for (ClassLoaderData* data = _head; data != NULL; data = data->next()) { ! if (loader_data == data) { ! return true; ! } ! } ! return false; } + // callable from debugger + extern "C" int print_loader_data_graph() { + ClassLoaderDataGraph::dump_on(tty); + return 0; + } + + #endif // !PRODUCT + ClassLoaderDataGraphKlassIteratorAtomic::ClassLoaderDataGraphKlassIteratorAtomic() : _next_klass(NULL) { ClassLoaderData* cld = ClassLoaderDataGraph::_head; Klass* klass = NULL;
*** 1419,1484 **** // Nothing more for the iterator to hand out. assert(head == NULL, "head is " PTR_FORMAT ", expected not null:", p2i(head)); return NULL; } ! ClassLoaderDataGraphMetaspaceIterator::ClassLoaderDataGraphMetaspaceIterator() { ! _data = ClassLoaderDataGraph::_head; ! } ! ! ClassLoaderDataGraphMetaspaceIterator::~ClassLoaderDataGraphMetaspaceIterator() {} ! ! #ifndef PRODUCT ! // callable from debugger ! extern "C" int print_loader_data_graph() { ! ClassLoaderDataGraph::dump_on(tty); ! return 0; ! } ! ! void ClassLoaderDataGraph::verify() { ! for (ClassLoaderData* data = _head; data != NULL; data = data->next()) { ! data->verify(); ! } ! } ! ! void ClassLoaderDataGraph::dump_on(outputStream * const out) { ! for (ClassLoaderData* data = _head; data != NULL; data = data->next()) { ! data->dump(out); ! } ! MetaspaceAux::dump(out); ! } ! #endif // PRODUCT ! ! void ClassLoaderData::print_value_on(outputStream* out) const { ! if (class_loader() == NULL) { ! out->print("NULL class loader"); ! } else { ! out->print("class loader " INTPTR_FORMAT " ", p2i(this)); ! class_loader()->print_value_on(out); ! } } - - void ClassLoaderData::print_on(outputStream* out) const { - if (class_loader() == NULL) { - out->print("NULL class loader"); - } else { - out->print("class loader " INTPTR_FORMAT " ", p2i(this)); - class_loader()->print_on(out); - } - } - - #if INCLUDE_TRACE - - Ticks ClassLoaderDataGraph::_class_unload_time; - - void ClassLoaderDataGraph::class_unload_event(Klass* const k) { - assert(k != NULL, "invariant"); - - // post class unload event - EventClassUnload event(UNTIMED); - event.set_endtime(_class_unload_time); - event.set_unloadedClass(k); - event.set_definingClassLoader(k->class_loader_data()); - event.commit(); - } - - #endif // INCLUDE_TRACE --- 1468,1475 ---- // Nothing more for the iterator to hand out. assert(head == NULL, "head is " PTR_FORMAT ", expected not null:", p2i(head)); return NULL; } ! ClassLoaderDataGraphMetaspaceIterator::ClassLoaderDataGraphMetaspaceIterator() : ! _data(ClassLoaderDataGraph::_head) { }
< prev index next >