8276184: Exclude lambda proxy class from the CDS archive if its caller class is excluded
Reviewed-by: iklam, dholmes
This commit is contained in:
parent
a59c9b2ac2
commit
bd92674be5
@ -112,7 +112,6 @@ public:
|
||||
// Block concurrent class unloading from changing the _dumptime_table
|
||||
MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag);
|
||||
SystemDictionaryShared::check_excluded_classes();
|
||||
SystemDictionaryShared::cleanup_lambda_proxy_class_dictionary();
|
||||
|
||||
// save dumptime tables
|
||||
SystemDictionaryShared::clone_dumptime_tables();
|
||||
|
@ -521,7 +521,6 @@ void VM_PopulateDumpSharedSpace::doit() {
|
||||
// Block concurrent class unloading from changing the _dumptime_table
|
||||
MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag);
|
||||
SystemDictionaryShared::check_excluded_classes();
|
||||
SystemDictionaryShared::cleanup_lambda_proxy_class_dictionary();
|
||||
|
||||
StaticArchiveBuilder builder;
|
||||
builder.gather_source_objs();
|
||||
|
@ -245,6 +245,14 @@ bool SystemDictionaryShared::is_registered_lambda_proxy_class(InstanceKlass* ik)
|
||||
return (info != NULL) ? info->_is_archived_lambda_proxy : false;
|
||||
}
|
||||
|
||||
void SystemDictionaryShared::reset_registered_lambda_proxy_class(InstanceKlass* ik) {
|
||||
DumpTimeClassInfo* info = _dumptime_table->get(ik);
|
||||
if (info != NULL) {
|
||||
info->_is_archived_lambda_proxy = false;
|
||||
info->set_excluded();
|
||||
}
|
||||
}
|
||||
|
||||
bool SystemDictionaryShared::is_early_klass(InstanceKlass* ik) {
|
||||
DumpTimeClassInfo* info = _dumptime_table->get(ik);
|
||||
return (info != NULL) ? info->is_early_klass() : false;
|
||||
@ -325,6 +333,7 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
InstanceKlass* intf = interfaces->at(i);
|
||||
if (check_for_exclusion(intf, NULL)) {
|
||||
ResourceMark rm;
|
||||
log_warning(cds)("Skipping %s: interface %s is excluded", k->name()->as_C_string(), intf->name()->as_C_string());
|
||||
return true;
|
||||
}
|
||||
@ -663,6 +672,8 @@ void SystemDictionaryShared::check_excluded_classes() {
|
||||
ExcludeDumpTimeSharedClasses excl;
|
||||
_dumptime_table->iterate(&excl);
|
||||
_dumptime_table->update_counts();
|
||||
|
||||
cleanup_lambda_proxy_class_dictionary();
|
||||
}
|
||||
|
||||
bool SystemDictionaryShared::is_excluded_class(InstanceKlass* k) {
|
||||
@ -1602,9 +1613,19 @@ class CleanupDumpTimeLambdaProxyClassTable: StackObj {
|
||||
public:
|
||||
bool do_entry(LambdaProxyClassKey& key, DumpTimeLambdaProxyClassInfo& info) {
|
||||
assert_lock_strong(DumpTimeTable_lock);
|
||||
for (int i = 0; i < info._proxy_klasses->length(); i++) {
|
||||
InstanceKlass* caller_ik = key.caller_ik();
|
||||
if (SystemDictionaryShared::check_for_exclusion(caller_ik, NULL)) {
|
||||
// If the caller class is excluded, unregister all the associated lambda proxy classes
|
||||
// so that they will not be included in the CDS archive.
|
||||
for (int i = info._proxy_klasses->length() - 1; i >= 0; i--) {
|
||||
SystemDictionaryShared::reset_registered_lambda_proxy_class(info._proxy_klasses->at(i));
|
||||
info._proxy_klasses->remove_at(i);
|
||||
}
|
||||
}
|
||||
for (int i = info._proxy_klasses->length() - 1; i >= 0; i--) {
|
||||
InstanceKlass* ik = info._proxy_klasses->at(i);
|
||||
if (!ik->can_be_verified_at_dumptime()) {
|
||||
if (SystemDictionaryShared::check_for_exclusion(ik, NULL)) {
|
||||
SystemDictionaryShared::reset_registered_lambda_proxy_class(ik);
|
||||
info._proxy_klasses->remove_at(i);
|
||||
}
|
||||
}
|
||||
|
@ -136,6 +136,7 @@ class SharedClassLoadingMark {
|
||||
|
||||
class SystemDictionaryShared: public SystemDictionary {
|
||||
friend class ExcludeDumpTimeSharedClasses;
|
||||
friend class CleanupDumpTimeLambdaProxyClassTable;
|
||||
public:
|
||||
enum {
|
||||
FROM_FIELD_IS_PROTECTED = 1 << 0,
|
||||
@ -173,6 +174,8 @@ private:
|
||||
static void write_dictionary(RunTimeSharedDictionary* dictionary,
|
||||
bool is_builtin);
|
||||
static void write_lambda_proxy_class_dictionary(LambdaProxyClassDictionary* dictionary);
|
||||
static void cleanup_lambda_proxy_class_dictionary();
|
||||
static void reset_registered_lambda_proxy_class(InstanceKlass* ik);
|
||||
static bool is_jfr_event_class(InstanceKlass *k);
|
||||
static bool is_registered_lambda_proxy_class(InstanceKlass* ik);
|
||||
static bool check_for_exclusion_impl(InstanceKlass* k);
|
||||
@ -288,7 +291,6 @@ public:
|
||||
static size_t estimate_size_for_archive();
|
||||
static void write_to_archive(bool is_static_archive = true);
|
||||
static void adjust_lambda_proxy_class_dictionary();
|
||||
static void cleanup_lambda_proxy_class_dictionary();
|
||||
static void serialize_dictionary_headers(class SerializeClosure* soc,
|
||||
bool is_static_archive = true);
|
||||
static void serialize_vm_classes(class SerializeClosure* soc);
|
||||
|
@ -2598,6 +2598,11 @@ void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handl
|
||||
// retrieved during dump time.
|
||||
// Verification of archived old classes will be performed during run time.
|
||||
bool InstanceKlass::can_be_verified_at_dumptime() const {
|
||||
if (MetaspaceShared::is_in_shared_metaspace(this)) {
|
||||
// This is a class that was dumped into the base archive, so we know
|
||||
// it was verified at dump time.
|
||||
return true;
|
||||
}
|
||||
if (major_version() < 50 /*JAVA_6_VERSION*/) {
|
||||
return false;
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8274944
|
||||
* @bug 8274944 8276184
|
||||
* @summary VM should not crash during CDS dump when a lambda proxy class
|
||||
* contains an old version of interface.
|
||||
* @requires vm.cds
|
||||
@ -49,30 +49,35 @@ public class LambdaContainsOldInf {
|
||||
String classList = namePrefix + ".list";
|
||||
String archiveName = namePrefix + ".jsa";
|
||||
|
||||
// dump class list
|
||||
CDSTestUtils.dumpClassList(classList, "-cp", appJar, mainClass);
|
||||
String[] mainArgs = { "dummy", "addLambda" };
|
||||
|
||||
// create archive with the class list
|
||||
CDSOptions opts = (new CDSOptions())
|
||||
.addPrefix("-XX:ExtraSharedClassListFile=" + classList,
|
||||
"-cp", appJar,
|
||||
"-Xlog:class+load,cds")
|
||||
.setArchiveName(archiveName);
|
||||
OutputAnalyzer output = CDSTestUtils.createArchiveAndCheck(opts);
|
||||
TestCommon.checkExecReturn(output, 0, true,
|
||||
"Skipping OldProvider: Old class has been linked");
|
||||
output.shouldMatch("Skipping.LambdaContainsOldInfApp[$][$]Lambda[$].*0x.*:.*Old.class.has.been.linked");
|
||||
for (String mainArg : mainArgs) {
|
||||
// dump class list
|
||||
CDSTestUtils.dumpClassList(classList, "-cp", appJar, mainClass, mainArg);
|
||||
|
||||
// run with archive
|
||||
CDSOptions runOpts = (new CDSOptions())
|
||||
.addPrefix("-cp", appJar, "-Xlog:class+load,cds=debug")
|
||||
.setArchiveName(archiveName)
|
||||
.setUseVersion(false)
|
||||
.addSuffix(mainClass);
|
||||
output = CDSTestUtils.runWithArchive(runOpts);
|
||||
TestCommon.checkExecReturn(output, 0, true,
|
||||
"[class,load] LambdaContainsOldInfApp source: shared objects file");
|
||||
output.shouldMatch(".class.load. OldProvider.source:.*lambdacontainsoldinf.jar")
|
||||
.shouldMatch(".class.load. LambdaContainsOldInfApp[$][$]Lambda[$].*/0x.*source:.*LambdaContainsOldInf");
|
||||
// create archive with the class list
|
||||
CDSOptions opts = (new CDSOptions())
|
||||
.addPrefix("-XX:ExtraSharedClassListFile=" + classList,
|
||||
"-cp", appJar,
|
||||
"-Xlog:class+load,cds")
|
||||
.setArchiveName(archiveName);
|
||||
OutputAnalyzer output = CDSTestUtils.createArchiveAndCheck(opts);
|
||||
TestCommon.checkExecReturn(output, 0, true,
|
||||
"Skipping OldProvider: Old class has been linked");
|
||||
output.shouldMatch("Skipping.LambdaContainsOldInfApp[$][$]Lambda[$].*0x.*:.*Old.class.has.been.linked");
|
||||
|
||||
// run with archive
|
||||
CDSOptions runOpts = (new CDSOptions())
|
||||
.addPrefix("-cp", appJar, "-Xlog:class+load,cds=debug")
|
||||
.setArchiveName(archiveName)
|
||||
.setUseVersion(false)
|
||||
.addSuffix(mainClass)
|
||||
.addSuffix(mainArg);
|
||||
output = CDSTestUtils.runWithArchive(runOpts);
|
||||
TestCommon.checkExecReturn(output, 0, true,
|
||||
"[class,load] LambdaContainsOldInfApp source: shared objects file");
|
||||
output.shouldMatch(".class.load. OldProvider.source:.*lambdacontainsoldinf.jar")
|
||||
.shouldMatch(".class.load. LambdaContainsOldInfApp[$][$]Lambda[$].*/0x.*source:.*LambdaContainsOldInf");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8276184
|
||||
* @summary AppCDS handling of signed JAR.
|
||||
* @requires vm.cds
|
||||
* @library /test/lib
|
||||
@ -42,24 +43,42 @@ public class SignedJar {
|
||||
// Test class exists in signed JAR
|
||||
String signedJar = TestCommon.getTestJar("signed_hello.jar");
|
||||
OutputAnalyzer output;
|
||||
output = TestCommon.dump(signedJar, TestCommon.list("Hello"));
|
||||
TestCommon.checkDump(output, "Skipping Hello: Signed JAR");
|
||||
|
||||
// At runtime, the Hello class should be loaded from the jar file
|
||||
// instead of from the shared archive since a class from a signed
|
||||
// jar shouldn't be dumped into the archive.
|
||||
output = TestCommon.exec(signedJar, "-verbose:class", "Hello");
|
||||
String expectedOutput = ".class,load. Hello source: file:.*signed_hello.jar";
|
||||
// "testlambda" is for testing JDK-8276184
|
||||
String[] mainArgs = { "dummy", "testlambda" };
|
||||
String mainClass = "Hello";
|
||||
|
||||
try {
|
||||
output.shouldMatch(expectedOutput);
|
||||
} catch (Exception e) {
|
||||
TestCommon.checkCommonExecExceptions(output, e);
|
||||
String skipMsg = "Skipping Hello: Signed JAR";
|
||||
String lambdaInArchive = "klasses.*=.*app.*Hello[$][$]Lambda[$].*hidden";
|
||||
String loadFromJar = ".class,load. Hello source: file:.*signed_hello.jar";
|
||||
String lambdaLoadFromHello = ".class.load. Hello[$][$]Lambda[$].*/0x.*source.*Hello";
|
||||
|
||||
for (String mainArg : mainArgs) {
|
||||
output = TestCommon.dump(signedJar, TestCommon.list(mainClass),
|
||||
"-Xlog:cds+class=debug", mainClass, mainArg);
|
||||
TestCommon.checkDump(output, skipMsg);
|
||||
output.shouldNotContain(lambdaInArchive);
|
||||
|
||||
// At runtime, the Hello class should be loaded from the jar file
|
||||
// instead of from the shared archive since a class from a signed
|
||||
// jar shouldn't be dumped into the archive.
|
||||
output = TestCommon.exec(signedJar, "-verbose:class", mainClass, mainArg);
|
||||
|
||||
try {
|
||||
output.shouldMatch(loadFromJar);
|
||||
if (mainArg.equals("testlambda")) {
|
||||
output.shouldMatch(lambdaLoadFromHello);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
TestCommon.checkCommonExecExceptions(output, e);
|
||||
}
|
||||
|
||||
// Test class exists in both signed JAR and unsigned JAR
|
||||
String jars = signedJar + System.getProperty("path.separator") + unsignedJar;
|
||||
output = TestCommon.dump(jars, TestCommon.list(mainClass),
|
||||
"-Xlog:cds+class=debug", mainClass, mainArg);
|
||||
TestCommon.checkDump(output, skipMsg);
|
||||
output.shouldNotContain(lambdaInArchive);
|
||||
}
|
||||
|
||||
// Test class exists in both signed JAR and unsigned JAR
|
||||
String jars = signedJar + System.getProperty("path.separator") + unsignedJar;
|
||||
output = TestCommon.dump(jars, TestCommon.list("Hello"));
|
||||
TestCommon.checkDump(output, "Skipping Hello: Signed JAR");
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8274944
|
||||
* @bug 8274944 8276184
|
||||
* @summary VM should not crash during CDS dump when a lambda proxy class
|
||||
* contains an old version of interface.
|
||||
* @requires vm.cds
|
||||
@ -53,29 +53,34 @@ public class LambdaContainsOldInf extends DynamicArchiveTestBase {
|
||||
String wbJar = ClassFileInstaller.getJarPath("WhiteBox.jar");
|
||||
String use_whitebox_jar = "-Xbootclasspath/a:" + wbJar;
|
||||
|
||||
dump(topArchiveName,
|
||||
"-XX:+UnlockDiagnosticVMOptions",
|
||||
"-XX:+WhiteBoxAPI",
|
||||
"-Xlog:class+load=debug,cds=debug,cds+dynamic=info",
|
||||
use_whitebox_jar,
|
||||
"-cp", appJar, mainClass)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldContain("Skipping OldProvider: Old class has been linked")
|
||||
.shouldMatch("Skipping.LambdaContainsOldInfApp[$][$]Lambda[$].*0x.*:.*Old.class.has.been.linked")
|
||||
.shouldHaveExitValue(0);
|
||||
String[] mainArgs = { "dummy", "addLambda" };
|
||||
|
||||
for (String mainArg : mainArgs) {
|
||||
|
||||
dump(topArchiveName,
|
||||
"-XX:+UnlockDiagnosticVMOptions",
|
||||
"-XX:+WhiteBoxAPI",
|
||||
"-Xlog:class+load=debug,cds=debug,cds+dynamic=info",
|
||||
use_whitebox_jar,
|
||||
"-cp", appJar, mainClass, mainArg)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldContain("Skipping OldProvider: Old class has been linked")
|
||||
.shouldMatch("Skipping.LambdaContainsOldInfApp[$][$]Lambda[$].*0x.*:.*Old.class.has.been.linked")
|
||||
.shouldHaveExitValue(0);
|
||||
});
|
||||
|
||||
run(topArchiveName,
|
||||
"-XX:+UnlockDiagnosticVMOptions",
|
||||
"-XX:+WhiteBoxAPI",
|
||||
use_whitebox_jar,
|
||||
"-Xlog:class+load=debug",
|
||||
"-cp", appJar, mainClass)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldContain("[class,load] LambdaContainsOldInfApp source: shared objects file (top)")
|
||||
.shouldMatch(".class.load. OldProvider.source:.*lambda_contains_old_inf.jar")
|
||||
.shouldMatch(".class.load. LambdaContainsOldInfApp[$][$]Lambda[$].*/0x.*source:.*LambdaContainsOldInf")
|
||||
.shouldHaveExitValue(0);
|
||||
run(topArchiveName,
|
||||
"-XX:+UnlockDiagnosticVMOptions",
|
||||
"-XX:+WhiteBoxAPI",
|
||||
use_whitebox_jar,
|
||||
"-Xlog:class+load=debug",
|
||||
"-cp", appJar, mainClass, mainArg)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldContain("[class,load] LambdaContainsOldInfApp source: shared objects file (top)")
|
||||
.shouldMatch(".class.load. OldProvider.source:.*lambda_contains_old_inf.jar")
|
||||
.shouldMatch(".class.load. LambdaContainsOldInfApp[$][$]Lambda[$].*/0x.*source:.*LambdaContainsOldInf")
|
||||
.shouldHaveExitValue(0);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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
|
||||
* @bug 8276184
|
||||
* @summary Archive an old interface in the base archive and an app class which
|
||||
* uses the old interface via a lambda expression in the dynamic archive.
|
||||
* The lambda proxy class of the app class should be in the dynamic archive.
|
||||
* @requires vm.cds
|
||||
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/test-classes
|
||||
* @build LambdaContainsOldInfApp sun.hotspot.WhiteBox OldProvider
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar old-inf-base-archive.jar LambdaContainsOldInfApp OldProvider
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
|
||||
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. LambdaForOldInfInBaseArchive
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import jdk.test.lib.cds.CDSOptions;
|
||||
import jdk.test.lib.cds.CDSTestUtils;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.helpers.ClassFileInstaller;
|
||||
|
||||
public class LambdaForOldInfInBaseArchive extends DynamicArchiveTestBase {
|
||||
static final String classList = CDSTestUtils.getOutputFileName("classlist");
|
||||
static final String appClass = "LambdaContainsOldInfApp";
|
||||
static final String baseArchiveClass = "OldProvider";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
runTest(LambdaForOldInfInBaseArchive::testCustomBase);
|
||||
}
|
||||
|
||||
static void testCustomBase() throws Exception {
|
||||
String topArchiveName = getNewArchiveName("top");
|
||||
doTestCustomBase(topArchiveName);
|
||||
}
|
||||
|
||||
private static void doTestCustomBase(String topArchiveName) throws Exception {
|
||||
String appJar = ClassFileInstaller.getJarPath("old-inf-base-archive.jar");
|
||||
|
||||
// create a custom base archive containing and old interface
|
||||
OutputAnalyzer output = TestCommon.dump(appJar,
|
||||
TestCommon.list("OldProvider"), "-Xlog:class+load,cds+class=debug");
|
||||
TestCommon.checkDump(output);
|
||||
// Check that the OldProvider is being dumped into the base archive.
|
||||
output.shouldMatch(".cds,class.*klass.*0x.*app.*OldProvider.*unlinked");
|
||||
|
||||
String baseArchiveName = TestCommon.getCurrentArchiveName();
|
||||
|
||||
// create a dynamic archive with the custom base archive.
|
||||
// The old interface is in the base archive and will be
|
||||
// accessed using a lambda expression of LambdaContainsOldInfApp.
|
||||
// The lambda proxy class and the app class will be archived in the dynamic archive.
|
||||
dump2(baseArchiveName, topArchiveName,
|
||||
"-Xlog:cds,cds+dynamic,class+load,cds+class=debug",
|
||||
"-cp", appJar,
|
||||
appClass)
|
||||
.assertNormalExit(out -> {
|
||||
out.shouldContain("OldProvider source: shared objects file")
|
||||
.shouldMatch("Archiving hidden LambdaContainsOldInfApp[$][$]Lambda[$][\\d+]*");
|
||||
});
|
||||
|
||||
// Run with both base and dynamic archives. The OldProvider class
|
||||
// should be loaded from the base archive. The LambdaContainsOldInfApp
|
||||
// and its lambda proxy class should be loaded from the dynamic archive.
|
||||
run2(baseArchiveName, topArchiveName,
|
||||
"-Xlog:cds,cds+dynamic,class+load",
|
||||
"-cp", appJar,
|
||||
appClass)
|
||||
.assertNormalExit(out -> {
|
||||
out.shouldContain("OldProvider source: shared objects file")
|
||||
.shouldContain("LambdaContainsOldInfApp source: shared objects file (top)")
|
||||
.shouldMatch(".class.load. LambdaContainsOldInfApp[$][$]Lambda[$].*/0x.*source:.*shared.*objects.*file.*(top)");
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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
|
||||
* @bug 8276184
|
||||
* @summary Archive an old class in the base archive and an app class which
|
||||
* uses the old class in the dynamic archive.
|
||||
* The old class should be loaded from the base archive. The app class
|
||||
* should be loaded from the dynamic archive.
|
||||
* @requires vm.cds
|
||||
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/test-classes
|
||||
* @build OldSuperApp sun.hotspot.WhiteBox OldSuper ChildOldSuper GChild
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar old-class-base-archive.jar OldSuperApp OldSuper ChildOldSuper GChild
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
|
||||
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. OldClassInBaseArchive
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import jdk.test.lib.cds.CDSOptions;
|
||||
import jdk.test.lib.cds.CDSTestUtils;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.helpers.ClassFileInstaller;
|
||||
|
||||
public class OldClassInBaseArchive extends DynamicArchiveTestBase {
|
||||
static final String classList = CDSTestUtils.getOutputFileName("classlist");
|
||||
static final String appClass = "OldSuperApp";
|
||||
static final String baseArchiveClass = "OldSuper";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
runTest(OldClassInBaseArchive::testCustomBase);
|
||||
}
|
||||
|
||||
static void testCustomBase() throws Exception {
|
||||
String topArchiveName = getNewArchiveName("top");
|
||||
doTestCustomBase(topArchiveName);
|
||||
}
|
||||
|
||||
private static void doTestCustomBase(String topArchiveName) throws Exception {
|
||||
String appJar = ClassFileInstaller.getJarPath("old-class-base-archive.jar");
|
||||
|
||||
// create a custom base archive containing and old class
|
||||
OutputAnalyzer output = TestCommon.dump(appJar,
|
||||
TestCommon.list("OldSuper"), "-Xlog:class+load,cds+class=debug");
|
||||
TestCommon.checkDump(output);
|
||||
// Check the OldSuper is being dumped into the base archive.
|
||||
output.shouldMatch(".cds.class.*klass.*0x.*app.*OldSuper.*unlinked");
|
||||
|
||||
String baseArchiveName = TestCommon.getCurrentArchiveName();
|
||||
|
||||
// create a dynamic archive with the custom base archive.
|
||||
// The old class is in the base archive and will be
|
||||
// accessed from OldSuperApp.
|
||||
// The OldSuperApp, ChildOldSuper, and GChild classes will be archived
|
||||
// in the dynamic archive.
|
||||
dump2(baseArchiveName, topArchiveName,
|
||||
"-Xlog:cds,cds+dynamic,class+load,cds+class=debug",
|
||||
"-cp", appJar,
|
||||
appClass)
|
||||
.assertNormalExit(out -> {
|
||||
out.shouldContain("OldSuper source: shared objects file")
|
||||
// Check the following classes are being dumped into the dynamic archive.
|
||||
.shouldMatch(".cds,class.*klass.*0x.*app.*OldSuperApp")
|
||||
.shouldMatch(".cds,class.*klass.*0x.*app.*ChildOldSuper")
|
||||
.shouldMatch(".cds,class.*klass.*0x.*app.*GChild");
|
||||
});
|
||||
|
||||
// Run with both base and dynamic archives. The OldSuper class
|
||||
// should be loaded from the base archive. The OldSuperApp
|
||||
// and related classes should be loaded from the dynamic archive.
|
||||
run2(baseArchiveName, topArchiveName,
|
||||
"-Xlog:cds,cds+dynamic,class+load",
|
||||
"-cp", appJar,
|
||||
appClass)
|
||||
.assertNormalExit(out -> {
|
||||
out.shouldContain("OldSuper source: shared objects file")
|
||||
.shouldContain("OldSuperApp source: shared objects file (top)")
|
||||
.shouldContain("ChildOldSuper source: shared objects file (top)")
|
||||
.shouldContain("GChild source: shared objects file (top)");
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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
|
||||
* @bug 8276184
|
||||
* @summary If the caller class is redefined during dump time, the caller class
|
||||
* and its lambda proxy class should not be archived.
|
||||
* @requires vm.cds
|
||||
* @requires vm.jvmti
|
||||
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
|
||||
* /test/hotspot/jtreg/runtime/cds/appcds/test-classes
|
||||
* /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes
|
||||
* @build sun.hotspot.WhiteBox OldProvider
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
|
||||
* @run driver RedefineClassHelper
|
||||
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. RedefineCallerClassTest
|
||||
*/
|
||||
|
||||
import jdk.test.lib.helpers.ClassFileInstaller;
|
||||
|
||||
public class RedefineCallerClassTest extends DynamicArchiveTestBase {
|
||||
static String mainClass = RedefineCallerClass.class.getName();
|
||||
|
||||
static String providerClass = OldProvider.class.getName();
|
||||
|
||||
static String sharedClasses[] = {
|
||||
mainClass,
|
||||
"SimpleLambda", // caller class will be redefined in RedefineCallerClass
|
||||
providerClass, // inteface with class file major version < 50
|
||||
"jdk/test/lib/compiler/InMemoryJavaCompiler",
|
||||
"jdk/test/lib/compiler/InMemoryJavaCompiler$FileManagerWrapper",
|
||||
"jdk/test/lib/compiler/InMemoryJavaCompiler$FileManagerWrapper$1",
|
||||
"jdk/test/lib/compiler/InMemoryJavaCompiler$MemoryJavaFileObject"
|
||||
};
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
runTest(RedefineCallerClassTest::test);
|
||||
}
|
||||
|
||||
static void test() throws Exception {
|
||||
String topArchiveName = getNewArchiveName();
|
||||
String appJar = ClassFileInstaller.writeJar("redefine_caller_class.jar", sharedClasses);
|
||||
|
||||
String[] mainArgs = {
|
||||
"redefineCaller", // redefine caller class only
|
||||
"useOldInf", // use old interface only
|
||||
"both" // both of the above
|
||||
};
|
||||
|
||||
for (String mainArg : mainArgs) {
|
||||
String[] options = {
|
||||
"-Xlog:class+load,cds",
|
||||
"-XX:+UnlockDiagnosticVMOptions",
|
||||
"-XX:+AllowArchivingWithJavaAgent",
|
||||
"-javaagent:redefineagent.jar",
|
||||
"-cp", appJar, mainClass, mainArg
|
||||
};
|
||||
|
||||
dump(topArchiveName, options)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldHaveExitValue(0);
|
||||
if (mainArg.equals("both") || mainArg.equals("useOldInf")) {
|
||||
output.shouldContain("Skipping OldProvider: Old class has been linked")
|
||||
.shouldMatch("Skipping.SimpleLambda[$][$]Lambda[$].*0x.*:.*Old.class.has.been.linked");
|
||||
}
|
||||
if (mainArg.equals("both") || mainArg.equals("redefineCaller")) {
|
||||
output.shouldContain("Skipping SimpleLambda: Has been redefined");
|
||||
}
|
||||
});
|
||||
|
||||
run(topArchiveName, options)
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldHaveExitValue(0)
|
||||
.shouldContain("RedefineCallerClass source: shared objects file (top)")
|
||||
.shouldMatch(".class.load. SimpleLambda[$][$]Lambda[$].*/0x.*source:.*SimpleLambda");
|
||||
if (mainArg.equals("both") || mainArg.equals("useOldInf")) {
|
||||
output.shouldMatch(".class.load. OldProvider.source:.*redefine_caller_class.jar");
|
||||
}
|
||||
if (mainArg.equals("both") || mainArg.equals("redefineCaller")) {
|
||||
output.shouldMatch(".class.load. SimpleLambda.source:.*redefine_caller_class.jar");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
class SimpleLambda {
|
||||
public Runnable getRunnable() {
|
||||
return () -> {};
|
||||
}
|
||||
public OldProvider getProvider() {
|
||||
return () -> {
|
||||
return null;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class RedefineCallerClass {
|
||||
|
||||
public static String newClass =
|
||||
" class SimpleLambda { " +
|
||||
" public Runnable getRunnable() { " +
|
||||
" return () -> {}; " +
|
||||
" } " +
|
||||
" public OldProvider getProvider() { " +
|
||||
" return () -> { " +
|
||||
" return null; " +
|
||||
" }; " +
|
||||
" } " +
|
||||
" } ";
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
String mode = "both";
|
||||
if (args.length == 1) {
|
||||
mode = args[0];
|
||||
}
|
||||
SimpleLambda s = new SimpleLambda();
|
||||
if (mode.equals("both") || mode.equals("useOldInf")) {
|
||||
System.out.println(s.getProvider());
|
||||
} else {
|
||||
System.out.println(s.getRunnable());
|
||||
}
|
||||
if (mode.equals("both") || mode.equals("redefineCaller")) {
|
||||
RedefineClassHelper.redefineClass(s.getClass(), newClass);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 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
|
||||
@ -25,5 +25,12 @@
|
||||
public class Hello {
|
||||
public static void main(String args[]) {
|
||||
System.out.println("Hello World");
|
||||
if (args.length > 0 && args[0].equals("testlambda")) {
|
||||
System.out.println(getRunnable());
|
||||
}
|
||||
}
|
||||
|
||||
public static Runnable getRunnable() {
|
||||
return () -> {};
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,9 @@
|
||||
public class LambdaContainsOldInfApp {
|
||||
public static void main(final String... args) {
|
||||
getProvider();
|
||||
if (args.length == 1 && args[0].equals("addLambda")) {
|
||||
getProvider2();
|
||||
}
|
||||
}
|
||||
|
||||
public static OldProvider getProvider() {
|
||||
@ -31,4 +34,10 @@ public class LambdaContainsOldInfApp {
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
public static OldProvider getProvider2() {
|
||||
return () -> {
|
||||
return null;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user