1 /* 2 * Copyright (c) 2025, 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 interation between static archive and dynamic archive related to 28 * regenerated lambda form invoker classes. 29 * @requires vm.cds 30 * @requires vm.cds.supports.aot.class.linking 31 * @library /test/lib 32 * @build RegeneratedClassesInDynamicArchive 33 * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar TestApp CachedInDynamic MyInterface 34 * @run driver RegeneratedClassesInDynamicArchive 35 */ 36 37 import java.util.List; 38 import java.util.stream.Collectors; 39 40 import jdk.test.lib.cds.CDSTestUtils; 41 import jdk.test.lib.helpers.ClassFileInstaller; 42 import jdk.test.lib.process.OutputAnalyzer; 43 import jdk.test.lib.process.ProcessTools; 44 45 public class RegeneratedClassesInDynamicArchive { 46 static String appJar = ClassFileInstaller.getJarPath("app.jar"); 47 static String aotConfigFile = "app.aotconfig"; 48 static String aotCacheFile = "app.aot"; 49 static String appClass = TestApp.class.getName(); 50 static String dynamicArchive = "dynamic.jsa"; 51 static String helloMsg = "hello, world"; 52 static String outputWithDynamicArchive = "Hello 1 in 20.0"; 53 54 public static void main(String[] args) throws Exception { 55 //---------------------------------------------------------------------- 56 printTestCase("Training Run For Base Archive"); 57 ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( 58 "-XX:AOTMode=record", 59 "-XX:AOTConfiguration=" + aotConfigFile, 60 "-Xlog:cds=debug", 61 "-cp", appJar, appClass, "base"); 62 63 OutputAnalyzer out = CDSTestUtils.executeAndLog(pb, "train"); 64 out.shouldContain("AOTConfiguration recorded: " + aotConfigFile); 65 out.shouldContain(helloMsg); 66 out.shouldNotContain(outputWithDynamicArchive); 67 out.shouldHaveExitValue(0); 68 69 test(false); 70 test(true); 71 } 72 73 static void test(boolean aotClassLinkingForBaseArchive) throws Exception { 74 ProcessBuilder pb; 75 OutputAnalyzer out; 76 String usingAOTClassesMsg = "Using AOT-linked classes: true (static archive: has aot-linked classes)"; 77 String regenerateMsg = "Regenerate MethodHandle Holder classes...done"; 78 79 //---------------------------------------------------------------------- 80 printTestCase("Assembly Phase"); 81 pb = ProcessTools.createLimitedTestJavaProcessBuilder( 82 "-XX:AOTMode=create", 83 "-XX:AOTConfiguration=" + aotConfigFile, 84 "-XX:AOTCache=" + aotCacheFile, 85 "-XX:" + (aotClassLinkingForBaseArchive ? "+" : "-") + "AOTClassLinking", 86 "-Xlog:cds=debug,cds+class=debug", 87 "-cp", appJar); 88 out = CDSTestUtils.executeAndLog(pb, "asm"); 89 out.shouldContain("Dumping shared data to file:"); 90 out.shouldMatch("cds,class.* TestApp"); 91 out.shouldNotMatch("cds,class.* CachedInDynamic"); 92 out.shouldHaveExitValue(0); 93 94 //---------------------------------------------------------------------- 95 printTestCase("Production Run with AOTCache, to Generate " + dynamicArchive); 96 pb = ProcessTools.createLimitedTestJavaProcessBuilder( 97 "-XX:AOTCache=" + aotCacheFile, 98 "-Xlog:cds=debug,cds+class=debug,class+load", 99 "-XX:ArchiveClassesAtExit=" + dynamicArchive, 100 "-cp", appJar, appClass, "top"); 101 out = CDSTestUtils.executeAndLog(pb, "prod"); 102 if (aotClassLinkingForBaseArchive) { 103 out.shouldContain(usingAOTClassesMsg); 104 out.shouldNotContain(regenerateMsg); 105 } else { 106 out.shouldNotContain(usingAOTClassesMsg); 107 out.shouldContain(regenerateMsg); 108 } 109 out.shouldContain("Opened AOT cache app.aot."); 110 out.shouldContain(helloMsg); 111 out.shouldContain(outputWithDynamicArchive); 112 out.shouldHaveExitValue(0); 113 114 //---------------------------------------------------------------------- 115 printTestCase("Production Run with " + dynamicArchive); 116 pb = ProcessTools.createLimitedTestJavaProcessBuilder( 117 "-XX:SharedArchiveFile=" + dynamicArchive, 118 "-Xlog:cds,class+load", 119 "-cp", appJar, appClass, "top"); 120 out = CDSTestUtils.executeAndLog(pb, "prod"); 121 out.shouldContain(helloMsg); 122 out.shouldContain(outputWithDynamicArchive); 123 out.shouldContain("CachedInDynamic source: shared objects file (top)"); 124 out.shouldHaveExitValue(0); 125 } 126 127 static int testNum = 0; 128 static void printTestCase(String s) { 129 System.out.println("vvvvvvv TEST CASE " + testNum + ": " + s + ": starts here vvvvvvv"); 130 testNum++; 131 } 132 } 133 134 class TestApp { 135 public static void main(String args[]) { 136 // Run a few lambdas -- if -XX:+AOTClassLinking is enabled, 137 // these will be cached. with AOT-resolved references to the lambda form invoker 138 // classes. These references should still work when dynamic.jsa is loaded. 139 var words = List.of("hello", "fuzzy", "world"); 140 var greeting = words.stream() 141 .filter(w -> !w.contains("z")) 142 .collect(Collectors.joining(", ")); 143 System.out.println(greeting); // hello, world 144 if (args[0].equals("top")) { 145 CachedInDynamic.func(); 146 } 147 } 148 } 149 150 interface MyInterface { 151 public Object doit(Object a, long b, Object c, int d, double e); 152 153 154 } 155 156 class CachedInDynamic { 157 static void func() { 158 System.out.println("CachedInDynamic.func(): start"); 159 MyInterface m = (a, b, c, d, e) -> { 160 return "" + a + b + c + d + e; 161 }; 162 System.out.println(m.doit("Hello ", 1, " in ", 2, 0.0)); 163 System.out.println("CachedInDynamic.func(): done"); 164 } 165 }