1 /* 2 * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 /* 26 * @test In Leyden repo, classes that are linked during the assembly phase can 27 * skip verification constraint checks. See JDK-8317269. 28 * NOTE: this feature is not included when JDK-8315737 is upstreamed to the mainline. 29 * @requires vm.cds 30 * @requires vm.cds.supports.aot.class.linking 31 * @summary Test for verification of classes that are aot-linked 32 * @library /test/jdk/lib/testlibrary 33 * /test/lib 34 * /test/hotspot/jtreg/runtime/cds/appcds 35 * /test/hotspot/jtreg/runtime/cds/appcds/test-classes 36 * @build GoodOldClass BadOldClass BadOldClass2 BadNewClass BadNewClass2 37 * @build AOTClassLinkingVerification 38 * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar WhiteBox.jar jdk.test.whitebox.WhiteBox 39 * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app1.jar 40 * AOTClassLinkingVerificationApp 41 * Unlinked UnlinkedSuper 42 * BadOldClass 43 * BadOldClass2 44 * BadNewClass 45 * BadNewClass2 46 * GoodOldClass Vehicle Car 47 * Util 48 * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app2.jar 49 * UnlinkedSub 50 * Foo NotFoo 51 * @run driver AOTClassLinkingVerification 52 */ 53 54 import java.io.File; 55 import java.lang.invoke.MethodHandles; 56 import jdk.test.lib.helpers.ClassFileInstaller; 57 import jdk.test.whitebox.WhiteBox; 58 59 public class AOTClassLinkingVerification { 60 static final String app1Jar = ClassFileInstaller.getJarPath("app1.jar"); 61 static final String app2Jar = ClassFileInstaller.getJarPath("app2.jar"); 62 static final String wbJar = TestCommon.getTestJar("WhiteBox.jar"); 63 static final String bootAppendWhiteBox = "-Xbootclasspath/a:" + wbJar; 64 static final String mainClass = AOTClassLinkingVerificationApp.class.getName(); 65 66 public static void main(String[] args) throws Exception { 67 // Dump without app2.jar so: 68 // - Unlinked can be resolved, but UnlinkedSuper UnlinkedSub cannot be resolved, 69 // so Unlinked cannot be verified at dump time. 70 // - BadOldClass2 can be resolved, but Foo and NotFoo cannot be resolved, 71 // so BadOldClass2 cannot be verified at dump time. 72 // - BadNewClass2 can be resolved, but Foo and NotFoo cannot be resolved, 73 // so BadNewClass2 cannot be verified at dump time. 74 TestCommon.testDump(app1Jar, TestCommon.list("Unlinked", 75 "BadOldClass", 76 "BadOldClass2", 77 "BadNewClass", 78 "BadNewClass2", 79 "GoodOldClass"), 80 bootAppendWhiteBox, 81 "-XX:+AOTClassLinking", 82 "-Xlog:cds+class=debug"); 83 84 TestCommon.run("-cp", app1Jar + File.pathSeparator + app2Jar, 85 "-XX:+UnlockDiagnosticVMOptions", 86 "-XX:+WhiteBoxAPI", 87 bootAppendWhiteBox, 88 "AOTClassLinkingVerificationApp", app1Jar) 89 .assertNormalExit(); 90 } 91 } 92 93 class AOTClassLinkingVerificationApp { 94 static WhiteBox wb = WhiteBox.getWhiteBox(); 95 static ClassLoader classLoader = AOTClassLinkingVerificationApp.class.getClassLoader(); 96 static File app1Jar; 97 98 public static void main(String[] args) throws Exception { 99 app1Jar = new File(args[0]); 100 assertNotShared(UnlinkedSub.class); 101 assertShared(UnlinkedSuper.class); 102 assertShared(Unlinked.class); 103 assertNotShared(Foo.class); 104 assertNotShared(NotFoo.class); 105 String s = Unlinked.doit(); 106 if (!s.equals("heyhey")) { 107 throw new RuntimeException("Unlinked.doit() returns wrong result: " + s); 108 } 109 110 Class cls_BadOldClass = Class.forName("BadOldClass", false, classLoader); 111 assertShared(cls_BadOldClass); 112 try { 113 cls_BadOldClass.newInstance(); 114 throw new RuntimeException("BadOldClass cannot be verified"); 115 } catch (VerifyError expected) {} 116 117 Class cls_BadOldClass2 = Class.forName("BadOldClass2", false, classLoader); 118 assertShared(cls_BadOldClass2); 119 try { 120 cls_BadOldClass2.newInstance(); 121 throw new RuntimeException("BadOldClass2 cannot be verified"); 122 } catch (VerifyError expected) {} 123 124 Class cls_BadNewClass = Class.forName("BadNewClass", false, classLoader); 125 assertShared(cls_BadNewClass); 126 try { 127 cls_BadNewClass.newInstance(); 128 throw new RuntimeException("BadNewClass cannot be verified"); 129 } catch (VerifyError expected) {} 130 131 Class cls_BadNewClass2 = Class.forName("BadNewClass2", false, classLoader); 132 assertShared(cls_BadNewClass2); 133 try { 134 cls_BadNewClass2.newInstance(); 135 throw new RuntimeException("BadNewClass2 cannot be verified"); 136 } catch (VerifyError expected) {} 137 138 139 // Although Vehicle and Car are not specified in the classlist, they are archived as 140 // they were used during dumptime verification of GoodOldClass 141 assertAlreadyLoaded("Vehicle"); 142 assertAlreadyLoaded("Car"); 143 assertAlreadyLoaded("GoodOldClass"); 144 145 assertShared(GoodOldClass.class); 146 assertShared(Vehicle.class); 147 assertShared(Car.class); 148 149 GoodOldClass.doit(); // Should not fail 150 } 151 152 static void assertShared(Class c) { 153 if (!wb.isSharedClass(c)) { 154 throw new RuntimeException("wb.isSharedClass(" + c.getName() + ") should be true"); 155 } 156 } 157 158 static void assertNotShared(Class c) { 159 if (wb.isSharedClass(c)) { 160 throw new RuntimeException("wb.isSharedClass(" + c.getName() + ") should be false"); 161 } 162 } 163 164 static void assertAlreadyLoaded(String className) throws Exception { 165 byte[] data = Util.getClassFileFromJar(app1Jar, className); 166 try { 167 MethodHandles.lookup().defineClass(data); 168 } catch (LinkageError e) { 169 if (e.getMessage().contains("duplicate class definition for " + className)) { 170 return; 171 } else { 172 throw e; 173 } 174 } 175 throw new RuntimeException(className + " must have already been loaded"); 176 } 177 } 178 179 180 class Unlinked { 181 static String doit() { 182 UnlinkedSuper sup = new UnlinkedSub(); 183 return sup.doit(); 184 } 185 } 186 187 abstract class UnlinkedSuper { 188 abstract String doit(); 189 } 190 191 class UnlinkedSub extends UnlinkedSuper { 192 String doit() { 193 return "heyhey"; 194 } 195 } 196 197 class Foo {} 198 class NotFoo {} 199 200 class Vehicle {} 201 class Car extends Vehicle {}