< prev index next >

src/hotspot/share/classfile/classLoaderHierarchyDCmd.cpp

Print this page
rev 58565 : 8238358: Implementation of JEP 371: Hidden Classes
Reviewed-by: duke
Contributed-by: mandy.chung@oracle.com, lois.foltan@oracle.com, david.holmes@oracle.com, harold.seigel@oracle.com, serguei.spitsyn@oracle.com, alex.buckley@oracle.com, jamsheed.c.m@oracle.com
rev 58568 : [mq]: hidden-class-4
   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.


 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 non-unsafe_anonymous, 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   // 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 
 158   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       if (loader_name != NULL) {
 181         st->print(" \"%s\",", loader_name->as_C_string());
 182       }
 183       st->print(" %s", loader_klass != NULL ? loader_klass->external_name() : "??");
 184       if (_num_folded > 0) {
 185         st->print(" (+ %d more)", _num_folded);
 186       }
 187     }
 188     st->cr();
 189 
 190     // Output following this node (node details and child nodes) - up to the next sibling node
 191     // needs to be prefixed with "|" if there is a follow up sibling.
 192     const bool have_sibling = _next != NULL;
 193     BranchTracker::Mark trm(branchtracker, have_sibling);
 194 
 195     {
 196       // optional node details following this node needs to be prefixed with "|"
 197       // if there are follow up child nodes.
 198       const bool have_child = _child != NULL;
 199       BranchTracker::Mark trm(branchtracker, have_child);


 203       st->cr();
 204 
 205       const int indentation = 18;
 206 
 207       if (verbose) {
 208         branchtracker.print(st);
 209         st->print_cr("%*s " PTR_FORMAT, indentation, "Loader Oop:", p2i(_loader_oop));
 210         branchtracker.print(st);
 211         st->print_cr("%*s " PTR_FORMAT, indentation, "Loader Data:", p2i(_cld));
 212         branchtracker.print(st);
 213         st->print_cr("%*s " PTR_FORMAT, indentation, "Loader Klass:", p2i(loader_klass));
 214 
 215         // Empty line
 216         branchtracker.print(st);
 217         st->cr();
 218       }
 219 
 220       if (print_classes) {
 221         if (_classes != NULL) {
 222           for (LoadedClassInfo* lci = _classes; lci; lci = lci->_next) {
 223             // Non-unsafe anonymous classes should live in the primary CLD of its loader
 224             assert(lci->_cld == _cld, "must be");
 225 
 226             branchtracker.print(st);
 227             if (lci == _classes) { // first iteration
 228               st->print("%*s ", indentation, "Classes:");
 229             } else {
 230               st->print("%*s ", indentation, "");
 231             }
 232             st->print("%s", lci->_klass->external_name());
 233 
 234             // Special treatment for generated core reflection accessor classes: print invocation target.
 235             if (ReflectionAccessorImplKlassHelper::is_generated_accessor(lci->_klass)) {
 236               st->print(" (invokes: ");
 237               ReflectionAccessorImplKlassHelper::print_invocation_target(st, lci->_klass);
 238               st->print(")");
 239             }
 240 
 241             st->cr();
 242           }
 243           branchtracker.print(st);
 244           st->print("%*s ", indentation, "");
 245           st->print_cr("(%u class%s)", _num_classes, (_num_classes == 1) ? "" : "es");
 246 
 247           // Empty line
 248           branchtracker.print(st);
 249           st->cr();
 250         }
 251 
 252         if (_anon_classes != NULL) {
 253           for (LoadedClassInfo* lci = _anon_classes; lci; lci = lci->_next) {
 254             branchtracker.print(st);
 255             if (lci == _anon_classes) { // first iteration
 256               st->print("%*s ", indentation, "Unsafe Anonymous Classes:");
 257             } else {
 258               st->print("%*s ", indentation, "");
 259             }
 260             st->print("%s", lci->_klass->external_name());
 261             // For unsafe anonymous classes, also print CLD if verbose. Should be a different one than the primary CLD.




























 262             assert(lci->_cld != _cld, "must be");
 263             if (verbose) {
 264               st->print("  (Loader Data: " PTR_FORMAT ")", p2i(lci->_cld));
 265             }
 266             st->cr();
 267           }
 268           branchtracker.print(st);
 269           st->print("%*s ", indentation, "");
 270           st->print_cr("(%u unsafe anonymous class%s)", _num_anon_classes, (_num_anon_classes == 1) ? "" : "es");

 271 
 272           // Empty line
 273           branchtracker.print(st);
 274           st->cr();
 275         }
 276 
 277       } // end: print_classes
 278 
 279     } // Pop branchtracker mark
 280 
 281     // Print children, recursively
 282     LoaderTreeNode* c = _child;
 283     while (c != NULL) {
 284       c->print_with_childs(st, branchtracker, print_classes, verbose);
 285       c = c->_next;
 286     }
 287 
 288   }
 289 
 290   // Helper: Attempt to fold this node into the target node. If success, returns true.
 291   // Folding can be done if both nodes are leaf nodes and they refer to the same loader class
 292   // and they have the same name or no name (note: leaf check is done by caller).
 293   bool can_fold_into(LoaderTreeNode* target_node) const {
 294     assert(is_leaf() && target_node->is_leaf(), "must be leaf");
 295     return _cld->class_loader_klass() == target_node->_cld->class_loader_klass() &&
 296            _cld->name() == target_node->_cld->name();
 297   }
 298 
 299 public:
 300 
 301   LoaderTreeNode(const oop loader_oop)
 302     : _loader_oop(loader_oop), _cld(NULL), _child(NULL), _next(NULL),
 303       _classes(NULL), _num_classes(0), _anon_classes(NULL), _num_anon_classes(0),

 304       _num_folded(0)
 305     {}
 306 
 307   void set_cld(const ClassLoaderData* cld) {
 308     _cld = cld;
 309   }
 310 
 311   void add_child(LoaderTreeNode* info) {
 312     info->_next = _child;
 313     _child = info;
 314   }
 315 
 316   void add_sibling(LoaderTreeNode* info) {
 317     assert(info->_next == NULL, "must be");
 318     info->_next = _next;
 319     _next = info;
 320   }
 321 
 322   void add_classes(LoadedClassInfo* first_class, int num_classes, bool is_unsafe_anonymous) {
 323     LoadedClassInfo** p_list_to_add_to = is_unsafe_anonymous ? &_anon_classes : &_classes;






 324     // Search tail.
 325     while ((*p_list_to_add_to) != NULL) {
 326       p_list_to_add_to = &(*p_list_to_add_to)->_next;
 327     }
 328     *p_list_to_add_to = first_class;
 329     if (is_unsafe_anonymous) {



 330       _num_anon_classes += num_classes;

 331     } else {
 332       _num_classes += num_classes;
 333     }
 334   }
 335 
 336   const ClassLoaderData* cld() const {
 337     return _cld;
 338   }
 339 
 340   const oop loader_oop() const {
 341     return _loader_oop;
 342   }
 343 
 344   LoaderTreeNode* find(const oop loader_oop) {
 345     LoaderTreeNode* result = NULL;
 346     if (_loader_oop == loader_oop) {
 347       result = this;
 348     } else {
 349       LoaderTreeNode* c = _child;
 350       while (c != NULL && result == NULL) {


 404     : _list(NULL), _cld(cld), _num_classes(0) {}
 405   void do_klass(Klass* k) {
 406     LoadedClassInfo* lki = new LoadedClassInfo(k, _cld);
 407     lki->_next = _list;
 408     _list = lki;
 409     _num_classes ++;
 410   }
 411 };
 412 
 413 class LoaderInfoScanClosure : public CLDClosure {
 414 
 415   const bool _print_classes;
 416   const bool _verbose;
 417   LoaderTreeNode* _root;
 418 
 419   static void fill_in_classes(LoaderTreeNode* info, const ClassLoaderData* cld) {
 420     assert(info != NULL && cld != NULL, "must be");
 421     LoadedClassCollectClosure lccc(cld);
 422     const_cast<ClassLoaderData*>(cld)->classes_do(&lccc);
 423     if (lccc._num_classes > 0) {
 424       info->add_classes(lccc._list, lccc._num_classes, cld->is_unsafe_anonymous());
 425     }
 426   }
 427 
 428   LoaderTreeNode* find_node_or_add_empty_node(oop loader_oop) {
 429 
 430     assert(_root != NULL, "root node must exist");
 431 
 432     if (loader_oop == NULL) {
 433       return _root;
 434     }
 435 
 436     // Check if a node for this oop already exists.
 437     LoaderTreeNode* info = _root->find(loader_oop);
 438 
 439     if (info == NULL) {
 440       // It does not. Create a node.
 441       info = new LoaderTreeNode(loader_oop);
 442 
 443       // Add it to tree.
 444       LoaderTreeNode* parent_info = NULL;


 464     _root = new LoaderTreeNode(NULL);
 465   }
 466 
 467   void print_results(outputStream* st) const {
 468     _root->print_with_childs(st, _print_classes, _verbose);
 469   }
 470 
 471   void do_cld (ClassLoaderData* cld) {
 472 
 473     // We do not display unloading loaders, for now.
 474     if (!cld->is_alive()) {
 475       return;
 476     }
 477 
 478     const oop loader_oop = cld->class_loader();
 479 
 480     LoaderTreeNode* info = find_node_or_add_empty_node(loader_oop);
 481     assert(info != NULL, "must be");
 482 
 483     // Update CLD in node, but only if this is the primary CLD for this loader.
 484     if (cld->is_unsafe_anonymous() == false) {
 485       assert(info->cld() == NULL, "there should be only one primary CLD per loader");
 486       info->set_cld(cld);
 487     }
 488 
 489     // Add classes.
 490     fill_in_classes(info, cld);
 491   }
 492 
 493   void fold() {
 494     _root->fold_children();
 495   }
 496 
 497 };
 498 
 499 
 500 class ClassLoaderHierarchyVMOperation : public VM_Operation {
 501   outputStream* const _out;
 502   const bool _show_classes;
 503   const bool _verbose;
 504   const bool _fold;


   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.


 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);


 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) {


 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;


 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;


< prev index next >