nestmates and transitive overriding
Karen Kinnear
karen.kinnear at oracle.com
Wed Oct 25 14:26:57 UTC 2017
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
More information about the valhalla-spec-observers
mailing list