--- old/src/hotspot/share/classfile/classLoaderHierarchyDCmd.cpp 2018-06-05 19:29:33.202025799 +0200 +++ new/src/hotspot/share/classfile/classLoaderHierarchyDCmd.cpp 2018-06-05 19:29:33.098024794 +0200 @@ -29,6 +29,7 @@ #include "classfile/classLoaderHierarchyDCmd.hpp" #include "memory/allocation.hpp" #include "memory/resourceArea.hpp" +#include "runtime/safepoint.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" @@ -55,7 +56,7 @@ } // Helper class for drawing the branches to the left of a node. -class BranchTracker { +class BranchTracker : public StackObj { // "" // " |---" // " | | @@ -113,7 +114,7 @@ }; // end: BranchTracker -struct LoadedClassInfo : public CHeapObj { +struct LoadedClassInfo : public ResourceObj { public: LoadedClassInfo* _next; Klass* const _klass; @@ -125,7 +126,13 @@ }; -class LoaderTreeNode : public CHeapObj { +class LoaderTreeNode : public ResourceObj { + + // We walk the CLDG and, for each CLD which is non-anonymous, add + // a tree node. To add a node we need its parent node; if it itself + // does not exist yet, we add a preliminary node for it. This preliminary + // node just contains its loader oop; later, when encountering its CLD in + // our CLDG walk, we complete the missing information in this node. const oop _loader_oop; const ClassLoaderData* _cld; @@ -144,45 +151,39 @@ { ResourceMark rm; - // Retrieve information. - const Klass* loader_klass = NULL; - const char* loader_name = NULL; - const char* loader_class_name = NULL; - - if (_loader_oop != NULL) { - loader_klass = _loader_oop->klass(); - if (loader_klass != NULL) { - loader_class_name = loader_klass->external_name(); - } - oop nameOop = java_lang_ClassLoader::name(_loader_oop); - if (nameOop != NULL) { - const char* s = java_lang_String::as_utf8_string(nameOop); - if (s != NULL) { - loader_name = s; - } - } - } else { - // Boot loader - loader_name = ""; + if (_cld == NULL) { + // Not sure how this could happen: we added a preliminary node for a parent but then never encountered + // its CLD? + return; } + // Retrieve information. + const Klass* const loader_klass = _cld->class_loader_klass(); + const Symbol* const loader_name = _cld->class_loader_name(); + branchtracker.print(st); - // e.g. "+--- ABC (instance of DEF)" - st->print("+%.*s ", BranchTracker::twiglen, "----------"); - st->print("%s", loader_name != NULL ? loader_name : ""); - if (loader_class_name != NULL) { - st->print(" (instance of %s)", loader_class_name); + // e.g. "+--- jdk.internal.reflect.DelegatingClassLoader" + st->print("+%.*s", BranchTracker::twiglen, "----------"); + if (_cld->is_the_null_class_loader_data()) { + st->print(" "); + } else { + if (loader_name != NULL) { + st->print(" \"%s\",", loader_name->as_C_string()); + } + st->print(" %s", loader_klass != NULL ? loader_klass->external_name() : "??"); + st->print(" {" PTR_FORMAT "}", p2i(_loader_oop)); } st->cr(); + // Output following this node (node details and child nodes) - up to the next sibling node + // needs to be prefixed with "|" if there is a follow up sibling. const bool have_sibling = _next != NULL; BranchTracker::Mark trm(branchtracker, have_sibling); - // Area below class loader name, but not belonging to child nodes. Here - // we print additional infos about the loader (e..g. loaded classes). - { + // optional node details following this node needs to be prefixed with "|" + // if there are follow up child nodes. const bool have_child = _child != NULL; BranchTracker::Mark trm(branchtracker, have_child); @@ -190,15 +191,13 @@ branchtracker.print(st); st->cr(); - const int indentation = 22; + const int indentation = 18; if (verbose) { branchtracker.print(st); - st->print_cr("%*s " PTR_FORMAT, indentation, "CLD:", p2i(_cld)); + st->print_cr("%*s " PTR_FORMAT, indentation, "Loader Data:", p2i(_cld)); branchtracker.print(st); st->print_cr("%*s " PTR_FORMAT, indentation, "Loader Klass:", p2i(loader_klass)); - branchtracker.print(st); - st->print_cr("%*s " PTR_FORMAT, indentation, "Loader Oop:", p2i(_loader_oop)); // Empty line branchtracker.print(st); @@ -247,7 +246,7 @@ } branchtracker.print(st); st->print("%*s ", indentation, ""); - st->print_cr("(%u anononymous class%s)", _num_anon_classes, (_num_anon_classes == 1) ? "" : "es"); + st->print_cr("(%u anonymous class%s)", _num_anon_classes, (_num_anon_classes == 1) ? "" : "es"); // Empty line branchtracker.print(st); @@ -267,24 +266,6 @@ } - void free_child_nodes() { - LoaderTreeNode* c = _child; - while (c) { - LoaderTreeNode* next = c->_next; - delete c; - c = next; - } - } - - void free_class_info_list(LoadedClassInfo* first) { - LoadedClassInfo* p = first; - while (p) { - LoadedClassInfo* next = p->_next; - delete p; - p = next; - } - } - public: LoaderTreeNode(const oop loader_oop) @@ -294,12 +275,6 @@ , _num_classes(0), _num_anon_classes(0) {} - ~LoaderTreeNode() { - free_child_nodes(); - free_class_info_list(_classes); - free_class_info_list(_anon_classes); - } - void set_cld(const ClassLoaderData* cld) { _cld = cld; } void add_child(LoaderTreeNode* info) { @@ -359,7 +334,6 @@ LoadedClassCollectClosure(const ClassLoaderData* cld) : _list(NULL), _cld(cld), _num_classes(0) {} void do_klass(Klass* k) { - ResourceMark rm; LoadedClassInfo* lki = new LoadedClassInfo(k, _cld); lki->_next = _list; _list = lki; @@ -422,10 +396,6 @@ _root = new LoaderTreeNode(NULL); } - ~LoaderInfoScanClosure() { - delete _root; - } - void print_results(outputStream* st) const { _root->print_with_childs(st, _print_classes, _verbose); } @@ -469,15 +439,15 @@ } void doit() { + assert(SafepointSynchronize::is_at_safepoint(), "must be a safepoint"); + ResourceMark rm; LoaderInfoScanClosure cl (_show_classes, _verbose); ClassLoaderDataGraph::cld_do(&cl); cl.print_results(_out); } - }; - - +// This command needs to be executed at a safepoint. void ClassLoaderHierarchyDCmd::execute(DCmdSource source, TRAPS) { ClassLoaderHierarchyVMOperation op(output(), _show_classes.value(), _verbose.value()); VMThread::execute(&op);