Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8244540: Print more information with -XX:+PrintSharedArchiveAndExit #3187

Closed
wants to merge 4 commits into from
Closed
Changes from all commits
Commits
File filter
Filter file types
Jump to
Jump to file
Failed to load files.

Always

Just for now

@@ -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);
@@ -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
@@ -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);
@@ -2223,6 +2223,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;
@@ -2231,23 +2249,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));
This conversation was marked as resolved by yminqi

This comment has been minimized.

@iklam

iklam Mar 25, 2021
Member

The "loaded by: xxx_loader" seems a bit verbose:

  23: java.lang.invoke.VarHandleLongs$FieldInstanceReadWrite loaded by: boot_loader
  24: java.util.Map loaded by: boot_loader

How about

  23: java.lang.invoke.VarHandleLongs$FieldInstanceReadWrite boot_loader
  24: java.util.Map boot_loader
}
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();
}
}
@@ -2261,15 +2281,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);
@@ -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;
@@ -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);
@@ -1332,6 +1332,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.

@@ -1366,10 +1394,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);
@@ -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")
This conversation was marked as resolved by yminqi
Comment on lines +85 to +93

This comment has been minimized.

@calvinccheung

calvinccheung Mar 30, 2021
Member

Since the print output includes "VM version", perhaps the above should look for it?

This comment has been minimized.

@yminqi

yminqi Mar 30, 2021
Author Contributor

Thanks, will add the check.

.shouldMatch("Number of shared symbols: \\d+")
.shouldMatch("Number of shared strings: \\d+")
.shouldMatch("VM version: .*");
});
}
}
ProTip! Use n and p to navigate between commits in a pull request.