< prev index next >

src/hotspot/share/classfile/classLoaderData.cpp

Print this page

        

*** 83,104 **** 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(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 --- 83,122 ---- volatile size_t ClassLoaderDataGraph::_num_array_classes = 0; volatile size_t ClassLoaderDataGraph::_num_instance_classes = 0; ClassLoaderData * ClassLoaderData::_the_null_class_loader_data = NULL; ! void ClassLoaderData::init_null_class_loader_data() { ! assert(_the_null_class_loader_data == NULL, "cannot initialize twice"); ! assert(ClassLoaderDataGraph::_head == NULL, "cannot initialize twice"); ! ! _the_null_class_loader_data = new ClassLoaderData(Handle(), false); ! ClassLoaderDataGraph::_head = _the_null_class_loader_data; ! assert(_the_null_class_loader_data->is_the_null_class_loader_data(), "Must be"); ! ! LogTarget(Debug, class, loader, data) lt; ! if (lt.is_enabled()) { ! ResourceMark rm; ! LogStream ls(lt); ! ls.print("create "); ! _the_null_class_loader_data->print_value_on(&ls); ! ls.cr(); ! } ! } ! ! ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous) : _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), _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
*** 110,141 **** _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) { --- 128,147 ---- _unnamed_module = ModuleEntry::create_boot_unnamed_module(this); } else { // Create unnamed module for all other loaders _unnamed_module = ModuleEntry::create_unnamed_module(this); } _dictionary = create_dictionary(); } else { + _packages = NULL; + _unnamed_module = NULL; _dictionary = NULL; } ! NOT_PRODUCT(_dependency_count = 0); // number of class loader dependencies ! TRACE_INIT_ID(this); } ClassLoaderData::ChunkedHandleList::~ChunkedHandleList() { Chunk* c = _head; while (c != NULL) {
*** 154,163 **** --- 160,179 ---- *handle = o; OrderAccess::release_store(&_head->_size, _head->_size + 1); return handle; } + int ClassLoaderData::ChunkedHandleList::count() const { + int count = 0; + Chunk* chunk = _head; + while (chunk != NULL) { + count += chunk->_size; + chunk = chunk->_next; + } + return count; + } + 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]); }
*** 173,192 **** 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; } } void do_oop(narrowOop* p) { --- 189,207 ---- oops_do_chunk(f, c, c->_size); } } } class VerifyContainsOopClosure : public OopClosure { ! oop _target; bool _found; public: ! VerifyContainsOopClosure(oop target) : _target(target), _found(false) {} void do_oop(oop* p) { ! if (p != NULL && *p == _target) { _found = true; } } void do_oop(narrowOop* p) {
*** 197,212 **** bool found() const { return _found; } }; ! bool ClassLoaderData::ChunkedHandleList::contains(oop* p) { VerifyContainsOopClosure cl(p); oops_do(&cl); return cl.found(); } - #endif // ASSERT bool ClassLoaderData::claim() { if (_claimed == 1) { return false; } --- 212,226 ---- bool found() const { return _found; } }; ! bool ClassLoaderData::ChunkedHandleList::contains(oop p) { VerifyContainsOopClosure cl(p); oops_do(&cl); return cl.found(); } bool ClassLoaderData::claim() { if (_claimed == 1) { return false; }
*** 242,259 **** 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!"); --- 256,268 ----
*** 324,334 **** } } } } ! 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(); --- 333,343 ---- } } } } ! void ClassLoaderData::record_dependency(const Klass* k) { assert(k != NULL, "invariant"); ClassLoaderData * const from_cld = this; ClassLoaderData * const to_cld = k->class_loader_data();
*** 359,438 **** if (from == to || java_lang_ClassLoader::isAncestor(from, to)) { return; // this class loader is in the parent list, no need to add it. } } ! // 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(); } --- 368,397 ---- if (from == to || java_lang_ClassLoader::isAncestor(from, to)) { return; // this class loader is in the parent list, no need to add it. } } ! // It's a dependency we won't find through GC, add it. ! if (!_handles.contains(to)) { ! NOT_PRODUCT(Atomic::inc(&_dependency_count)); ! LogTarget(Trace, class, loader, data) lt; ! if (lt.is_enabled()) { ! ResourceMark rm; ! LogStream ls(lt); ! ls.print("adding dependency from "); ! print_value_on(&ls); ! ls.print(" to "); ! to_cld->print_value_on(&ls); ! ls.cr(); ! } ! Handle dependency(Thread::current(), to); ! add_handle(dependency); // Added a potentially young gen oop to the ClassLoaderData record_modified_oops(); } } void ClassLoaderDataGraph::clear_claimed_marks() { for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { cld->clear_claimed(); }
*** 451,469 **** } else { ClassLoaderDataGraph::inc_instance_classes(1); } } ! 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. --- 410,428 ---- } else { ClassLoaderDataGraph::inc_instance_classes(1); } } ! if (publicize) { ! LogTarget(Trace, class, loader, data) lt; ! if (lt.is_enabled()) { ResourceMark rm; ! LogStream ls(lt); ! ls.print("Adding k: " PTR_FORMAT " %s to ", p2i(k), k->external_name()); ! print_value_on(&ls); ! ls.cr(); ! } } } // Class iterator used by the compiler. It gets some number of classes at // a safepoint to decay invocation counters on the methods.
*** 576,591 **** LogTarget(Debug, class, loader, data) lt; if (lt.is_enabled()) { ResourceMark rm; LogStream ls(lt); ! ls.print(": unload loader data " INTPTR_FORMAT, p2i(this)); ! ls.print(" for instance " INTPTR_FORMAT " of %s", p2i((void *)class_loader()), ! loader_name()); ! if (is_anonymous()) { ! ls.print(" for anonymous class " INTPTR_FORMAT " ", p2i(_klasses)); ! } ls.cr(); } // Some items on the _deallocate_list need to free their C heap structures // if they are not already on the _klasses list. --- 535,546 ---- LogTarget(Debug, class, loader, data) lt; if (lt.is_enabled()) { ResourceMark rm; LogStream ls(lt); ! ls.print("unload "); ! print_value_on(&ls); ls.cr(); } // Some items on the _deallocate_list need to free their C heap structures // if they are not already on the _klasses list.
*** 777,794 **** 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()); - } metaspace = new Metaspace(_metaspace_lock, Metaspace::AnonymousMetaspaceType); } else if (class_loader()->is_a(SystemDictionary::reflect_DelegatingClassLoader_klass())) { - if (class_loader() != NULL) { - log_trace(class, loader, data)("is_reflection: %s", class_loader()->klass()->internal_name()); - } metaspace = new Metaspace(_metaspace_lock, Metaspace::ReflectionMetaspaceType); } else { metaspace = new Metaspace(_metaspace_lock, Metaspace::StandardMetaspaceType); } // Ensure _metaspace is stable, since it is examined without a lock --- 732,743 ----
*** 806,816 **** void ClassLoaderData::remove_handle(OopHandle h) { assert(!is_unloading(), "Do not remove a handle for a CLD that is unloading"); oop* ptr = h.ptr_raw(); if (ptr != NULL) { ! assert(_handles.contains(ptr), "Got unexpected handle " PTR_FORMAT, p2i(ptr)); // This root is not walked in safepoints, and hence requires an appropriate // decorator that e.g. maintains the SATB invariant in SATB collectors. RootAccess<IN_CONCURRENT_ROOT>::oop_store(ptr, oop(NULL)); } } --- 755,765 ---- void ClassLoaderData::remove_handle(OopHandle h) { assert(!is_unloading(), "Do not remove a handle for a CLD that is unloading"); oop* ptr = h.ptr_raw(); if (ptr != NULL) { ! assert(_handles.contains(*ptr), "Got unexpected handle " PTR_FORMAT, p2i(ptr)); // This root is not walked in safepoints, and hence requires an appropriate // decorator that e.g. maintains the SATB invariant in SATB collectors. RootAccess<IN_CONCURRENT_ROOT>::oop_store(ptr, oop(NULL)); } }
*** 900,952 **** } } } // 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 ! void ClassLoaderData::dump(outputStream * const out) { ! out->print("ClassLoaderData CLD: " PTR_FORMAT ", loader: " PTR_FORMAT ", loader_klass: " PTR_FORMAT " %s {", ! p2i(this), p2i((void *)class_loader()), ! p2i(class_loader() != NULL ? class_loader()->klass() : NULL), loader_name()); ! if (claimed()) out->print(" claimed "); ! if (is_unloading()) out->print(" unloading "); ! out->cr(); ! if (metaspace_or_null() != NULL) { ! out->print_cr("metaspace: " INTPTR_FORMAT, p2i(metaspace_or_null())); ! metaspace_or_null()->dump(out); } else { ! out->print_cr("metaspace: NULL"); ! } ! ! #ifdef CLD_DUMP_KLASSES ! if (Verbose) { ! Klass* k = _klasses; ! while (k != NULL) { ! out->print_cr("klass " PTR_FORMAT ", %s", p2i(k), k->name()->as_C_string()); ! assert(k != k->next_link(), "no loops!"); ! k = k->next_link(); } } ! #endif // CLD_DUMP_KLASSES ! #undef CLD_DUMP_KLASSES if (_jmethod_ids != NULL) { Method::print_jmethod_ids(this, out); } out->print_cr("}"); } #endif // PRODUCT void ClassLoaderData::verify() { --- 849,896 ---- } } } // These anonymous class loaders are to contain classes used for JSR292 ! ClassLoaderData* ClassLoaderData::anonymous_class_loader_data(Handle loader) { // Add a new class loader data to the graph. ! return ClassLoaderDataGraph::add(loader, true); } ! const char* ClassLoaderData::loader_name() const { // Handles null class loader return SystemDictionary::loader_name(class_loader()); } ! void ClassLoaderData::print_value_on(outputStream* out) const { ! if (class_loader() != NULL) { ! out->print("loader data: " INTPTR_FORMAT " for instance ", p2i(this)); ! class_loader()->print_value_on(out); // includes loader_name() and address of class loader instance } else { ! // loader data: 0xsomeaddr of <bootloader> ! out->print("loader data: " INTPTR_FORMAT " of %s", p2i(this), loader_name()); } + if (is_anonymous()) { + out->print(" anonymous"); } ! } ! ! #ifndef PRODUCT ! void ClassLoaderData::print_on(outputStream* out) const { ! out->print("ClassLoaderData CLD: " PTR_FORMAT ", loader: " PTR_FORMAT ", loader_klass: %s {", ! p2i(this), p2i((void *)class_loader()), loader_name()); ! if (is_anonymous()) out->print(" anonymous"); ! if (claimed()) out->print(" claimed"); ! if (is_unloading()) out->print(" unloading"); ! out->print(" metaspace: " INTPTR_FORMAT, p2i(metaspace_or_null())); ! if (_jmethod_ids != NULL) { Method::print_jmethod_ids(this, out); } + out->print(" handles count %d", _handles.count()); + out->print(" dependencies %d", _dependency_count); out->print_cr("}"); } #endif // PRODUCT void ClassLoaderData::verify() {
*** 986,1005 **** bool ClassLoaderDataGraph::_should_purge = 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(Handle loader, bool is_anonymous, TRAPS) { ! // We need to allocate all the oops for the ClassLoaderData before allocating the ! // actual ClassLoaderData object. ! ClassLoaderData::Dependencies dependencies(CHECK_NULL); ! NoSafepointVerifier no_safepoints; // we mustn't GC until we've installed the // ClassLoaderData in the graph since the CLD // contains unhandled oops ! ClassLoaderData* cld = new ClassLoaderData(loader, is_anonymous, dependencies); if (!is_anonymous) { // First, Atomically set it ClassLoaderData* old = java_lang_ClassLoader::cmpxchg_loader_data(cld, loader(), NULL); --- 930,945 ---- bool ClassLoaderDataGraph::_should_purge = 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(Handle loader, bool is_anonymous) { NoSafepointVerifier no_safepoints; // we mustn't GC until we've installed the // ClassLoaderData in the graph since the CLD // contains unhandled oops ! ClassLoaderData* cld = new ClassLoaderData(loader, is_anonymous); if (!is_anonymous) { // First, Atomically set it ClassLoaderData* old = java_lang_ClassLoader::cmpxchg_loader_data(cld, loader(), NULL);
*** 1019,1068 **** cld->set_next(next); ClassLoaderData* exchanged = Atomic::cmpxchg(cld, list_head, next); if (exchanged == next) { LogTarget(Debug, class, loader, data) lt; if (lt.is_enabled()) { ! PauseNoSafepointVerifier pnsv(&no_safepoints); // Need safe points for JavaCalls::call_virtual LogStream ls(lt); ! print_creation(&ls, loader, cld, CHECK_NULL); } return cld; } 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); } } --- 959,980 ---- cld->set_next(next); ClassLoaderData* exchanged = Atomic::cmpxchg(cld, list_head, next); if (exchanged == next) { LogTarget(Debug, 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; } next = exchanged; } while (true); } void ClassLoaderDataGraph::oops_do(OopClosure* f, bool must_claim) { for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { cld->oops_do(f, must_claim); } }
*** 1475,1520 **** 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) { --- 1387,1414 ---- 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() { for (ClassLoaderData* data = _head; data != NULL; data = data->next()) { data->verify(); } } ! void ClassLoaderDataGraph::print_on(outputStream * const out) { for (ClassLoaderData* data = _head; data != NULL; data = data->next()) { ! data->print_on(out); } } #endif // PRODUCT #if INCLUDE_TRACE Ticks ClassLoaderDataGraph::_class_unload_time; void ClassLoaderDataGraph::class_unload_event(Klass* const k) {
< prev index next >