8184994: Add Dictionary size logging and jcmd
Summary: added dcmd for printing system dictionary like the stringtable and symboltable and making print functions go to outputstream rather than tty
Reviewed-by: shade, hseigel
--- a/hotspot/src/share/vm/classfile/classLoaderData.cpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp Wed Aug 02 10:52:50 2017 -0400
@@ -1136,12 +1136,22 @@
}
}
-void ClassLoaderDataGraph::print_dictionary(bool details) {
+void ClassLoaderDataGraph::print_dictionary(outputStream* st) {
FOR_ALL_DICTIONARY(cld) {
- tty->print("Dictionary for class loader ");
- cld->print_value();
- tty->cr();
- cld->dictionary()->print(details);
+ st->print("Dictionary for ");
+ cld->print_value_on(st);
+ st->cr();
+ cld->dictionary()->print_on(st);
+ st->cr();
+ }
+}
+
+void ClassLoaderDataGraph::print_dictionary_statistics(outputStream* st) {
+ FOR_ALL_DICTIONARY(cld) {
+ ResourceMark rm;
+ stringStream tempst;
+ tempst.print("System Dictionary for %s", cld->loader_name());
+ cld->dictionary()->print_table_statistics(st, tempst.as_string());
}
}
@@ -1422,7 +1432,7 @@
void ClassLoaderData::print_value_on(outputStream* out) const {
if (class_loader() == NULL) {
- out->print("NULL class_loader");
+ out->print("NULL class loader");
} else {
out->print("class loader " INTPTR_FORMAT " ", p2i(this));
class_loader()->print_value_on(out);
@@ -1431,7 +1441,7 @@
void ClassLoaderData::print_on(outputStream* out) const {
if (class_loader() == NULL) {
- out->print("NULL class_loader");
+ out->print("NULL class loader");
} else {
out->print("class loader " INTPTR_FORMAT " ", p2i(this));
class_loader()->print_on(out);
--- a/hotspot/src/share/vm/classfile/classLoaderData.hpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp Wed Aug 02 10:52:50 2017 -0400
@@ -125,7 +125,8 @@
static InstanceKlass* try_get_next_class();
static void verify_dictionary();
- static void print_dictionary(bool details);
+ static void print_dictionary(outputStream* st);
+ static void print_dictionary_statistics(outputStream* st);
// CMS support.
static void remember_new_clds(bool remember) { _saved_head = (remember ? _head : NULL); }
--- a/hotspot/src/share/vm/classfile/compactHashtable.cpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/classfile/compactHashtable.cpp Wed Aug 02 10:52:50 2017 -0400
@@ -29,6 +29,7 @@
#include "memory/metadataFactory.hpp"
#include "memory/metaspaceShared.hpp"
#include "prims/jvm.h"
+#include "runtime/vmThread.hpp"
#include "utilities/numberSeq.hpp"
#include <sys/stat.h>
--- a/hotspot/src/share/vm/classfile/compactHashtable.hpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/classfile/compactHashtable.hpp Wed Aug 02 10:52:50 2017 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. 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
@@ -25,10 +25,8 @@
#ifndef SHARE_VM_CLASSFILE_COMPACTHASHTABLE_HPP
#define SHARE_VM_CLASSFILE_COMPACTHASHTABLE_HPP
-#include "classfile/stringTable.hpp"
-#include "classfile/symbolTable.hpp"
+#include "oops/array.hpp"
#include "oops/symbol.hpp"
-#include "services/diagnosticCommand.hpp"
#include "utilities/hashtable.hpp"
template <class T, class N> class CompactHashtable;
@@ -357,89 +355,4 @@
static void put_utf8(outputStream* st, const char* utf8_string, int utf8_length);
};
-///////////////////////////////////////////////////////////////////////
-//
-// jcmd command support for symbol table and string table dumping:
-// VM.symboltable -verbose: for dumping the symbol table
-// VM.stringtable -verbose: for dumping the string table
-//
-class VM_DumpHashtable : public VM_Operation {
-private:
- outputStream* _out;
- int _which;
- bool _verbose;
-public:
- enum {
- DumpSymbols = 1 << 0,
- DumpStrings = 1 << 1,
- DumpSysDict = 1 << 2 // not implemented yet
- };
- VM_DumpHashtable(outputStream* out, int which, bool verbose) {
- _out = out;
- _which = which;
- _verbose = verbose;
- }
-
- virtual VMOp_Type type() const { return VMOp_DumpHashtable; }
-
- virtual void doit() {
- switch (_which) {
- case DumpSymbols:
- SymbolTable::dump(_out, _verbose);
- break;
- case DumpStrings:
- StringTable::dump(_out, _verbose);
- break;
- default:
- ShouldNotReachHere();
- }
- }
-};
-
-class SymboltableDCmd : public DCmdWithParser {
-protected:
- DCmdArgument<bool> _verbose;
-public:
- SymboltableDCmd(outputStream* output, bool heap);
- static const char* name() {
- return "VM.symboltable";
- }
- static const char* description() {
- return "Dump symbol table.";
- }
- static const char* impact() {
- return "Medium: Depends on Java content.";
- }
- 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 StringtableDCmd : public DCmdWithParser {
-protected:
- DCmdArgument<bool> _verbose;
-public:
- StringtableDCmd(outputStream* output, bool heap);
- static const char* name() {
- return "VM.stringtable";
- }
- static const char* description() {
- return "Dump string table.";
- }
- static const char* impact() {
- return "Medium: Depends on Java content.";
- }
- static const JavaPermission permission() {
- JavaPermission p = {"java.lang.management.ManagementPermission",
- "monitor", NULL};
- return p;
- }
- static int num_arguments();
- virtual void execute(DCmdSource source, TRAPS);
-};
-
#endif // SHARE_VM_CLASSFILE_COMPACTHASHTABLE_HPP
--- a/hotspot/src/share/vm/classfile/dictionary.cpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/classfile/dictionary.cpp Wed Aug 02 10:52:50 2017 -0400
@@ -435,16 +435,13 @@
// ----------------------------------------------------------------------------
-void Dictionary::print(bool details) {
+void Dictionary::print_on(outputStream* st) const {
ResourceMark rm;
assert(loader_data() != NULL, "loader data should not be null");
- if (details) {
- tty->print_cr("Java dictionary (table_size=%d, classes=%d)",
- table_size(), number_of_entries());
- tty->print_cr("^ indicates that initiating loader is different from "
- "defining loader");
- }
+ st->print_cr("Java dictionary (table_size=%d, classes=%d)",
+ table_size(), number_of_entries());
+ st->print_cr("^ indicates that initiating loader is different from defining loader");
for (int index = 0; index < table_size(); index++) {
for (DictionaryEntry* probe = bucket(index);
@@ -453,17 +450,15 @@
Klass* e = probe->instance_klass();
bool is_defining_class =
(loader_data() == e->class_loader_data());
- if (details) {
- tty->print("%4d: ", index);
+ st->print("%4d: %s%s, loader ", index, is_defining_class ? " " : "^", e->external_name());
+ ClassLoaderData* loader_data = e->class_loader_data();
+ if (loader_data == NULL) {
+ // Shared class not restored yet in shared dictionary
+ st->print("<shared, not restored>");
+ } else {
+ loader_data->print_value_on(st);
}
- tty->print("%s%s", ((!details) || is_defining_class) ? " " : "^",
- e->external_name());
-
- if (details) {
- tty->print(", loader ");
- e->class_loader_data()->print_value();
- }
- tty->cr();
+ st->cr();
}
}
tty->cr();
@@ -493,4 +488,3 @@
tempst.print("System Dictionary for %s", cld->loader_name());
verify_table<DictionaryEntry>(tempst.as_string());
}
-
--- a/hotspot/src/share/vm/classfile/dictionary.hpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/classfile/dictionary.hpp Wed Aug 02 10:52:50 2017 -0400
@@ -103,10 +103,7 @@
// Sharing support
void reorder_dictionary();
- void print(bool details = true);
-#ifdef ASSERT
- void printPerformanceInfoDetails();
-#endif // ASSERT
+ void print_on(outputStream* st) const;
void verify();
};
@@ -223,7 +220,7 @@
return (SymbolPropertyEntry**)HashtableEntry<Symbol*, mtSymbol>::next_addr();
}
- void print_on(outputStream* st) const {
+ void print_entry(outputStream* st) const {
symbol()->print_value_on(st);
st->print("/mode=" INTX_FORMAT, symbol_mode());
st->print(" -> ");
@@ -306,9 +303,6 @@
// Sharing support
void reorder_dictionary();
-#ifndef PRODUCT
- void print();
-#endif
void verify();
};
#endif // SHARE_VM_CLASSFILE_DICTIONARY_HPP
--- a/hotspot/src/share/vm/classfile/loaderConstraints.cpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/classfile/loaderConstraints.cpp Wed Aug 02 10:52:50 2017 -0400
@@ -466,27 +466,24 @@
}
}
-#ifndef PRODUCT
-
// Called with the system dictionary lock held
-void LoaderConstraintTable::print() {
+void LoaderConstraintTable::print_on(outputStream* st) const {
ResourceMark rm;
assert_locked_or_safepoint(SystemDictionary_lock);
- tty->print_cr("Java loader constraints (entries=%d, constraints=%d)",
- table_size(), number_of_entries());
+ st->print_cr("Java loader constraints (table_size=%d, constraints=%d)",
+ table_size(), number_of_entries());
for (int cindex = 0; cindex < table_size(); cindex++) {
for (LoaderConstraintEntry* probe = bucket(cindex);
probe != NULL;
probe = probe->next()) {
- tty->print("%4d: ", cindex);
- probe->name()->print();
- tty->print(" , loaders:");
+ st->print("%4d: ", cindex);
+ probe->name()->print_on(st);
+ st->print(" , loaders:");
for (int n = 0; n < probe->num_loaders(); n++) {
- probe->loader_data(n)->print_value();
- tty->print(", ");
+ probe->loader_data(n)->print_value_on(st);
+ st->print(", ");
}
- tty->cr();
+ st->cr();
}
}
}
-#endif
--- a/hotspot/src/share/vm/classfile/loaderConstraints.hpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/classfile/loaderConstraints.hpp Wed Aug 02 10:52:50 2017 -0400
@@ -47,7 +47,7 @@
int max_loaders);
void free_entry(LoaderConstraintEntry *entry);
- LoaderConstraintEntry* bucket(int i) {
+ LoaderConstraintEntry* bucket(int i) const {
return (LoaderConstraintEntry*)Hashtable<InstanceKlass*, mtClass>::bucket(i);
}
@@ -79,9 +79,7 @@
void purge_loader_constraints();
void verify(PlaceholderTable* placeholders);
-#ifndef PRODUCT
- void print();
-#endif
+ void print_on(outputStream* st) const;
};
class LoaderConstraintEntry : public HashtableEntry<InstanceKlass*, mtClass> {
--- a/hotspot/src/share/vm/classfile/placeholders.cpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/classfile/placeholders.cpp Wed Aug 02 10:52:50 2017 -0400
@@ -175,39 +175,6 @@
: Hashtable<Symbol*, mtClass>(table_size, sizeof(PlaceholderEntry)) {
}
-#ifndef PRODUCT
-// Note, doesn't append a cr
-void PlaceholderEntry::print() const {
- klassname()->print_value();
- if (loader_data() != NULL) {
- tty->print(", loader ");
- loader_data()->print_value();
- }
- if (supername() != NULL) {
- tty->print(", supername ");
- supername()->print_value();
- }
- if (definer() != NULL) {
- tty->print(", definer ");
- definer()->print_value();
- }
- if (instance_klass() != NULL) {
- tty->print(", InstanceKlass ");
- instance_klass()->print_value();
- }
- tty->print("\n");
- tty->print("loadInstanceThreadQ threads:");
- loadInstanceThreadQ()->printActionQ();
- tty->print("\n");
- tty->print("superThreadQ threads:");
- superThreadQ()->printActionQ();
- tty->print("\n");
- tty->print("defineThreadQ threads:");
- defineThreadQ()->printActionQ();
- tty->print("\n");
-}
-#endif
-
void PlaceholderEntry::verify() const {
guarantee(loader_data() != NULL, "Must have been setup.");
guarantee(loader_data()->class_loader() == NULL || loader_data()->class_loader()->is_instance(),
@@ -222,20 +189,48 @@
}
-#ifndef PRODUCT
-void PlaceholderTable::print() {
- tty->print_cr("Placeholder table table_size=%d, entries=%d",
+// Note, doesn't append a cr
+// Can't call this print_on because HashtableEntry doesn't initialize its vptr
+// and print_on is a virtual function so the vptr call crashes.
+void PlaceholderEntry::print_entry(outputStream* st) const {
+ klassname()->print_value_on(st);
+ if (loader_data() != NULL) {
+ st->print(", loader ");
+ loader_data()->print_value_on(st);
+ }
+ if (supername() != NULL) {
+ st->print(", supername ");
+ supername()->print_value_on(st);
+ }
+ if (definer() != NULL) {
+ st->print(", definer ");
+ definer()->print_value_on(st);
+ }
+ if (instance_klass() != NULL) {
+ st->print(", InstanceKlass ");
+ instance_klass()->print_value_on(st);
+ }
+ st->cr();
+ st->print("loadInstanceThreadQ threads:");
+ loadInstanceThreadQ()->print_action_queue(st);
+ st->cr();
+ st->print("superThreadQ threads:");
+ superThreadQ()->print_action_queue(st);
+ st->cr();
+ st->print("defineThreadQ threads:");
+ defineThreadQ()->print_action_queue(st);
+ st->cr();
+}
+
+void PlaceholderTable::print_on(outputStream* st) const {
+ st->print_cr("Placeholder table (table_size=%d, placeholders=%d)",
table_size(), number_of_entries());
for (int pindex = 0; pindex < table_size(); pindex++) {
for (PlaceholderEntry* probe = bucket(pindex);
probe != NULL;
probe = probe->next()) {
- tty->print("%4d: ", pindex);
- tty->print(" place holder ");
-
- probe->print();
- tty->cr();
+ st->print("%4d: placeholder ", pindex);
+ probe->print_entry(st);
}
}
}
-#endif
--- a/hotspot/src/share/vm/classfile/placeholders.hpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/classfile/placeholders.hpp Wed Aug 02 10:52:50 2017 -0400
@@ -42,7 +42,7 @@
PlaceholderEntry* new_entry(int hash, Symbol* name, ClassLoaderData* loader_data, bool havesupername, Symbol* supername);
void free_entry(PlaceholderEntry* entry);
- PlaceholderEntry* bucket(int i) {
+ PlaceholderEntry* bucket(int i) const {
return (PlaceholderEntry*)Hashtable<Symbol*, mtClass>::bucket(i);
}
@@ -97,9 +97,7 @@
Symbol* name, ClassLoaderData* loader_data,
classloadAction action, Thread* thread);
-#ifndef PRODUCT
- void print();
-#endif
+ void print_on(outputStream* st) const;
void verify();
};
@@ -129,16 +127,14 @@
void set_next(SeenThread *seen) { _stnext = seen; }
void set_prev(SeenThread *seen) { _stprev = seen; }
-#ifndef PRODUCT
- void printActionQ() {
+ void print_action_queue(outputStream* st) {
SeenThread* seen = this;
while (seen != NULL) {
- seen->thread()->print_value();
- tty->print(", ");
+ seen->thread()->print_value_on(st);
+ st->print(", ");
seen = seen->next();
}
}
-#endif // PRODUCT
};
// Placeholder objects represent classes currently being loaded.
@@ -321,7 +317,7 @@
}
// Print method doesn't append a cr
- void print() const PRODUCT_RETURN;
+ void print_entry(outputStream* st) const;
void verify() const;
};
--- a/hotspot/src/share/vm/classfile/protectionDomainCache.cpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/classfile/protectionDomainCache.cpp Wed Aug 02 10:52:50 2017 -0400
@@ -80,25 +80,18 @@
}
}
-#ifndef PRODUCT
-void ProtectionDomainCacheTable::print() {
- tty->print_cr("Protection domain cache table (table_size=%d, classes=%d)",
- table_size(), number_of_entries());
+void ProtectionDomainCacheTable::print_on(outputStream* st) const {
+ st->print_cr("Protection domain cache table (table_size=%d, classes=%d)",
+ table_size(), number_of_entries());
for (int index = 0; index < table_size(); index++) {
for (ProtectionDomainCacheEntry* probe = bucket(index);
probe != NULL;
probe = probe->next()) {
- tty->print("%4d: ", index);
- probe->print();
+ st->print_cr("%4d: protection_domain: " PTR_FORMAT, index, p2i(probe->literal()));
}
}
}
-void ProtectionDomainCacheEntry::print() {
- tty->print_cr("protection_domain: " PTR_FORMAT, p2i(literal()));
-}
-#endif
-
void ProtectionDomainCacheTable::verify() {
verify_table<ProtectionDomainCacheEntry>("Protection Domain Table");
}
--- a/hotspot/src/share/vm/classfile/protectionDomainCache.hpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/classfile/protectionDomainCache.hpp Wed Aug 02 10:52:50 2017 -0400
@@ -51,7 +51,6 @@
f->do_oop(literal_addr());
}
- void print() PRODUCT_RETURN;
void verify();
};
@@ -67,7 +66,7 @@
class ProtectionDomainCacheTable : public Hashtable<oop, mtClass> {
friend class VMStructs;
private:
- ProtectionDomainCacheEntry* bucket(int i) {
+ ProtectionDomainCacheEntry* bucket(int i) const {
return (ProtectionDomainCacheEntry*) Hashtable<oop, mtClass>::bucket(i);
}
@@ -96,7 +95,7 @@
// GC support
void oops_do(OopClosure* f);
- void print() PRODUCT_RETURN;
+ void print_on(outputStream* st) const;
void verify();
};
--- a/hotspot/src/share/vm/classfile/stringTable.cpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/classfile/stringTable.cpp Wed Aug 02 10:52:50 2017 -0400
@@ -37,6 +37,7 @@
#include "oops/oop.inline.hpp"
#include "runtime/atomic.hpp"
#include "runtime/mutexLocker.hpp"
+#include "services/diagnosticCommand.hpp"
#include "utilities/hashtable.inline.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
@@ -439,7 +440,7 @@
void StringTable::dump(outputStream* st, bool verbose) {
if (!verbose) {
- the_table()->dump_table(st, "StringTable");
+ the_table()->print_table_statistics(st, "StringTable");
} else {
Thread* THREAD = Thread::current();
st->print_cr("VERSION: 1.1");
--- a/hotspot/src/share/vm/classfile/symbolTable.cpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/classfile/symbolTable.cpp Wed Aug 02 10:52:50 2017 -0400
@@ -36,6 +36,7 @@
#include "oops/oop.inline.hpp"
#include "runtime/atomic.hpp"
#include "runtime/mutexLocker.hpp"
+#include "services/diagnosticCommand.hpp"
#include "utilities/hashtable.inline.hpp"
// --------------------------------------------------------------------------
@@ -550,7 +551,7 @@
void SymbolTable::dump(outputStream* st, bool verbose) {
if (!verbose) {
- the_table()->dump_table(st, "SymbolTable");
+ the_table()->print_table_statistics(st, "SymbolTable");
} else {
st->print_cr("VERSION: 1.0");
for (int i = 0; i < the_table()->table_size(); ++i) {
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Wed Aug 02 10:52:50 2017 -0400
@@ -74,6 +74,7 @@
#include "runtime/orderAccess.inline.hpp"
#include "runtime/signature.hpp"
#include "services/classLoadingService.hpp"
+#include "services/diagnosticCommand.hpp"
#include "services/threadService.hpp"
#include "trace/traceMacros.hpp"
#include "utilities/macros.hpp"
@@ -2808,33 +2809,32 @@
}
// ----------------------------------------------------------------------------
-void SystemDictionary::print_shared(bool details) {
- shared_dictionary()->print(details);
+void SystemDictionary::print_shared(outputStream *st) {
+ shared_dictionary()->print_on(st);
}
-void SystemDictionary::print(bool details) {
+void SystemDictionary::print_on(outputStream *st) {
if (shared_dictionary() != NULL) {
tty->print_cr("Shared Dictionary");
- shared_dictionary()->print(details);
+ shared_dictionary()->print_on(st);
}
GCMutexLocker mu(SystemDictionary_lock);
- ClassLoaderDataGraph::print_dictionary(details);
+ ClassLoaderDataGraph::print_dictionary(st);
// Placeholders
- placeholders()->print();
- tty->cr();
+ placeholders()->print_on(st);
+ st->cr();
// loader constraints - print under SD_lock
- constraints()->print();
- tty->cr();
-
- _pd_cache_table->print();
- tty->cr();
+ constraints()->print_on(st);
+ st->cr();
+
+ _pd_cache_table->print_on(st);
+ st->cr();
}
-
void SystemDictionary::verify() {
guarantee(constraints() != NULL,
"Verify of loader constraints failed");
@@ -2855,6 +2855,44 @@
_pd_cache_table->verify();
}
+void SystemDictionary::dump(outputStream *st, bool verbose) {
+ assert_locked_or_safepoint(SystemDictionary_lock);
+ if (verbose) {
+ print_on(st);
+ } else {
+ ClassLoaderDataGraph::print_dictionary_statistics(st);
+ placeholders()->print_table_statistics(st, "Placeholder Table");
+ constraints()->print_table_statistics(st, "LoaderConstraints Table");
+ _pd_cache_table->print_table_statistics(st, "ProtectionDomainCache Table");
+ }
+}
+
+// Utility for dumping dictionaries.
+SystemDictionaryDCmd::SystemDictionaryDCmd(outputStream* output, bool heap) :
+ DCmdWithParser(output, heap),
+ _verbose("-verbose", "Dump the content of each dictionary entry for all class loaders",
+ "BOOLEAN", false, "false") {
+ _dcmdparser.add_dcmd_option(&_verbose);
+}
+
+void SystemDictionaryDCmd::execute(DCmdSource source, TRAPS) {
+ VM_DumpHashtable dumper(output(), VM_DumpHashtable::DumpSysDict,
+ _verbose.value());
+ VMThread::execute(&dumper);
+}
+
+int SystemDictionaryDCmd::num_arguments() {
+ ResourceMark rm;
+ SystemDictionaryDCmd* dcmd = new SystemDictionaryDCmd(NULL, false);
+ if (dcmd != NULL) {
+ DCmdMark mark(dcmd);
+ return dcmd->_dcmdparser.num_arguments();
+ } else {
+ return 0;
+ }
+}
+
+
// caller needs ResourceMark
const char* SystemDictionary::loader_name(const oop loader) {
return ((loader) == NULL ? "<bootloader>" :
--- a/hotspot/src/share/vm/classfile/systemDictionary.hpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp Wed Aug 02 10:52:50 2017 -0400
@@ -388,8 +388,10 @@
static void set_shared_dictionary(HashtableBucket<mtClass>* t, int length,
int number_of_entries);
// Printing
- static void print(bool details = true);
- static void print_shared(bool details = true);
+ static void print() { return print_on(tty); }
+ static void print_on(outputStream* st);
+ static void print_shared(outputStream* st);
+ static void dump(outputStream* st, bool verbose);
// Monotonically increasing counter which grows as classes are
// loaded or modifications such as hot-swapping or setting/removing
--- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp Wed Aug 02 10:52:50 2017 -0400
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "aot/aotLoader.hpp"
#include "classfile/symbolTable.hpp"
+#include "classfile/stringTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "code/codeCache.hpp"
--- a/hotspot/src/share/vm/memory/filemap.cpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/memory/filemap.cpp Wed Aug 02 10:52:50 2017 -0400
@@ -26,6 +26,7 @@
#include "classfile/classLoader.hpp"
#include "classfile/compactHashtable.inline.hpp"
#include "classfile/sharedClassUtil.hpp"
+#include "classfile/stringTable.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "classfile/altHashing.hpp"
--- a/hotspot/src/share/vm/memory/filemap.hpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/memory/filemap.hpp Wed Aug 02 10:52:50 2017 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, Oracle and/or its affiliates. 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
@@ -25,8 +25,10 @@
#ifndef SHARE_VM_MEMORY_FILEMAP_HPP
#define SHARE_VM_MEMORY_FILEMAP_HPP
+#include "classfile/classLoader.hpp"
#include "memory/metaspaceShared.hpp"
#include "memory/metaspace.hpp"
+#include "memory/universe.hpp"
#include "utilities/align.hpp"
// Layout of the file:
--- a/hotspot/src/share/vm/memory/metaspaceShared.cpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp Wed Aug 02 10:52:50 2017 -0400
@@ -30,6 +30,7 @@
#include "classfile/placeholders.hpp"
#include "classfile/sharedClassUtil.hpp"
#include "classfile/symbolTable.hpp"
+#include "classfile/stringTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "code/codeCache.hpp"
@@ -1328,7 +1329,7 @@
if (PrintSharedArchiveAndExit) {
if (PrintSharedDictionary) {
tty->print_cr("\nShared classes:\n");
- SystemDictionary::print_shared(false);
+ SystemDictionary::print_shared(tty);
}
if (_archive_loading_failed) {
tty->print_cr("archive is invalid");
--- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.cpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.cpp Wed Aug 02 10:52:50 2017 -0400
@@ -23,14 +23,16 @@
*/
#include "precompiled.hpp"
+#include "code/relocInfo.hpp"
+#include "compiler/compilerDefinitions.hpp"
#include "oops/metadata.hpp"
#include "runtime/os.hpp"
-#include "code/relocInfo.hpp"
#include "interpreter/invocationCounter.hpp"
#include "runtime/arguments.hpp"
#include "runtime/commandLineFlagConstraintsCompiler.hpp"
#include "runtime/commandLineFlagRangeList.hpp"
#include "runtime/globals.hpp"
+#include "runtime/globals_extension.hpp"
#include "utilities/defaultStream.hpp"
Flag::Error AliasLevelConstraintFunc(intx value, bool verbose) {
--- a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp Wed Aug 02 10:52:50 2017 -0400
@@ -27,9 +27,11 @@
#include "classfile/symbolTable.hpp"
#include "gc/shared/referenceProcessor.hpp"
#include "prims/jvm.h"
+#include "oops/markOop.hpp"
#include "runtime/arguments.hpp"
#include "runtime/commandLineFlagConstraintList.hpp"
#include "runtime/commandLineFlagRangeList.hpp"
+#include "runtime/globals_extension.hpp"
#include "runtime/os.hpp"
#include "runtime/task.hpp"
#include "utilities/defaultStream.hpp"
--- a/hotspot/src/share/vm/runtime/thread.cpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/runtime/thread.cpp Wed Aug 02 10:52:50 2017 -0400
@@ -848,6 +848,13 @@
}
}
+void Thread::print_value_on(outputStream* st) const {
+ if (is_Named_thread()) {
+ st->print(" \"%s\" ", name());
+ }
+ st->print(INTPTR_FORMAT, p2i(this)); // print address
+}
+
#ifdef ASSERT
void Thread::print_owned_locks_on(outputStream* st) const {
Monitor *cur = _owned_locks;
--- a/hotspot/src/share/vm/runtime/thread.hpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/runtime/thread.hpp Wed Aug 02 10:52:50 2017 -0400
@@ -574,6 +574,7 @@
virtual void print_on(outputStream* st) const;
void print() const { print_on(tty); }
virtual void print_on_error(outputStream* st, char* buf, int buflen) const;
+ void print_value_on(outputStream* st) const;
// Debug-only code
#ifdef ASSERT
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Wed Aug 02 10:52:50 2017 -0400
@@ -32,6 +32,7 @@
#include "classfile/dictionary.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/stringTable.hpp"
+#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/codeBlob.hpp"
#include "code/codeCache.hpp"
--- a/hotspot/src/share/vm/services/diagnosticCommand.cpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp Wed Aug 02 10:52:50 2017 -0400
@@ -84,6 +84,7 @@
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HeapDumpDCmd>(DCmd_Source_Internal | DCmd_Source_AttachAPI, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassHistogramDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassStatsDCmd>(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<SymboltableDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<StringtableDCmd>(full_export, true, false));
--- a/hotspot/src/share/vm/services/diagnosticCommand.hpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp Wed Aug 02 10:52:50 2017 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2017, Oracle and/or its affiliates. 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
@@ -25,6 +25,9 @@
#ifndef SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP
#define SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP
+#include "classfile/stringTable.hpp"
+#include "classfile/symbolTable.hpp"
+#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "runtime/arguments.hpp"
#include "runtime/os.hpp"
@@ -724,4 +727,116 @@
virtual void execute(DCmdSource source, TRAPS);
};
+///////////////////////////////////////////////////////////////////////
+//
+// jcmd command support for symbol table, string table and system dictionary dumping:
+// VM.symboltable -verbose: for dumping the symbol table
+// VM.stringtable -verbose: for dumping the string table
+// VM.systemdictionary -verbose: for dumping the system dictionary table
+//
+class VM_DumpHashtable : public VM_Operation {
+private:
+ outputStream* _out;
+ int _which;
+ bool _verbose;
+public:
+ enum {
+ DumpSymbols = 1 << 0,
+ DumpStrings = 1 << 1,
+ DumpSysDict = 1 << 2 // not implemented yet
+ };
+ VM_DumpHashtable(outputStream* out, int which, bool verbose) {
+ _out = out;
+ _which = which;
+ _verbose = verbose;
+ }
+
+ virtual VMOp_Type type() const { return VMOp_DumpHashtable; }
+
+ virtual void doit() {
+ switch (_which) {
+ case DumpSymbols:
+ SymbolTable::dump(_out, _verbose);
+ break;
+ case DumpStrings:
+ StringTable::dump(_out, _verbose);
+ break;
+ case DumpSysDict:
+ SystemDictionary::dump(_out, _verbose);
+ break;
+ default:
+ ShouldNotReachHere();
+ }
+ }
+};
+
+class SymboltableDCmd : public DCmdWithParser {
+protected:
+ DCmdArgument<bool> _verbose;
+public:
+ SymboltableDCmd(outputStream* output, bool heap);
+ static const char* name() {
+ return "VM.symboltable";
+ }
+ static const char* description() {
+ return "Dump symbol table.";
+ }
+ static const char* impact() {
+ return "Medium: Depends on Java content.";
+ }
+ 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 StringtableDCmd : public DCmdWithParser {
+protected:
+ DCmdArgument<bool> _verbose;
+public:
+ StringtableDCmd(outputStream* output, bool heap);
+ static const char* name() {
+ return "VM.stringtable";
+ }
+ static const char* description() {
+ return "Dump string table.";
+ }
+ static const char* impact() {
+ return "Medium: Depends on Java content.";
+ }
+ 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 SystemDictionaryDCmd : public DCmdWithParser {
+protected:
+ DCmdArgument<bool> _verbose;
+public:
+ SystemDictionaryDCmd(outputStream* output, bool heap);
+ static const char* name() {
+ return "VM.systemdictionary";
+ }
+ static const char* description() {
+ return "Prints the statistics for dictionary hashtable sizes and bucket length";
+ }
+ static const char* impact() {
+ return "Medium: Depends on Java content.";
+ }
+ static const JavaPermission permission() {
+ JavaPermission p = {"java.lang.management.ManagementPermission",
+ "monitor", NULL};
+ return p;
+ }
+ static int num_arguments();
+ virtual void execute(DCmdSource source, TRAPS);
+};
+
#endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP
--- a/hotspot/src/share/vm/utilities/hashtable.cpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/utilities/hashtable.cpp Wed Aug 02 10:52:50 2017 -0400
@@ -231,24 +231,42 @@
}
}
-template <class T, MEMFLAGS F> int RehashableHashtable<T, F>::literal_size(Symbol *symbol) {
+// For oops and Strings the size of the literal is interesting. For other types, nobody cares.
+static int literal_size(ConstantPool*) { return 0; }
+static int literal_size(Klass*) { return 0; }
+#if INCLUDE_ALL_GCS
+static int literal_size(nmethod*) { return 0; }
+#endif
+
+static int literal_size(Symbol *symbol) {
return symbol->size() * HeapWordSize;
}
-template <class T, MEMFLAGS F> int RehashableHashtable<T, F>::literal_size(oop oop) {
+static int literal_size(oop obj) {
// NOTE: this would over-count if (pre-JDK8) java_lang_Class::has_offset_field() is true,
// and the String.value array is shared by several Strings. However, starting from JDK8,
// the String.value array is not shared anymore.
- assert(oop != NULL && oop->klass() == SystemDictionary::String_klass(), "only strings are supported");
- return (oop->size() + java_lang_String::value(oop)->size()) * HeapWordSize;
+ if (obj == NULL) {
+ return 0;
+ } else if (obj->klass() == SystemDictionary::String_klass()) {
+ return (obj->size() + java_lang_String::value(obj)->size()) * HeapWordSize;
+ } else {
+ return obj->size();
+ }
}
+
// Dump footprint and bucket length statistics
//
// Note: if you create a new subclass of Hashtable<MyNewType, F>, you will need to
-// add a new function Hashtable<T, F>::literal_size(MyNewType lit)
+// add a new function static int literal_size(MyNewType lit)
+// because I can't get template <class T> int literal_size(T) to pick the specializations for Symbol and oop.
+//
+// The StringTable and SymbolTable dumping print how much footprint is used by the String and Symbol
+// literals.
-template <class T, MEMFLAGS F> void RehashableHashtable<T, F>::dump_table(outputStream* st, const char *table_name) {
+template <class T, MEMFLAGS F> void Hashtable<T, F>::print_table_statistics(outputStream* st,
+ const char *table_name) {
NumberSeq summary;
int literal_bytes = 0;
for (int i = 0; i < this->table_size(); ++i) {
@@ -267,14 +285,16 @@
int entry_bytes = (int)num_entries * sizeof(HashtableEntry<T, F>);
int total_bytes = literal_bytes + bucket_bytes + entry_bytes;
- double bucket_avg = (num_buckets <= 0) ? 0 : (bucket_bytes / num_buckets);
- double entry_avg = (num_entries <= 0) ? 0 : (entry_bytes / num_entries);
- double literal_avg = (num_entries <= 0) ? 0 : (literal_bytes / num_entries);
+ int bucket_size = (num_buckets <= 0) ? 0 : (bucket_bytes / num_buckets);
+ int entry_size = (num_entries <= 0) ? 0 : (entry_bytes / num_entries);
st->print_cr("%s statistics:", table_name);
- st->print_cr("Number of buckets : %9d = %9d bytes, avg %7.3f", (int)num_buckets, bucket_bytes, bucket_avg);
- st->print_cr("Number of entries : %9d = %9d bytes, avg %7.3f", (int)num_entries, entry_bytes, entry_avg);
- st->print_cr("Number of literals : %9d = %9d bytes, avg %7.3f", (int)num_entries, literal_bytes, literal_avg);
+ st->print_cr("Number of buckets : %9d = %9d bytes, each %d", (int)num_buckets, bucket_bytes, bucket_size);
+ st->print_cr("Number of entries : %9d = %9d bytes, each %d", (int)num_entries, entry_bytes, entry_size);
+ if (literal_bytes != 0) {
+ double literal_avg = (num_entries <= 0) ? 0 : (literal_bytes / num_entries);
+ st->print_cr("Number of literals : %9d = %9d bytes, avg %7.3f", (int)num_entries, literal_bytes, literal_avg);
+ }
st->print_cr("Total footprint : %9s = %9d bytes", "", total_bytes);
st->print_cr("Average bucket size : %9.3f", summary.avg());
st->print_cr("Variance of bucket size : %9.3f", summary.variance());
@@ -300,7 +320,6 @@
*top += len;
}
-
#ifndef PRODUCT
template <class T, MEMFLAGS F> void Hashtable<T, F>::print() {
@@ -398,4 +417,3 @@
template void BasicHashtable<mtModule>::verify_table<PackageEntry>(char const*);
template void BasicHashtable<mtClass>::verify_table<ProtectionDomainCacheEntry>(char const*);
template void BasicHashtable<mtClass>::verify_table<PlaceholderEntry>(char const*);
-
--- a/hotspot/src/share/vm/utilities/hashtable.hpp Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/src/share/vm/utilities/hashtable.hpp Wed Aug 02 10:52:50 2017 -0400
@@ -226,14 +226,14 @@
// is mt-safe wrt. to other calls of this method.
void bulk_free_entries(BucketUnlinkContext* context);
public:
- int table_size() { return _table_size; }
+ int table_size() const { return _table_size; }
void set_entry(int index, BasicHashtableEntry<F>* entry);
void add_entry(int index, BasicHashtableEntry<F>* entry);
void free_entry(BasicHashtableEntry<F>* entry);
- int number_of_entries() { return _number_of_entries; }
+ int number_of_entries() const { return _number_of_entries; }
template <class T> void verify_table(const char* table_name) PRODUCT_RETURN;
};
@@ -261,7 +261,9 @@
return this->hash_to_index(compute_hash(name));
}
-protected:
+ void print_table_statistics(outputStream* st, const char *table_name);
+
+ protected:
// Table entry management
HashtableEntry<T, F>* new_entry(unsigned int hashValue, T obj);
@@ -306,18 +308,6 @@
static bool use_alternate_hashcode();
static juint seed();
- static int literal_size(Symbol *symbol);
- static int literal_size(oop oop);
-
- // The following two are currently not used, but are needed anyway because some
- // C++ compilers (MacOS and Solaris) force the instantiation of
- // Hashtable<ConstantPool*, mtClass>::dump_table() even though we never call this function
- // in the VM code.
- static int literal_size(ConstantPool *cp) {Unimplemented(); return 0;}
- static int literal_size(Klass *k) {Unimplemented(); return 0;}
-
- void dump_table(outputStream* st, const char *table_name);
-
private:
static juint _seed;
};
--- a/hotspot/test/runtime/SharedArchiveFile/DumpSymbolAndStringTable.java Wed Aug 02 08:19:09 2017 -0400
+++ b/hotspot/test/runtime/SharedArchiveFile/DumpSymbolAndStringTable.java Wed Aug 02 10:52:50 2017 -0400
@@ -56,5 +56,25 @@
} catch (RuntimeException e) {
output.shouldContain("Unknown diagnostic command");
}
+
+ pb.command(new String[] {JDKToolFinder.getJDKTool("jcmd"), pid, "VM.systemdictionary"});
+ output = CDSTestUtils.executeAndLog(pb, "jcmd-systemdictionary");
+ try {
+ output.shouldContain("System Dictionary for jdk/internal/loader/ClassLoaders$AppClassLoader statistics:");
+ output.shouldContain("Number of buckets");
+ output.shouldContain("Number of entries");
+ output.shouldContain("Maximum bucket size");
+ } catch (RuntimeException e) {
+ output.shouldContain("Unknown diagnostic command");
+ }
+
+ pb.command(new String[] {JDKToolFinder.getJDKTool("jcmd"), pid, "VM.systemdictionary", "-verbose"});
+ output = CDSTestUtils.executeAndLog(pb, "jcmd-systemdictionary");
+ try {
+ output.shouldContain("Dictionary for class loader 0x");
+ output.shouldContain("^java.lang.String");
+ } catch (RuntimeException e) {
+ output.shouldContain("Unknown diagnostic command");
+ }
}
}