test/hotspot/jtreg/runtime/exceptionMsgs/IncompatibleClassChangeError/IncompatibleClassChangeErrorTest.java
changeset 49368 2ed1c37df3a5
child 49399 e0fec3292f00
equal deleted inserted replaced
49366:f95ef5511e1f 49368:2ed1c37df3a5
       
     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=="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 errorneous 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         System.out.println("warmup done.");
       
   101     }
       
   102 
       
   103     // Should never be compiled.
       
   104     public static void test_iccInt() {
       
   105         boolean caught_icc = false;
       
   106         try {
       
   107             InterfaceICCE1 objectInterface = new ImplementsSomeInterfaces();
       
   108             // IncompatibleClassChangeError gets thrown in
       
   109             // - TemplateTable::invokeinterface()
       
   110             // - LinkResolver::runtime_resolve_interface_method()
       
   111             objectInterface.aFunctionOfMyInterface();
       
   112         } catch (IncompatibleClassChangeError e) {
       
   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             caught_icc = true;
       
   120         } catch (Throwable e) {
       
   121             throw new RuntimeException("Caught unexpected exception: " + e);
       
   122         }
       
   123 
       
   124         // Check we got the exception.
       
   125         if (!caught_icc) {
       
   126             throw new RuntimeException("Expected IncompatibleClassChangeError was not thrown.");
       
   127         }
       
   128     }
       
   129 
       
   130     // -------------------------------------------------------------------------
       
   131     // Test AbstractMethodErrors detected in itable stubs.
       
   132     // Note: How can we verify that we really stepped through the vtable stub?
       
   133     // - Bimorphic inlining should not happen since we have no profiling data when
       
   134     //   we compile the method
       
   135     // - As a result, an inline cache call should be generated
       
   136     // - This inline cache call is patched into a real vtable call at the first
       
   137     //   re-resolve, which happens constantly during the first 10 iterations of the loop.
       
   138     // => we should be fine! :-)
       
   139     public static void test_icc_compiled_itable_stub() {
       
   140         // Allocated the objects we need and call a valid method.
       
   141         boolean caught_icc = false;
       
   142         ICC_B b = new ICC_B();
       
   143         ICC_C c = new ICC_C();
       
   144         ICC_D d = new ICC_D();
       
   145         ICC_E e = new ICC_E();
       
   146         b.a();
       
   147         c.a();
       
   148         d.a();
       
   149         e.a();
       
   150 
       
   151         try {
       
   152             final int iterations = 10;
       
   153             // Test: calls b.b() in the last iteration.
       
   154             for (int i = 0; i < iterations; i++) {
       
   155                 ICC_iB a = b;
       
   156                 if (i % 3 == 0 && i < iterations - 1) {
       
   157                     a = c;
       
   158                 }
       
   159                 if (i % 3 == 1 && i < iterations - 1) {
       
   160                     a = d;
       
   161                 }
       
   162                 if (i % 3 == 2 && i < iterations - 1) {
       
   163                     a = e;
       
   164                 }
       
   165                 a.b();
       
   166             }
       
   167         } catch (AbstractMethodError exc) {
       
   168             // It's a subclass of IncompatibleClassChangeError, so we must catch this first.
       
   169             System.out.println();
       
   170             System.out.println(exc);
       
   171             if (enableChecks) {
       
   172                 String errorMsg = exc.getMessage();
       
   173                 if (errorMsg == null) {
       
   174                     throw new RuntimeException("Caught unexpected AbstractMethodError with empty message.");
       
   175                 }
       
   176                 throw new RuntimeException("Caught unexpected AbstractMethodError.");
       
   177             }
       
   178         } catch (IncompatibleClassChangeError exc) {
       
   179             caught_icc = true;
       
   180             System.out.println();
       
   181             String errorMsg = exc.getMessage();
       
   182             if (enableChecks && errorMsg == null) {
       
   183                 System.out.println(exc);
       
   184                 throw new RuntimeException("Empty error message of IncompatibleClassChangeError.");
       
   185             }
       
   186             if (enableChecks &&
       
   187                 !errorMsg.equals(expectedErrorMessageCompiled)) {
       
   188                 System.out.println("Expected: " + expectedErrorMessageCompiled + "\n" +
       
   189                                    "but got:  " + errorMsg);
       
   190                 System.out.println(exc);
       
   191                 throw new RuntimeException("Wrong error message of IncompatibleClassChangeError.");
       
   192             }
       
   193             if (enableChecks) {
       
   194                 System.out.println("Passed with message: " + errorMsg);
       
   195             }
       
   196         } catch (Throwable exc) {
       
   197             throw exc; // new RuntimeException("Caught unexpected exception: " + exc);
       
   198         }
       
   199 
       
   200         // Check we got the exception at some point.
       
   201         if (enableChecks && !caught_icc) {
       
   202             throw new RuntimeException("Expected IncompatibleClassChangeError was not thrown.");
       
   203         }
       
   204     }
       
   205 
       
   206     public static void main(String[] args) throws Exception {
       
   207         setup_test();
       
   208         test_iccInt();
       
   209         test_icc_compiled_itable_stub();
       
   210     }
       
   211 }
       
   212 
       
   213 
       
   214 // Helper classes to test incompatible class change in interpreter.
       
   215 //
       
   216 // The test also contains .jasm files with implementations
       
   217 // of the classes that shall generate the errors.
       
   218 
       
   219 
       
   220 //   I0         // interface defining aFunctionOfMyInterface()
       
   221 //   |
       
   222 //   |    I1    // interface
       
   223 //   |     |
       
   224 //   A0    |    // abstract class
       
   225 //    \   /
       
   226 //      C       // class not implementing I1 and
       
   227 //                       not implementing I0::aFunctionOfMyInterface()
       
   228 //
       
   229 // Test is expected to throw error because of missing interface and not
       
   230 // because of missing method.
       
   231 
       
   232 interface InterfaceICCE0 {
       
   233     public String firstFunctionOfMyInterface0();
       
   234     public String secondFunctionOfMyInterface0();
       
   235 }
       
   236 
       
   237 interface InterfaceICCE1 {
       
   238 
       
   239     public String firstFunctionOfMyInterface();
       
   240 
       
   241     public String secondFunctionOfMyInterface();
       
   242 
       
   243     public String aFunctionOfMyInterface();
       
   244 }
       
   245 
       
   246 abstract class AbstractICCE0 implements InterfaceICCE0 {
       
   247     abstract public String firstAbstractMethod();
       
   248     abstract public String secondAbstractMethod();
       
   249 
       
   250     abstract public String anAbstractMethod();
       
   251 }
       
   252 
       
   253 class ImplementsSomeInterfaces extends
       
   254         AbstractICCE0
       
   255     // This interface is missing in the .jasm implementation.
       
   256     implements InterfaceICCE1
       
   257 {
       
   258 
       
   259     public String firstAbstractMethod() {
       
   260         return this.getClass().getName();
       
   261     }
       
   262 
       
   263     public String secondAbstractMethod() {
       
   264         return this.getClass().getName();
       
   265     }
       
   266 
       
   267     // This method is missing in the .jasm implementation.
       
   268     public String anAbstractMethod() {
       
   269         return this.getClass().getName();
       
   270     }
       
   271 
       
   272     public String firstFunctionOfMyInterface0() {
       
   273         return this.getClass().getName();
       
   274     }
       
   275 
       
   276     public String secondFunctionOfMyInterface0() {
       
   277         return this.getClass().getName();
       
   278     }
       
   279 
       
   280     public String firstFunctionOfMyInterface() {
       
   281         return this.getClass().getName();
       
   282     }
       
   283 
       
   284     public String secondFunctionOfMyInterface() {
       
   285         return this.getClass().getName();
       
   286     }
       
   287 
       
   288     // This method is missing in the .jasm implementation.
       
   289     public String aFunctionOfMyInterface() {
       
   290         return this.getClass().getName();
       
   291     }
       
   292 }
       
   293 
       
   294 // Helper classes to test incompatible class change in itable stub.
       
   295 //
       
   296 // Class hierachy:
       
   297 //
       
   298 //          iA,iB   (interfaces)
       
   299 //          /|\ \
       
   300 //         C D E \
       
   301 //                B (bad class, missing interface implementation)
       
   302 
       
   303 interface ICC_iA {
       
   304     public void a();
       
   305 }
       
   306 
       
   307 interface ICC_iB {
       
   308     public void b();
       
   309 }
       
   310 
       
   311 // This is the errorneous class. A variant of it not
       
   312 // implementing ICC_iB is copied into the test before
       
   313 // it is run.
       
   314 class ICC_B implements ICC_iA,
       
   315                        // This interface is missing in the .jasm implementation.
       
   316                        ICC_iB {
       
   317     public void a() {
       
   318         System.out.print("B.a() ");
       
   319     }
       
   320 
       
   321     public void b() {
       
   322         System.out.print("B.b() ");
       
   323     }
       
   324 }
       
   325 
       
   326 class ICC_C implements ICC_iA, ICC_iB {
       
   327     public void a() {
       
   328         System.out.print("C.a() ");
       
   329     }
       
   330 
       
   331     public void b() {
       
   332         System.out.print("C.b() ");
       
   333     }
       
   334 }
       
   335 
       
   336 class ICC_D implements ICC_iA, ICC_iB {
       
   337     public void a() {
       
   338         System.out.print("D.a() ");
       
   339     }
       
   340 
       
   341     public void b() {
       
   342         System.out.print("D.b() ");
       
   343     }
       
   344 }
       
   345 
       
   346 class ICC_E implements ICC_iA, ICC_iB {
       
   347     public void a() {
       
   348         System.out.print("E.a() ");
       
   349     }
       
   350 
       
   351     public void b() {
       
   352         System.out.print("E.b() ");
       
   353     }
       
   354 }