Skip to content

Commit

Permalink
8244540: Print more information with -XX:+PrintSharedArchiveAndExit
Browse files Browse the repository at this point in the history
Reviewed-by: iklam, ccheung
  • Loading branch information
yminqi committed Mar 31, 2021
1 parent e073486 commit 928fa5b
Show file tree
Hide file tree
Showing 8 changed files with 294 additions and 11 deletions.
7 changes: 7 additions & 0 deletions src/hotspot/share/classfile/symbolTable.cpp
Expand Up @@ -275,6 +275,13 @@ void SymbolTable::symbols_do(SymbolClosure *cl) {
_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,
int len, unsigned int hash) {
Symbol* sym = do_lookup(name, len, hash);
Expand Down
3 changes: 2 additions & 1 deletion src/hotspot/share/classfile/symbolTable.hpp
@@ -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.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -207,6 +207,7 @@ class SymbolTable : public AllStatic {
static void symbols_do(SymbolClosure *cl);

// Sharing
static void shared_symbols_do(SymbolClosure *cl); // no safepoint iteration.
private:
static void copy_shared_symbol_table(GrowableArray<Symbol*>* symbols,
CompactHashtableWriter* ch_table);
Expand Down
49 changes: 42 additions & 7 deletions src/hotspot/share/classfile/systemDictionaryShared.cpp
Expand Up @@ -2224,6 +2224,24 @@ void SystemDictionaryShared::update_shared_entry(InstanceKlass* k, int 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 {
outputStream* _st;
int _index;
Expand All @@ -2232,23 +2250,25 @@ class SharedDictionaryPrinter : StackObj {

void do_value(const RunTimeSharedClassInfo* record) {
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 {
outputStream* _st;
int _index;
public:
SharedLambdaDictionaryPrinter(outputStream* st) : _st(st), _index(0) {}
SharedLambdaDictionaryPrinter(outputStream* st, int idx) : _st(st), _index(idx) {}

void do_value(const RunTimeLambdaProxyClassInfo* record) {
if (record->proxy_klass_head()->lambda_proxy_is_available()) {
ResourceMark rm;
_st->print_cr("%4d: %s", (_index++), record->proxy_klass_head()->external_name());
Klass* k = record->proxy_klass_head()->next_link();
while (k != NULL) {
_st->print_cr("%4d: %s", (_index++), k->external_name());
Klass* k = record->proxy_klass_head();
while (k != nullptr) {
_st->print_cr("%4d: %s %s", (++_index), k->external_name(),
class_loader_name_for_shared(k));
k = k->next_link();
}
}
Expand All @@ -2262,15 +2282,30 @@ void SystemDictionaryShared::print_on(const char* prefix,
outputStream* st) {
st->print_cr("%sShared Dictionary", prefix);
SharedDictionaryPrinter p(st);
st->print_cr("%sShared Builtin Dictionary", prefix);
builtin_dictionary->iterate(&p);
st->print_cr("%sShared Unregistered Dictionary", prefix);
unregistered_dictionary->iterate(&p);
if (!lambda_dictionary->empty()) {
st->print_cr("%sShared Lambda Dictionary", prefix);
SharedLambdaDictionaryPrinter ldp(st);
SharedLambdaDictionaryPrinter ldp(st, p.index());
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) {
if (UseSharedSpaces) {
print_on("", &_builtin_dictionary, &_unregistered_dictionary, &_lambda_proxy_class_dictionary, st);
Expand Down
1 change: 1 addition & 0 deletions src/hotspot/share/classfile/systemDictionaryShared.hpp
Expand Up @@ -316,6 +316,7 @@ class SystemDictionaryShared: public SystemDictionary {
static void serialize_vm_classes(class SerializeClosure* soc);
static void print() { return print_on(tty); }
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 bool empty_dumptime_table() NOT_CDS_RETURN_(true);
static void start_dumping() NOT_CDS_RETURN;
Expand Down
4 changes: 4 additions & 0 deletions src/hotspot/share/memory/filemap.hpp
Expand Up @@ -544,6 +544,10 @@ class FileMapInfo : public CHeapObj<mtInternal> {
header()->print(st);
}

const char* vm_version() {
return header()->jvm_ident();
}

private:
void seek_to_position(size_t pos);
char* skip_first_path_entry(const char* path) NOT_CDS_RETURN_(NULL);
Expand Down
54 changes: 51 additions & 3 deletions src/hotspot/share/memory/metaspaceShared.cpp
Expand Up @@ -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
// serialize it out to its various destinations.

Expand Down Expand Up @@ -1362,10 +1390,30 @@ void MetaspaceShared::initialize_shared_spaces() {
}

if (PrintSharedArchiveAndExit) {
if (PrintSharedDictionary) {
tty->print_cr("\nShared classes:\n");
SystemDictionaryShared::print_on(tty);
// Print archive names
if (dynamic_mapinfo != nullptr) {
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) {
tty->print_cr("archive is invalid");
vm_exit(1);
Expand Down
@@ -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: .*");
}
}
@@ -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: .*");
});
}
}

1 comment on commit 928fa5b

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.