23 Star 19 Fork 75

src-openEuler / openjdk-1.8.0

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
8275775-Add-jcmd-VM.classes-to-print-details-of-all-.patch 16.45 KB
一键复制 编辑 原始数据 按行查看 历史
eapen 提交于 2023-01-11 10:00 . I69W1Y: Add feature and bug fix for 8u352
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
1
https://gitee.com/src-openeuler/openjdk-1.8.0.git
git@gitee.com:src-openeuler/openjdk-1.8.0.git
src-openeuler
openjdk-1.8.0
openjdk-1.8.0
master

搜索帮助