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