Nestmates JVMS Overriding 5.4.5 request

Karen Kinnear karen.kinnear at oracle.com
Fri Nov 10 17:48:54 UTC 2017


Dan Smith - this is a request for a change to one line of the Nestmates JVMS 5.4.5 Overriding.
The rest of the wording for 5.4.5 is an improvement, so thank you.

Dan Heidinga, Graham Chapman (IBM) and I met to discuss the JVM implementations of
JVMS 5.4.5 Overriding, specifically to discuss the expectations relative to the
bullet describing transitive overriding that was added for CFV 51 in JDK7.

The JVMS 9 bullet says:
 mC overrides a method m' (m' distinct from mC and mA) such that m' overrides mA.

The proposed NestMates bullet says:
mC overrides a method m' (m' distinct from mC and mA) such that m' overrides mA mA is marked neither ACC_PUBLIC nor ACC_PROTECTED nor ACC_PRIVATE, and, where mC is declared in a class C and mA is declared in a class A, there exists a method mB declared in a class B, such that C is a subclass of B, B is a subclass of A, mC can override mB, and mB can override mA.
From examining a number of test cases, we would like to request that the updated version be modified to remove the restriction on mA as package private. We need to perform what I call transitive overriding checks as long as mA is not ACC_PRIVATE.

Dan H also suggested it would be very helpful to all of us if you could add some non-normative examples in the spec here. Examples that might be useful would be:

1. reason we added transitive overriding to start with - see postscript

2. example of why we need to do the transitive overriding even if mA is public/protected as well as package private: (test 841 from our internal test matrix for invoke virtual)

>  841|   A PUB        a.B PP     b.C PUB
>  
> call A with B - B.m (B overrides A)
> call A with C - C.m (C overrides A)
> call B with C - B.m (C does not override B)


3. a fix we had to make in 2014:
P1.A: public m()
P2.B extends A, PP m()
P1.C extends B, public m()

P1.C.m() needs to override P1.A.m() and can not override P2.B.m()


thanks,
Karen

p.s. extract from JVMS Clarifications and Addenda to 2nd edition (since the original link is gone):

With classfile version 51, which is 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:

Description of the original problem from: Why the Definition of Method Override was Revised:
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 private 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.

Therefore invokevirtual was modified in JVMS Clarifications and Addenda to 2nd edition to: 

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 is raised.

From the 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 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"



More information about the valhalla-spec-observers mailing list