Ioi Lam 7077535c0b 8356595: Convert -Xlog:cds to -Xlog:aot (step1)
Reviewed-by: ccheung, dholmes, jsjolen, matsaave
2025-05-20 03:44:25 +00:00

173 lines
6.6 KiB
Java

/*
* 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 Do not cache classes that are loaded from a fake location.
* @bug 8352001
* @requires vm.cds.supports.aot.class.linking
* @comment work around JDK-8345635
* @requires !vm.jvmci.enabled
* @library /test/jdk/lib/testlibrary /test/lib
* @build FakeCodeLocation
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar FakeCodeLocationApp
* @run driver jdk.test.lib.helpers.ClassFileInstaller ClassNotInJar1 ClassNotInJar2
* @run driver FakeCodeLocation
*/
import java.lang.invoke.MethodHandles;
import java.lang.reflect.InaccessibleObjectException;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.ProtectionDomain;
import jdk.test.lib.cds.CDSAppTester;
import jdk.test.lib.helpers.ClassFileInstaller;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.StringArrayUtils;
public class FakeCodeLocation {
static final String appJar = "app.jar";
static final String mainClass = FakeCodeLocationApp.class.getName();
public static void main(String[] args) throws Exception {
(new Tester(false)).run(new String[] {"STATIC"});
(new Tester(true )).run(new String[] {"STATIC"});
(new Tester(false)).run(new String[] {"AOT"});
(new Tester(true )).run(new String[] {"AOT"});
}
static class Tester extends CDSAppTester {
boolean addOpen;;
public Tester(boolean addOpen) {
super(mainClass);
this.addOpen = addOpen;
}
@Override
public String classpath(RunMode runMode) {
return appJar;
}
@Override
public String[] vmArgs(RunMode runMode) {
String[] args = new String[] {
"-Xlog:aot",
"-Xlog:cds",
"-Xlog:aot+class=debug",
"-Xlog:cds+class=debug",
"-Xlog:class+load",
};
if (addOpen) {
args = StringArrayUtils.concat(args, "--add-opens", "java.base/java.lang=ALL-UNNAMED", "-XX:-AOTClassLinking");
}
return args;
}
@Override
public String[] appCommandLine(RunMode runMode) {
return new String[] {
mainClass,
addOpen ? "hasAddedOpen" : "hasNotAddedOpen",
};
}
@Override
public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception {
if (isDumping(runMode)) {
out.shouldMatch(",class.* FakeCodeLocationApp");
out.shouldNotMatch(",class.* ClassNotInJar1");
out.shouldNotMatch(",class.* ClassNotInJar2");
}
if (runMode.isProductionRun()) {
out.shouldMatch("class,load.* FakeCodeLocationApp .*source: shared objects file");
out.shouldNotMatch("class,load.* ClassNotInJar1 .*source: shared objects file");
out.shouldNotMatch("class,load.* ClassNotInJar2 .*source: shared objects file");
}
}
}
}
class FakeCodeLocationApp {
static boolean hasAddedOpen;
public static void main(String args[]) throws Exception {
hasAddedOpen = args[0].equals("hasAddedOpen");
testWithLookup();
testWithSetAccessible();
}
// Define a class using Lookup.defineClass(). The ClassFileParser should see "__JVM_DefineClass__"
// as the source location, so this class will be excluded, as the location is not supported.
static void testWithLookup() throws Exception {
byte[] data = Files.readAllBytes(Paths.get("ClassNotInJar1.class"));
Class c = MethodHandles.lookup().defineClass(data);
System.out.println(c.getProtectionDomain());
System.out.println(c.getProtectionDomain().getCodeSource());
}
// Use setAccessible to call into ClassLoader.defineClass(). In this case, the ClassFileParser
// sees "app.jar" as the source location, but the app.jar doesn't contain this class file, so we
// should exclude this class.
static void testWithSetAccessible() throws Exception {
Method m = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class, ProtectionDomain.class);
System.out.println(m);
try {
m.setAccessible(true);
if (!hasAddedOpen) {
throw new RuntimeException("setAccessible() should have failed because '--add-opens java.base/java.lang=ALL-UNNAMED' was not specified");
}
} catch (InaccessibleObjectException t) {
if (hasAddedOpen) {
throw new RuntimeException("setAccessible() failed even though '--add-opens java.base/java.lang=ALL-UNNAMED' was specified");
} else {
System.out.println("\n\nExpected: " + t);
t.printStackTrace(System.out);
return;
}
}
ProtectionDomain pd = FakeCodeLocationApp.class.getProtectionDomain();
ClassLoader appLoader = FakeCodeLocationApp.class.getClassLoader();
byte[] data = Files.readAllBytes(Paths.get("ClassNotInJar2.class"));
Class c = null;
try {
c = (Class)m.invoke(appLoader, "ClassNotInJar2", data, 0, data.length, pd);
} catch (Throwable t) {
System.out.println(t);
t.printStackTrace(System.out);
return;
}
System.out.println(c);
System.out.println(c.getProtectionDomain());
System.out.println(c.getProtectionDomain().getCodeSource());
}
}
class ClassNotInJar1 {}
class ClassNotInJar2 {}