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
 27  * @requires vm.cds
 28  * @summary Test for verification of classes that are preloaded
 29  * @library /test/jdk/lib/testlibrary
 30  *          /test/lib
 31  *          /test/hotspot/jtreg/runtime/cds/appcds
 32  *          /test/hotspot/jtreg/runtime/cds/appcds/test-classes
 33  * @build GoodOldClass BadOldClass BadOldClass2 BadNewClass BadNewClass2
 34  * @build PreloadedClassesVerification
 35  * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar WhiteBox.jar jdk.test.whitebox.WhiteBox
 36  * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app1.jar
 37  *                 PreloadedClassesVerificationApp
 38  *                 Unlinked UnlinkedSuper
 39  *                 BadOldClass
 40  *                 BadOldClass2
 41  *                 BadNewClass
 42  *                 BadNewClass2
 43  *                 GoodOldClass Vehicle Car
 44  *                 Util
 45  * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app2.jar
 46  *                 UnlinkedSub
 47  *                 Foo NotFoo
 48  * @run driver PreloadedClassesVerification
 49  */
 50 
 51 import java.io.File;
 52 import java.lang.invoke.MethodHandles;
 53 import jdk.test.lib.helpers.ClassFileInstaller;
 54 import jdk.test.whitebox.WhiteBox;
 55 
 56 public class PreloadedClassesVerification {
 57     static final String app1Jar = ClassFileInstaller.getJarPath("app1.jar");
 58     static final String app2Jar = ClassFileInstaller.getJarPath("app2.jar");
 59     static final String wbJar = TestCommon.getTestJar("WhiteBox.jar");
 60     static final String bootAppendWhiteBox = "-Xbootclasspath/a:" + wbJar;
 61     static final String mainClass = PreloadedClassesVerificationApp.class.getName();
 62 
 63     public static void main(String[] args) throws Exception {
 64         // Dump without app2.jar so:
 65         //  - Unlinked can be resolved, but UnlinkedSuper UnlinkedSub cannot be resolved,
 66         //    so Unlinked cannot be verified at dump time.
 67         //  - BadOldClass2 can be resolved, but Foo and NotFoo cannot be resolved,
 68         //    so BadOldClass2 cannot be verified at dump time.
 69         //  - BadNewClass2 can be resolved, but Foo and NotFoo cannot be resolved,
 70         //    so BadNewClass2 cannot be verified at dump time.
 71         TestCommon.testDump(app1Jar, TestCommon.list("Unlinked",
 72                                                      "BadOldClass",
 73                                                      "BadOldClass2",
 74                                                      "BadNewClass",
 75                                                      "BadNewClass2",
 76                                                      "GoodOldClass"),
 77                             bootAppendWhiteBox,
 78                             "-XX:+PreloadSharedClasses",
 79                             "-Xlog:cds+class=debug");
 80 
 81         TestCommon.run("-cp", app1Jar + File.pathSeparator + app2Jar,
 82                        "-XX:+UnlockDiagnosticVMOptions",
 83                        "-XX:+WhiteBoxAPI",
 84                        bootAppendWhiteBox,
 85                        "PreloadedClassesVerificationApp", app1Jar)
 86             .assertNormalExit();
 87     }
 88 }
 89 
 90 class PreloadedClassesVerificationApp {
 91     static WhiteBox wb = WhiteBox.getWhiteBox();
 92     static ClassLoader classLoader = PreloadedClassesVerificationApp.class.getClassLoader();
 93     static File app1Jar;
 94 
 95     public static void main(String[] args) throws Exception {
 96         app1Jar = new File(args[0]);
 97         assertNotShared(UnlinkedSub.class);
 98         assertShared(UnlinkedSuper.class);
 99         assertShared(Unlinked.class);
100         assertNotShared(Foo.class);
101         assertNotShared(NotFoo.class);
102         String s = Unlinked.doit();
103         if (!s.equals("heyhey")) {
104             throw new RuntimeException("Unlinked.doit() returns wrong result: " + s);
105         }
106 
107         Class cls_BadOldClass = Class.forName("BadOldClass", false, classLoader);
108         assertShared(cls_BadOldClass);
109         try {
110             cls_BadOldClass.newInstance();
111             throw new RuntimeException("BadOldClass cannot be verified");
112         } catch (VerifyError expected) {}
113 
114         Class cls_BadOldClass2 = Class.forName("BadOldClass2", false, classLoader);
115         assertShared(cls_BadOldClass2);
116         try {
117             cls_BadOldClass2.newInstance();
118             throw new RuntimeException("BadOldClass2 cannot be verified");
119         } catch (VerifyError expected) {}
120 
121         Class cls_BadNewClass = Class.forName("BadNewClass", false, classLoader);
122         assertShared(cls_BadNewClass);
123         try {
124             cls_BadNewClass.newInstance();
125             throw new RuntimeException("BadNewClass cannot be verified");
126         } catch (VerifyError expected) {}
127 
128         Class cls_BadNewClass2 = Class.forName("BadNewClass2", false, classLoader);
129         assertShared(cls_BadNewClass2);
130         try {
131             cls_BadNewClass2.newInstance();
132             throw new RuntimeException("BadNewClass2 cannot be verified");
133         } catch (VerifyError expected) {}
134 
135 
136         // Although Vehicle and Car are not specified in the classlist, they are archived as
137         // they were used during dumptime verification of GoodOldClass
138         assertAlreadyLoaded("Vehicle");
139         assertAlreadyLoaded("Car");
140         assertAlreadyLoaded("GoodOldClass");
141 
142         assertShared(GoodOldClass.class);
143         assertShared(Vehicle.class);
144         assertShared(Car.class);
145 
146         GoodOldClass.doit(); // Should not fail
147     }
148 
149     static void assertShared(Class c) {
150         if (!wb.isSharedClass(c)) {
151             throw new RuntimeException("wb.isSharedClass(" + c.getName() + ") should be true");
152         }
153     }
154 
155     static void assertNotShared(Class c) {
156         if (wb.isSharedClass(c)) {
157             throw new RuntimeException("wb.isSharedClass(" + c.getName() + ") should be false");
158         }
159     }
160 
161     static void assertAlreadyLoaded(String className) throws Exception {
162         byte[] data = Util.getClassFileFromJar(app1Jar, className);
163         try {
164             MethodHandles.lookup().defineClass(data);
165         } catch (LinkageError e) {
166             if (e.getMessage().contains("duplicate class definition for " + className)) {
167                 return;
168             } else {
169                 throw e;
170             }
171         }
172         throw new RuntimeException(className + " must have already been loaded");
173     }
174 }
175 
176 
177 class Unlinked {
178     static String doit() {
179         UnlinkedSuper sup = new UnlinkedSub();
180         return sup.doit();
181     }
182 }
183 
184 abstract class UnlinkedSuper {
185     abstract String doit();
186 }
187 
188 class UnlinkedSub extends UnlinkedSuper {
189     String doit() {
190         return "heyhey";
191     }
192 }
193 
194 class Foo {}
195 class NotFoo {}
196 
197 class Vehicle {}
198 class Car extends Vehicle {}