Path: blob/master/test/hotspot/jtreg/runtime/InvocationTests/invokeinterface/Generator.java
40948 views
/*1* Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324/*25* INVOKE_INTERFACE EXPECTED RESULTS26*27* Let C be the class of objectref. The actual method to be invoked is selected28* by the following lookup procedure:29* - If C contains a declaration for an instance method with the same name30* and descriptor as the resolved method, then this is the method to be31* invoked, and the lookup procedure terminates.32*33* - Otherwise, if C has a superclass, this same lookup procedure is34* performed recursively using the direct superclass of C; the method to be35* invoked is the result of the recursive invocation of this lookup36* procedure.37*38* Otherwise, if the class of objectref does not implement the resolved39* interface, invokeinterface throws an IncompatibleClassChangeError?.40*41* Otherwise, if no method matching the resolved name and descriptor is42* selected, invokeinterface throws an AbstractMethodError?.43*44* Otherwise, if the selected method is not public, invokeinterface throws an45* IllegalAccessError. Note that it cannot be private because private methods46* are ignored when searching for an interface method.47*48* My translation:49* 1. Resolve compile-time class/method.50* 2. Look up runtime class C, if it contains a name/signature match,51* and it is not private, invoke it.52* 3. If it does not, recursively lookup direct superclass of C.53* 4. If selected method is not public, throw IllegalAccessError54*55* InvokeInterface Results:56* - A interface class, declares A.m57* - A compile-time resolved class58* - C runtime resolved class59* - InvokeInterface will ALWAYS invoke C.m if C.m exists and is not private,60* regardless of overriding or accessibility61* - InvokeInterface will invoke a non-private B.m if C.m does not exist,62* regardless of overriding or accessibility63*64* Note: assuming Interface is public65*66* TODO: member interfaces can be protected and private and have special hiding67* rules (JLS 8.5)68*/6970package invokeinterface;7172import static jdk.internal.org.objectweb.asm.Opcodes.*;73import shared.AbstractGenerator;74import shared.AccessType;75import shared.Utils;7677import java.util.HashMap;78import java.util.Map;7980public class Generator extends AbstractGenerator {81public Generator(String[] args) {82super(args);83}8485protected Checker getChecker(Class paramClass, Class targetClass) {86return new Checker(paramClass, targetClass);87}8889public static void main (String[] args) throws Exception {90new Generator(args).run();91}9293private void run() throws Exception {94// Specify package names95String pkg1 = "a.";96String pkg2 = "b.";97String pkg3 = "c.";98String pkgIntf = "i.";99String[] packages = new String[] { "", pkg1, pkg2, pkg3, pkgIntf };100101int testNum = 0;102boolean isPassed = true;103104// Hierarchy105// The following triples will be used during further106// hierarchy construction and will specify packages for A, B and C107String[][] packageSets = new String[][] {108{ "", "", "", ""}109, { "", "", "", pkgIntf }110111, { "", pkg1, pkg1, "" }112, { "", pkg1, pkg1, pkg1 }113, { "", pkg1, pkg1, pkgIntf }114115, { "", pkg1, pkg2, "" }116, { "", pkg1, pkg2, pkg1}117, { "", pkg1, pkg2, pkg2}118, { "", pkg1, pkg2, pkgIntf}119120, { pkg1, pkg1, pkg1, pkg1 }121, { pkg1, pkg1, pkg1, pkgIntf }122123, { pkg1, pkg1, pkg2, pkg1 }124, { pkg1, pkg1, pkg2, pkg2 }125, { pkg1, pkg1, pkg2, pkgIntf }126127, { pkg1, pkg2, pkg1, pkg1 }128, { pkg1, pkg2, pkg1, pkg2 }129, { pkg1, pkg2, pkg1, pkgIntf }130131, { pkg1, pkg2, pkg2, pkg1 }132, { pkg1, pkg2, pkg2, pkg2 }133, { pkg1, pkg2, pkg2, pkgIntf }134};135136String [] header = new String[] {137String.format("%30s %68s %25s", "Method access modifiers", "Call site location", "Status")138, String.format("%5s %-12s %-12s %-12s %-12s %7s %7s %7s %7s %7s %7s %7s"139, " # "140, "A.m()"141, "B.m()"142, "C.m()"143, "I.m()"144, " C "145, "pkgC "146, " B "147, " pkgB"148, " A "149, "pkgA"150, "Intf"151)152, "--------------------------------------------------------------------------------------------------------------------"153};154155for (String aHeader : header) {156System.out.println(aHeader);157}158159for (String[] pkgSet : packageSets) {160String packageA = pkgSet[0];161String packageB = pkgSet[1];162String packageC = pkgSet[2];163164String packageIntf = pkgSet[3];165166String classNameA = packageA + "A";167String classNameB = packageB + "B";168String classNameC = packageC + "C";169String classNameIntf = packageIntf + "I";170171// For all possible access modifier combinations172for (AccessType accessA : AccessType.values()) {173for (AccessType accessB : AccessType.values()) {174for (AccessType accessC : AccessType.values()) {175for (AccessType accessIntf : AccessType.values()) {176177if (accessIntf == AccessType.UNDEF) {178continue;179}180181for (int I = 0; I < 4; I++) {182boolean isAbstractA = ((I & 1) != 0);183boolean isAbstractB = ((I & 2) != 0);184185testNum++;186187Map<String, byte[]> classes = new HashMap<String, byte[]>();188189// TODO: add non-PUBLIC interfaces, then particular call sites will affect the results190191// Generate interface Intf192classes.put(193classNameIntf194, new ClassGenerator( classNameIntf195, "java.lang.Object"196, ACC_ABSTRACT | ACC_INTERFACE | accessIntf.value())197.addTargetMethod(AccessType.PUBLIC)198.getClassFile()199);200201// Generate class A202classes.put(203classNameA204, new ClassGenerator( classNameA205, "java.lang.Object"206, ACC_PUBLIC | ( isAbstractA ? ACC_ABSTRACT : 0))207.addTargetMethod(accessA)208.addCaller(classNameIntf)209.getClassFile()210);211212// Generate class B213classes.put(214classNameB215, new ClassGenerator( classNameB216, classNameA217, ACC_PUBLIC | ( isAbstractB ? ACC_ABSTRACT : 0)218, new String[] { Utils.getInternalName(classNameIntf) })219.addTargetMethod(accessB)220.addCaller(classNameIntf)221.getClassFile()222);223224// Generate class C225classes.put( classNameC226, new ClassGenerator( classNameC, classNameB )227.addTargetMethod(accessC)228.addCaller(classNameIntf)229.getClassFile()230);231232// Generate package callers233for (String pkg : packages) {234classes.put( pkg+"Caller"235, new ClassGenerator(pkg+"Caller")236.addCaller(classNameIntf)237.getClassFile()238);239}240241String caseDescription =242String.format("%-12s %-12s %-12s %-12s| "243, (isAbstractA ? "! " : " ") + classNameA + " " + accessA244, (isAbstractB ? "! " : " ") + classNameB + " " + accessB245, classNameC + " " + accessC246, accessIntf + " " + classNameIntf247);248249String[] callSites = new String[] {250classNameC251, packageC+"Caller"252, classNameB253, packageB+"Caller"254, classNameA255, packageA+"Caller"256, packageIntf+"Caller"257};258259boolean result = exec(classes, caseDescription, classNameIntf, classNameC, callSites);260isPassed = isPassed && result;261}262}263}264}265}266}267268// Print footer269270for (int i = header.length-1; i >= 0; i--) {271System.out.println(header[i]);272}273274if (executeTests) {275System.out.printf("\nEXECUTION STATUS: %s\n", (isPassed? "PASSED" : "FAILED"));276}277}278}279280281