1 /*
   2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2018 SAP SE. All rights reserved.
   4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5  *
   6  * This code is free software; you can redistribute it and/or modify it
   7  * under the terms of the GNU General Public License version 2 only, as
   8  * published by the Free Software Foundation.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  *
  24  */
  25 
  26 #include "precompiled.hpp"
  27 
  28 #include "classfile/classLoaderData.inline.hpp"
  29 #include "classfile/classLoaderHierarchyDCmd.hpp"
  30 #include "memory/allocation.hpp"
  31 #include "memory/resourceArea.hpp"
  32 #include "runtime/safepoint.hpp"
  33 #include "utilities/globalDefinitions.hpp"
  34 #include "utilities/ostream.hpp"
  35 
  36 
  37 ClassLoaderHierarchyDCmd::ClassLoaderHierarchyDCmd(outputStream* output, bool heap)
  38   : DCmdWithParser(output, heap)
  39   , _show_classes("show-classes", "Print loaded classes.", "BOOLEAN", false, "false")
  40   , _verbose("verbose", "Print detailed information.", "BOOLEAN", false, "false") {
  41   _dcmdparser.add_dcmd_option(&_show_classes);
  42   _dcmdparser.add_dcmd_option(&_verbose);
  43 }
  44 
  45 
  46 int ClassLoaderHierarchyDCmd::num_arguments() {
  47   ResourceMark rm;
  48   ClassLoaderHierarchyDCmd* dcmd = new ClassLoaderHierarchyDCmd(NULL, false);
  49   if (dcmd != NULL) {
  50     DCmdMark mark(dcmd);
  51     return dcmd->_dcmdparser.num_arguments();
  52   } else {
  53     return 0;
  54   }
  55 }
  56 
  57 // Helper class for drawing the branches to the left of a node.
  58 class BranchTracker : public StackObj {
  59   //       "<x>"
  60   //       " |---<y>"
  61   //       " |    |
  62   //       " |   <z>"
  63   //       " |    |---<z1>
  64   //       " |    |---<z2>
  65   //       ^^^^^^^ ^^^
  66   //        A       B
  67 
  68   // Some terms for the graphics:
  69   // - branch: vertical connection between a node's ancestor to a later sibling.
  70   // - branchwork: (A) the string to print as a prefix at the start of each line, contains all branches.
  71   // - twig (B): Length of the dashed line connecting a node to its branch.
  72   // - branch spacing: how many spaces between branches are printed.
  73 
  74 public:
  75 
  76   enum { max_depth = 64, twig_len = 2, branch_spacing = 5 };
  77 
  78 private:
  79 
  80   char _branches[max_depth];
  81   int _pos;
  82 
  83 public:
  84   BranchTracker()
  85     : _pos(0) {}
  86 
  87   void push(bool has_branch) {
  88     if (_pos < max_depth) {
  89       _branches[_pos] = has_branch ? '|' : ' ';
  90     }
  91     _pos ++; // beyond max depth, omit branch drawing but do count on.
  92   }
  93 
  94   void pop() {
  95     assert(_pos > 0, "must be");
  96     _pos --;
  97   }
  98 
  99   void print(outputStream* st) {
 100     for (int i = 0; i < _pos; i ++) {
 101       st->print("%c%.*s", _branches[i], branch_spacing, "          ");
 102     }
 103   }
 104 
 105   class Mark {
 106     BranchTracker& _tr;
 107   public:
 108     Mark(BranchTracker& tr, bool has_branch_here)
 109       : _tr(tr)  { _tr.push(has_branch_here); }
 110     ~Mark() { _tr.pop(); }
 111   };
 112 
 113 }; // end: BranchTracker
 114 
 115 struct LoadedClassInfo : public ResourceObj {
 116 public:
 117   LoadedClassInfo* _next;
 118   Klass* const _klass;
 119   const ClassLoaderData* const _cld;
 120 
 121   LoadedClassInfo(Klass* klass, const ClassLoaderData* cld)
 122     : _klass(klass), _cld(cld) {}
 123 
 124 };
 125 
 126 class LoaderTreeNode : public ResourceObj {
 127 
 128   // We walk the CLDG and, for each CLD which is non-anonymous, add
 129   // a tree node. To add a node we need its parent node; if it itself
 130   // does not exist yet, we add a preliminary node for it. This preliminary
 131   // node just contains its loader oop; later, when encountering its CLD in
 132   // our CLDG walk, we complete the missing information in this node.
 133 
 134   const oop _loader_oop;
 135   const ClassLoaderData* _cld;
 136 
 137   LoaderTreeNode* _child;
 138   LoaderTreeNode* _next;
 139 
 140   LoadedClassInfo* _classes;
 141   int _num_classes;
 142 
 143   LoadedClassInfo* _anon_classes;
 144   int _num_anon_classes;
 145 
 146   void print_with_childs(outputStream* st, BranchTracker& branchtracker,
 147       bool print_classes, bool verbose) const {
 148 
 149     ResourceMark rm;
 150 
 151     if (_cld == NULL) {
 152       // Not sure how this could happen: we added a preliminary node for a parent but then never encountered
 153       // its CLD?
 154       return;
 155     }
 156 
 157     // Retrieve information.
 158     const Klass* const loader_klass = _cld->class_loader_klass();
 159 
 160     branchtracker.print(st);
 161 
 162     // e.g. "+--- jdk.internal.reflect.DelegatingClassLoader"
 163     st->print("+%.*s", BranchTracker::twig_len, "----------");
 164     st->print(" %s,", _cld->loader_name_and_id());
 165     if (!_cld->is_the_null_class_loader_data()) {
 166       st->print(" %s", loader_klass != NULL ? loader_klass->external_name() : "??");
 167       st->print(" {" PTR_FORMAT "}", p2i(_loader_oop));
 168     }
 169     st->cr();
 170 
 171     // Output following this node (node details and child nodes) - up to the next sibling node
 172     // needs to be prefixed with "|" if there is a follow up sibling.
 173     const bool have_sibling = _next != NULL;
 174     BranchTracker::Mark trm(branchtracker, have_sibling);
 175 
 176     {
 177       // optional node details following this node needs to be prefixed with "|"
 178       // if there are follow up child nodes.
 179       const bool have_child = _child != NULL;
 180       BranchTracker::Mark trm(branchtracker, have_child);
 181 
 182       // Empty line
 183       branchtracker.print(st);
 184       st->cr();
 185 
 186       const int indentation = 18;
 187 
 188       if (verbose) {
 189         branchtracker.print(st);
 190         st->print_cr("%*s " PTR_FORMAT, indentation, "Loader Data:", p2i(_cld));
 191         branchtracker.print(st);
 192         st->print_cr("%*s " PTR_FORMAT, indentation, "Loader Klass:", p2i(loader_klass));
 193 
 194         // Empty line
 195         branchtracker.print(st);
 196         st->cr();
 197       }
 198 
 199       if (print_classes) {
 200 
 201         if (_classes != NULL) {
 202           for (LoadedClassInfo* lci = _classes; lci; lci = lci->_next) {
 203             branchtracker.print(st);
 204             if (lci == _classes) { // first iteration
 205               st->print("%*s ", indentation, "Classes:");
 206             } else {
 207               st->print("%*s ", indentation, "");
 208             }
 209             st->print("%s", lci->_klass->external_name());
 210             st->cr();
 211             // Non-anonymous classes should live in the primary CLD of its loader
 212             assert(lci->_cld == _cld, "must be");
 213           }
 214           branchtracker.print(st);
 215           st->print("%*s ", indentation, "");
 216           st->print_cr("(%u class%s)", _num_classes, (_num_classes == 1) ? "" : "es");
 217 
 218           // Empty line
 219           branchtracker.print(st);
 220           st->cr();
 221         }
 222 
 223         if (_anon_classes != NULL) {
 224           for (LoadedClassInfo* lci = _anon_classes; lci; lci = lci->_next) {
 225             branchtracker.print(st);
 226             if (lci == _anon_classes) { // first iteration
 227               st->print("%*s ", indentation, "Anonymous Classes:");
 228             } else {
 229               st->print("%*s ", indentation, "");
 230             }
 231             st->print("%s", lci->_klass->external_name());
 232             // For anonymous classes, also print CLD if verbose. Should be a different one than the primary CLD.
 233             assert(lci->_cld != _cld, "must be");
 234             if (verbose) {
 235               st->print("  (CLD: " PTR_FORMAT ")", p2i(lci->_cld));
 236             }
 237             st->cr();
 238           }
 239           branchtracker.print(st);
 240           st->print("%*s ", indentation, "");
 241           st->print_cr("(%u anonymous class%s)", _num_anon_classes, (_num_anon_classes == 1) ? "" : "es");
 242 
 243           // Empty line
 244           branchtracker.print(st);
 245           st->cr();
 246         }
 247 
 248       } // end: print_classes
 249 
 250     } // Pop branchtracker mark
 251 
 252     // Print children, recursively
 253     LoaderTreeNode* c = _child;
 254     while (c != NULL) {
 255       c->print_with_childs(st, branchtracker, print_classes, verbose);
 256       c = c->_next;
 257     }
 258 
 259   }
 260 
 261 public:
 262 
 263   LoaderTreeNode(const oop loader_oop)
 264     : _loader_oop(loader_oop), _cld(NULL)
 265     , _child(NULL), _next(NULL)
 266     , _classes(NULL), _anon_classes(NULL)
 267     , _num_classes(0), _num_anon_classes(0) {}
 268 
 269   void set_cld(const ClassLoaderData* cld) {
 270     _cld = cld;
 271   }
 272 
 273   void add_child(LoaderTreeNode* info) {
 274     info->_next = _child;
 275     _child = info;
 276   }
 277 
 278   void add_sibling(LoaderTreeNode* info) {
 279     assert(info->_next == NULL, "must be");
 280     info->_next = _next;
 281     _next = info;
 282   }
 283 
 284   void add_classes(LoadedClassInfo* first_class, int num_classes, bool anonymous) {
 285     LoadedClassInfo** p_list_to_add_to = anonymous ? &_anon_classes : &_classes;
 286     // Search tail.
 287     while ((*p_list_to_add_to) != NULL) {
 288       p_list_to_add_to = &(*p_list_to_add_to)->_next;
 289     }
 290     *p_list_to_add_to = first_class;
 291     if (anonymous) {
 292       _num_anon_classes += num_classes;
 293     } else {
 294       _num_classes += num_classes;
 295     }
 296   }
 297 
 298   const ClassLoaderData* cld() const {
 299     return _cld;
 300   }
 301 
 302   const oop loader_oop() const {
 303     return _loader_oop;
 304   }
 305 
 306   LoaderTreeNode* find(const oop loader_oop) {
 307     LoaderTreeNode* result = NULL;
 308     if (_loader_oop == loader_oop) {
 309       result = this;
 310     } else {
 311       LoaderTreeNode* c = _child;
 312       while (c != NULL && result == NULL) {
 313         result = c->find(loader_oop);
 314         c = c->_next;
 315       }
 316     }
 317     return result;
 318   }
 319 
 320   void print_with_childs(outputStream* st, bool print_classes, bool print_add_info) const {
 321     BranchTracker bwt;
 322     print_with_childs(st, bwt, print_classes, print_add_info);
 323   }
 324 
 325 };
 326 
 327 class LoadedClassCollectClosure : public KlassClosure {
 328 public:
 329   LoadedClassInfo* _list;
 330   const ClassLoaderData* _cld;
 331   int _num_classes;
 332   LoadedClassCollectClosure(const ClassLoaderData* cld)
 333     : _list(NULL), _cld(cld), _num_classes(0) {}
 334   void do_klass(Klass* k) {
 335     LoadedClassInfo* lki = new LoadedClassInfo(k, _cld);
 336     lki->_next = _list;
 337     _list = lki;
 338     _num_classes ++;
 339   }
 340 };
 341 
 342 class LoaderInfoScanClosure : public CLDClosure {
 343 
 344   const bool _print_classes;
 345   const bool _verbose;
 346   LoaderTreeNode* _root;
 347 
 348   static void fill_in_classes(LoaderTreeNode* info, const ClassLoaderData* cld) {
 349     assert(info != NULL && cld != NULL, "must be");
 350     LoadedClassCollectClosure lccc(cld);
 351     const_cast<ClassLoaderData*>(cld)->classes_do(&lccc);
 352     if (lccc._num_classes > 0) {
 353       info->add_classes(lccc._list, lccc._num_classes, cld->is_anonymous());
 354     }
 355   }
 356 
 357   LoaderTreeNode* find_node_or_add_empty_node(oop loader_oop) {
 358 
 359     assert(_root != NULL, "root node must exist");
 360 
 361     if (loader_oop == NULL) {
 362       return _root;
 363     }
 364 
 365     // Check if a node for this oop already exists.
 366     LoaderTreeNode* info = _root->find(loader_oop);
 367 
 368     if (info == NULL) {
 369       // It does not. Create a node.
 370       info = new LoaderTreeNode(loader_oop);
 371 
 372       // Add it to tree.
 373       LoaderTreeNode* parent_info = NULL;
 374 
 375       // Recursively add parent nodes if needed.
 376       const oop parent_oop = java_lang_ClassLoader::parent(loader_oop);
 377       if (parent_oop == NULL) {
 378         parent_info = _root;
 379       } else {
 380         parent_info = find_node_or_add_empty_node(parent_oop);
 381       }
 382       assert(parent_info != NULL, "must be");
 383 
 384       parent_info->add_child(info);
 385     }
 386     return info;
 387   }
 388 
 389 
 390 public:
 391   LoaderInfoScanClosure(bool print_classes, bool verbose)
 392     : _print_classes(print_classes), _verbose(verbose), _root(NULL) {
 393     _root = new LoaderTreeNode(NULL);
 394   }
 395 
 396   void print_results(outputStream* st) const {
 397     _root->print_with_childs(st, _print_classes, _verbose);
 398   }
 399 
 400   void do_cld (ClassLoaderData* cld) {
 401 
 402     // We do not display unloading loaders, for now.
 403     if (cld->is_unloading()) {
 404       return;
 405     }
 406 
 407     const oop loader_oop = cld->class_loader();
 408 
 409     LoaderTreeNode* info = find_node_or_add_empty_node(loader_oop);
 410     assert(info != NULL, "must be");
 411 
 412     // Update CLD in node, but only if this is the primary CLD for this loader.
 413     if (cld->is_anonymous() == false) {
 414       assert(info->cld() == NULL, "there should be only one primary CLD per loader");
 415       info->set_cld(cld);
 416     }
 417 
 418     // Add classes.
 419     fill_in_classes(info, cld);
 420   }
 421 
 422 };
 423 
 424 
 425 class ClassLoaderHierarchyVMOperation : public VM_Operation {
 426   outputStream* const _out;
 427   const bool _show_classes;
 428   const bool _verbose;
 429 public:
 430   ClassLoaderHierarchyVMOperation(outputStream* out, bool show_classes, bool verbose) :
 431     _out(out), _show_classes(show_classes), _verbose(verbose)
 432   {}
 433 
 434   VMOp_Type type() const {
 435     return VMOp_ClassLoaderHierarchyOperation;
 436   }
 437 
 438   void doit() {
 439     assert(SafepointSynchronize::is_at_safepoint(), "must be a safepoint");
 440     ResourceMark rm;
 441     LoaderInfoScanClosure cl (_show_classes, _verbose);
 442     ClassLoaderDataGraph::cld_do(&cl);
 443     cl.print_results(_out);
 444   }
 445 };
 446 
 447 // This command needs to be executed at a safepoint.
 448 void ClassLoaderHierarchyDCmd::execute(DCmdSource source, TRAPS) {
 449   ClassLoaderHierarchyVMOperation op(output(), _show_classes.value(), _verbose.value());
 450   VMThread::execute(&op);
 451 }