1 /*
  2  * Copyright Amazon.com Inc. 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 import java.util.ArrayList;
 26 import java.util.List;
 27 import java.nio.file.Path;
 28 import java.nio.file.Paths;
 29 import java.nio.file.Files;
 30 
 31 import jdk.test.lib.cds.CDSJarUtils;
 32 import jdk.test.lib.cds.CDSTestUtils;
 33 import jdk.test.lib.process.OutputAnalyzer;
 34 
 35 /*
 36  * @test
 37  * @summary Try to archive lots and lots of classes.
 38  * @requires vm.cds
 39  * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
 40  * @run driver/timeout=500 LotsOfSyntheticClasses
 41  */
 42 
 43 public class LotsOfSyntheticClasses {
 44 
 45     // Generate 70 top-level classes, each containing 1000 nested classes.
 46     // 70K total classes is enough to push the CDS limits. Any archived
 47     // collection that holds Classes should not have backing storage larger
 48     // than CDS archival limit (256KB). This means we want at least 64K classes
 49     // to probe that limit.
 50     private static final int NUM_CLASSES = 70;
 51     private static final int NUM_NESTED_CLASSES = 1000;
 52 
 53     private static final Path USER_DIR = Paths.get(CDSTestUtils.getOutputDir());
 54     private static final Path APP_JAR = USER_DIR.resolve("test.jar");
 55     private static final Path SRC_DIR = USER_DIR.resolve("src");
 56 
 57     private static final String TOP_CLASS_NAME = "Class";
 58     private static final String NESTED_CLASS_NAME = "Nested";
 59     private static final String MAIN_CLASS_NAME = "Main";
 60 
 61     public static List<String> generateClass(int idx) {
 62         List<String> out = new ArrayList<>();
 63         out.add("public class " + TOP_CLASS_NAME + idx + " {");
 64         out.add("public " + TOP_CLASS_NAME + idx + "() {");
 65         for (int c = 0; c < NUM_NESTED_CLASSES; c++) {
 66             out.add("new " + NESTED_CLASS_NAME + c + "();");
 67         }
 68         out.add("}");
 69         for (int c = 0; c < NUM_NESTED_CLASSES; c++) {
 70             out.add("public static class " + NESTED_CLASS_NAME + c + " {}");
 71         }
 72         out.add("}");
 73         return out;
 74     }
 75 
 76     public static List<String> generateMainClass() {
 77         List<String> out = new ArrayList<>();
 78         out.add("public class " + MAIN_CLASS_NAME + " {");
 79         out.add("public static void main(String... args) {");
 80         for (int c = 0; c < NUM_CLASSES; c++) {
 81             out.add("new " + TOP_CLASS_NAME + c + "();");
 82         }
 83         out.add("System.out.println(\"Success\");");
 84         out.add("}");
 85         out.add("}");
 86         return out;
 87     }
 88 
 89     public static String[] listAppClasses() {
 90         String[] res = new String[NUM_CLASSES * NUM_NESTED_CLASSES];
 91         for (int c = 0; c < NUM_CLASSES; c++) {
 92             for (int sc = 0; sc < NUM_NESTED_CLASSES; sc++) {
 93                 res[c * NUM_NESTED_CLASSES + sc] = TOP_CLASS_NAME + c + "$" + NESTED_CLASS_NAME + sc;
 94             }
 95         }
 96         return res;
 97     }
 98 
 99     public static void main(String[] args) throws Exception {
100         // Step 1. Generate classes and build the JAR with them.
101         {
102             SRC_DIR.toFile().mkdirs();
103 
104             for (int i = 0; i < NUM_CLASSES; i++) {
105                 Path file = SRC_DIR.resolve(TOP_CLASS_NAME + i + ".java");
106                 Files.write(file, generateClass(i));
107             }
108 
109             Path mainFile = SRC_DIR.resolve(MAIN_CLASS_NAME + ".java");
110             Files.write(mainFile, generateMainClass());
111 
112             CDSJarUtils.buildFromSourceDirectory(
113                 APP_JAR.toString(),
114                 SRC_DIR.toString()
115             );
116         }
117 
118         // Step 2. Try to dump the archive.
119         {
120             OutputAnalyzer output = TestCommon.createArchive(
121                 APP_JAR.toString(),
122                 listAppClasses(),
123                 // Verification for lots of classes slows down the test.
124                 "-XX:+IgnoreUnrecognizedVMOptions",
125                 "-XX:+UnlockDiagnosticVMOptions",
126                 "-XX:-ArchiveLoaderLookupCache", // LEYDEN_ONLY - work around JDK-8365959
127                 "-XX:-VerifyDependencies",
128                 "-XX:-VerifyBeforeExit"
129             );
130             TestCommon.checkDump(output);
131         }
132 
133         // Step 3. Try to run, touching every class.
134         {
135             TestCommon.run(
136                 // Verification for lots of classes slows down the test.
137                 "-XX:+IgnoreUnrecognizedVMOptions",
138                 "-XX:+UnlockDiagnosticVMOptions",
139                 "-XX:-VerifyDependencies",
140                 "-XX:-VerifyBeforeExit",
141                 "-cp", APP_JAR.toString(),
142                 MAIN_CLASS_NAME).
143                     assertNormalExit("Success");
144         }
145 
146     }
147 }