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 id=aot
 27  * @requires vm.cds.supports.aot.class.linking
 28  * @comment work around JDK-8345635
 29  * @requires !vm.jvmci.enabled
 30  * @library /test/jdk/lib/testlibrary /test/lib
 31  * @build EndTrainingOnMethodEntry
 32  * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar MyTestApp ShouldBeCached ShouldNotBeCached
 33  * @run driver EndTrainingOnMethodEntry AOT
 34  */
 35 
 36 import jdk.test.lib.cds.CDSAppTester;
 37 import jdk.test.lib.helpers.ClassFileInstaller;
 38 import jdk.test.lib.process.OutputAnalyzer;
 39 
 40 public class EndTrainingOnMethodEntry {
 41     static final String appJar = ClassFileInstaller.getJarPath("app.jar");
 42     static final String mainClass = "MyTestApp";
 43 
 44     public static void main(String[] args) throws Exception {
 45         // We want to test the entry count implementation in both interpreter and compiler.
 46         (new Tester(1)).run(args);
 47         (new Tester(10)).run(args);    // the loop will probably be interpreted
 48         (new Tester(10000)).run(args); // the loop will probably be compiled.
 49     }
 50 
 51     static class Tester extends CDSAppTester {
 52         int count;
 53 
 54         public Tester(int count) {
 55             super(mainClass);
 56             this.count = count;
 57         }
 58 
 59         @Override
 60         public String classpath(RunMode runMode) {
 61             return appJar;
 62         }
 63 
 64         public String[] vmArgs(RunMode runMode) {
 65             String stop = count > 1 ? ("stopTrainingOnMeWithCount,count=" + count) : "stopTrainingOnMe";
 66             return new String[] {
 67                 "-Xlog:aot+class=debug",
 68                 "-Xlog:cds+class=debug",
 69                 "-XX:AOTEndTrainingOnMethodEntry=MyTestApp." + stop,
 70             };
 71         }
 72 
 73         @Override
 74         public String[] appCommandLine(RunMode runMode) {
 75             return new String[] {
 76                 mainClass, runMode.name(), Integer.toString(count),
 77             };
 78         }
 79 
 80         @Override
 81         public void checkExecution(OutputAnalyzer out, RunMode runMode) {
 82             if (runMode.isApplicationExecuted()) {
 83                 out.shouldContain("Hello Leyden " + runMode.name());
 84                 out.shouldContain("ShouldBeCached.dummy()");
 85                 out.shouldContain("ShouldNotBeCached.dummy()");
 86             }
 87             if (isDumping(runMode)) {
 88                 if (isAOTWorkflow()) {
 89                     out.shouldMatch("aot,class.* ShouldBeCached");
 90                     out.shouldNotMatch("aot,class.* ShouldNotBeCached");
 91                 } else {
 92                     out.shouldMatch("cds,class.* ShouldBeCached");
 93                     out.shouldNotMatch("cds,class.* ShouldNotBeCached");
 94                 }
 95             }
 96         }
 97     }
 98 }
 99 
100 class MyTestApp {
101     public static int COUNT;
102     public static void main(String args[]) throws Exception {
103         System.out.println("Hello Leyden " + args[0] + ", count = " + args[1]);
104         COUNT = Integer.parseInt(args[1]);
105         if (COUNT > 1) {
106             int max = COUNT + 10;
107             for (int i = 0; i < max; i++) {
108                 stopTrainingOnMeWithCount(i);
109             }
110         } else {
111             ShouldBeCached.dummy();
112             stopTrainingOnMe();
113         }
114     }
115 
116     static void stopTrainingOnMe() {
117         // The AOT configuration file should have been recorded before the body
118         // of this method is executed, so the ShouldNotBeCached class should not be
119         // recorded in the config.
120         ShouldNotBeCached.dummy();
121     }
122 
123     static void stopTrainingOnMeWithCount(int i) {
124         if (i >= COUNT - 2) {
125             ShouldBeCached.dummy();
126         }
127         if (i >= COUNT) {
128             // The AOT configuration file should have been recorded before this block is entered,
129             // so the ShouldNotBeCached class should not be recorded in the config.
130             ShouldNotBeCached.dummy();
131         }
132     }
133 }
134 
135 class ShouldBeCached {
136     static void dummy() {
137         System.out.println("ShouldBeCached.dummy()");
138     }
139 }
140 
141 class ShouldNotBeCached {
142     static void dummy() {
143         System.out.println("ShouldNotBeCached.dummy()");
144     }
145 }