Projects
openEuler:24.03:SP1:Everything
openjdk-1.8.0
_service:tar_scm:8275775-Add-jcmd-VM.classes-to...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:tar_scm:8275775-Add-jcmd-VM.classes-to-print-details-of-all-.patch of Package openjdk-1.8.0
From c427ef7ceeea1fb8f8ebd035e59b6f06b5ec34c1 Mon Sep 17 00:00:00 2001 From: eapen <zhangyipeng7@huawei.com> Date: Tue, 13 Dec 2022 21:06:41 +0800 Subject: [PATCH 15/33] I68TO2: 8275775: Add jcmd VM.classes to print details of all classes --- hotspot/src/share/vm/oops/instanceKlass.cpp | 56 ++++++++++++++++++++-- hotspot/src/share/vm/oops/instanceKlass.hpp | 17 ++++--- hotspot/src/share/vm/runtime/fieldDescriptor.cpp | 4 +- hotspot/src/share/vm/runtime/fieldDescriptor.hpp | 4 +- hotspot/src/share/vm/runtime/globals.hpp | 2 +- hotspot/src/share/vm/runtime/vm_operations.hpp | 1 + .../src/share/vm/services/diagnosticCommand.cpp | 53 ++++++++++++++++++++ .../src/share/vm/services/diagnosticCommand.hpp | 23 +++++++++ hotspot/test/runtime/CommandLine/PrintClasses.java | 51 ++++++++++++++++++++ 9 files changed, 195 insertions(+), 16 deletions(-) create mode 100644 hotspot/test/runtime/CommandLine/PrintClasses.java diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index 2a9cd92..538645b 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -1799,6 +1799,52 @@ Method* InstanceKlass::lookup_method_in_all_interfaces(Symbol* name, return NULL; } +PrintClassClosure::PrintClassClosure(outputStream* st, bool verbose) + :_st(st), _verbose(verbose) { + ResourceMark rm; + _st->print("%-18s ", "KlassAddr"); + _st->print("%-4s ", "Size"); + _st->print("%-20s ", "State"); + _st->print("%-7s ", "Flags"); + _st->print("%-5s ", "ClassName"); + _st->cr(); +} + +void PrintClassClosure::do_klass(Klass* k) { + ResourceMark rm; + // klass pointer + _st->print(INTPTR_FORMAT " ", p2i(k)); + // klass size + _st->print("%4d ", k->size()); + // initialization state + if (k->oop_is_instance()) { + _st->print("%-20s ",InstanceKlass::cast(k)->init_state_name()); + } else { + _st->print("%-20s ",""); + } + // misc flags(Changes should synced with ClassesDCmd::ClassesDCmd help doc) + char buf[10]; + int i = 0; + if (k->has_finalizer()) buf[i++] = 'F'; + if (k->has_final_method()) buf[i++] = 'f'; + if (k->oop_is_instance()) { + InstanceKlass* ik = InstanceKlass::cast(k); + if (ik->is_rewritten()) buf[i++] = 'W'; + if (ik->is_contended()) buf[i++] = 'C'; + if (ik->has_been_redefined()) buf[i++] = 'R'; + if (ik->is_shared()) buf[i++] = 'S'; + } + buf[i++] = '\0'; + _st->print("%-7s ", buf); + // klass name + _st->print("%-5s ", k->external_name()); + // end + _st->cr(); + if (_verbose) { + k->print_on(_st); + } +} + /* jni_id_for_impl for jfieldIds only */ JNIid* InstanceKlass::jni_id_for_impl(instanceKlassHandle this_oop, int offset) { MutexLocker ml(JfieldIdCreation_lock); @@ -3244,7 +3290,6 @@ oop InstanceKlass::add_member_name(Handle mem_name, bool intern) { // ----------------------------------------------------------------------------------------------------- // Printing -#ifndef PRODUCT #define BULLET " - " @@ -3264,6 +3309,10 @@ static void print_vtable(intptr_t* start, int len, outputStream* st) { } } +const char* InstanceKlass::init_state_name() const { + return state_names[_init_state]; +} + void InstanceKlass::print_on(outputStream* st) const { assert(is_klass(), "must be klass"); Klass::print_on(st); @@ -3271,7 +3320,7 @@ void InstanceKlass::print_on(outputStream* st) const { st->print(BULLET"instance size: %d", size_helper()); st->cr(); st->print(BULLET"klass size: %d", size()); st->cr(); st->print(BULLET"access: "); access_flags().print_on(st); st->cr(); - st->print(BULLET"state: "); st->print_cr("%s", state_names[_init_state]); + st->print(BULLET"state: "); st->print_cr("%s", init_state_name()); st->print(BULLET"name: "); name()->print_value_on(st); st->cr(); st->print(BULLET"super: "); super()->print_value_on_maybe_null(st); st->cr(); st->print(BULLET"sub: "); @@ -3380,7 +3429,6 @@ void InstanceKlass::print_on(outputStream* st) const { st->cr(); } -#endif //PRODUCT void InstanceKlass::print_value_on(outputStream* st) const { assert(is_klass(), "must be klass"); @@ -3388,7 +3436,6 @@ void InstanceKlass::print_value_on(outputStream* st) const { name()->print_value_on(st); } -#ifndef PRODUCT void FieldPrinter::do_field(fieldDescriptor* fd) { _st->print(BULLET); @@ -3449,7 +3496,6 @@ void InstanceKlass::oop_print_on(oop obj, outputStream* st) { } } -#endif //PRODUCT void InstanceKlass::oop_print_value_on(oop obj, outputStream* st) { st->print("a "); diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp index 43919e8..6e36fa4 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp @@ -99,7 +99,6 @@ public: virtual void do_field(fieldDescriptor* fd) = 0; }; -#ifndef PRODUCT // Print fields. // If "obj" argument to constructor is NULL, prints static fields, otherwise prints non-static fields. class FieldPrinter: public FieldClosure { @@ -109,7 +108,6 @@ class FieldPrinter: public FieldClosure { FieldPrinter(outputStream* st, oop obj = NULL) : _obj(obj), _st(st) {} void do_field(fieldDescriptor* fd); }; -#endif // !PRODUCT // ValueObjs embedded in klass. Describes where oops are located in instances of // this klass. @@ -462,6 +460,7 @@ class InstanceKlass: public Klass { bool is_in_error_state() const { return _init_state == initialization_error; } bool is_reentrant_initialization(Thread *thread) { return thread == _init_thread; } ClassState init_state() { return (ClassState)_init_state; } + const char* init_state_name() const; bool is_rewritten() const { return (_misc_flags & _misc_rewritten) != 0; } // defineClass specified verification @@ -1174,16 +1173,13 @@ public: public: // Printing -#ifndef PRODUCT void print_on(outputStream* st) const; -#endif void print_value_on(outputStream* st) const; void oop_print_value_on(oop obj, outputStream* st); -#ifndef PRODUCT void oop_print_on (oop obj, outputStream* st); - +#ifndef PRODUCT void print_dependent_nmethods(bool verbose = false); bool is_dependent_nmethod(nmethod* nm); #endif @@ -1217,6 +1213,15 @@ inline u2 InstanceKlass::next_method_idnum() { } } +class PrintClassClosure : public KlassClosure { +private: + outputStream* _st; + bool _verbose; +public: + PrintClassClosure(outputStream* st, bool verbose); + + void do_klass(Klass* k); +}; /* JNIid class for jfieldIDs only */ class JNIid: public CHeapObj<mtClass> { diff --git a/hotspot/src/share/vm/runtime/fieldDescriptor.cpp b/hotspot/src/share/vm/runtime/fieldDescriptor.cpp index 610402d..288e82d 100644 --- a/hotspot/src/share/vm/runtime/fieldDescriptor.cpp +++ b/hotspot/src/share/vm/runtime/fieldDescriptor.cpp @@ -123,6 +123,8 @@ void fieldDescriptor::verify() const { } } +#endif /* PRODUCT */ + void fieldDescriptor::print_on(outputStream* st) const { access_flags().print_on(st); name()->print_value_on(st); @@ -206,5 +208,3 @@ void fieldDescriptor::print_on_for(outputStream* st, oop obj) { st->print(" (%x)", as_int); } } - -#endif /* PRODUCT */ diff --git a/hotspot/src/share/vm/runtime/fieldDescriptor.hpp b/hotspot/src/share/vm/runtime/fieldDescriptor.hpp index 1810a16..f7e9a26 100644 --- a/hotspot/src/share/vm/runtime/fieldDescriptor.hpp +++ b/hotspot/src/share/vm/runtime/fieldDescriptor.hpp @@ -129,8 +129,8 @@ class fieldDescriptor VALUE_OBJ_CLASS_SPEC { // Print void print() { print_on(tty); } - void print_on(outputStream* st) const PRODUCT_RETURN; - void print_on_for(outputStream* st, oop obj) PRODUCT_RETURN; + void print_on(outputStream* st) const; + void print_on_for(outputStream* st, oop obj); void verify() const PRODUCT_RETURN; }; diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index ec48c48..41b1392 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -3097,7 +3097,7 @@ class CommandLineFlags { notproduct(intx, MaxElementPrintSize, 256, \ "maximum number of elements to print") \ \ - notproduct(intx, MaxSubklassPrintSize, 4, \ + product(intx, MaxSubklassPrintSize, 4, \ "maximum number of subklasses to print when printing klass") \ \ product(intx, MaxInlineLevel, 9, \ diff --git a/hotspot/src/share/vm/runtime/vm_operations.hpp b/hotspot/src/share/vm/runtime/vm_operations.hpp index 8c6795a..a8ba78b 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.hpp +++ b/hotspot/src/share/vm/runtime/vm_operations.hpp @@ -99,6 +99,7 @@ template(WhiteBoxOperation) \ template(ClassLoaderStatsOperation) \ template(JFROldObject) \ + template(PrintClasses) \ class VM_Operation: public CHeapObj<mtInternal> { public: diff --git a/hotspot/src/share/vm/services/diagnosticCommand.cpp b/hotspot/src/share/vm/services/diagnosticCommand.cpp index 60417b5..e4e6185 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.cpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp @@ -64,6 +64,7 @@ void DCmdRegistrant::register_dcmds(){ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HeapDumpDCmd>(DCmd_Source_Internal | DCmd_Source_AttachAPI, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<DynamicCDSDumpDCmd>(DCmd_Source_Internal | DCmd_Source_AttachAPI, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassHistogramDCmd>(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassesDCmd>(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassStatsDCmd>(full_export, true, false)); #endif // INCLUDE_SERVICES DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(full_export, true, false)); @@ -98,9 +99,14 @@ HelpDCmd::HelpDCmd(outputStream* output, bool heap) : DCmdWithParser(output, hea _dcmdparser.add_dcmd_argument(&_cmd); }; +static int compare_strings(const char** s1, const char** s2) { + return ::strcmp(*s1, *s2); +} + void HelpDCmd::execute(DCmdSource source, TRAPS) { if (_all.value()) { GrowableArray<const char*>* cmd_list = DCmdFactory::DCmd_list(source); + cmd_list->sort(compare_strings); for (int i = 0; i < cmd_list->length(); i++) { DCmdFactory* factory = DCmdFactory::factory(source, cmd_list->at(i), strlen(cmd_list->at(i))); @@ -141,6 +147,7 @@ void HelpDCmd::execute(DCmdSource source, TRAPS) { } else { output()->print_cr("The following commands are available:"); GrowableArray<const char *>* cmd_list = DCmdFactory::DCmd_list(source); + cmd_list->sort(compare_strings); for (int i = 0; i < cmd_list->length(); i++) { DCmdFactory* factory = DCmdFactory::factory(source, cmd_list->at(i), strlen(cmd_list->at(i))); @@ -419,6 +426,52 @@ int ClassHistogramDCmd::num_arguments() { } } +ClassesDCmd::ClassesDCmd(outputStream* output, bool heap) : + DCmdWithParser(output, heap), + _verbose("-verbose", + "Dump the detailed content of a Java class. " + "Some classes are annotated with flags: " + "F = has, or inherits, a non-empty finalize method, " + "f = has final method, " + "W = methods rewritten, " + "C = marked with @Contended annotation, " + "R = has been redefined, " + "S = is shared class", + "BOOLEAN", false, "false") { + _dcmdparser.add_dcmd_option(&_verbose); +} + +class VM_PrintClasses : public VM_Operation { +private: + outputStream* _out; + bool _verbose; +public: + VM_PrintClasses(outputStream* out, bool verbose) : _out(out), _verbose(verbose) {} + + virtual VMOp_Type type() const { return VMOp_PrintClasses; } + + virtual void doit() { + PrintClassClosure closure(_out, _verbose); + ClassLoaderDataGraph::classes_do(&closure); + } +}; + +void ClassesDCmd::execute(DCmdSource source, TRAPS) { + VM_PrintClasses vmop(output(), _verbose.is_set()); + VMThread::execute(&vmop); +} + +int ClassesDCmd::num_arguments() { + ResourceMark rm; + ClassesDCmd* dcmd = new ClassesDCmd(NULL, false); + if (dcmd != NULL) { + DCmdMark mark(dcmd); + return dcmd->_dcmdparser.num_arguments(); + } else { + return 0; + } +} + #define DEFAULT_COLUMNS "InstBytes,KlassBytes,CpAll,annotations,MethodCount,Bytecodes,MethodAll,ROAll,RWAll,Total" ClassStatsDCmd::ClassStatsDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), diff --git a/hotspot/src/share/vm/services/diagnosticCommand.hpp b/hotspot/src/share/vm/services/diagnosticCommand.hpp index e28011f..f86ab5f 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.hpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp @@ -314,6 +314,29 @@ public: virtual void execute(DCmdSource source, TRAPS); }; +class ClassesDCmd : public DCmdWithParser { +protected: + DCmdArgument<bool> _verbose; +public: + ClassesDCmd(outputStream* output, bool heap); + static const char* name() { + return "VM.classes"; + } + static const char* description() { + return "Print all loaded classes"; + } + static const char* impact() { + return "Medium: Depends on number of loaded classes."; + } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "monitor", NULL}; + return p; + } + static int num_arguments(); + virtual void execute(DCmdSource source, TRAPS); +}; + class ClassStatsDCmd : public DCmdWithParser { protected: DCmdArgument<bool> _all; diff --git a/hotspot/test/runtime/CommandLine/PrintClasses.java b/hotspot/test/runtime/CommandLine/PrintClasses.java new file mode 100644 index 0000000..7c1d4db --- /dev/null +++ b/hotspot/test/runtime/CommandLine/PrintClasses.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited. All rights reserved. + * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +/* + * @test + * @bug 8275775 + * @summary Test jcmd VM.classes + * @library /testlibrary + * @run main/othervm PrintClasses + */ + +import com.oracle.java.testlibrary.*; + +public class PrintClasses { + public static void main(String args[]) throws Exception { + String pid = Integer.toString(ProcessTools.getProcessId()); + ProcessBuilder pb = new ProcessBuilder(); + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.classes"}); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("instance size"); + output.shouldContain(PrintClasses.class.getSimpleName()); + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.classes", "-verbose"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("instance size"); + output.shouldContain(PrintClasses.class.getSimpleName()); + } +} \ No newline at end of file -- 1.8.3.1
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2