src/hotspot/share/classfile/classLoaderHierarchyDCmd.cpp
changeset 50863 9084fd587141
parent 50634 c349d409262a
child 51334 cc2c79d22508
equal deleted inserted replaced
50862:350ae1b408da 50863:9084fd587141
    34 #include "utilities/globalDefinitions.hpp"
    34 #include "utilities/globalDefinitions.hpp"
    35 #include "utilities/ostream.hpp"
    35 #include "utilities/ostream.hpp"
    36 
    36 
    37 
    37 
    38 ClassLoaderHierarchyDCmd::ClassLoaderHierarchyDCmd(outputStream* output, bool heap)
    38 ClassLoaderHierarchyDCmd::ClassLoaderHierarchyDCmd(outputStream* output, bool heap)
    39   : DCmdWithParser(output, heap)
    39   : DCmdWithParser(output, heap),
    40   , _show_classes("show-classes", "Print loaded classes.", "BOOLEAN", false, "false")
    40    _show_classes("show-classes", "Print loaded classes.", "BOOLEAN", false, "false"),
    41   , _verbose("verbose", "Print detailed information.", "BOOLEAN", false, "false") {
    41   _verbose("verbose", "Print detailed information.", "BOOLEAN", false, "false"),
       
    42   _fold("fold", "Show loaders of the same name and class as one.", "BOOLEAN", true, "true") {
    42   _dcmdparser.add_dcmd_option(&_show_classes);
    43   _dcmdparser.add_dcmd_option(&_show_classes);
    43   _dcmdparser.add_dcmd_option(&_verbose);
    44   _dcmdparser.add_dcmd_option(&_verbose);
       
    45   _dcmdparser.add_dcmd_option(&_fold);
    44 }
    46 }
    45 
    47 
    46 
    48 
    47 int ClassLoaderHierarchyDCmd::num_arguments() {
    49 int ClassLoaderHierarchyDCmd::num_arguments() {
    48   ResourceMark rm;
    50   ResourceMark rm;
   125 };
   127 };
   126 
   128 
   127 class LoaderTreeNode : public ResourceObj {
   129 class LoaderTreeNode : public ResourceObj {
   128 
   130 
   129   // We walk the CLDG and, for each CLD which is non-anonymous, add
   131   // We walk the CLDG and, for each CLD which is non-anonymous, add
   130   // a tree node. To add a node we need its parent node; if it itself
   132   // a tree node.
   131   // does not exist yet, we add a preliminary node for it. This preliminary
   133   // To add a node we need its parent node; if the parent node does not yet
   132   // node just contains its loader oop; later, when encountering its CLD in
   134   // exist - because we have not yet encountered the CLD for the parent loader -
   133   // our CLDG walk, we complete the missing information in this node.
   135   // we add a preliminary empty LoaderTreeNode for it. This preliminary node
       
   136   // just contains the loader oop and nothing else. Once we encounter the CLD of
       
   137   // this parent loader, we fill in all the other details.
   134 
   138 
   135   const oop _loader_oop;
   139   const oop _loader_oop;
   136   const ClassLoaderData* _cld;
   140   const ClassLoaderData* _cld;
   137 
   141 
   138   LoaderTreeNode* _child;
   142   LoaderTreeNode* _child;
   141   LoadedClassInfo* _classes;
   145   LoadedClassInfo* _classes;
   142   int _num_classes;
   146   int _num_classes;
   143 
   147 
   144   LoadedClassInfo* _anon_classes;
   148   LoadedClassInfo* _anon_classes;
   145   int _num_anon_classes;
   149   int _num_anon_classes;
       
   150 
       
   151   // In default view, similar tree nodes (same loader class, same name or no name)
       
   152   // are folded into each other to make the output more readable.
       
   153   // _num_folded contains the number of nodes which have been folded into this
       
   154   // one.
       
   155   int _num_folded;
   146 
   156 
   147   void print_with_childs(outputStream* st, BranchTracker& branchtracker,
   157   void print_with_childs(outputStream* st, BranchTracker& branchtracker,
   148       bool print_classes, bool verbose) const {
   158       bool print_classes, bool verbose) const {
   149 
   159 
   150     ResourceMark rm;
   160     ResourceMark rm;
   168     } else {
   178     } else {
   169       if (loader_name != NULL) {
   179       if (loader_name != NULL) {
   170         st->print(" \"%s\",", loader_name->as_C_string());
   180         st->print(" \"%s\",", loader_name->as_C_string());
   171       }
   181       }
   172       st->print(" %s", loader_klass != NULL ? loader_klass->external_name() : "??");
   182       st->print(" %s", loader_klass != NULL ? loader_klass->external_name() : "??");
   173       st->print(" {" PTR_FORMAT "}", p2i(_loader_oop));
   183       if (_num_folded > 0) {
       
   184         st->print(" (+ %d more)", _num_folded);
       
   185       }
   174     }
   186     }
   175     st->cr();
   187     st->cr();
   176 
   188 
   177     // Output following this node (node details and child nodes) - up to the next sibling node
   189     // Output following this node (node details and child nodes) - up to the next sibling node
   178     // needs to be prefixed with "|" if there is a follow up sibling.
   190     // needs to be prefixed with "|" if there is a follow up sibling.
   190       st->cr();
   202       st->cr();
   191 
   203 
   192       const int indentation = 18;
   204       const int indentation = 18;
   193 
   205 
   194       if (verbose) {
   206       if (verbose) {
       
   207         branchtracker.print(st);
       
   208         st->print_cr("%*s " PTR_FORMAT, indentation, "Loader Oop:", p2i(_loader_oop));
   195         branchtracker.print(st);
   209         branchtracker.print(st);
   196         st->print_cr("%*s " PTR_FORMAT, indentation, "Loader Data:", p2i(_cld));
   210         st->print_cr("%*s " PTR_FORMAT, indentation, "Loader Data:", p2i(_cld));
   197         branchtracker.print(st);
   211         branchtracker.print(st);
   198         st->print_cr("%*s " PTR_FORMAT, indentation, "Loader Klass:", p2i(loader_klass));
   212         st->print_cr("%*s " PTR_FORMAT, indentation, "Loader Klass:", p2i(loader_klass));
   199 
   213 
   244             }
   258             }
   245             st->print("%s", lci->_klass->external_name());
   259             st->print("%s", lci->_klass->external_name());
   246             // For anonymous classes, also print CLD if verbose. Should be a different one than the primary CLD.
   260             // For anonymous classes, also print CLD if verbose. Should be a different one than the primary CLD.
   247             assert(lci->_cld != _cld, "must be");
   261             assert(lci->_cld != _cld, "must be");
   248             if (verbose) {
   262             if (verbose) {
   249               st->print("  (CLD: " PTR_FORMAT ")", p2i(lci->_cld));
   263               st->print("  (Loader Data: " PTR_FORMAT ")", p2i(lci->_cld));
   250             }
   264             }
   251             st->cr();
   265             st->cr();
   252           }
   266           }
   253           branchtracker.print(st);
   267           branchtracker.print(st);
   254           st->print("%*s ", indentation, "");
   268           st->print("%*s ", indentation, "");
   270       c = c->_next;
   284       c = c->_next;
   271     }
   285     }
   272 
   286 
   273   }
   287   }
   274 
   288 
       
   289   // Helper: Attempt to fold this node into the target node. If success, returns true.
       
   290   // Folding can be done if both nodes are leaf nodes and they refer to the same loader class
       
   291   // and they have the same name or no name (note: leaf check is done by caller).
       
   292   bool can_fold_into(LoaderTreeNode* target_node) const {
       
   293     assert(is_leaf() && target_node->is_leaf(), "must be leaf");
       
   294     return _cld->class_loader_klass() == target_node->_cld->class_loader_klass() &&
       
   295            _cld->name() == target_node->_cld->name();
       
   296   }
       
   297 
   275 public:
   298 public:
   276 
   299 
   277   LoaderTreeNode(const oop loader_oop)
   300   LoaderTreeNode(const oop loader_oop)
   278     : _loader_oop(loader_oop), _cld(NULL)
   301     : _loader_oop(loader_oop), _cld(NULL), _child(NULL), _next(NULL),
   279     , _child(NULL), _next(NULL)
   302       _classes(NULL), _anon_classes(NULL), _num_classes(0), _num_anon_classes(0),
   280     , _classes(NULL), _anon_classes(NULL)
   303       _num_folded(0)
   281     , _num_classes(0), _num_anon_classes(0) {}
   304     {}
   282 
   305 
   283   void set_cld(const ClassLoaderData* cld) {
   306   void set_cld(const ClassLoaderData* cld) {
   284     _cld = cld;
   307     _cld = cld;
   285   }
   308   }
   286 
   309 
   327         result = c->find(loader_oop);
   350         result = c->find(loader_oop);
   328         c = c->_next;
   351         c = c->_next;
   329       }
   352       }
   330     }
   353     }
   331     return result;
   354     return result;
       
   355   }
       
   356 
       
   357   bool is_leaf() const { return _child == NULL; }
       
   358 
       
   359   // Attempt to fold similar nodes among this node's children. We only fold leaf nodes
       
   360   // (no child class loaders).
       
   361   // For non-leaf nodes (class loaders with child class loaders), do this recursivly.
       
   362   void fold_children() {
       
   363     LoaderTreeNode* node = _child;
       
   364     LoaderTreeNode* prev = NULL;
       
   365     while (node != NULL) {
       
   366       LoaderTreeNode* matching_node = NULL;
       
   367       if (node->is_leaf()) {
       
   368         // Look among the preceeding node siblings for a match.
       
   369         for (LoaderTreeNode* node2 = _child; node2 != node && matching_node == NULL;
       
   370             node2 = node2->_next) {
       
   371           if (node2->is_leaf() && node->can_fold_into(node2)) {
       
   372             matching_node = node2;
       
   373           }
       
   374         }
       
   375       } else {
       
   376         node->fold_children();
       
   377       }
       
   378       if (matching_node != NULL) {
       
   379         // Increase fold count for the matching node and remove folded node from the child list.
       
   380         matching_node->_num_folded ++;
       
   381         assert(prev != NULL, "Sanity"); // can never happen since we do not fold the first node.
       
   382         prev->_next = node->_next;
       
   383       } else {
       
   384         prev = node;
       
   385       }
       
   386       node = node->_next;
       
   387     }
   332   }
   388   }
   333 
   389 
   334   void print_with_childs(outputStream* st, bool print_classes, bool print_add_info) const {
   390   void print_with_childs(outputStream* st, bool print_classes, bool print_add_info) const {
   335     BranchTracker bwt;
   391     BranchTracker bwt;
   336     print_with_childs(st, bwt, print_classes, print_add_info);
   392     print_with_childs(st, bwt, print_classes, print_add_info);
   431 
   487 
   432     // Add classes.
   488     // Add classes.
   433     fill_in_classes(info, cld);
   489     fill_in_classes(info, cld);
   434   }
   490   }
   435 
   491 
       
   492   void fold() {
       
   493     _root->fold_children();
       
   494   }
       
   495 
   436 };
   496 };
   437 
   497 
   438 
   498 
   439 class ClassLoaderHierarchyVMOperation : public VM_Operation {
   499 class ClassLoaderHierarchyVMOperation : public VM_Operation {
   440   outputStream* const _out;
   500   outputStream* const _out;
   441   const bool _show_classes;
   501   const bool _show_classes;
   442   const bool _verbose;
   502   const bool _verbose;
   443 public:
   503   const bool _fold;
   444   ClassLoaderHierarchyVMOperation(outputStream* out, bool show_classes, bool verbose) :
   504 public:
   445     _out(out), _show_classes(show_classes), _verbose(verbose)
   505   ClassLoaderHierarchyVMOperation(outputStream* out, bool show_classes, bool verbose, bool fold) :
       
   506     _out(out), _show_classes(show_classes), _verbose(verbose), _fold(fold)
   446   {}
   507   {}
   447 
   508 
   448   VMOp_Type type() const {
   509   VMOp_Type type() const {
   449     return VMOp_ClassLoaderHierarchyOperation;
   510     return VMOp_ClassLoaderHierarchyOperation;
   450   }
   511   }
   452   void doit() {
   513   void doit() {
   453     assert(SafepointSynchronize::is_at_safepoint(), "must be a safepoint");
   514     assert(SafepointSynchronize::is_at_safepoint(), "must be a safepoint");
   454     ResourceMark rm;
   515     ResourceMark rm;
   455     LoaderInfoScanClosure cl (_show_classes, _verbose);
   516     LoaderInfoScanClosure cl (_show_classes, _verbose);
   456     ClassLoaderDataGraph::cld_do(&cl);
   517     ClassLoaderDataGraph::cld_do(&cl);
       
   518     // In non-verbose and non-show-classes mode, attempt to fold the tree.
       
   519     if (_fold) {
       
   520       if (!_verbose && !_show_classes) {
       
   521         cl.fold();
       
   522       }
       
   523     }
   457     cl.print_results(_out);
   524     cl.print_results(_out);
   458   }
   525   }
   459 };
   526 };
   460 
   527 
   461 // This command needs to be executed at a safepoint.
   528 // This command needs to be executed at a safepoint.
   462 void ClassLoaderHierarchyDCmd::execute(DCmdSource source, TRAPS) {
   529 void ClassLoaderHierarchyDCmd::execute(DCmdSource source, TRAPS) {
   463   ClassLoaderHierarchyVMOperation op(output(), _show_classes.value(), _verbose.value());
   530   ClassLoaderHierarchyVMOperation op(output(), _show_classes.value(), _verbose.value(), _fold.value());
   464   VMThread::execute(&op);
   531   VMThread::execute(&op);
   465 }
   532 }