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 * @summary test the handling of classes that are excluded from the CDS dump. 28 * @requires vm.cds.write.archived.java.heap 29 * @library /test/jdk/lib/testlibrary /test/lib 30 * /test/hotspot/jtreg/runtime/cds/appcds/leyden/test-classes 31 * @build ExcludedClasses Custy 32 * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar 33 * TestApp 34 * TestApp$Foo 35 * TestApp$Foo$Bar 36 * TestApp$Foo$ShouldBeExcluded 37 * TestApp$MyInvocationHandler 38 * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar cust.jar 39 * Custy 40 * @run driver ExcludedClasses LEYDEN 41 */ 42 43 import java.io.File; 44 import java.lang.invoke.MethodHandles; 45 import java.lang.invoke.MethodHandles.Lookup; 46 import java.lang.reflect.InvocationHandler; 47 import java.lang.reflect.Method; 48 import java.lang.reflect.Proxy; 49 import java.net.URL; 50 import java.net.URLClassLoader; 51 import java.nio.file.Files; 52 import java.nio.file.Path; 53 import java.security.ProtectionDomain; 54 import java.util.Map; 55 56 import jdk.jfr.Event; 57 import jdk.test.lib.cds.CDSAppTester; 58 import jdk.test.lib.helpers.ClassFileInstaller; 59 import jdk.test.lib.process.OutputAnalyzer; 60 61 public class ExcludedClasses { 62 static final String appJar = ClassFileInstaller.getJarPath("app.jar"); 63 static final String mainClass = "TestApp"; 64 65 public static void main(String[] args) throws Exception { 66 Tester t = new Tester(); 67 t.run(args); 68 } 69 70 static class Tester extends CDSAppTester { 71 public Tester() { 72 super(mainClass);; 73 } 74 75 @Override 76 public String classpath(RunMode runMode) { 77 return appJar; 78 } 79 80 @Override 81 public String[] vmArgs(RunMode runMode) { 82 return new String[] { 83 "-Xlog:cds+resolve=trace", 84 //TEMP: uncomment the next line to see the TrainingData::_archived_training_data_dictionary 85 //"-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintTrainingInfo", 86 }; 87 } 88 89 @Override 90 public String[] appCommandLine(RunMode runMode) { 91 return new String[] { 92 mainClass, runMode.name() 93 }; 94 } 95 96 @Override 97 public void checkExecution(OutputAnalyzer out, RunMode runMode) { 98 switch (runMode) { 99 case RunMode.TRAINING: 100 case RunMode.TRAINING0: 101 case RunMode.TRAINING1: 102 case RunMode.DUMP_STATIC: 103 out.shouldMatch("cds,resolve.*archived field.*TestApp.Foo => TestApp.Foo.Bar.f:I"); 104 out.shouldNotMatch("cds,resolve.*archived field.*TestApp.Foo => TestApp.Foo.ShouldBeExcluded.f:I"); 105 } 106 } 107 } 108 } 109 110 class TestApp { 111 static Object custInstance; 112 113 public static void main(String args[]) throws Exception { 114 // In new workflow, classes from custom loaders are passed from the preimage 115 // to the final image. See ClassPrelinker::record_unregistered_klasses(). 116 custInstance = initFromCustomLoader(); 117 System.out.println("Counter = " + Foo.hotSpot()); 118 } 119 120 static Object initFromCustomLoader() throws Exception { 121 String path = "cust.jar"; 122 URL url = new File(path).toURI().toURL(); 123 URL[] urls = new URL[] {url}; 124 URLClassLoader urlClassLoader = 125 new URLClassLoader("MyLoader", urls, null); 126 Class c = Class.forName("Custy", true, urlClassLoader); 127 return c.newInstance(); 128 } 129 130 static class MyInvocationHandler implements InvocationHandler { 131 volatile static int cnt; 132 133 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 134 long start = System.currentTimeMillis(); 135 while (System.currentTimeMillis() - start < 20) { 136 cnt += 2; 137 for (int i = 0; i < 1000; i++) { 138 int n = cnt - 2; 139 if (n < 2) { 140 n = 2; 141 } 142 cnt += (i + cnt) % n + cnt % 2; 143 } 144 } 145 return Integer.valueOf(cnt); 146 } 147 } 148 149 static class Foo { 150 volatile static int counter; 151 static Class c = ShouldBeExcluded.class; 152 153 static Map mapProxy = (Map) Proxy.newProxyInstance( 154 Foo.class.getClassLoader(), 155 new Class[] { Map.class }, 156 new MyInvocationHandler()); 157 158 static int hotSpot() { 159 ShouldBeExcluded s = new ShouldBeExcluded(); 160 Bar b = new Bar(); 161 162 long start = System.currentTimeMillis(); 163 while (System.currentTimeMillis() - start < 1000) { 164 lambdaHotSpot(); 165 s.hotSpot2(); 166 b.hotSpot3(); 167 168 // Currently, generated proxy classes are excluded from the CDS archive 169 Integer i = (Integer)mapProxy.get(null); 170 counter += i.intValue(); 171 172 173 if (custInstance != null) { 174 // For new workflow only: 175 // Currently, classes loaded by custom loaders are included in the preimage run 176 // but excluded from the final image. 177 counter += custInstance.equals(null) ? 1 : 2; 178 } 179 } 180 181 return counter + s.m() + s.f + b.m() + b.f; 182 } 183 184 static void f() { 185 if (counter % 2 == 1) { 186 counter ++; 187 } 188 } 189 190 // Lambda classes should be excluded from new workflow training run 191 static void lambdaHotSpot() { 192 long start = System.currentTimeMillis(); 193 while (System.currentTimeMillis() - start < 20) { 194 doit(() -> { 195 counter ++; 196 }); 197 } 198 } 199 200 static void doit(Runnable r) { 201 r.run(); 202 } 203 204 // All subclasses of jdk.jfr.Event are excluded from the CDS archive. 205 static class ShouldBeExcluded extends jdk.jfr.Event { 206 int f = (int)(System.currentTimeMillis()) + 123; 207 int m() { 208 return f + 456; 209 } 210 211 void hotSpot2() { 212 long start = System.currentTimeMillis(); 213 while (System.currentTimeMillis() - start < 20) { 214 for (int i = 0; i < 50000; i++) { 215 counter += i; 216 } 217 f(); 218 } 219 } 220 } 221 222 static class Bar { 223 int f = (int)(System.currentTimeMillis()) + 123; 224 int m() { 225 return f + 456; 226 } 227 228 void hotSpot3() { 229 long start = System.currentTimeMillis(); 230 while (System.currentTimeMillis() - start < 20) { 231 for (int i = 0; i < 50000; i++) { 232 counter += i; 233 } 234 f(); 235 } 236 } 237 } 238 } 239 }