test/hotspot/jtreg/runtime/InvocationTests/invokeinterface/Generator.java
changeset 55497 d3a33953b936
equal deleted inserted replaced
55496:8e0ae3830fca 55497:d3a33953b936
       
     1 /*
       
     2  * Copyright (c) 2009, 2019, 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  * INVOKE_INTERFACE EXPECTED RESULTS
       
    27  *
       
    28  * Let C be the class of objectref. The actual method to be invoked is selected
       
    29  * by the following lookup procedure:
       
    30  *     - If C contains a declaration for an instance method with the same name
       
    31  *     and descriptor as the resolved method, then this is the method to be
       
    32  *     invoked, and the lookup procedure terminates.
       
    33  *
       
    34  *     - Otherwise, if C has a superclass, this same lookup procedure is
       
    35  *     performed recursively using the direct superclass of C; the method to be
       
    36  *     invoked is the result of the recursive invocation of this lookup
       
    37  *     procedure.
       
    38  *
       
    39  * Otherwise, if the class of objectref does not implement the resolved
       
    40  * interface, invokeinterface throws an IncompatibleClassChangeError?.
       
    41  *
       
    42  * Otherwise, if no method matching the resolved name and descriptor is
       
    43  * selected, invokeinterface throws an AbstractMethodError?.
       
    44  *
       
    45  * Otherwise, if the selected method is not public, invokeinterface throws an
       
    46  * IllegalAccessError. Note that it cannot be private because private methods
       
    47  * are ignored when searching for an interface method.
       
    48  *
       
    49  * My translation:
       
    50  *      1. Resolve compile-time class/method.
       
    51  *      2. Look up runtime class C, if it contains a name/signature match,
       
    52  *      and it is not private, invoke it.
       
    53  *      3. If it does not, recursively lookup direct superclass of C.
       
    54  *      4. If selected method is not public, throw IllegalAccessError
       
    55  *
       
    56  * InvokeInterface Results:
       
    57  *    - A interface class, declares A.m
       
    58  *    - A compile-time resolved class
       
    59  *    - C runtime resolved class
       
    60  *    - InvokeInterface will ALWAYS invoke C.m if C.m exists and is not private,
       
    61  *    regardless of overriding or accessibility
       
    62  *    - InvokeInterface will invoke a non-private B.m if C.m does not exist,
       
    63  *    regardless of overriding or accessibility
       
    64  *
       
    65  * Note: assuming Interface is public
       
    66  *
       
    67  * TODO: member interfaces can be protected and private and have special hiding
       
    68  * rules (JLS 8.5)
       
    69  */
       
    70 
       
    71 package invokeinterface;
       
    72 
       
    73 import static jdk.internal.org.objectweb.asm.Opcodes.*;
       
    74 import shared.AbstractGenerator;
       
    75 import shared.AccessType;
       
    76 import shared.Utils;
       
    77 
       
    78 import java.util.HashMap;
       
    79 import java.util.Map;
       
    80 
       
    81 public class Generator extends AbstractGenerator {
       
    82     public Generator(String[] args) {
       
    83         super(args);
       
    84     }
       
    85 
       
    86     protected Checker getChecker(Class paramClass, Class targetClass) {
       
    87         return new Checker(paramClass, targetClass);
       
    88     }
       
    89 
       
    90     public static void main (String[] args) throws Exception {
       
    91         new Generator(args).run();
       
    92     }
       
    93 
       
    94     private void run() throws Exception {
       
    95         // Specify package names
       
    96         String pkg1 = "a.";
       
    97         String pkg2 = "b.";
       
    98         String pkg3 = "c.";
       
    99         String pkgIntf = "i.";
       
   100         String[] packages = new String[] { "", pkg1, pkg2, pkg3, pkgIntf };
       
   101 
       
   102         int testNum = 0;
       
   103         boolean isPassed = true;
       
   104 
       
   105         // Hierarchy
       
   106         // The following triples will be used during further
       
   107         // hierarchy construction and will specify packages for A, B and C
       
   108         String[][] packageSets = new String[][] {
       
   109               {   "",   "",   "", ""}
       
   110             , {   "",   "",   "", pkgIntf }
       
   111 
       
   112             , {   "", pkg1, pkg1, "" }
       
   113             , {   "", pkg1, pkg1, pkg1 }
       
   114             , {   "", pkg1, pkg1, pkgIntf }
       
   115 
       
   116             , {   "", pkg1, pkg2, "" }
       
   117             , {   "", pkg1, pkg2, pkg1}
       
   118             , {   "", pkg1, pkg2, pkg2}
       
   119             , {   "", pkg1, pkg2, pkgIntf}
       
   120 
       
   121             , { pkg1, pkg1, pkg1, pkg1 }
       
   122             , { pkg1, pkg1, pkg1, pkgIntf }
       
   123 
       
   124             , { pkg1, pkg1, pkg2, pkg1 }
       
   125             , { pkg1, pkg1, pkg2, pkg2 }
       
   126             , { pkg1, pkg1, pkg2, pkgIntf }
       
   127 
       
   128             , { pkg1, pkg2, pkg1, pkg1 }
       
   129             , { pkg1, pkg2, pkg1, pkg2 }
       
   130             , { pkg1, pkg2, pkg1, pkgIntf }
       
   131 
       
   132             , { pkg1, pkg2, pkg2, pkg1 }
       
   133             , { pkg1, pkg2, pkg2, pkg2 }
       
   134             , { pkg1, pkg2, pkg2, pkgIntf }
       
   135         };
       
   136 
       
   137         String [] header = new String[] {
       
   138             String.format("%30s %68s %25s", "Method access modifiers", "Call site location", "Status")
       
   139                 , String.format("%5s  %-12s %-12s %-12s %-12s   %7s %7s %7s %7s %7s %7s %7s"
       
   140                         , "  # "
       
   141                         , "A.m()"
       
   142                         , "B.m()"
       
   143                         , "C.m()"
       
   144                         , "I.m()"
       
   145                         , "  C  "
       
   146                         , "pkgC "
       
   147                         , "  B  "
       
   148                         , " pkgB"
       
   149                         , "  A  "
       
   150                         , "pkgA"
       
   151                         , "Intf"
       
   152                         )
       
   153                 , "--------------------------------------------------------------------------------------------------------------------"
       
   154         };
       
   155 
       
   156         for (String aHeader : header) {
       
   157             System.out.println(aHeader);
       
   158         }
       
   159 
       
   160         for (String[] pkgSet : packageSets) {
       
   161             String packageA = pkgSet[0];
       
   162             String packageB = pkgSet[1];
       
   163             String packageC = pkgSet[2];
       
   164 
       
   165             String packageIntf = pkgSet[3];
       
   166 
       
   167             String classNameA = packageA + "A";
       
   168             String classNameB = packageB + "B";
       
   169             String classNameC = packageC + "C";
       
   170             String classNameIntf = packageIntf + "I";
       
   171 
       
   172             // For all possible access modifier combinations
       
   173             for (AccessType accessA : AccessType.values()) {
       
   174                 for (AccessType accessB : AccessType.values()) {
       
   175                     for (AccessType accessC : AccessType.values()) {
       
   176                         for (AccessType accessIntf : AccessType.values()) {
       
   177 
       
   178                             if (accessIntf == AccessType.UNDEF) {
       
   179                                 continue;
       
   180                             }
       
   181 
       
   182                             for (int I = 0; I < 4; I++) {
       
   183                                 boolean isAbstractA = ((I & 1) != 0);
       
   184                                 boolean isAbstractB = ((I & 2) != 0);
       
   185 
       
   186                                 testNum++;
       
   187 
       
   188                                 Map<String, byte[]> classes = new HashMap<String, byte[]>();
       
   189 
       
   190                                 // TODO: add non-PUBLIC interfaces, then particular call sites will affect the results
       
   191 
       
   192                                 // Generate interface Intf
       
   193                                 classes.put(
       
   194                                         classNameIntf
       
   195                                         , new ClassGenerator( classNameIntf
       
   196                                                             , "java.lang.Object"
       
   197                                                             , ACC_ABSTRACT | ACC_INTERFACE | accessIntf.value())
       
   198                                             .addTargetMethod(AccessType.PUBLIC)
       
   199                                             .getClassFile()
       
   200                                         );
       
   201 
       
   202                                 // Generate class A
       
   203                                 classes.put(
       
   204                                         classNameA
       
   205                                         , new ClassGenerator( classNameA
       
   206                                                             , "java.lang.Object"
       
   207                                                             , ACC_PUBLIC | ( isAbstractA ? ACC_ABSTRACT : 0))
       
   208                                             .addTargetMethod(accessA)
       
   209                                             .addCaller(classNameIntf)
       
   210                                             .getClassFile()
       
   211                                         );
       
   212 
       
   213                                 // Generate class B
       
   214                                 classes.put(
       
   215                                         classNameB
       
   216                                         , new ClassGenerator( classNameB
       
   217                                                             , classNameA
       
   218                                                             , ACC_PUBLIC | ( isAbstractB ? ACC_ABSTRACT : 0)
       
   219                                                             , new String[] { Utils.getInternalName(classNameIntf) })
       
   220                                             .addTargetMethod(accessB)
       
   221                                             .addCaller(classNameIntf)
       
   222                                             .getClassFile()
       
   223                                         );
       
   224 
       
   225                                 // Generate class C
       
   226                                 classes.put( classNameC
       
   227                                            , new ClassGenerator( classNameC, classNameB )
       
   228                                                .addTargetMethod(accessC)
       
   229                                                .addCaller(classNameIntf)
       
   230                                                .getClassFile()
       
   231                                            );
       
   232 
       
   233                                 // Generate package callers
       
   234                                 for (String pkg : packages) {
       
   235                                     classes.put( pkg+"Caller"
       
   236                                                , new ClassGenerator(pkg+"Caller")
       
   237                                                    .addCaller(classNameIntf)
       
   238                                                    .getClassFile()
       
   239                                                );
       
   240                                 }
       
   241 
       
   242                                 String caseDescription =
       
   243                                         String.format("%-12s %-12s %-12s %-12s| "
       
   244                                             , (isAbstractA ? "! " : "  ") + classNameA + " " + accessA
       
   245                                             , (isAbstractB ? "! " : "  ") + classNameB + " " + accessB
       
   246                                             , classNameC + " " + accessC
       
   247                                             , accessIntf + " " + classNameIntf
       
   248                                             );
       
   249 
       
   250                                 String[] callSites = new String[] {
       
   251                                         classNameC
       
   252                                         , packageC+"Caller"
       
   253                                         , classNameB
       
   254                                         , packageB+"Caller"
       
   255                                         , classNameA
       
   256                                         , packageA+"Caller"
       
   257                                         , packageIntf+"Caller"
       
   258                                 };
       
   259 
       
   260                                 boolean result = exec(classes, caseDescription, classNameIntf, classNameC, callSites);
       
   261                                 isPassed = isPassed && result;
       
   262                             }
       
   263                         }
       
   264                     }
       
   265                 }
       
   266             }
       
   267         }
       
   268 
       
   269         // Print footer
       
   270 
       
   271         for (int i = header.length-1; i >= 0; i--) {
       
   272             System.out.println(header[i]);
       
   273         }
       
   274 
       
   275         if (executeTests) {
       
   276             System.out.printf("\nEXECUTION STATUS: %s\n", (isPassed? "PASSED" : "FAILED"));
       
   277         }
       
   278     }
       
   279 }