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