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