1 /* 2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 2018 SAP SE. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 */ 24 25 /** 26 * @test 27 * @summary Check that the verbose message of ICCE is printed correctly. 28 * The test forces errors in vtable stubs and interpreter. 29 * @requires !(os.arch=="aarch64" | os.arch=="arm") 30 * @library /test/lib / 31 * @build sun.hotspot.WhiteBox 32 * @run driver ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission 33 * @compile IncompatibleClassChangeErrorTest.java 34 * @compile ImplementsSomeInterfaces.jasm ICC_B.jasm 35 * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 36 * -XX:-BackgroundCompilation -XX:-Inline 37 * -XX:CompileCommand=exclude,IncompatibleClassChangeErrorTest::test_iccInt 38 * IncompatibleClassChangeErrorTest 39 */ 40 41 import sun.hotspot.WhiteBox; 42 import compiler.whitebox.CompilerWhiteBoxTest; 43 import java.lang.reflect.Method; 44 45 // This test assembles an errornous installation of classes. 46 // First, compile the test by @compile. This results in a legal set 47 // of classes. 48 // Then, with jasm, generate incompatible classes that overwrite 49 // the class files in the build directory. 50 // Last, call the real tests throwing IncompatibleClassChangeErrors 51 // and check the messages generated. 52 public class IncompatibleClassChangeErrorTest { 53 54 private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); 55 56 private static boolean enableChecks = true; 57 58 private static String expectedErrorMessageInterpreted = 59 "Class ImplementsSomeInterfaces " + 60 "does not implement the requested interface InterfaceICCE1"; 61 private static String expectedErrorMessageCompiled = 62 "Class ICC_B does not implement the requested interface ICC_iB"; 63 // old message: "vtable stub" 64 65 public static void setup_test() { 66 // Assure all exceptions are loaded. 67 new AbstractMethodError(); 68 new IncompatibleClassChangeError(); 69 70 enableChecks = false; 71 // Warmup 72 System.out.println("warmup:"); 73 test_iccInt(); 74 test_icc_compiled_itable_stub(); 75 enableChecks = true; 76 77 // Compile 78 try { 79 Method method = IncompatibleClassChangeErrorTest.class.getMethod("test_icc_compiled_itable_stub"); 80 WHITE_BOX.enqueueMethodForCompilation(method, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION); 81 if (!WHITE_BOX.isMethodCompiled(method)) { 82 throw new RuntimeException(method.getName() + " is not compiled"); 83 } 84 method = ICC_C.class.getMethod("b"); 85 WHITE_BOX.enqueueMethodForCompilation(method, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION); 86 if (!WHITE_BOX.isMethodCompiled(method)) { 87 throw new RuntimeException("ICC_C." + method.getName() + " is not compiled"); 88 } 89 method = ICC_D.class.getMethod("b"); 90 WHITE_BOX.enqueueMethodForCompilation(method, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION); 91 if (!WHITE_BOX.isMethodCompiled(method)) { 92 throw new RuntimeException("ICC_D." + method.getName() + " is not compiled"); 93 } 94 method = ICC_E.class.getMethod("b"); 95 WHITE_BOX.enqueueMethodForCompilation(method, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION); 96 if (!WHITE_BOX.isMethodCompiled(method)) { 97 throw new RuntimeException("ICC_E." + method.getName() + " is not compiled"); 98 } 99 } catch (NoSuchMethodException e) { } 100 } 101 102 // Should never be compiled. 103 public static void test_iccInt() { 104 boolean caught_icc = false; 105 try { 106 InterfaceICCE1 objectInterface = new ImplementsSomeInterfaces(); 107 // IncompatibleClassChangeError gets thrown in 108 // - TemplateTable::invokeinterface() 109 // - LinkResolver::runtime_resolve_interface_method() 110 objectInterface.aFunctionOfMyInterface(); 111 } catch (IncompatibleClassChangeError e) { 112 caught_icc = true; 113 String errorMsg = e.getMessage(); 114 if (enableChecks && !errorMsg.equals(expectedErrorMessageInterpreted)) { 115 System.out.println("Expected: " + expectedErrorMessageInterpreted + "\n" + 116 "but got: " + errorMsg); 117 throw new RuntimeException("Wrong error message of IncompatibleClassChangeError."); 118 } 119 } catch (Throwable e) { 120 throw new RuntimeException("Caught unexpected exception: " + e); 121 } 122 123 // Check we got the exception. 124 if (!caught_icc) { 125 throw new RuntimeException("Expected IncompatibleClassChangeError was not thrown."); 126 } 127 } 128 129 // ------------------------------------------------------------------------- 130 // Test AbstractMethodErrors detected in itable stubs. 131 // Note: How can we verify that we really stepped through the vtable stub? 132 // - Bimorphic inlining should not happen since we have no profiling data when 133 // we compile the method 134 // - As a result, an inline cache call should be generated 135 // - This inline cache call is patched into a real vtable call at the first 136 // re-resolve, which happens constantly during the first 10 iterations of the loop. 137 // => we should be fine! :-) 138 public static void test_icc_compiled_itable_stub() { 139 // Allocated the objects we need and call a valid method. 140 boolean caught_icc = false; 141 ICC_B b = new ICC_B(); 142 ICC_C c = new ICC_C(); 143 ICC_D d = new ICC_D(); 144 ICC_E e = new ICC_E(); 145 b.a(); 146 c.a(); 147 d.a(); 148 e.a(); 149 150 try { 151 final int iterations = 10; 152 // Test: calls b.b() in the last iteration. 153 for (int i = 0; i < iterations; i++) { 154 ICC_iB a = b; 155 if (i % 3 == 0 && i < iterations - 1) { 156 a = c; 157 } 158 if (i % 3 == 1 && i < iterations - 1) { 159 a = d; 160 } 161 if (i % 3 == 2 && i < iterations - 1) { 162 a = e; 163 } 164 a.b(); 165 } 166 } catch (AbstractMethodError exc) { 167 // It's a subclass of IncompatibleClassChangeError, so we must catch this first. 168 System.out.println(); 169 System.out.println(exc); 170 if (enableChecks) { 171 String errorMsg = exc.getMessage(); 172 if (errorMsg == null) { 173 throw new RuntimeException("Caught unexpected AbstractMethodError with empty message."); 174 } 175 throw new RuntimeException("Caught unexpected AbstractMethodError."); 176 } 177 } catch (IncompatibleClassChangeError exc) { 178 caught_icc = true; 179 System.out.println(); 180 String errorMsg = exc.getMessage(); 181 if (enableChecks && errorMsg == null) { 182 System.out.println(exc); 183 throw new RuntimeException("Empty error message of IncompatibleClassChangeError."); 184 } 185 if (enableChecks && 186 !errorMsg.equals(expectedErrorMessageCompiled)) { 187 System.out.println("Expected: " + expectedErrorMessageCompiled + "\n" + 188 "but got: " + errorMsg); 189 System.out.println(exc); 190 throw new RuntimeException("Wrong error message of IncompatibleClassChangeError."); 191 } 192 if (enableChecks) { 193 System.out.println("Passed with message: " + errorMsg); 194 } 195 } catch (Throwable exc) { 196 throw exc; // new RuntimeException("Caught unexpected exception: " + exc); 197 } 198 199 // Check we got the exception at some point. 200 if (enableChecks && !caught_icc) { 201 throw new RuntimeException("Expected IncompatibleClassChangeError was not thrown."); 202 } 203 } 204 205 public static void main(String[] args) throws Exception { 206 setup_test(); 207 test_iccInt(); 208 test_icc_compiled_itable_stub(); 209 } 210 } 211 212 213 // Helper classes to test incompatible class change in interpreter. 214 // 215 // The test also contains .jasm files with implementations 216 // of the classes that shall generate the errors. 217 218 interface InterfaceICCE0 { 219 public String firstFunctionOfMyInterface0(); 220 public String secondFunctionOfMyInterface0(); 221 } 222 223 interface InterfaceICCE1 { 224 225 public String firstFunctionOfMyInterface(); 226 227 public String secondFunctionOfMyInterface(); 228 229 public String aFunctionOfMyInterface(); 230 } 231 232 abstract class AbstractICCE0 implements InterfaceICCE0 { 233 abstract public String firstAbstractMethod(); 234 abstract public String secondAbstractMethod(); 235 236 abstract public String anAbstractMethod(); 237 } 238 239 class ImplementsSomeInterfaces extends 240 AbstractICCE0 241 // This interface is missing in the .jasm implementation. 242 implements InterfaceICCE1 243 { 244 245 public String firstAbstractMethod() { 246 return this.getClass().getName(); 247 } 248 249 public String secondAbstractMethod() { 250 return this.getClass().getName(); 251 } 252 253 // This method is missing in the .jasm implementation. 254 public String anAbstractMethod() { 255 return this.getClass().getName(); 256 } 257 258 public String firstFunctionOfMyInterface0() { 259 return this.getClass().getName(); 260 } 261 262 public String secondFunctionOfMyInterface0() { 263 return this.getClass().getName(); 264 } 265 266 public String firstFunctionOfMyInterface() { 267 return this.getClass().getName(); 268 } 269 270 public String secondFunctionOfMyInterface() { 271 return this.getClass().getName(); 272 } 273 274 // This method is missing in the .jasm implementation. 275 public String aFunctionOfMyInterface() { 276 return this.getClass().getName(); 277 } 278 } 279 280 // Helper classes to test incompatible class change in itable stub. 281 // 282 // Class hierachy: 283 // 284 // iA,iB (interfaces) 285 // /|\ \ 286 // C D E \ 287 // B (bad class, missing interface implementation) 288 289 interface ICC_iA { 290 public void a(); 291 } 292 293 interface ICC_iB { 294 public void b(); 295 } 296 297 // This is the errornous class. A variant of it not 298 // implementing ICC_iB is copied into the test before 299 // it is run. 300 class ICC_B implements ICC_iA 301 // This interface is missing in the .jasm implementation. 302 , ICC_iB 303 { 304 public void a() { 305 System.out.print("B.a() "); 306 } 307 308 public void b() { 309 System.out.print("B.b() "); 310 } 311 } 312 313 class ICC_C implements ICC_iA, ICC_iB { 314 public void a() { 315 System.out.print("C.a() "); 316 } 317 318 public void b() { 319 System.out.print("C.b() "); 320 } 321 } 322 323 class ICC_D implements ICC_iA, ICC_iB { 324 public void a() { 325 System.out.print("D.a() "); 326 } 327 328 public void b() { 329 System.out.print("D.b() "); 330 } 331 } 332 333 class ICC_E implements ICC_iA, ICC_iB { 334 public void a() { 335 System.out.print("E.a() "); 336 } 337 338 public void b() { 339 System.out.print("E.b() "); 340 } 341 }