mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
8275775: Add jcmd VM.classes to print details of all classes
Reviewed-by: dholmes, iklam, stuefe
This commit is contained in:
parent
cde923dd47
commit
3f0684d0b8
@ -2074,6 +2074,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->is_instance_klass()) {
|
||||
_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->is_instance_klass()) {
|
||||
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 for jfieldIds only */
|
||||
JNIid* InstanceKlass::jni_id_for(int offset) {
|
||||
MutexLocker ml(JfieldIdCreation_lock);
|
||||
@ -3393,6 +3439,10 @@ static void print_vtable(vtableEntry* start, int len, outputStream* st) {
|
||||
return print_vtable(reinterpret_cast<intptr_t*>(start), len, 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);
|
||||
@ -3400,7 +3450,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: "); Metadata::print_value_on_maybe_null(st, super()); st->cr();
|
||||
st->print(BULLET"sub: ");
|
||||
|
||||
@ -547,6 +547,7 @@ public:
|
||||
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; }
|
||||
|
||||
// is this a sealed class
|
||||
@ -1277,6 +1278,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> {
|
||||
|
||||
@ -95,6 +95,7 @@
|
||||
template(CleanClassLoaderDataMetaspaces) \
|
||||
template(PrintCompileQueue) \
|
||||
template(PrintClassHierarchy) \
|
||||
template(PrintClasses) \
|
||||
template(ICBufferFull) \
|
||||
template(PrintMetadata) \
|
||||
template(GTestExecuteAtSafepoint) \
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
#include "jvm.h"
|
||||
#include "classfile/classLoaderHierarchyDCmd.hpp"
|
||||
#include "classfile/classLoaderStats.hpp"
|
||||
#include "classfile/classLoaderDataGraph.hpp"
|
||||
#include "classfile/javaClasses.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "classfile/vmClasses.hpp"
|
||||
@ -102,6 +103,7 @@ void DCmdRegistrant::register_dcmds(){
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassHistogramDCmd>(full_export, true, false));
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SystemDictionaryDCmd>(full_export, true, false));
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassHierarchyDCmd>(full_export, true, false));
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassesDCmd>(full_export, true, false));
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SymboltableDCmd>(full_export, true, false));
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<StringtableDCmd>(full_export, true, false));
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<metaspace::MetaspaceDCmd>(full_export, true, false));
|
||||
@ -954,6 +956,41 @@ void TouchedMethodsDCmd::execute(DCmdSource source, TRAPS) {
|
||||
VMThread::execute(&dumper);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS
|
||||
DumpSharedArchiveDCmd::DumpSharedArchiveDCmd(outputStream* output, bool heap) :
|
||||
DCmdWithParser(output, heap),
|
||||
|
||||
@ -858,6 +858,28 @@ 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;
|
||||
}
|
||||
virtual void execute(DCmdSource source, TRAPS);
|
||||
};
|
||||
|
||||
#if INCLUDE_JVMTI
|
||||
class DebugOnCmdStartDCmd : public DCmd {
|
||||
public:
|
||||
|
||||
51
test/hotspot/jtreg/runtime/CommandLine/PrintClasses.java
Normal file
51
test/hotspot/jtreg/runtime/CommandLine/PrintClasses.java
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Alibaba Group Holding Limited. 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 /test/lib
|
||||
* @run main/othervm PrintClasses
|
||||
*/
|
||||
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.JDKToolFinder;
|
||||
|
||||
public class PrintClasses {
|
||||
public static void main(String args[]) throws Exception {
|
||||
var pid = Long.toString(ProcessHandle.current().pid());
|
||||
var pb = new ProcessBuilder();
|
||||
|
||||
pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.classes"});
|
||||
var 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());
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user