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