8244540: Print more information with -XX:+PrintSharedArchiveAndExit

Reviewed-by: iklam, ccheung
This commit is contained in:
Yumin Qi 2021-03-31 03:10:38 +00:00
parent e073486ffe
commit 928fa5b5f9
8 changed files with 294 additions and 11 deletions

View file

@ -275,6 +275,13 @@ void SymbolTable::symbols_do(SymbolClosure *cl) {
_local_table->do_safepoint_scan(sd); _local_table->do_safepoint_scan(sd);
} }
// Call function for all symbols in shared table. Used by -XX:+PrintSharedArchiveAndExit
void SymbolTable::shared_symbols_do(SymbolClosure *cl) {
SharedSymbolIterator iter(cl);
_shared_table.iterate(&iter);
_dynamic_shared_table.iterate(&iter);
}
Symbol* SymbolTable::lookup_dynamic(const char* name, Symbol* SymbolTable::lookup_dynamic(const char* name,
int len, unsigned int hash) { int len, unsigned int hash) {
Symbol* sym = do_lookup(name, len, hash); Symbol* sym = do_lookup(name, len, hash);

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -207,6 +207,7 @@ public:
static void symbols_do(SymbolClosure *cl); static void symbols_do(SymbolClosure *cl);
// Sharing // Sharing
static void shared_symbols_do(SymbolClosure *cl); // no safepoint iteration.
private: private:
static void copy_shared_symbol_table(GrowableArray<Symbol*>* symbols, static void copy_shared_symbol_table(GrowableArray<Symbol*>* symbols,
CompactHashtableWriter* ch_table); CompactHashtableWriter* ch_table);

View file

@ -2224,6 +2224,24 @@ void SystemDictionaryShared::update_shared_entry(InstanceKlass* k, int id) {
info->_id = id; info->_id = id;
} }
const char* class_loader_name_for_shared(Klass* k) {
assert(k != nullptr, "Sanity");
assert(k->is_shared(), "Must be");
assert(k->is_instance_klass(), "Must be");
InstanceKlass* ik = InstanceKlass::cast(k);
if (ik->is_shared_boot_class()) {
return "boot_loader";
} else if (ik->is_shared_platform_class()) {
return "platform_loader";
} else if (ik->is_shared_app_class()) {
return "app_loader";
} else if (ik->is_shared_unregistered_class()) {
return "unregistered_loader";
} else {
return "unknown loader";
}
}
class SharedDictionaryPrinter : StackObj { class SharedDictionaryPrinter : StackObj {
outputStream* _st; outputStream* _st;
int _index; int _index;
@ -2232,23 +2250,25 @@ public:
void do_value(const RunTimeSharedClassInfo* record) { void do_value(const RunTimeSharedClassInfo* record) {
ResourceMark rm; ResourceMark rm;
_st->print_cr("%4d: %s", (_index++), record->_klass->external_name()); _st->print_cr("%4d: %s %s", (_index++), record->_klass->external_name(),
class_loader_name_for_shared(record->_klass));
} }
int index() const { return _index; }
}; };
class SharedLambdaDictionaryPrinter : StackObj { class SharedLambdaDictionaryPrinter : StackObj {
outputStream* _st; outputStream* _st;
int _index; int _index;
public: public:
SharedLambdaDictionaryPrinter(outputStream* st) : _st(st), _index(0) {} SharedLambdaDictionaryPrinter(outputStream* st, int idx) : _st(st), _index(idx) {}
void do_value(const RunTimeLambdaProxyClassInfo* record) { void do_value(const RunTimeLambdaProxyClassInfo* record) {
if (record->proxy_klass_head()->lambda_proxy_is_available()) { if (record->proxy_klass_head()->lambda_proxy_is_available()) {
ResourceMark rm; ResourceMark rm;
_st->print_cr("%4d: %s", (_index++), record->proxy_klass_head()->external_name()); Klass* k = record->proxy_klass_head();
Klass* k = record->proxy_klass_head()->next_link(); while (k != nullptr) {
while (k != NULL) { _st->print_cr("%4d: %s %s", (++_index), k->external_name(),
_st->print_cr("%4d: %s", (_index++), k->external_name()); class_loader_name_for_shared(k));
k = k->next_link(); k = k->next_link();
} }
} }
@ -2262,15 +2282,30 @@ void SystemDictionaryShared::print_on(const char* prefix,
outputStream* st) { outputStream* st) {
st->print_cr("%sShared Dictionary", prefix); st->print_cr("%sShared Dictionary", prefix);
SharedDictionaryPrinter p(st); SharedDictionaryPrinter p(st);
st->print_cr("%sShared Builtin Dictionary", prefix);
builtin_dictionary->iterate(&p); builtin_dictionary->iterate(&p);
st->print_cr("%sShared Unregistered Dictionary", prefix);
unregistered_dictionary->iterate(&p); unregistered_dictionary->iterate(&p);
if (!lambda_dictionary->empty()) { if (!lambda_dictionary->empty()) {
st->print_cr("%sShared Lambda Dictionary", prefix); st->print_cr("%sShared Lambda Dictionary", prefix);
SharedLambdaDictionaryPrinter ldp(st); SharedLambdaDictionaryPrinter ldp(st, p.index());
lambda_dictionary->iterate(&ldp); lambda_dictionary->iterate(&ldp);
} }
} }
void SystemDictionaryShared::print_shared_archive(outputStream* st, bool is_static) {
if (UseSharedSpaces) {
if (is_static) {
print_on("", &_builtin_dictionary, &_unregistered_dictionary, &_lambda_proxy_class_dictionary, st);
} else {
if (DynamicArchive::is_mapped()) {
print_on("", &_dynamic_builtin_dictionary, &_dynamic_unregistered_dictionary,
&_dynamic_lambda_proxy_class_dictionary, st);
}
}
}
}
void SystemDictionaryShared::print_on(outputStream* st) { void SystemDictionaryShared::print_on(outputStream* st) {
if (UseSharedSpaces) { if (UseSharedSpaces) {
print_on("", &_builtin_dictionary, &_unregistered_dictionary, &_lambda_proxy_class_dictionary, st); print_on("", &_builtin_dictionary, &_unregistered_dictionary, &_lambda_proxy_class_dictionary, st);

View file

@ -316,6 +316,7 @@ public:
static void serialize_vm_classes(class SerializeClosure* soc); static void serialize_vm_classes(class SerializeClosure* soc);
static void print() { return print_on(tty); } static void print() { return print_on(tty); }
static void print_on(outputStream* st) NOT_CDS_RETURN; static void print_on(outputStream* st) NOT_CDS_RETURN;
static void print_shared_archive(outputStream* st, bool is_static = true) NOT_CDS_RETURN;
static void print_table_statistics(outputStream* st) NOT_CDS_RETURN; static void print_table_statistics(outputStream* st) NOT_CDS_RETURN;
static bool empty_dumptime_table() NOT_CDS_RETURN_(true); static bool empty_dumptime_table() NOT_CDS_RETURN_(true);
static void start_dumping() NOT_CDS_RETURN; static void start_dumping() NOT_CDS_RETURN;

View file

@ -544,6 +544,10 @@ public:
header()->print(st); header()->print(st);
} }
const char* vm_version() {
return header()->jvm_ident();
}
private: private:
void seek_to_position(size_t pos); void seek_to_position(size_t pos);
char* skip_first_path_entry(const char* path) NOT_CDS_RETURN_(NULL); char* skip_first_path_entry(const char* path) NOT_CDS_RETURN_(NULL);

View file

@ -1328,6 +1328,34 @@ void MetaspaceShared::unmap_archive(FileMapInfo* mapinfo) {
} }
} }
// For -XX:PrintSharedArchiveAndExit
class CountSharedSymbols : public SymbolClosure {
private:
int _count;
public:
CountSharedSymbols() : _count(0) {}
void do_symbol(Symbol** sym) {
_count++;
}
int total() { return _count; }
};
// For -XX:PrintSharedArchiveAndExit
class CountSharedStrings : public OopClosure {
private:
int _count;
public:
CountSharedStrings() : _count(0) {}
void do_oop(oop* p) {
_count++;
}
void do_oop(narrowOop* p) {
_count++;
}
int total() { return _count; }
};
// Read the miscellaneous data from the shared file, and // Read the miscellaneous data from the shared file, and
// serialize it out to its various destinations. // serialize it out to its various destinations.
@ -1362,10 +1390,30 @@ void MetaspaceShared::initialize_shared_spaces() {
} }
if (PrintSharedArchiveAndExit) { if (PrintSharedArchiveAndExit) {
if (PrintSharedDictionary) { // Print archive names
tty->print_cr("\nShared classes:\n"); if (dynamic_mapinfo != nullptr) {
SystemDictionaryShared::print_on(tty); tty->print_cr("\n\nBase archive name: %s", Arguments::GetSharedArchivePath());
tty->print_cr("Base archive version %d", static_mapinfo->version());
} else {
tty->print_cr("Static archive name: %s", static_mapinfo->full_path());
tty->print_cr("Static archive version %d", static_mapinfo->version());
} }
SystemDictionaryShared::print_shared_archive(tty);
if (dynamic_mapinfo != nullptr) {
tty->print_cr("\n\nDynamic archive name: %s", dynamic_mapinfo->full_path());
tty->print_cr("Dynamic archive version %d", dynamic_mapinfo->version());
SystemDictionaryShared::print_shared_archive(tty, false/*dynamic*/);
}
// collect shared symbols and strings
CountSharedSymbols cl;
SymbolTable::shared_symbols_do(&cl);
tty->print_cr("Number of shared symbols: %d", cl.total());
CountSharedStrings cs;
StringTable::shared_oops_do(&cs);
tty->print_cr("Number of shared strings: %d", cs.total());
tty->print_cr("VM version: %s\r\n", static_mapinfo->vm_version());
if (FileMapInfo::current_info() == NULL || _archive_loading_failed) { if (FileMapInfo::current_info() == NULL || _archive_loading_failed) {
tty->print_cr("archive is invalid"); tty->print_cr("archive is invalid");
vm_exit(1); vm_exit(1);

View file

@ -0,0 +1,88 @@
/*
* Copyright (c) 2021, 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
* 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
* @summary test -XX:+PrintSharedArchiveAndExit output for shared class.
* @comment the code is mostly copied from HelloCustom
* @requires vm.cds
* @requires vm.cds.custom.loaders
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
* @compile test-classes/HelloUnload.java test-classes/CustomLoadee.java
* @build sun.hotspot.WhiteBox jdk.test.lib.classloader.ClassUnloadCommon
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar hello.jar HelloUnload
* jdk.test.lib.classloader.ClassUnloadCommon
* jdk.test.lib.classloader.ClassUnloadCommon$1
* jdk.test.lib.classloader.ClassUnloadCommon$TestFailure
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar hello_custom.jar CustomLoadee
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
* @run driver PrintSharedArchiveAndExit
*/
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.helpers.ClassFileInstaller;
import sun.hotspot.WhiteBox;
public class PrintSharedArchiveAndExit {
public static void main(String[] args) throws Exception {
run();
}
public static void run(String... extra_runtime_args) throws Exception {
String wbJar = ClassFileInstaller.getJarPath("WhiteBox.jar");
String use_whitebox_jar = "-Xbootclasspath/a:" + wbJar;
String appJar = ClassFileInstaller.getJarPath("hello.jar");
String customJarPath = ClassFileInstaller.getJarPath("hello_custom.jar");
// Dump the archive
String classlist[] = new String[] {
"HelloUnload",
"java/lang/Object id: 1",
"CustomLoadee id: 2 super: 1 source: " + customJarPath
};
OutputAnalyzer output;
TestCommon.testDump(appJar, classlist,
// command-line arguments ...
use_whitebox_jar);
output = TestCommon.exec(appJar,
TestCommon.concat(extra_runtime_args,
// command-line arguments ...
use_whitebox_jar,
"-XX:+UnlockDiagnosticVMOptions",
"-XX:+WhiteBoxAPI",
"-XX:+PrintSharedArchiveAndExit",
"HelloUnload", customJarPath, "true", "true"));
output.shouldMatch(".* archive version \\d+")
.shouldContain("java.lang.Object boot_loader")
.shouldContain("HelloUnload app_loader")
.shouldContain("CustomLoadee unregistered_loader")
.shouldContain("Shared Builtin Dictionary")
.shouldContain("Shared Unregistered Dictionary")
.shouldMatch("Number of shared symbols: \\d+")
.shouldMatch("Number of shared strings: \\d+")
.shouldMatch("VM version: .*");
}
}

View file

@ -0,0 +1,99 @@
/*
* Copyright (c) 2021, 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
* 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
* @summary Hello World test for dynamic archive with custom loader
* @requires vm.cds
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/customLoader/test-classes
* @build HelloUnload CustomLoadee jdk.test.lib.classloader.ClassUnloadCommon
* @build sun.hotspot.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar hello.jar HelloUnload
* jdk.test.lib.classloader.ClassUnloadCommon
* jdk.test.lib.classloader.ClassUnloadCommon$1
* jdk.test.lib.classloader.ClassUnloadCommon$TestFailure
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar hello_custom.jar CustomLoadee
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:./WhiteBox.jar PrintSharedArchiveAndExit
*/
import java.io.File;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.helpers.ClassFileInstaller;
public class PrintSharedArchiveAndExit extends DynamicArchiveTestBase {
private static final String ARCHIVE_NAME = CDSTestUtils.getOutputFileName("top.jsa");
public static void main(String... args) throws Exception {
runTest(PrintSharedArchiveAndExit::testPrtNExit);
}
public static void testPrtNExit() throws Exception {
String wbJar = ClassFileInstaller.getJarPath("WhiteBox.jar");
String use_whitebox_jar = "-Xbootclasspath/a:" + wbJar;
String appJar = ClassFileInstaller.getJarPath("hello.jar");
String customJarPath = ClassFileInstaller.getJarPath("hello_custom.jar");
String mainAppClass = "HelloUnload";
dump(ARCHIVE_NAME,
use_whitebox_jar,
"-XX:+UnlockDiagnosticVMOptions",
"-XX:+WhiteBoxAPI",
"-Xlog:cds",
"-Xlog:cds+dynamic=debug",
"-cp", appJar,
mainAppClass, customJarPath, "false", "false")
.assertNormalExit(output -> {
output.shouldContain("Written dynamic archive 0x")
.shouldNotContain("klasses.*=.*CustomLoadee")
.shouldHaveExitValue(0);
});
run(ARCHIVE_NAME,
use_whitebox_jar,
"-XX:+UnlockDiagnosticVMOptions",
"-XX:+WhiteBoxAPI",
"-Xlog:class+load",
"-Xlog:cds=debug",
"-Xlog:cds+dynamic=info",
"-cp", appJar,
"-XX:+PrintSharedArchiveAndExit",
mainAppClass, customJarPath, "false", "true")
.assertNormalExit(output -> {
output.shouldHaveExitValue(0)
.shouldMatch("Base archive name: .*.jsa") // given name ends with .jsa, maynot default name.
.shouldMatch("Dynamic archive name: .*" + ARCHIVE_NAME)
.shouldMatch("Base archive version \\d+")
.shouldContain("java.lang.Object boot_loader")
.shouldContain("HelloUnload app_loader")
.shouldContain("CustomLoadee unregistered_loader")
.shouldContain("Shared Builtin Dictionary")
.shouldContain("Shared Unregistered Dictionary")
.shouldMatch("Number of shared symbols: \\d+")
.shouldMatch("Number of shared strings: \\d+")
.shouldMatch("VM version: .*");
});
}
}