JLS and JVMS SE8 Disagreement: Method Resolution Behavior with Multiple Maximally-Specific Default Methods
John Vilk
jvilk at cs.umass.edu
Wed Dec 31 20:51:43 UTC 2014
Hello,
I recently noticed a disagreement between the JLS and the JVMS for SE8
concerning the scenario where multiple direct superinterfaces of a class
provide a default method for a method reference with the same name and
signature. I believe this is a bug in the JVM specification, which
specifies behavior that is not present in the reference implementation of
the specification, and which differs from the behavior specified in the JLS.
The JVM specification states the following should occur in the section on
method resolution, §5.4.3.3
<http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.3>,
should there be no single maximally-specific default method (meaning, there
are multiple) (emphasis mine):
Otherwise, if any superinterface of C declares a method with the name and
descriptor specified by the method reference that has neither its
ACC_PRIVATE flag nor its ACC_STATIC flag set, *one of these is arbitrarily
chosen and method lookup succeeds.*
However, the JLS specification states the following in the section on
Interface Method Declarations in the binary compatibility chapter, §13.5.6
<http://docs.oracle.com/javase/specs/jls/se8/html/jls-13.html#jls-13.5.6>:
Adding a default method, or changing a method from abstract to default,
does not break compatibility with pre-existing binaries, but may *cause an
IncompatibleClassChangeError if a pre-existing binary attempts to invoke
the method.*
This section of the JLS contains a full example that exemplifies the
specification bug I am describing in this email. In particular, the JLS
states:
If Cowboy is recompiled but not CowboyArtist, then running the new binary
with the existing binary for CowboyArtist will link without error *but
cause an IncompatibleClassChangeError when main attempts to invoke draw().*
However, this behavior description is in contrast to the JVM specification,
which claims that one of the draw methods should be arbitrarily chosen and
invoked.
Using separate compilation on the example, I verified that the JVM does, in
fact, throw an IncompatibleClassChangeError, which disagrees with the
behavior specified in the JVMS:
$ java example/CowboyArtist
Exception in thread "main" java.lang.IncompatibleClassChangeError:
Conflicting default methods: example/Cowboy.draw example/Painter.draw
at example.CowboyArtist.draw(CowboyArtist.java)
at example.CowboyArtist.main(CowboyArtist.java:6)
Since this behavior originates in the JVM, rather than in the bytecode
produced from the Java Compiler, it should be included in the JVM
specification.
Thus, to fix this specification bug, I propose that the quoted section of
the JVMS from the method resolution section be replaced with the following
text:
Otherwise, if there are multiple maximally-specific superinterface methods
of C for the name and descriptor specified by the method reference, method
resolution throws an IncompatibleClassChangeError.
I believe the above text captures the behavior of the current reference
implementation, and is in line with the JLS.
Let me know if you have any questions, comments, or if you find a mistake
in my reasoning above. It is very possible that I am missing a subtlety.
Thanks for reading!
John
More information about the jls-jvms-spec-comments
mailing list