To sanity check the JVMS changes relative to “transitive” overriding in the JVMS update for JEP 181: nestmates: http://cr.openjdk.java.net/~dlsmith/nestmates.html <http://cr.openjdk.java.net/~dlsmith/nestmates.html>
The first goal here is to ensure that we are all in agreement on the intended behavior of invoke virtual relative to transitive overriding. Once we are sure about that - then we can double-check that the new wording of 5.4.4. Overriding works for all of us. While I agree that the transitive overriding only applies in cases where there is a package private method in the hierarchy, it is not the case that it only applies if the resolved method is package private. I went back to the pre-default method changes in JDK7 when the transitive overriding was added to find the reasoning, examples, and in particular to find the test cases which demonstrated a change in behavior in invoke virtual due to the JVMS change from JVMS 2nd edition to JVMS 3rd edition based on the JVMS Clarifications and Addenda to 2nd edition. I have appended first my notes at the time, then the explicit list of tests that had behavioral changes due to the JVMS change for us. In practice, we create a virtual method table, or vtable, at preparation time, as an invoke virtual selection cache. The conceptual model is that each potential resolved class creates a new index in the vtable which will be overridden for each potential receiver to contain the selected method based on the search and overriding rules. To save space we actually don’t always create a new index - if A.m is public and B extends A has public m as well, they can share an index. We are extremely careful that any package private method does create a new index because even if it overrides a superclass’s public method, a subclass may not override it. So the theory is that we are testing overriding on the root of the index. In practice we are testing overriding of the latest overrider. I think that is where we have a translation from the JVMS and need to make sure we are all saying the same thing. The set of tests that changed behavior when we added the transitive overriding all look like: class A public or protected m() class B extends A package private m() class C extends B public or protected or package private m() call: invoke virtual A.m object ref C The old result was B.m or AME (if B.m is abstract), the new result was C.m (unless IAE due to caller access of A.m protected) I am appending my notes from the change at the time. Below that is the test matrix reporting the tests that changed and the results are listed as : 1.6 results/1.7 expected results. We are internally in the process of cleaning up the tests and making them open jtreg tests. They currently use a very old ASM. However you can find them in JDK-8163974. Give a shout if you need help figuring out how to run them. If you run them on our jvm - you might need to run -Xint -Xverify:none right now. thanks, Karen Here are my notes from the change at the time: Changes in Invoke-Virtual behavior due to specification changes With classfile version 51, which will be introduced in JDK7, the invokevirtual behavior will be fixed to match the clarifications in the JVMS which were made to handle the following test case: Sample test case from: Why the Definition of Method Override was Revised <http://java.sun.com/docs/books/jls/method-override-rationale.html> package P1; class A { void m(){System.out.println("A.m");} public void callM(){ m();} } public class B extends A { protected void m() { System.out.println("B.m");} } package P2; class C extends P1.B { protected void m(){ System.out.println("C.m");} public static void main(String[] args) { C c = new C(); c.callM(); } Given the original definition of override, we find that the method m() declared in C overrides the method m() declared in B(), since it has the same name and signature and is accessible from class C. However, we a lso find that the method m() declared in C does not override the method m() declared in A(), since it is pr ivate to package P1 and therefore not accessible from class C. In this case, invoking callM() on an instance of C causes a call of m() where the target of the method invocation is an instance of C as well. However, this call is in the class P1.A, and is attempting to invoke a package private method of A. Since this method is not overridden by C, the code will not print "C.m" as expected. Instead, it prints "B.m". This is quite unintuitive, and also incompatible with the behavior of the classic VM. We believe that this interpretation, while literally accurate, is undesirable. It prevents a package private method from ever being overridden outside its package, even if a subclass within the package has increased the method's accessibility. * Invokevirtual modifications: * Invokevirtual, JVMS Clarifications and Addenda to 2nd edition Let C be the class of objectref. The actual method to be invoked is selected by the following lookup procedure: If C contains a declaration for an instance method M with the same name and descriptor as the resolved method, and M overrides the resolved method, then M is the method to be invoked, and the lookup procedure terminates. Otherwise, if C has a superclass, this same lookup procedure is performed recursively using the direct superclass of C ; the method to be invoked is the result of the recursive invocation of this lookup procedure. Otherwise, an AbstractMethodError? <http://j2se.us.oracle.com/web/bin/edit/HotspotRuntime/AbstractMethodError?topicparent=HotspotRuntime.VtableAccess> is raised. JVMS 2nd edition invokevirtual: Let C be the class of objectref. The actual method to be invoked is selected by the following lookup procedure: If C contains a declaration for an instance method with the same name and descriptor as the resolved method, and the resolved method is accessible from C, then this is the method to be invoked, and the lookup procedure terminates. Otherwise, if C has a superclass, this same lookup procedure is performed recursively using the direct superclass of C ; the method to be invoked is the result of the recursive invocation of this lookup procedure. Otherwise, an AbstractMethodError? <http://j2se.us.oracle.com/web/bin/edit/HotspotRuntime/AbstractMethodError?topicparent=HotspotRuntime.VtableAccess> is raised. Note: the key difference here is the phrase: "the resolved method is accessible from C" which in the Clarifications and Addenda has been replaced with "M overrides the resolved method” Inheritance rules: JLS 3rd edition, 8.4.8 Inheritance, Overriding, and Hiding A class C inherits from its direct superclass and direct superinterfaces all non-private methods (whether abstract or not) of the superclass and superinterfaces that are public, protected or declared with default access in the same package as C and are neither overridden ('8.4.8.1) nor hidden ('8.4.8.2) by a declaration in the class. JLS 3rd edition 8.4.8.1 Overriding (by Instance Methods) An instance method m1 declared in a class C overrides another instance method, m2, declared in class A iff all of the following are true: 1. C is a subclass of A. 2. The signature of m1 is a subsignature (§8.4.2) of the signature of m2. 3. Either o m2 is public, protected or declared with default access in the same package as C, or o m1 overrides a method m3, m3 distinct from m1, m3 distinct from m2, such that m3 overrides m2. Moreover, if m1 is not abstract, then m1 is said to implement any and all declarations of abstract methods that it overrides. Note that based on the JVMS 3rd edition transitive overriding rules, we need to do an override check first for the direct superclass and if the current class does not override the direct superclass, recursively for the superclass' superclass. Thanks to Alex Buckley and Vladimir V. Ivanov for help understanding this. ======== Invokevirtual behavior differences between JDK 1.6 and upcoming 1.7. Changes in behavior due to clarification of overriding behavior as transitive, clarified Invokevirtual JVMS 3rd edition and JLS 3rd edition: 8.4.8.1 Overriding (by Instance Methods) This test represents a run of a 1.6 JDK relative to 1.7 expected results. The 1.6 results are listed/expected results are listed. In all of these examples, B.m was the old expected result (sometimes resulting in AME), but with the clarification of overriding behavior as transitive, C.m is now the expected result. Method access modifiers Call site location Status # A.m() B.m() C.m() A pkgA B pkgB C pkgC ------------------------------------------------------------------------------------------------- 841| A PUB a.B PP b.C PUB | B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m | FAILED 842| ! A PUB a.B PP b.C PUB | B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m | FAILED 843| A PUB ! a.B PP b.C PUB | AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m | FAILED 844| ! A PUB ! a.B PP b.C PUB | AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m | FAILED 845| A PUB a.B PP b.C PROT | B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m | FAILED 846| ! A PUB a.B PP b.C PROT | B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m | FAILED 847| A PUB ! a.B PP b.C PROT | AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m | FAILED 848| ! A PUB ! a.B PP b.C PROT | AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m | FAILED 849| A PUB a.B PP b.C PP | B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m | FAILED 850| ! A PUB a.B PP b.C PP | B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m | FAILED 851| A PUB ! a.B PP b.C PP | AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m | FAILED 852| ! A PUB ! a.B PP b.C PP | AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m | FAILED 941| A PROT a.B PP b.C PUB | B.m/C.m B.m/C.m B.m/C.m IAE B.m/C.m IAE | FAILED 942| ! A PROT a.B PP b.C PUB | B.m/C.m B.m/C.m B.m/C.m IAE B.m/C.m IAE | FAILED 943| A PROT ! a.B PP b.C PUB | AME/C.m AME/C.m AME/C.m IAE AME/C.m IAE | FAILED 944| ! A PROT ! a.B PP b.C PUB | AME/C.m AME/C.m AME/C.m IAE AME/C.m IAE | FAILED 945| A PROT a.B PP b.C PROT | B.m/C.m B.m/C.m B.m/C.m IAE B.m/C.m IAE | FAILED 946| ! A PROT a.B PP b.C PROT | B.m/C.m B.m/C.m B.m/C.m IAE B.m/C.m IAE | FAILED 947| A PROT ! a.B PP b.C PROT | AME/C.m AME/C.m AME/C.m IAE AME/C.m IAE | FAILED 948| ! A PROT ! a.B PP b.C PROT | AME/C.m AME/C.m AME/C.m IAE AME/C.m IAE | FAILED 949| A PROT a.B PP b.C PP | B.m/C.m B.m/C.m B.m/C.m IAE B.m/C.m IAE | FAILED 950| ! A PROT a.B PP b.C PP | B.m/C.m B.m/C.m B.m/C.m IAE B.m/C.m IAE | FAILED 951| A PROT ! a.B PP b.C PP | AME/C.m AME/C.m AME/C.m IAE AME/C.m IAE | FAILED 952| ! A PROT ! a.B PP b.C PP | AME/C.m AME/C.m AME/C.m IAE AME/C.m IAE | FAILED 1641| a.A PUB a.B PP b.C PUB | B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m | FAILED 1642| ! a.A PUB a.B PP b.C PUB | B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m | FAILED 1643| a.A PUB ! a.B PP b.C PUB | AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m | FAILED 1644| ! a.A PUB ! a.B PP b.C PUB | AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m | FAILED 1645| a.A PUB a.B PP b.C PROT | B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m | FAILED 1646| ! a.A PUB a.B PP b.C PROT | B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m | FAILED 1647| a.A PUB ! a.B PP b.C PROT | AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m | FAILED 1648| ! a.A PUB ! a.B PP b.C PROT | AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m | FAILED 1649| a.A PUB a.B PP b.C PP | B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m | FAILED 1650| ! a.A PUB a.B PP b.C PP | B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m | FAILED 1651| a.A PUB ! a.B PP b.C PP | AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m | FAILED 1652| ! a.A PUB ! a.B PP b.C PP | AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m | FAILED 1741| a.A PROT a.B PP b.C PUB | B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m IAE | FAILED 1742| ! a.A PROT a.B PP b.C PUB | B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m IAE | FAILED 1743| a.A PROT ! a.B PP b.C PUB | AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m IAE | FAILED 1744| ! a.A PROT ! a.B PP b.C PUB | AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m IAE | FAILED 1745| a.A PROT a.B PP b.C PROT | B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m IAE | FAILED 1746| ! a.A PROT a.B PP b.C PROT | B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m IAE | FAILED 1747| a.A PROT ! a.B PP b.C PROT | AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m IAE | FAILED 1748| ! a.A PROT ! a.B PP b.C PROT | AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m IAE | FAILED 1749| a.A PROT a.B PP b.C PP | B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m IAE | FAILED 1750| ! a.A PROT a.B PP b.C PP | B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m IAE | FAILED 1751| a.A PROT ! a.B PP b.C PP | AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m IAE | FAILED 1752| ! a.A PROT ! a.B PP b.C PP | AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m IAE | FAILED 2041| a.A PUB b.B PP a.C PUB | B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m | FAILED 2042| ! a.A PUB b.B PP a.C PUB | B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m | FAILED 2043| a.A PUB ! b.B PP a.C PUB | AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m | FAILED 2044| ! a.A PUB ! b.B PP a.C PUB | AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m | FAILED 2045| a.A PUB b.B PP a.C PROT | B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m | FAILED 2046| ! a.A PUB b.B PP a.C PROT | B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m | FAILED 2047| a.A PUB ! b.B PP a.C PROT | AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m | FAILED 2048| ! a.A PUB ! b.B PP a.C PROT | AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m | FAILED 2049| a.A PUB b.B PP a.C PP | B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m | FAILED 2050| ! a.A PUB b.B PP a.C PP | B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m B.m/C.m | FAILED 2051| a.A PUB ! b.B PP a.C PP | AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m | FAILED 2052| ! a.A PUB ! b.B PP a.C PP | AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m AME/C.m | FAILED 2141| a.A PROT b.B PP a.C PUB | B.m/C.m B.m/C.m B.m/C.m IAE B.m/C.m B.m/C.m | FAILED 2142| ! a.A PROT b.B PP a.C PUB | B.m/C.m B.m/C.m B.m/C.m IAE B.m/C.m B.m/C.m | FAILED 2143| a.A PROT ! b.B PP a.C PUB | AME/C.m AME/C.m AME/C.m IAE AME/C.m AME/C.m | FAILED 2144| ! a.A PROT ! b.B PP a.C PUB | AME/C.m AME/C.m AME/C.m IAE AME/C.m AME/C.m | FAILED 2145| a.A PROT b.B PP a.C PROT | B.m/C.m B.m/C.m B.m/C.m IAE B.m/C.m B.m/C.m | FAILED 2146| ! a.A PROT b.B PP a.C PROT | B.m/C.m B.m/C.m B.m/C.m IAE B.m/C.m B.m/C.m | FAILED 2147| a.A PROT ! b.B PP a.C PROT | AME/C.m AME/C.m AME/C.m IAE AME/C.m AME/C.m | FAILED 2148| ! a.A PROT ! b.B PP a.C PROT | AME/C.m AME/C.m AME/C.m IAE AME/C.m AME/C.m | FAILED 2149| a.A PROT b.B PP a.C PP | B.m/C.m B.m/C.m B.m/C.m IAE B.m/C.m B.m/C.m | FAILED 2150| ! a.A PROT b.B PP a.C PP | B.m/C.m B.m/C.m B.m/C.m IAE B.m/C.m B.m/C.m | FAILED 2151| a.A PROT ! b.B PP a.C PP | AME/C.m AME/C.m AME/C.m IAE AME/C.m AME/C.m | FAILED 2152| ! a.A PROT ! b.B PP a.C PP | AME/C.m AME/C.m AME/C.m IAE AME/C.m AME/C.m | FAILED