Why does javac use "invokespecial" for diamond inheritance?

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Mon Oct 3 14:30:37 UTC 2016


Hi,
I had the same reaction as Remi when first reading this thread. In 
principle, yes, replacing invokespecial with invokevirtual can cause 
bridge calls to go up and down the hierarchy and has more potential for 
generating infinite loops. That said, I have not been able to come up 
with a reasonable test case that would introduce an infinite loop should 
javac implement the proposed change. While 6996415 is definitively 
related, I believe that the loop in that example is started by a bad 
descriptor ending up in the explicit supercall (see bug evaluation) 
rather than by a problem between invokevirtual vs. invokespecial.

I also note that ECJ already generates an invokevirtual in the reported 
example. Again, I could not find any clue of a bridge-related loop that 
shows up in ECJ but not in javac (but I'd be happy to know if something 
like that exists),.

So, maybe it's a safe move after all?

Maurizio



On 03/10/16 14:42, Remi Forax wrote:
> Hi Rafael,
> it's not a binary compatible change.
>
> if the compiler emits an invokevirtual instead of an invokespecial, 
> you can create an infinite loop between the bridges
> https://bugs.openjdk.java.net/browse/JDK-6996415
>
> Rémi
>
> ------------------------------------------------------------------------
>
>     *De: *"Rafael Winterhalter" <rafael.wth at gmail.com>
>     *À: *compiler-dev at openjdk.java.net
>     *Envoyé: *Lundi 3 Octobre 2016 12:13:29
>     *Objet: *Why does javac use "invokespecial" for diamond inheritance?
>
>     I am wondering why javac is using an invokespecial instruction for
>     a bridge method in the following case. Considering the following
>     refactoring starting from:
>
>     class A {
>       public void m(String s) {
>         System.out.println("foo");
>       }
>     }
>
>     class B extends A { }
>
>     class C extends B {
>       public void m(String s) {
>         System.out.println("bar");
>       }
>     }
>
>     I would change the implementing of B to implement an additional
>     interface:
>
>     interface I<T> {
>       void m(T t);
>     }
>
>     class B extends A implements I<String> { }
>
>     C would live in its own module that is not recompiled upon
>     changing B. I do however not consider this a problem as the change
>     of B is binary compatible. However, B ends up with the following
>     bridge method:
>
>     class B extends A implements I<String> {
>       public bridge void m(Object o) {
>         Foo.special.m((String) o);
>       }
>     }
>
>     If a program does now invoke I::m on an instance of C, "foo" is
>     printed instead of "bar". This violates the intended virtual
>     dispatch for C. In my opinion, this should not happen. Bridge
>     methods, unless "visibility bridges" should always use
>     invokevirtual as an override in C, should make it impossible to
>     invoke A::m directly from outside the class.
>
>     Did I miss something here or is this a bug?
>
>     Thank you for the clarification,
>     Best regards, Rafael
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20161003/0bacfa1c/attachment.html>


More information about the compiler-dev mailing list