| /* |
| * 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. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * 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. |
| */ |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.File; |
| import java.io.PrintStream; |
| import java.nio.charset.StandardCharsets; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| import java.util.spi.ToolProvider; |
| import java.util.stream.Stream; |
| import static java.util.stream.Collectors.*; |
| |
| // This program is executed by make/RunTests.gmk to support running HotSpot tests |
| // in the "AOT mode", for example: |
| // |
| // make test JTREG=AOT_JDK=onestep TEST=open/test/hotspot/jtreg/runtime/invokedynamic |
| // make test JTREG=AOT_JDK=twostep TEST=open/test/hotspot/jtreg/runtime/invokedynamic |
| // |
| // The onestep and twostep options specify whether the AOT cache is created with |
| // a single JVM command (java -XX:AOTMode=record -XX:AOTCacheOutput=jdk.aotcache ...) or |
| // two JVM commands (java -XX:AOTMode=record ...; java -XX:AOTMode=create -XX:AOTCache=jdk.aotcache ...) |
| // |
| // All JDK classes touched by this program will be stored into a customized AOT cache. |
| // This is a larger set of classes than those stored in the JDK's default CDS archive. |
| // This customized cache can also have additional optimizations that are not |
| // enabled in the default CDS archive. For example, AOT-linked classes and lambda |
| // expressions. In the future, it can also contain AOT profiles and AOT compiled methods. |
| // |
| // We can use this customized AOT cache to run various HotSpot tests to improve |
| // coverage on AOT. |
| // |
| // Note that make/RunTests.gmk loads this class using an implicit classpath of ".", so |
| // this class will be excluded from the customized AOT cache. As a result, |
| // the customized AOT cache contains *only* classes from the JDK itself. |
| |
| public class TestSetupAOT { |
| private static final Logger LOGGER = Logger.getLogger("Hello"); |
| |
| public static void main(String[] args) throws Throwable { |
| runJDKTools(args); |
| invokedynamicTests(args); |
| LOGGER.log(Level.FINE, "Done"); |
| } |
| |
| static class ToolOutput { |
| ByteArrayOutputStream baos; |
| PrintStream ps; |
| String output; |
| |
| ToolOutput() throws Exception { |
| baos = new ByteArrayOutputStream(); |
| ps = new PrintStream(baos, true, StandardCharsets.UTF_8.name()); |
| } |
| void finish() throws Exception { |
| output = baos.toString(StandardCharsets.UTF_8.name()); |
| System.out.println(output); |
| } |
| |
| ToolOutput shouldContain(String... substrings) { |
| for (String s : substrings) { |
| if (!output.contains(s)) { |
| throw new RuntimeException("\"" + s + "\" missing from tool output"); |
| } |
| } |
| |
| return this; |
| } |
| |
| ToolOutput shouldMatch(String... regexps) { |
| for (String regexp : regexps) { |
| Pattern pattern = Pattern.compile(regexp, Pattern.MULTILINE); |
| if (!pattern.matcher(output).find()) { |
| throw new RuntimeException("Pattern \"" + regexp + "\" missing from tool output"); |
| } |
| } |
| |
| return this; |
| } |
| } |
| |
| static void runJDKTools(String[] args) throws Throwable { |
| String tmpDir = args[0]; |
| System.out.println("Working Directory = " + System.getProperty("user.dir")); |
| System.out.println("Temp output dir = " + tmpDir); |
| |
| // ------------------------------ |
| // javac |
| |
| execTool("javac", "--help") |
| .shouldContain("Usage: javac <options> <source files>"); |
| |
| JavacBenchApp.main(new String[] {"5"}); |
| |
| // ------------------------------ |
| // javap |
| |
| execTool("javap", "--help") |
| .shouldContain("Show package/protected/public classes"); |
| execTool("javap", "-c", "-private", "-v", "-verify", |
| "java.lang.System", |
| "java/util/stream/IntStream", |
| "jdk.internal.module.ModuleBootstrap") |
| .shouldContain("Compiled from \"System.java\"", |
| "public static java.io.Console console()"); |
| |
| // ------------------------------ |
| // jlink |
| |
| String jlinkOutput = tmpDir + File.separator + "jlinkOutput"; |
| |
| execTool("jlink", "--help") |
| .shouldContain("Compression to use in compressing resources"); |
| execTool("jlink", "--list-plugins") |
| .shouldContain("List of available plugins", |
| "--generate-cds-archive "); |
| |
| deleteAll(jlinkOutput); |
| execTool("jlink", "--add-modules", "java.base", "--strip-debug", "--output", jlinkOutput); |
| deleteAll(jlinkOutput); |
| |
| // ------------------------------ |
| // jar |
| |
| String jarOutput = tmpDir + File.separator + "tmp.jar"; |
| |
| execTool("jar", "--help") |
| .shouldContain("--main-class=CLASSNAME"); |
| |
| deleteAll(jarOutput); |
| execTool("jar", "cvf", jarOutput, "TestSetupAOT.class") |
| .shouldContain("adding: TestSetupAOT.class"); |
| execTool("jar", "uvf", jarOutput, "TestSetupAOT.class") |
| .shouldContain("adding: TestSetupAOT.class"); |
| execTool("jar", "tvf", jarOutput) |
| .shouldContain("META-INF/MANIFEST.MF"); |
| execTool("jar", "--describe-module", "--file=" + jarOutput) |
| .shouldMatch("Unable to derive module descriptor for: .*tmp.jar"); |
| deleteAll(jarOutput); |
| |
| // ------------------------------ |
| // jdeps |
| |
| execTool("jdeps", "--help") |
| .shouldContain("--ignore-missing-deps"); |
| execTool("jdeps", "-v", "TestSetupAOT.class") |
| .shouldContain("-> JavacBenchApp"); |
| } |
| |
| static void deleteAll(String f) { |
| deleteAll(new File(f)); |
| } |
| |
| static void deleteAll(File f) { |
| File[] files = f.listFiles(); |
| if (files != null) { |
| for (File file : files) { |
| deleteAll(file); |
| } |
| } |
| System.out.println("Deleting: " + f); |
| f.delete(); |
| } |
| |
| static ToolOutput execTool(String tool, String... args) throws Throwable { |
| System.out.println("== Running tool ======================================================"); |
| System.out.print(tool); |
| for (String s : args) { |
| System.out.print(" " + s); |
| } |
| System.out.println(); |
| System.out.println("======================================================================"); |
| |
| ToolOutput output = new ToolOutput(); |
| ToolProvider t = ToolProvider.findFirst(tool) |
| .orElseThrow(() -> new RuntimeException(tool + " not found")); |
| t.run(output.ps, output.ps, args); |
| |
| output.finish(); |
| return output; |
| } |
| |
| |
| // Run some operations with java.util.stream, lambda expressions and string concatenation. This |
| // will lead to AOT resolution of invokedynamic call sites. |
| static void invokedynamicTests(String args[]) { |
| List<String> strings = Arrays.asList("Hello", "World!"); |
| |
| String helloWorld = strings.parallelStream() |
| .filter(s -> s.contains("o")) |
| .map(s -> s.toLowerCase(Locale.ROOT)) |
| .collect(joining(",")); |
| |
| Stream.of(helloWorld.split("([,x-z]{1,3})([\\s]*)")) |
| .map(String::toString) |
| .forEach(System.out::println); |
| |
| // Common concatenation patterns |
| int i = args.length * 12357; // Seed with this so javac will not perform constant folding. |
| String s = String.valueOf(i); |
| |
| String SS = s + s; |
| String CS = "string" + s; |
| String SC = s + "string"; |
| String SCS = s + "string" + s; |
| String CSS = "string" + s + s; |
| String CSC = "string" + s + "string"; |
| String SSC = s + s + "string"; |
| String CSCS = "string" + s + "string" + s; |
| String SCSC = s + "string" + s + "string"; |
| String CSCSC = "string" + s + "string" + s + "string"; |
| String SCSCS = s + "string" + s + "string" + s; |
| String SSCSS = s + s + "string" + s + s; |
| String S5 = s + s + s + s + s; |
| String S6 = s + s + s + s + s + s; |
| String S7 = s + s + s + s + s + s + s; |
| String S8 = s + s + s + s + s + s + s + s; |
| String S9 = s + s + s + s + s + s + s + s + s; |
| String S10 = s + s + s + s + s + s + s + s + s + s; |
| |
| String CI = "string" + i; |
| String IC = i + "string"; |
| String SI = s + i; |
| String IS = i + s; |
| String CIS = "string" + i + s; |
| String CSCI = "string" + s + "string" + i; |
| String CIC = "string" + i + "string"; |
| String CICI = "string" + i + "string" + i; |
| |
| float f = 0.1f; |
| String CF = "string" + f; |
| String CFS = "string" + f + s; |
| String CSCF = "string" + s + "string" + f; |
| |
| char c = 'a'; |
| String CC = "string" + c; |
| String CCS = "string" + c + s; |
| String CSCC = "string" + s + "string" + c; |
| |
| long l = i + 12345678; |
| String CJ = "string" + l; |
| String JC = l + "string"; |
| String CJC = "string" + l + "string"; |
| String CJCJ = "string" + l + "string" + l; |
| String CJCJC = "string" + l + "string" + l + "string"; |
| double d = i / 2.0; |
| String CD = "string" + d; |
| String CDS = "string" + d + s; |
| String CSCD = "string" + s + "string" + d; |
| } |
| } |