< prev index next >

src/hotspot/share/classfile/classLoaderHierarchyDCmd.cpp

Print this page
rev 50411 : imported patch 8203682-jcmd-print-classloader-hierarchy
rev 50412 : [mq]: 8203682-jcmd-print-classloader-hierarchy-delta

@@ -27,10 +27,11 @@
 
 #include "classfile/classLoaderData.inline.hpp"
 #include "classfile/classLoaderHierarchyDCmd.hpp"
 #include "memory/allocation.hpp"
 #include "memory/resourceArea.hpp"
+#include "runtime/safepoint.hpp"
 #include "utilities/globalDefinitions.hpp"
 #include "utilities/ostream.hpp"
 
 
 ClassLoaderHierarchyDCmd::ClassLoaderHierarchyDCmd(outputStream* output, bool heap)

@@ -53,11 +54,11 @@
     return 0;
   }
 }
 
 // Helper class for drawing the branches to the left of a node.
-class BranchTracker {
+class BranchTracker : public StackObj {
   //       "<x>"
   //       " |---<y>"
   //       " |    |
   //       " |   <z>"
   //       " |    |---<z1>

@@ -111,11 +112,11 @@
     ~Mark() { _tr.pop(); }
   };
 
 }; // end: BranchTracker
 
-struct LoadedClassInfo : public CHeapObj<mtInternal> {
+struct LoadedClassInfo : public ResourceObj {
 public:
   LoadedClassInfo* _next;
   Klass* const _klass;
   const ClassLoaderData* const _cld;
 

@@ -123,11 +124,17 @@
     : _klass(klass), _cld(cld)
   {}
 
 };
 
-class LoaderTreeNode : public CHeapObj<mtInternal> {
+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;
 
   LoaderTreeNode* _child;

@@ -142,65 +149,57 @@
   void print_with_childs(outputStream* st, BranchTracker& branchtracker,
       bool print_classes, bool verbose) const
   {
     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 = "<bootstrap>";
+    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 : "<unnamed>");
-    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(" <bootstrap>");
+    } 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);
 
       // Empty line
       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);
         st->cr();
       }

@@ -245,11 +244,11 @@
             }
             st->cr();
           }
           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);
           st->cr();
         }

@@ -265,43 +264,19 @@
       c = c->_next;
     }
 
   }
 
-  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)
     : _loader_oop(loader_oop), _cld(NULL)
     , _child(NULL), _next(NULL)
     , _classes(NULL), _anon_classes(NULL)
     , _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) {
     info->_next = _child;
     _child = info;

@@ -357,11 +332,10 @@
   const ClassLoaderData* _cld;
   int _num_classes;
   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;
     _num_classes ++;
   }

@@ -420,14 +394,10 @@
     : _print_classes(print_classes), _verbose(verbose), _root(NULL)
   {
     _root = new LoaderTreeNode(NULL);
   }
 
-  ~LoaderInfoScanClosure() {
-    delete _root;
-  }
-
   void print_results(outputStream* st) const {
     _root->print_with_childs(st, _print_classes, _verbose);
   }
 
   void do_cld (ClassLoaderData* cld) {

@@ -467,18 +437,18 @@
   VMOp_Type type() const {
     return VMOp_ClassLoaderHierarchyOperation;
   }
 
   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);
 }
< prev index next >