8354558: -XX:AOTMode=record crashes with boot loader package-info class

Reviewed-by: ccheung, matsaave
This commit is contained in:
Ioi Lam 2025-04-24 00:00:36 +00:00
parent b10a304b2b
commit bbec3c0730
4 changed files with 114 additions and 14 deletions

View File

@ -1219,6 +1219,7 @@ void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik,
// must be valid since the class has been successfully parsed.
const char* path = ClassLoader::uri_to_path(src);
assert(path != nullptr, "sanity");
bool found_invalid = false;
AOTClassLocationConfig::dumptime_iterate([&] (AOTClassLocation* cl) {
int i = cl->index();
// for index 0 and the stream->source() is the modules image or has the jrt: protocol.
@ -1242,10 +1243,15 @@ void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik,
classpath_index = i;
} else {
if (cl->from_boot_classpath()) {
// The class must be from boot loader append path which consists of
// -Xbootclasspath/a and jvmti appended entries.
assert(loader == nullptr, "sanity");
classpath_index = i;
if (loader != nullptr) {
// Probably loaded by jdk/internal/loader/ClassLoaders$BootClassLoader. Don't archive
// such classes.
ik->set_shared_classpath_index(-1);
ik->set_shared_class_loader_type(ClassLoader::BOOT_LOADER);
found_invalid = true;
} else {
classpath_index = i;
}
}
}
} else {
@ -1256,13 +1262,17 @@ void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik,
}
}
}
if (classpath_index >= 0) {
if (classpath_index >= 0 || found_invalid) {
return false; // quit iterating
} else {
return true; // Keep iterating
}
});
if (found_invalid) {
return;
}
// No path entry found for this class: most likely a shared class loaded by the
// user defined classloader.
if (classpath_index < 0 && !SystemDictionaryShared::is_builtin_loader(ik->class_loader_data())) {

View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2025, 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 AOT cache handling for package-info class loaded by jdk/internal/loader/ClassLoaders$BootClassLoader
* @bug 8354558
* @requires vm.cds.supports.aot.class.linking
* @comment work around JDK-8345635
* @requires !vm.jvmci.enabled
* @library /test/lib /test/jdk/java/lang/Package/bootclasspath/boot
* @build PackageInfoClass foo.Foo foo.MyAnnotation foo.package-info
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar boot.jar foo.Foo foo.package-info foo.MyAnnotation
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar PackageInfoClassApp
* @run driver PackageInfoClass AOT
*/
import java.lang.annotation.Annotation;
import java.util.Arrays;
import jdk.test.lib.cds.CDSAppTester.RunMode;
import jdk.test.lib.cds.SimpleCDSAppTester;
import jdk.test.lib.process.OutputAnalyzer;
public class PackageInfoClass {
public static void main(String... args) throws Exception {
SimpleCDSAppTester.of("PackageInfoClass")
.classpath("app.jar")
.addVmArgs("-Xbootclasspath/a:boot.jar")
.appCommandLine("PackageInfoClassApp")
.setAssemblyChecker((OutputAnalyzer out, RunMode runMode) -> {
if (runMode == RunMode.TRAINING) {
out.shouldContain("Skipping foo/package-info: Unsupported location");
}
})
.runAOTWorkflow();
}
}
class PackageInfoClassApp {
public static void main(String[] args) throws Exception {
// This code is taken from test/jdk/java/lang/Package/bootclasspath/GetPackageFromBootClassPath.java
Class<?> c = Class.forName("foo.Foo", false, null);
Package p = c.getPackage();
Annotation[] annotations = p.getAnnotations();
Class<?> annType = Class.forName("foo.MyAnnotation", false, null);
if (annotations.length != 1 ||
annotations[0].annotationType() != annType) {
throw new RuntimeException("Expected foo.MyAnnotation but got " +
Arrays.toString(annotations));
}
}
}

View File

@ -86,7 +86,7 @@ abstract public class CDSAppTester {
}
public enum RunMode {
TRAINING, // -XX:DumpLoadedClassList OR {-XX:AOTMode=create -XX:AOTConfiguration}
TRAINING, // -XX:DumpLoadedClassList OR {-XX:AOTMode=record -XX:AOTConfiguration}
DUMP_STATIC, // -Xshare:dump
DUMP_DYNAMIC, // -XX:ArchiveClassesArExit
ASSEMBLY, // JEP 483 (assembly phase, app logic not executed)

View File

@ -24,11 +24,13 @@
package jdk.test.lib.cds;
import java.io.File;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import jdk.test.lib.cds.CDSAppTester.RunMode;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.StringArrayUtils;
import java.util.function.Consumer;
/*
* A simpler way to use CDSAppTester. Example:
*
@ -49,8 +51,8 @@ import java.util.function.Consumer;
*/
public class SimpleCDSAppTester {
private String name;
private Consumer<OutputAnalyzer> assemblyChecker;
private Consumer<OutputAnalyzer> productionChecker;
private BiConsumer<OutputAnalyzer, RunMode> assemblyChecker;
private BiConsumer<OutputAnalyzer, RunMode> productionChecker;
private String classpath;
private String modulepath;
private String[] appCommandLine;
@ -98,16 +100,31 @@ public class SimpleCDSAppTester {
return this;
}
public SimpleCDSAppTester setAssemblyChecker(Consumer<OutputAnalyzer> checker) {
public SimpleCDSAppTester setAssemblyChecker(BiConsumer<OutputAnalyzer, RunMode> checker) {
this.assemblyChecker = checker;
return this;
}
public SimpleCDSAppTester setProductionChecker(Consumer<OutputAnalyzer> checker) {
public SimpleCDSAppTester setProductionChecker(BiConsumer<OutputAnalyzer, RunMode> checker) {
this.productionChecker = checker;
return this;
}
public SimpleCDSAppTester setAssemblyChecker(Consumer<OutputAnalyzer> checker) {
this.assemblyChecker = (OutputAnalyzer out, RunMode runMode) -> {
checker.accept(out);
};
return this;
}
public SimpleCDSAppTester setProductionChecker(Consumer<OutputAnalyzer> checker) {
this.productionChecker = (OutputAnalyzer out, RunMode runMode) -> {
checker.accept(out);
};
return this;
}
class Tester extends CDSAppTester {
public Tester(String name) {
super(name);
@ -137,11 +154,11 @@ public class SimpleCDSAppTester {
public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception {
if (isDumping(runMode) && runMode != RunMode.TRAINING) {
if (assemblyChecker != null) {
assemblyChecker.accept(out);
assemblyChecker.accept(out, runMode);
}
} else if (runMode.isProductionRun()) {
if (productionChecker != null) {
productionChecker.accept(out);
productionChecker.accept(out, runMode);
}
}
}