Path: blob/master/test/hotspot/jtreg/runtime/InvocationTests/invokespecial/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* INVOKESPECIAL EXPECTED RESULTS26*27* From JVMS 3rd edition: invokespecial instruction:28*29* Invoke instance method; special handling for superclass, private, and instance30* initialization method invocations31*32* The named method is resolved (5.4.3.3). Finally, if the resolved method is33* protected (4.7), and it is a member of a superclass of the current class, and34* the method is not declared in the same run-time package (5.3) as the current35* class, then the class of objectref must be either the current class or a36* subclass of the current class.37*38* Next, the resolved method is selected for invocation unless all of the39* following conditions are true:40* * The ACC_SUPER flag (see Table 4.1, "Class access and property modifiers") is set for the current class.41* * The class of the resolved method is a superclass of the current class.42* * The resolved method is not an instance initialization method (3.9).43*44* If the above conditions are true, the actual method to be invoked is selected45* by the following lookup procedure. Let C be the direct superclass of the46* current class:47* * If C contains a declaration for an instance method with the same name and48* descriptor as the resolved method, then this method will be invoked.49* The lookup procedure terminates.50*51* * Otherwise, if C has a superclass, this same lookup procedure is performed52* recursively using the direct superclass of C. The method to be invoked is53* the result of the recursive invocation of this lookup procedure.54*55* * Otherwise, an AbstractMethodError? is raised.56*57* During resolution of the symbolic reference to the method, any of the58* exceptions pertaining to method resolution documented in Section 5.4.3.3 can be59* thrown.60*61* Otherwise, if the resolved method is an instance initialization method, and the62* class in which it is declared is not the class symbolically referenced by the63* instruction, a NoSuchMethodError? is thrown.64*65* Otherwise, if the resolved method is a class (static) method, the invokespecial66* instruction throws an IncompatibleClassChangeError?.67*68* Otherwise, if no method matching the resolved name and descriptor is selected,69* invokespecial throws an AbstractMethodError?.70*71* Otherwise, if the selected method is abstract, invokespecial throws an72* AbstractMethodError?.73*74* RUNTIME EXCEPTIONS75*76* Otherwise, if objectref is null, the invokespecial instruction throws a NullPointerException?.77*78* Otherwise, if the selected method is native and the code that implements the79* method cannot be bound, invokespecial throws an UnsatisfiedLinkError?.80*81* NOTES82*83* The difference between the invokespecial and the invokevirtual instructions is84* that invokevirtual invokes a method based on the class of the object. The85* invokespecial instruction is used to invoke instance initialization methods86* (3.9) as well as private methods and methods of a superclass of the current87* class.88*89* ACC_SUPER:90*91* The setting of the ACC_SUPER flag indicates which of two alternative semantics92* for its invokespecial instruction the Java virtual machine is to express; the93* ACC_SUPER flag exists for backward compatibility for code compiled by Sun's94* older compilers for the Java programming language. All new implementations of95* the Java virtual machine should implement the semantics for invokespecial96* documented in this specification. All new compilers to the instruction set of97* the Java virtual machine should set the ACC_SUPER flag. Sun's older compilers98* generated ClassFile? flags with ACC_SUPER unset. Sun's older Java virtual99* machine implementations ignore the flag if it is set.100*101* ACC_SUPER 0x0020 Treat superclass methods specially when invoked by the102* invokespecial instruction.103*104* My Translation:105* 1. compile-time resolved class B106* 2. A,B,C direct superclass relationships107* 3. If B.m is protected108* - if the caller is in B109* then runtime resolved class must be in B or C110* - if the caller is in C111* then runtime resolved class must be in C112* TODO: otherwise what is thrown? <noWikiWord>AbstractMethodError?113* 4. If B.m is an instance initialization method,114* invoke B.m115* 5. If backward compatible caller does not set ACC_SUPER,116* invoke B.m117* 6. If B is not a superclass of the caller, e.g. A is caller, or unrelated X118* is the caller, invoke B.m119* 7. Otherwise:120* If superclass of caller contains name/sig match, use it121* Else, recursively through that superclass122* 8. If none found, throw AbstractMethodError123*124* Note: there is NO mention of overriding or accessibility in determining125* resolved method, except for if the compile-time type is protected.126*127* Case 1: B.m is protected128* Caller in A: if runtime resolved class in A.m, AbstractMethodError129* Caller in B: if runtime resolved class in A.m, AbstractMethodError130* Case 2: B.m is an instance initialization method131* Always invoke B.m132* Case 3: older javac, caller does not set ACC_SUPER133* Always invoke B.m134* Case 4: A or X (not in hierarchy) calls invokespecial on B.m, invoke B.m135* Case 5: Caller in B:136* if A.m exists, call it, else <noWikiWord>AbstractMethodError137* Caller in C:138* if B.m exists, call it139* if B.m does not exist, and A.m exists, call it140*/141142// TODO: classes without ACC_SUPER attribute143// TODO: B.m is an instance initialization method144145/*146* invokespecial <method-spec>147*148* invokespecial is used in certain special cases to invoke a method149* Specifically, invokespecial is used to invoke:150* - the instance initialization method, <init>151* - a private method of this152* - a method in a superclass of this153*154* The main use of invokespecial is to invoke an object's instance155* initialization method, <init>, during the construction phase for a new object.156* For example, when you write in Java:157*158* new StringBuffer()159*160* code like the following is generated:161* new java/lang/StringBuffer ; create a new StringBuffer162* dup ; make an extra reference to the new instance163* ; now call an instance initialization method164* invokespecial java/lang/StringBuffer/<init>()V165* ; stack now contains an initialized StringBuffer.166*167* invokespecial is also used by the Java language by the 'super' keyword to168* access a superclass's version of a method. For example, in the class:169*170* class Example {171* // override equals172* public boolean equals(Object x) {173* // call Object's version of equals174* return super.equals(x);175* }176* }177*178* the 'super.equals(x)' expression is compiled to:179*180* aload_0 ; push 'this' onto the stack181* aload_1 ; push the first argument (i.e. x) onto the stack182* ; now invoke Object's equals() method.183* invokespecial java/lang/Object/equals(Ljava/lang/Object;)Z184*185* Finally, invokespecial is used to invoke a private method. Remember that186* private methods are only visible to other methods belonging the same class as187* the private method.188*189* Before performing the method invocation, the class and the method identified190* by <method-spec> are resolved. See Chapter 9 for a description of how methods191* are resolved.192*193* invokespecial first looks at the descriptor given in <method-spec>, and194* determines how many argument words the method takes (this may be zero). It195* pops these arguments off the operand stack. Next it pops objectref (a196* reference to an object) off the operand stack. objectref must be an instance197* of the class named in <method-spec>, or one of its subclasses. The interpreter198* searches the list of methods defined by the class named in <method-spec>,199* looking for a method called methodname whose descriptor is descriptor. This200* search is not based on the runtime type of objectref, but on the compile time201* type given in <method-spec>.202*203* Once a method has been located, invokespecial calls the method. First, if204* the method is marked as synchronized, the monitor associated with objectref is205* entered. Next, a new stack frame structure is established on the call stack.206* Then the arguments for the method (which were popped off the current method's207* operand stack) are placed in local variables of the new stack frame structure.208* arg1 is stored in local variable 1, arg2 is stored in local variable 2 and so209* on. objectref is stored in local variable 0 (the local variable used for the210* special Java variable this). Finally, execution continues at the first211*instruction in the bytecode of the new method.212*213* Methods marked as native are handled slightly differently. For native214* methods, the runtime system locates the platform-specific code for the method,215* loading it and linking it into the JVM if necessary. Then the native method216* code is executed with the arguments popped from the operand stack. The exact217* mechanism used to invoke native methods is implementation-specific.218*219* When the method called by invokespecial returns, any single (or double) word220* return result is placed on the operand stack of the current method. If the221* invoked method was marked as synchronized, the monitor associated with222* objectref is exited. Execution continues at the instruction that follows223* invokespecial in the bytecode.224*225* Notes226*227* 1. In Java Virtual Machine implementations prior to version JDK 1.02, this228* instruction was called invokenonvirtual, and was less restrictive than229* invokespecial - it wasn't limited to invoking only superclass, private or230* <init> methods. The class access flag ACC_SUPER (see Chapter 4) is used to231* indicate which semantics are used by a class. In older class files, the232* ACC_SUPER flag is unset. In all new classes, the ACC_SUPER flag should be set,233* indicating that the restrictions enforced by invokespecial are obeyed. (In234* practice, all the common uses of invokenonvirtual continue to be supported235* by invokespecial, so this change should have little impact on JVM users).236*237*/238239package invokespecial;240241import static jdk.internal.org.objectweb.asm.Opcodes.*;242import shared.AbstractGenerator;243import shared.AccessType;244245import java.util.HashMap;246import java.util.Map;247248public class Generator extends AbstractGenerator {249public static void main (String[] args) throws Exception {250new Generator(args).run();251}252public Generator(String[] args) {253super(args);254}255256protected Checker getChecker(Class paramClass, Class targetClass) {257return new Checker(paramClass, targetClass);258}259260public void run() throws Exception {261// Specify package names262String pkg1 = "a.";263String pkg2 = "b.";264String[] packages = new String[] { "", pkg1, pkg2 };265266boolean isPassed = true;267268// HIERARCHIES269// The following triples will be used during further270// hierarchy construction and will specify packages for A, B and C271String[][] packageSets = new String[][] {272{ "", "", "" }273, { "", pkg1, pkg1 }274, { "", pkg1, pkg2 }275, { pkg1, "", pkg1 }276, { pkg1, "", pkg2 }277, { pkg1, pkg1, "" }278, { pkg1, pkg2, "" }279, { pkg1, pkg1, pkg1 }280, { pkg1, pkg1, pkg2 }281, { pkg1, pkg2, pkg1 }282, { pkg1, pkg2, pkg2 }283};284285String [] header = new String[] {286String.format("%30s %35s", "Method access modifiers", "Call site location")287, String.format("%4s %-10s %-10s %-10s %7s %7s %7s %7s %7s %7s %7s"288, " # "289, "A.m()"290, "B.m()"291, "C.m()"292, " A "293, "pkgA"294, " B "295, " pkgB"296, " C "297, "pkgC "298, " X "299)300, "-----------------------------------------------------------------------------------------------------------"301};302303// Print header304for (String str : header) {305System.out.println(str);306}307308// Iterate over all interesting package combinations309for (String[] pkgSet : packageSets) {310String packageA = pkgSet[0];311String packageB = pkgSet[1];312String packageC = pkgSet[2];313314String classNameA = packageA + "A";315String classNameB = packageB + "B";316String classNameC = packageC + "C";317318// For all possible access modifier combinations319for (AccessType accessFlagA : AccessType.values()) {320for (AccessType accessFlagB : AccessType.values()) {321for (AccessType accessFlagC : AccessType.values()) {322Map<String, byte[]> classes = new HashMap<String, byte[]>();323324String calleeClassName = classNameB;325int classFlags = ACC_PUBLIC;326327// The following hierarhcy is created:328// c.C extends b.B extends a.A extends Object - base hierarchy329// X extends Object - external caller330// c.Caller, b.Caller, a.Caller extends Object - package callers331332// Generate result storage333classes.put(334"Result"335, new ClassGenerator(336"Result"337, "java.lang.Object"338, ACC_PUBLIC339)340.addField(341ACC_PUBLIC | ACC_STATIC342, "value"343, "java.lang.String"344)345.getClassFile()346);347348// Generate class A349classes.put(350classNameA351, new ClassGenerator(352classNameA353, "java.lang.Object"354, classFlags355)356.addTargetConstructor(accessFlagA)357.addTargetMethod(accessFlagA)358.addCaller(calleeClassName)359.getClassFile()360);361362// Generate class B363classes.put(364classNameB365, new ClassGenerator(366classNameB367, classNameA368, classFlags369)370.addTargetConstructor(accessFlagB)371.addTargetMethod(accessFlagB)372.addCaller(calleeClassName)373.getClassFile()374);375376// Generate class C377classes.put(378classNameC379, new ClassGenerator(380classNameC381, classNameB382, classFlags383)384.addTargetConstructor(accessFlagC)385.addTargetMethod(accessFlagC)386.addCaller(calleeClassName)387.getClassFile()388);389390// Generate class X391String classNameX = "x.X";392classes.put(393classNameX394, new ClassGenerator(395classNameX396, "java.lang.Object"397, classFlags398)399.addTargetMethod(accessFlagC)400.addCaller(calleeClassName)401.getClassFile()402);403404// Generate package callers405for (String pkg : packages) {406classes.put(407pkg+"Caller"408, new ClassGenerator(409pkg+"Caller"410, "java.lang.Object"411, classFlags412)413.addCaller(calleeClassName)414.getClassFile()415);416}417418String[] callSites = new String[] {419classNameA420, packageA+"Caller"421, classNameB422, packageB+"Caller"423, classNameC424, packageC+"Caller"425, classNameX426};427428String caseDescription = String.format(429"%-10s %-10s %-10s| "430, classNameA + " " + accessFlagA431, classNameB + " " + accessFlagB432, classNameC + " " + accessFlagC433);434435boolean result = exec(classes, caseDescription, calleeClassName, classNameC, callSites);436isPassed = isPassed && result;437}438}439}440}441442// Print footer443for (int i = header.length-1; i >= 0; i--) {444System.out.println(header[i]);445}446447if (executeTests) {448System.out.printf("\nEXECUTION STATUS: %s\n", (isPassed? "PASSED" : "FAILED"));449}450}451}452453454