1 /*
2  * Copyright (c) 2018, 2021, 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/classLoaderDataGraph.hpp"
30 #include "classfile/classLoaderHierarchyDCmd.hpp"
31 #include "memory/allocation.hpp"
32 #include "memory/resourceArea.hpp"
33 #include "runtime/safepoint.hpp"
34 #include "oops/reflectionAccessorImplKlassHelper.hpp"
35 #include "utilities/globalDefinitions.hpp"
36 #include "utilities/ostream.hpp"
37 
38 
ClassLoaderHierarchyDCmd(outputStream * output,bool heap)39 ClassLoaderHierarchyDCmd::ClassLoaderHierarchyDCmd(outputStream* output, bool heap)
40   : DCmdWithParser(output, heap),
41    _show_classes("show-classes", "Print loaded classes.", "BOOLEAN", false, "false"),
42   _verbose("verbose", "Print detailed information.", "BOOLEAN", false, "false"),
43   _fold("fold", "Show loaders of the same name and class as one.", "BOOLEAN", true, "true") {
44   _dcmdparser.add_dcmd_option(&_show_classes);
45   _dcmdparser.add_dcmd_option(&_verbose);
46   _dcmdparser.add_dcmd_option(&_fold);
47 }
48 
49 
num_arguments()50 int ClassLoaderHierarchyDCmd::num_arguments() {
51   ResourceMark rm;
52   ClassLoaderHierarchyDCmd* dcmd = new ClassLoaderHierarchyDCmd(NULL, false);
53   if (dcmd != NULL) {
54     DCmdMark mark(dcmd);
55     return dcmd->_dcmdparser.num_arguments();
56   } else {
57     return 0;
58   }
59 }
60 
61 // Helper class for drawing the branches to the left of a node.
62 class BranchTracker : public StackObj {
63   //       "<x>"
64   //       " |---<y>"
65   //       " |    |
66   //       " |   <z>"
67   //       " |    |---<z1>
68   //       " |    |---<z2>
69   //       ^^^^^^^ ^^^
70   //        A       B
71 
72   // Some terms for the graphics:
73   // - branch: vertical connection between a node's ancestor to a later sibling.
74   // - branchwork: (A) the string to print as a prefix at the start of each line, contains all branches.
75   // - twig (B): Length of the dashed line connecting a node to its branch.
76   // - branch spacing: how many spaces between branches are printed.
77 
78 public:
79 
80   enum { max_depth = 64, twig_len = 2, branch_spacing = 5 };
81 
82 private:
83 
84   char _branches[max_depth];
85   int _pos;
86 
87 public:
BranchTracker()88   BranchTracker()
89     : _pos(0) {}
90 
push(bool has_branch)91   void push(bool has_branch) {
92     if (_pos < max_depth) {
93       _branches[_pos] = has_branch ? '|' : ' ';
94     }
95     _pos ++; // beyond max depth, omit branch drawing but do count on.
96   }
97 
pop()98   void pop() {
99     assert(_pos > 0, "must be");
100     _pos --;
101   }
102 
print(outputStream * st)103   void print(outputStream* st) {
104     for (int i = 0; i < _pos; i ++) {
105       st->print("%c%.*s", _branches[i], branch_spacing, "          ");
106     }
107   }
108 
109   class Mark {
110     BranchTracker& _tr;
111   public:
Mark(BranchTracker & tr,bool has_branch_here)112     Mark(BranchTracker& tr, bool has_branch_here)
113       : _tr(tr)  { _tr.push(has_branch_here); }
~Mark()114     ~Mark() { _tr.pop(); }
115   };
116 
117 }; // end: BranchTracker
118 
119 struct LoadedClassInfo : public ResourceObj {
120 public:
121   LoadedClassInfo* _next;
122   Klass* const _klass;
123   const ClassLoaderData* const _cld;
124 
LoadedClassInfoLoadedClassInfo125   LoadedClassInfo(Klass* klass, const ClassLoaderData* cld)
126     : _klass(klass), _cld(cld) {}
127 
128 };
129 
130 class LoaderTreeNode : public ResourceObj {
131 
132   // We walk the CLDG and, for each CLD which is findable, add
133   // a tree node.
134   // To add a node we need its parent node; if the parent node does not yet
135   // exist - because we have not yet encountered the CLD for the parent loader -
136   // we add a preliminary empty LoaderTreeNode for it. This preliminary node
137   // just contains the loader oop and nothing else. Once we encounter the CLD of
138   // this parent loader, we fill in all the other details.
139 
140   const oop _loader_oop;
141   const ClassLoaderData* _cld;
142 
143   LoaderTreeNode* _child;
144   LoaderTreeNode* _next;
145 
146   LoadedClassInfo* _classes;
147   int _num_classes;
148 
149   LoadedClassInfo* _hidden_classes;
150   int _num_hidden_classes;
151 
152   // In default view, similar tree nodes (same loader class, same name or no name)
153   // are folded into each other to make the output more readable.
154   // _num_folded contains the number of nodes which have been folded into this
155   // one.
156   int _num_folded;
157 
print_with_childs(outputStream * st,BranchTracker & branchtracker,bool print_classes,bool verbose) const158   void print_with_childs(outputStream* st, BranchTracker& branchtracker,
159       bool print_classes, bool verbose) const {
160 
161     ResourceMark rm;
162 
163     if (_cld == NULL) {
164       // Not sure how this could happen: we added a preliminary node for a parent but then never encountered
165       // its CLD?
166       return;
167     }
168 
169     // Retrieve information.
170     const Klass* const loader_klass = _cld->class_loader_klass();
171     const Symbol* const loader_name = _cld->name();
172 
173     branchtracker.print(st);
174 
175     // e.g. "+--- jdk.internal.reflect.DelegatingClassLoader"
176     st->print("+%.*s", BranchTracker::twig_len, "----------");
177     if (_cld->is_the_null_class_loader_data()) {
178       st->print(" <bootstrap>");
179     } else {
180       assert(!_cld->has_class_mirror_holder(), "_cld must be the primary cld");
181       if (loader_name != NULL) {
182         st->print(" \"%s\",", loader_name->as_C_string());
183       }
184       st->print(" %s", loader_klass != NULL ? loader_klass->external_name() : "??");
185       if (_num_folded > 0) {
186         st->print(" (+ %d more)", _num_folded);
187       }
188     }
189     st->cr();
190 
191     // Output following this node (node details and child nodes) - up to the next sibling node
192     // needs to be prefixed with "|" if there is a follow up sibling.
193     const bool have_sibling = _next != NULL;
194     BranchTracker::Mark trm(branchtracker, have_sibling);
195 
196     {
197       // optional node details following this node needs to be prefixed with "|"
198       // if there are follow up child nodes.
199       const bool have_child = _child != NULL;
200       BranchTracker::Mark trm(branchtracker, have_child);
201 
202       // Empty line
203       branchtracker.print(st);
204       st->cr();
205 
206       const int indentation = 18;
207 
208       if (verbose) {
209         branchtracker.print(st);
210         st->print_cr("%*s " PTR_FORMAT, indentation, "Loader Oop:", p2i(_loader_oop));
211         branchtracker.print(st);
212         st->print_cr("%*s " PTR_FORMAT, indentation, "Loader Data:", p2i(_cld));
213         branchtracker.print(st);
214         st->print_cr("%*s " PTR_FORMAT, indentation, "Loader Klass:", p2i(loader_klass));
215 
216         // Empty line
217         branchtracker.print(st);
218         st->cr();
219       }
220 
221       if (print_classes) {
222         if (_classes != NULL) {
223           for (LoadedClassInfo* lci = _classes; lci; lci = lci->_next) {
224             // non-strong hidden classes should not live in
225             // the primary CLD of their loaders.
226             assert(lci->_cld == _cld, "must be");
227 
228             branchtracker.print(st);
229             if (lci == _classes) { // first iteration
230               st->print("%*s ", indentation, "Classes:");
231             } else {
232               st->print("%*s ", indentation, "");
233             }
234             st->print("%s", lci->_klass->external_name());
235 
236             // Special treatment for generated core reflection accessor classes: print invocation target.
237             if (ReflectionAccessorImplKlassHelper::is_generated_accessor(lci->_klass)) {
238               st->print(" (invokes: ");
239               ReflectionAccessorImplKlassHelper::print_invocation_target(st, lci->_klass);
240               st->print(")");
241             }
242 
243             st->cr();
244           }
245           branchtracker.print(st);
246           st->print("%*s ", indentation, "");
247           st->print_cr("(%u class%s)", _num_classes, (_num_classes == 1) ? "" : "es");
248 
249           // Empty line
250           branchtracker.print(st);
251           st->cr();
252         }
253 
254         if (_hidden_classes != NULL) {
255           for (LoadedClassInfo* lci = _hidden_classes; lci; lci = lci->_next) {
256             branchtracker.print(st);
257             if (lci == _hidden_classes) { // first iteration
258               st->print("%*s ", indentation, "Hidden Classes:");
259             } else {
260               st->print("%*s ", indentation, "");
261             }
262             st->print("%s", lci->_klass->external_name());
263             // For non-strong hidden classes, also print CLD if verbose. Should be a
264             // different one than the primary CLD.
265             assert(lci->_cld != _cld, "must be");
266             if (verbose) {
267               st->print("  (Loader Data: " PTR_FORMAT ")", p2i(lci->_cld));
268             }
269             st->cr();
270           }
271           branchtracker.print(st);
272           st->print("%*s ", indentation, "");
273           st->print_cr("(%u hidden class%s)", _num_hidden_classes,
274                        (_num_hidden_classes == 1) ? "" : "es");
275 
276           // Empty line
277           branchtracker.print(st);
278           st->cr();
279         }
280 
281       } // end: print_classes
282 
283     } // Pop branchtracker mark
284 
285     // Print children, recursively
286     LoaderTreeNode* c = _child;
287     while (c != NULL) {
288       c->print_with_childs(st, branchtracker, print_classes, verbose);
289       c = c->_next;
290     }
291 
292   }
293 
294   // Helper: Attempt to fold this node into the target node. If success, returns true.
295   // Folding can be done if both nodes are leaf nodes and they refer to the same loader class
296   // and they have the same name or no name (note: leaf check is done by caller).
can_fold_into(LoaderTreeNode * target_node) const297   bool can_fold_into(LoaderTreeNode* target_node) const {
298     assert(is_leaf() && target_node->is_leaf(), "must be leaf");
299     return _cld->class_loader_klass() == target_node->_cld->class_loader_klass() &&
300            _cld->name() == target_node->_cld->name();
301   }
302 
303 public:
304 
LoaderTreeNode(const oop loader_oop)305   LoaderTreeNode(const oop loader_oop)
306     : _loader_oop(loader_oop), _cld(NULL), _child(NULL), _next(NULL),
307       _classes(NULL), _num_classes(0), _hidden_classes(NULL),
308       _num_hidden_classes(0), _num_folded(0)
309     {}
310 
set_cld(const ClassLoaderData * cld)311   void set_cld(const ClassLoaderData* cld) {
312     _cld = cld;
313   }
314 
add_child(LoaderTreeNode * info)315   void add_child(LoaderTreeNode* info) {
316     info->_next = _child;
317     _child = info;
318   }
319 
add_sibling(LoaderTreeNode * info)320   void add_sibling(LoaderTreeNode* info) {
321     assert(info->_next == NULL, "must be");
322     info->_next = _next;
323     _next = info;
324   }
325 
add_classes(LoadedClassInfo * first_class,int num_classes,bool has_class_mirror_holder)326   void add_classes(LoadedClassInfo* first_class, int num_classes, bool has_class_mirror_holder) {
327     LoadedClassInfo** p_list_to_add_to;
328     bool is_hidden = first_class->_klass->is_hidden();
329     if (has_class_mirror_holder) {
330       p_list_to_add_to = &_hidden_classes;
331     } else {
332       p_list_to_add_to = &_classes;
333     }
334     // Search tail.
335     while ((*p_list_to_add_to) != NULL) {
336       p_list_to_add_to = &(*p_list_to_add_to)->_next;
337     }
338     *p_list_to_add_to = first_class;
339     if (has_class_mirror_holder) {
340       _num_hidden_classes += num_classes;
341     } else {
342       _num_classes += num_classes;
343     }
344   }
345 
cld() const346   const ClassLoaderData* cld() const {
347     return _cld;
348   }
349 
loader_oop() const350   const oop loader_oop() const {
351     return _loader_oop;
352   }
353 
find(const oop loader_oop)354   LoaderTreeNode* find(const oop loader_oop) {
355     LoaderTreeNode* result = NULL;
356     if (_loader_oop == loader_oop) {
357       result = this;
358     } else {
359       LoaderTreeNode* c = _child;
360       while (c != NULL && result == NULL) {
361         result = c->find(loader_oop);
362         c = c->_next;
363       }
364     }
365     return result;
366   }
367 
is_leaf() const368   bool is_leaf() const { return _child == NULL; }
369 
370   // Attempt to fold similar nodes among this node's children. We only fold leaf nodes
371   // (no child class loaders).
372   // For non-leaf nodes (class loaders with child class loaders), do this recursivly.
fold_children()373   void fold_children() {
374     LoaderTreeNode* node = _child;
375     LoaderTreeNode* prev = NULL;
376     while (node != NULL) {
377       LoaderTreeNode* matching_node = NULL;
378       if (node->is_leaf()) {
379         // Look among the preceeding node siblings for a match.
380         for (LoaderTreeNode* node2 = _child; node2 != node && matching_node == NULL;
381             node2 = node2->_next) {
382           if (node2->is_leaf() && node->can_fold_into(node2)) {
383             matching_node = node2;
384           }
385         }
386       } else {
387         node->fold_children();
388       }
389       if (matching_node != NULL) {
390         // Increase fold count for the matching node and remove folded node from the child list.
391         matching_node->_num_folded ++;
392         assert(prev != NULL, "Sanity"); // can never happen since we do not fold the first node.
393         prev->_next = node->_next;
394       } else {
395         prev = node;
396       }
397       node = node->_next;
398     }
399   }
400 
print_with_childs(outputStream * st,bool print_classes,bool print_add_info) const401   void print_with_childs(outputStream* st, bool print_classes, bool print_add_info) const {
402     BranchTracker bwt;
403     print_with_childs(st, bwt, print_classes, print_add_info);
404   }
405 
406 };
407 
408 class LoadedClassCollectClosure : public KlassClosure {
409 public:
410   LoadedClassInfo* _list;
411   const ClassLoaderData* _cld;
412   int _num_classes;
LoadedClassCollectClosure(const ClassLoaderData * cld)413   LoadedClassCollectClosure(const ClassLoaderData* cld)
414     : _list(NULL), _cld(cld), _num_classes(0) {}
do_klass(Klass * k)415   void do_klass(Klass* k) {
416     LoadedClassInfo* lki = new LoadedClassInfo(k, _cld);
417     lki->_next = _list;
418     _list = lki;
419     _num_classes ++;
420   }
421 };
422 
423 class LoaderInfoScanClosure : public CLDClosure {
424 
425   const bool _print_classes;
426   const bool _verbose;
427   LoaderTreeNode* _root;
428 
fill_in_classes(LoaderTreeNode * info,const ClassLoaderData * cld)429   static void fill_in_classes(LoaderTreeNode* info, const ClassLoaderData* cld) {
430     assert(info != NULL && cld != NULL, "must be");
431     LoadedClassCollectClosure lccc(cld);
432     const_cast<ClassLoaderData*>(cld)->classes_do(&lccc);
433     if (lccc._num_classes > 0) {
434       info->add_classes(lccc._list, lccc._num_classes, cld->has_class_mirror_holder());
435     }
436   }
437 
find_node_or_add_empty_node(oop loader_oop)438   LoaderTreeNode* find_node_or_add_empty_node(oop loader_oop) {
439 
440     assert(_root != NULL, "root node must exist");
441 
442     if (loader_oop == NULL) {
443       return _root;
444     }
445 
446     // Check if a node for this oop already exists.
447     LoaderTreeNode* info = _root->find(loader_oop);
448 
449     if (info == NULL) {
450       // It does not. Create a node.
451       info = new LoaderTreeNode(loader_oop);
452 
453       // Add it to tree.
454       LoaderTreeNode* parent_info = NULL;
455 
456       // Recursively add parent nodes if needed.
457       const oop parent_oop = java_lang_ClassLoader::parent(loader_oop);
458       if (parent_oop == NULL) {
459         parent_info = _root;
460       } else {
461         parent_info = find_node_or_add_empty_node(parent_oop);
462       }
463       assert(parent_info != NULL, "must be");
464 
465       parent_info->add_child(info);
466     }
467     return info;
468   }
469 
470 
471 public:
LoaderInfoScanClosure(bool print_classes,bool verbose)472   LoaderInfoScanClosure(bool print_classes, bool verbose)
473     : _print_classes(print_classes), _verbose(verbose), _root(NULL) {
474     _root = new LoaderTreeNode(NULL);
475   }
476 
print_results(outputStream * st) const477   void print_results(outputStream* st) const {
478     _root->print_with_childs(st, _print_classes, _verbose);
479   }
480 
do_cld(ClassLoaderData * cld)481   void do_cld (ClassLoaderData* cld) {
482 
483     // We do not display unloading loaders, for now.
484     if (!cld->is_alive()) {
485       return;
486     }
487 
488     const oop loader_oop = cld->class_loader();
489 
490     LoaderTreeNode* info = find_node_or_add_empty_node(loader_oop);
491     assert(info != NULL, "must be");
492 
493     // Update CLD in node, but only if this is the primary CLD for this loader.
494     if (cld->has_class_mirror_holder() == false) {
495       assert(info->cld() == NULL, "there should be only one primary CLD per loader");
496       info->set_cld(cld);
497     }
498 
499     // Add classes.
500     fill_in_classes(info, cld);
501   }
502 
fold()503   void fold() {
504     _root->fold_children();
505   }
506 
507 };
508 
509 
510 class ClassLoaderHierarchyVMOperation : public VM_Operation {
511   outputStream* const _out;
512   const bool _show_classes;
513   const bool _verbose;
514   const bool _fold;
515 public:
ClassLoaderHierarchyVMOperation(outputStream * out,bool show_classes,bool verbose,bool fold)516   ClassLoaderHierarchyVMOperation(outputStream* out, bool show_classes, bool verbose, bool fold) :
517     _out(out), _show_classes(show_classes), _verbose(verbose), _fold(fold)
518   {}
519 
type() const520   VMOp_Type type() const {
521     return VMOp_ClassLoaderHierarchyOperation;
522   }
523 
doit()524   void doit() {
525     assert(SafepointSynchronize::is_at_safepoint(), "must be a safepoint");
526     ResourceMark rm;
527     LoaderInfoScanClosure cl (_show_classes, _verbose);
528     ClassLoaderDataGraph::loaded_cld_do(&cl);
529     // In non-verbose and non-show-classes mode, attempt to fold the tree.
530     if (_fold) {
531       if (!_verbose && !_show_classes) {
532         cl.fold();
533       }
534     }
535     cl.print_results(_out);
536   }
537 };
538 
539 // This command needs to be executed at a safepoint.
execute(DCmdSource source,TRAPS)540 void ClassLoaderHierarchyDCmd::execute(DCmdSource source, TRAPS) {
541   ClassLoaderHierarchyVMOperation op(output(), _show_classes.value(), _verbose.value(), _fold.value());
542   VMThread::execute(&op);
543 }
544