1 /* 2 * Copyright (c) 2022, 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 * @bug 8294609 28 * @requires vm.compiler2.enabled & vm.flagless 29 * 30 * @library /test/lib 31 * 32 * @build compiler.c2.unloaded.TestInlineUnloaded 33 * 34 * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar launcher.jar 35 * compiler.c2.unloaded.TestInlineUnloaded 36 * compiler.c2.unloaded.TestInlineUnloaded$Launcher 37 * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar parent.jar 38 * compiler.c2.unloaded.TestInlineUnloaded$Parent 39 * compiler.c2.unloaded.TestInlineUnloaded$Parent$U 40 * compiler.c2.unloaded.TestInlineUnloaded$Parent$TestCase 41 * compiler.c2.unloaded.TestInlineUnloaded$Parent$Invoker 42 * compiler.c2.unloaded.TestInlineUnloaded$Parent$TestNull 43 * compiler.c2.unloaded.TestInlineUnloaded$Parent$TestLoadedRemotely 44 * compiler.c2.unloaded.TestInlineUnloaded$Parent$TestUnloaded 45 * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar caller.jar 46 * compiler.c2.unloaded.TestInlineUnloaded$Caller 47 * compiler.c2.unloaded.TestInlineUnloaded$Caller$TestNull 48 * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar callee.jar 49 * compiler.c2.unloaded.TestInlineUnloaded$Callee 50 * compiler.c2.unloaded.TestInlineUnloaded$Callee$TestNull 51 * 52 * @run driver compiler.c2.unloaded.TestInlineUnloaded 53 */ 54 55 package compiler.c2.unloaded; 56 57 import jdk.test.lib.JDKToolFinder; 58 import jdk.test.lib.process.OutputAnalyzer; 59 import jdk.test.lib.process.ProcessTools; 60 61 import java.io.IOException; 62 import java.net.URL; 63 import java.net.URLClassLoader; 64 import java.util.function.Consumer; 65 66 public class TestInlineUnloaded { 67 static final String THIS_CLASS = TestInlineUnloaded.class.getName(); 68 69 public static class Parent { 70 public class U { 71 } 72 73 public interface TestCase { 74 U test(Invoker obj, U arg); 75 76 void testArg(Invoker obj, U arg); 77 78 U testRet(Invoker obj); 79 80 void test(Invoker obj); 81 } 82 83 public interface Invoker { 84 void invokeArg(U obj); 85 86 U invokeRet(); 87 88 U invoke(U obj); 89 } 90 91 private static class TestNull implements Runnable { 92 final TestCase test; 93 final Invoker recv; 94 95 public TestNull(TestCase test, Invoker recv) { 96 this.test = test; 97 this.recv = recv; 98 } 99 100 @Override 101 public void run() { 102 test.testArg(recv, null); 103 test.testRet(recv); 104 test.test(recv, null); 105 } 106 } 107 108 public static class TestLoadedRemotely extends TestNull { 109 public TestLoadedRemotely(TestCase test, Invoker recv) throws Exception { 110 super(test, recv); 111 Class.forName(U.class.getName()); // preload in parent context 112 } 113 } 114 115 public static class TestUnloaded extends TestNull { 116 public TestUnloaded(TestCase test, Invoker recv) { 117 super(test, recv); 118 } 119 } 120 } 121 122 public static class Caller { 123 public static class TestNull implements Parent.TestCase { 124 public TestNull() {} 125 126 public Parent.U test(Parent.Invoker obj, Parent.U arg) { 127 return obj.invoke(arg); 128 } 129 130 public void testArg(Parent.Invoker obj, Parent.U arg) { 131 obj.invokeArg(arg); 132 } 133 134 public Parent.U testRet(Parent.Invoker obj) { 135 return obj.invokeRet(); 136 } 137 138 public void test(Parent.Invoker obj) { 139 test(obj, null); 140 } 141 } 142 } 143 144 public static class Callee { 145 public static class TestNull implements Parent.Invoker { 146 public void invokeArg(Parent.U obj) {} 147 148 public Parent.U invokeRet() { 149 return null; 150 } 151 152 public Parent.U invoke(Parent.U obj) { 153 return obj; 154 } 155 } 156 } 157 158 public static class Launcher { 159 public static void main(String... args) throws Exception { 160 final String testName = args[0]; 161 162 URLClassLoader parentCL = new URLClassLoader("parent", new URL[] { new URL("file:parent.jar") }, ClassLoader.getSystemClassLoader()); 163 URLClassLoader callerCL = new URLClassLoader("caller", new URL[] { new URL("file:caller.jar") }, parentCL); 164 URLClassLoader calleeCL = new URLClassLoader("callee", new URL[] { new URL("file:callee.jar") }, parentCL); 165 166 Object caller = Class.forName(THIS_CLASS + "$Caller$TestNull", false, callerCL) 167 .getDeclaredConstructor().newInstance(); 168 Object callee = Class.forName(THIS_CLASS + "$Callee$TestNull", false, calleeCL) 169 .getDeclaredConstructor().newInstance(); 170 171 Class<?> testClass = Class.forName(THIS_CLASS + "$Parent$TestCase", false, parentCL); 172 Class<?> invClass = Class.forName(THIS_CLASS + "$Parent$Invoker", false, parentCL); 173 Class<?> test = Class.forName(THIS_CLASS + "$Parent$" + testName, false, parentCL); 174 Runnable r = (Runnable) test.getDeclaredConstructor(testClass, invClass) 175 .newInstance(caller, callee); 176 177 for (int i = 0; i < 20_000; i ++) { 178 r.run(); 179 } 180 } 181 } 182 183 static void run(String testCaseName, Consumer<OutputAnalyzer> processor) throws Exception { 184 ProcessBuilder pb = new ProcessBuilder(); 185 186 pb.command(JDKToolFinder.getJDKTool("java"), 187 "-cp", "launcher.jar", 188 "-XX:+IgnoreUnrecognizedVMOptions", "-showversion", 189 "-XX:-TieredCompilation", "-Xbatch", 190 "-XX:-InlineTypeReturnedAsFields", // TODO Remove this once 8284443 fixed handling of unloaded return types 191 "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining", 192 "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,*TestNull::run", 193 Launcher.class.getName(), testCaseName); 194 195 System.out.println("Command line: [" + pb.command() + "]"); 196 197 OutputAnalyzer analyzer = ProcessTools.executeProcess(pb); 198 199 analyzer.shouldHaveExitValue(0); 200 201 // The test is applicable only to C2 (present in Server VM). 202 analyzer.stderrShouldContain("Server VM"); 203 204 analyzer.shouldContain("TestNull::run"); // ensure that relevant method is compiled 205 206 processor.accept(analyzer); // test-specific checks 207 } 208 209 public static void main(String[] args) throws Exception { 210 run("TestUnloaded", output -> { 211 output.shouldMatch("TestNull::testArg .* unloaded signature classes"); 212 output.shouldMatch("TestNull::testRet .* unloaded signature classes"); 213 output.shouldMatch("TestNull::test .* unloaded signature classes"); 214 215 output.shouldMatch("TestNull::testArg .* failed to inline"); 216 output.shouldMatch("TestNull::testRet .* failed to inline"); 217 output.shouldMatch("TestNull::test .* failed to inline"); 218 }); 219 run("TestLoadedRemotely", output -> { 220 output.shouldMatch("TestNull::testArg .* inline"); 221 output.shouldMatch("TestNull::testRet .* inline"); 222 output.shouldMatch("TestNull::test .* inline"); 223 224 output.shouldNotMatch("TestNull::testArg .* unloaded signature classes"); 225 output.shouldNotMatch("TestNull::testRet .* unloaded signature classes"); 226 output.shouldNotMatch("TestNull::test .* unloaded signature classes"); 227 }); 228 } 229 }