1 /* 2 * Copyright (c) 2018, 2020, 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 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 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: 88 BranchTracker() 89 : _pos(0) {} 90 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 98 void pop() { 99 assert(_pos > 0, "must be"); 100 _pos --; 101 } 102 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: 112 Mark(BranchTracker& tr, bool has_branch_here) 113 : _tr(tr) { _tr.push(has_branch_here); } 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 125 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* _anon_classes; 150 int _num_anon_classes; 151 152 LoadedClassInfo* _hidden_classes; 153 int _num_hidden_classes; 154 155 // In default view, similar tree nodes (same loader class, same name or no name) 156 // are folded into each other to make the output more readable. 157 // _num_folded contains the number of nodes which have been folded into this 158 // one. 159 int _num_folded; 160 161 void print_with_childs(outputStream* st, BranchTracker& branchtracker, 162 bool print_classes, bool verbose) const { 163 164 ResourceMark rm; 165 166 if (_cld == NULL) { 167 // Not sure how this could happen: we added a preliminary node for a parent but then never encountered 168 // its CLD? 169 return; 170 } 171 172 // Retrieve information. 173 const Klass* const loader_klass = _cld->class_loader_klass(); 174 const Symbol* const loader_name = _cld->name(); 175 176 branchtracker.print(st); 177 178 // e.g. "+--- jdk.internal.reflect.DelegatingClassLoader" 179 st->print("+%.*s", BranchTracker::twig_len, "----------"); 180 if (_cld->is_the_null_class_loader_data()) { 181 st->print(" <bootstrap>"); 182 } else { 183 assert(!_cld->has_class_mirror_holder(), "_cld must be the primary cld"); 184 if (loader_name != NULL) { 185 st->print(" \"%s\",", loader_name->as_C_string()); 186 } 187 st->print(" %s", loader_klass != NULL ? loader_klass->external_name() : "??"); 188 if (_num_folded > 0) { 189 st->print(" (+ %d more)", _num_folded); 190 } 191 } 192 st->cr(); 193 194 // Output following this node (node details and child nodes) - up to the next sibling node 195 // needs to be prefixed with "|" if there is a follow up sibling. 196 const bool have_sibling = _next != NULL; 197 BranchTracker::Mark trm(branchtracker, have_sibling); 198 199 { 200 // optional node details following this node needs to be prefixed with "|" 201 // if there are follow up child nodes. 202 const bool have_child = _child != NULL; 203 BranchTracker::Mark trm(branchtracker, have_child); 204 205 // Empty line 206 branchtracker.print(st); 207 st->cr(); 208 209 const int indentation = 18; 210 211 if (verbose) { 212 branchtracker.print(st); 213 st->print_cr("%*s " PTR_FORMAT, indentation, "Loader Oop:", p2i(_loader_oop)); 214 branchtracker.print(st); 215 st->print_cr("%*s " PTR_FORMAT, indentation, "Loader Data:", p2i(_cld)); 216 branchtracker.print(st); 217 st->print_cr("%*s " PTR_FORMAT, indentation, "Loader Klass:", p2i(loader_klass)); 218 219 // Empty line 220 branchtracker.print(st); 221 st->cr(); 222 } 223 224 if (print_classes) { 225 if (_classes != NULL) { 226 for (LoadedClassInfo* lci = _classes; lci; lci = lci->_next) { 227 // non-strong hidden and unsafe anonymous classes should not live in the primary CLD of their loaders. 228 assert(lci->_cld == _cld, "must be"); 229 230 branchtracker.print(st); 231 if (lci == _classes) { // first iteration 232 st->print("%*s ", indentation, "Classes:"); 233 } else { 234 st->print("%*s ", indentation, ""); 235 } 236 st->print("%s", lci->_klass->external_name()); 237 238 // Special treatment for generated core reflection accessor classes: print invocation target. 239 if (ReflectionAccessorImplKlassHelper::is_generated_accessor(lci->_klass)) { 240 st->print(" (invokes: "); 241 ReflectionAccessorImplKlassHelper::print_invocation_target(st, lci->_klass); 242 st->print(")"); 243 } 244 245 st->cr(); 246 } 247 branchtracker.print(st); 248 st->print("%*s ", indentation, ""); 249 st->print_cr("(%u class%s)", _num_classes, (_num_classes == 1) ? "" : "es"); 250 251 // Empty line 252 branchtracker.print(st); 253 st->cr(); 254 } 255 256 if (_anon_classes != NULL) { 257 for (LoadedClassInfo* lci = _anon_classes; lci; lci = lci->_next) { 258 branchtracker.print(st); 259 if (lci == _anon_classes) { // first iteration 260 st->print("%*s ", indentation, "Unsafe Anonymous Classes:"); 261 } else { 262 st->print("%*s ", indentation, ""); 263 } 264 st->print("%s", lci->_klass->external_name()); 265 // For unsafe anonymous classes, also print CLD if verbose. Should 266 // be a different one than the primary CLD. 267 assert(lci->_cld != _cld, "must be"); 268 if (verbose) { 269 st->print(" (Loader Data: " PTR_FORMAT ")", p2i(lci->_cld)); 270 } 271 st->cr(); 272 } 273 branchtracker.print(st); 274 st->print("%*s ", indentation, ""); 275 st->print_cr("(%u unsafe anonymous class%s)", _num_anon_classes, 276 (_num_anon_classes == 1) ? "" : "es"); 277 278 // Empty line 279 branchtracker.print(st); 280 st->cr(); 281 } 282 283 if (_hidden_classes != NULL) { 284 for (LoadedClassInfo* lci = _hidden_classes; lci; lci = lci->_next) { 285 branchtracker.print(st); 286 if (lci == _hidden_classes) { // first iteration 287 st->print("%*s ", indentation, "Hidden Classes:"); 288 } else { 289 st->print("%*s ", indentation, ""); 290 } 291 st->print("%s", lci->_klass->external_name()); 292 // For non-strong hidden classes, also print CLD if verbose. Should be a 293 // different one than the primary CLD. 294 assert(lci->_cld != _cld, "must be"); 295 if (verbose) { 296 st->print(" (Loader Data: " PTR_FORMAT ")", p2i(lci->_cld)); 297 } 298 st->cr(); 299 } 300 branchtracker.print(st); 301 st->print("%*s ", indentation, ""); 302 st->print_cr("(%u hidden class%s)", _num_hidden_classes, 303 (_num_hidden_classes == 1) ? "" : "es"); 304 305 // Empty line 306 branchtracker.print(st); 307 st->cr(); 308 } 309 310 } // end: print_classes 311 312 } // Pop branchtracker mark 313 314 // Print children, recursively 315 LoaderTreeNode* c = _child; 316 while (c != NULL) { 317 c->print_with_childs(st, branchtracker, print_classes, verbose); 318 c = c->_next; 319 } 320 321 } 322 323 // Helper: Attempt to fold this node into the target node. If success, returns true. 324 // Folding can be done if both nodes are leaf nodes and they refer to the same loader class 325 // and they have the same name or no name (note: leaf check is done by caller). 326 bool can_fold_into(LoaderTreeNode* target_node) const { 327 assert(is_leaf() && target_node->is_leaf(), "must be leaf"); 328 return _cld->class_loader_klass() == target_node->_cld->class_loader_klass() && 329 _cld->name() == target_node->_cld->name(); 330 } 331 332 public: 333 334 LoaderTreeNode(const oop loader_oop) 335 : _loader_oop(loader_oop), _cld(NULL), _child(NULL), _next(NULL), 336 _classes(NULL), _num_classes(0), _anon_classes(NULL), _num_anon_classes(0), 337 _hidden_classes(NULL), _num_hidden_classes(0), 338 _num_folded(0) 339 {} 340 341 void set_cld(const ClassLoaderData* cld) { 342 _cld = cld; 343 } 344 345 void add_child(LoaderTreeNode* info) { 346 info->_next = _child; 347 _child = info; 348 } 349 350 void add_sibling(LoaderTreeNode* info) { 351 assert(info->_next == NULL, "must be"); 352 info->_next = _next; 353 _next = info; 354 } 355 356 void add_classes(LoadedClassInfo* first_class, int num_classes, bool has_class_mirror_holder) { 357 LoadedClassInfo** p_list_to_add_to; 358 bool is_hidden = first_class->_klass->is_hidden(); 359 if (has_class_mirror_holder) { 360 p_list_to_add_to = is_hidden ? &_hidden_classes : &_anon_classes; 361 } else { 362 p_list_to_add_to = &_classes; 363 } 364 // Search tail. 365 while ((*p_list_to_add_to) != NULL) { 366 p_list_to_add_to = &(*p_list_to_add_to)->_next; 367 } 368 *p_list_to_add_to = first_class; 369 if (has_class_mirror_holder) { 370 if (is_hidden) { 371 _num_hidden_classes += num_classes; 372 } else { 373 _num_anon_classes += num_classes; 374 } 375 } else { 376 _num_classes += num_classes; 377 } 378 } 379 380 const ClassLoaderData* cld() const { 381 return _cld; 382 } 383 384 const oop loader_oop() const { 385 return _loader_oop; 386 } 387 388 LoaderTreeNode* find(const oop loader_oop) { 389 LoaderTreeNode* result = NULL; 390 if (_loader_oop == loader_oop) { 391 result = this; 392 } else { 393 LoaderTreeNode* c = _child; 394 while (c != NULL && result == NULL) { 395 result = c->find(loader_oop); 396 c = c->_next; 397 } 398 } 399 return result; 400 } 401 402 bool is_leaf() const { return _child == NULL; } 403 404 // Attempt to fold similar nodes among this node's children. We only fold leaf nodes 405 // (no child class loaders). 406 // For non-leaf nodes (class loaders with child class loaders), do this recursivly. 407 void fold_children() { 408 LoaderTreeNode* node = _child; 409 LoaderTreeNode* prev = NULL; 410 while (node != NULL) { 411 LoaderTreeNode* matching_node = NULL; 412 if (node->is_leaf()) { 413 // Look among the preceeding node siblings for a match. 414 for (LoaderTreeNode* node2 = _child; node2 != node && matching_node == NULL; 415 node2 = node2->_next) { 416 if (node2->is_leaf() && node->can_fold_into(node2)) { 417 matching_node = node2; 418 } 419 } 420 } else { 421 node->fold_children(); 422 } 423 if (matching_node != NULL) { 424 // Increase fold count for the matching node and remove folded node from the child list. 425 matching_node->_num_folded ++; 426 assert(prev != NULL, "Sanity"); // can never happen since we do not fold the first node. 427 prev->_next = node->_next; 428 } else { 429 prev = node; 430 } 431 node = node->_next; 432 } 433 } 434 435 void print_with_childs(outputStream* st, bool print_classes, bool print_add_info) const { 436 BranchTracker bwt; 437 print_with_childs(st, bwt, print_classes, print_add_info); 438 } 439 440 }; 441 442 class LoadedClassCollectClosure : public KlassClosure { 443 public: 444 LoadedClassInfo* _list; 445 const ClassLoaderData* _cld; 446 int _num_classes; 447 LoadedClassCollectClosure(const ClassLoaderData* cld) 448 : _list(NULL), _cld(cld), _num_classes(0) {} 449 void do_klass(Klass* k) { 450 LoadedClassInfo* lki = new LoadedClassInfo(k, _cld); 451 lki->_next = _list; 452 _list = lki; 453 _num_classes ++; 454 } 455 }; 456 457 class LoaderInfoScanClosure : public CLDClosure { 458 459 const bool _print_classes; 460 const bool _verbose; 461 LoaderTreeNode* _root; 462 463 static void fill_in_classes(LoaderTreeNode* info, const ClassLoaderData* cld) { 464 assert(info != NULL && cld != NULL, "must be"); 465 LoadedClassCollectClosure lccc(cld); 466 const_cast<ClassLoaderData*>(cld)->classes_do(&lccc); 467 if (lccc._num_classes > 0) { 468 info->add_classes(lccc._list, lccc._num_classes, cld->has_class_mirror_holder()); 469 } 470 } 471 472 LoaderTreeNode* find_node_or_add_empty_node(oop loader_oop) { 473 474 assert(_root != NULL, "root node must exist"); 475 476 if (loader_oop == NULL) { 477 return _root; 478 } 479 480 // Check if a node for this oop already exists. 481 LoaderTreeNode* info = _root->find(loader_oop); 482 483 if (info == NULL) { 484 // It does not. Create a node. 485 info = new LoaderTreeNode(loader_oop); 486 487 // Add it to tree. 488 LoaderTreeNode* parent_info = NULL; 489 490 // Recursively add parent nodes if needed. 491 const oop parent_oop = java_lang_ClassLoader::parent(loader_oop); 492 if (parent_oop == NULL) { 493 parent_info = _root; 494 } else { 495 parent_info = find_node_or_add_empty_node(parent_oop); 496 } 497 assert(parent_info != NULL, "must be"); 498 499 parent_info->add_child(info); 500 } 501 return info; 502 } 503 504 505 public: 506 LoaderInfoScanClosure(bool print_classes, bool verbose) 507 : _print_classes(print_classes), _verbose(verbose), _root(NULL) { 508 _root = new LoaderTreeNode(NULL); 509 } 510 511 void print_results(outputStream* st) const { 512 _root->print_with_childs(st, _print_classes, _verbose); 513 } 514 515 void do_cld (ClassLoaderData* cld) { 516 517 // We do not display unloading loaders, for now. 518 if (!cld->is_alive()) { 519 return; 520 } 521 522 const oop loader_oop = cld->class_loader(); 523 524 LoaderTreeNode* info = find_node_or_add_empty_node(loader_oop); 525 assert(info != NULL, "must be"); 526 527 // Update CLD in node, but only if this is the primary CLD for this loader. 528 if (cld->has_class_mirror_holder() == false) { 529 assert(info->cld() == NULL, "there should be only one primary CLD per loader"); 530 info->set_cld(cld); 531 } 532 533 // Add classes. 534 fill_in_classes(info, cld); 535 } 536 537 void fold() { 538 _root->fold_children(); 539 } 540 541 }; 542 543 544 class ClassLoaderHierarchyVMOperation : public VM_Operation { 545 outputStream* const _out; 546 const bool _show_classes; 547 const bool _verbose; 548 const bool _fold; 549 public: 550 ClassLoaderHierarchyVMOperation(outputStream* out, bool show_classes, bool verbose, bool fold) : 551 _out(out), _show_classes(show_classes), _verbose(verbose), _fold(fold) 552 {} 553 554 VMOp_Type type() const { 555 return VMOp_ClassLoaderHierarchyOperation; 556 } 557 558 void doit() { 559 assert(SafepointSynchronize::is_at_safepoint(), "must be a safepoint"); 560 ResourceMark rm; 561 LoaderInfoScanClosure cl (_show_classes, _verbose); 562 ClassLoaderDataGraph::loaded_cld_do(&cl); 563 // In non-verbose and non-show-classes mode, attempt to fold the tree. 564 if (_fold) { 565 if (!_verbose && !_show_classes) { 566 cl.fold(); 567 } 568 } 569 cl.print_results(_out); 570 } 571 }; 572 573 // This command needs to be executed at a safepoint. 574 void ClassLoaderHierarchyDCmd::execute(DCmdSource source, TRAPS) { 575 ClassLoaderHierarchyVMOperation op(output(), _show_classes.value(), _verbose.value(), _fold.value()); 576 VMThread::execute(&op); 577 }