Breaking binary compatibility due to adding private method to an interface compiled inconsistently
David M. Lloyd
david.lloyd at redhat.com
Wed Oct 19 12:16:08 UTC 2016
Forgive me, but that's quite an incredible response. How many
recompilations equals a hex edit? You can just as well say that Ch.13
doesn't apply to any changes ever because any recompilation is
tantamount to a hex edit, which is clearly counter to the intent of the
chapter.
It is completely reasonable to have two separate libraries in a
configuration that matches the description, and to have one of those
libraries be updated to a new version, which would cause the effect
quite trivially from the user's perspective. This is not an obscure
case at all. All he did was compact this into a simple
easy-to-understand test case, which yes might be more obscure but also
serves to illustrate the problem more clearly.
On 10/18/2016 05:52 PM, Alex Buckley wrote:
> I understand that you're going from executing A.class + B.class +
> Test.class to executing A.class + B.class[MODIFIED] + Test.class.
> However, because B.class[MODIFIED] was produced by a non-trivial
> sequence of recompilations, it's tantamount to a hex-edited version of
> the initial B.class. Ch.13 doesn't describe the binary compatibility of
> hex edits, only the binary compatibility of a single compilable change
> to a single compilation unit. I agree with Dan that the binary
> compatibility of adding a private method to an interface inherently
> assumes you immediately compile the interface.
>
> Alex
>
> On 10/18/2016 7:55 AM, Georgiy Rakov wrote:
>> I'd like to emphasize that in this case preexisting binaries supplied to
>> JVM during Test.main execution doesn't change and if they don't then,
>> according to my understanding, it doesn't matter how the modified B
>> class-file was produced.
>>
>> Thank you,
>> Georgiy.
>>
>> On 17.10.2016 21:15, Alex Buckley wrote:
>>> The key phrase is "with preexisting binaries". Given the initial
>>> A.class + B.class + Test.class, you get to make ONE change to ONE
>>> compilation unit that you recompile independently but inconsistently.
>>> The change you would like to make is adding a private method to B, but
>>> you can't make that change because of B's superinterface, so no
>>> independent recompilation is possible, and the question of whether the
>>> change is binary-incompatible is moot.
>>>
>>> Alex
>>>
>>> On 10/17/2016 10:26 AM, Georgiy Rakov wrote:
>>>> Hello Dan,
>>>>
>>>> comment [1] specifies following assertion and a note:
>>>>
>>>> Adding an 'abstract', ***'private', or 'static'*** method to an
>>>> interface does not break compatibility with preexisting binaries.
>>>>
>>>> [Note: I believe we can make this assertion because "adding a
>>>> method" means "adding a method that will compile", presumably?
>>>> Private and static methods can introduce errors if a reference like
>>>> I.m()V previously resolved to an abstract/default method in a
>>>> superinterface, and now resolves to the private/static method in I.
>>>> But that new method won't compile if there's a method with a
>>>> matching signature in a superinterface of I.]
>>>>
>>>> Namely, the note reads:
>>>>
>>>> ... "adding a method" means "adding a method that will compile" ...
>>>>
>>>> It's questionable if this is a valid point since spec should take into
>>>> account that a method added might be resulted from inconsistent
>>>> compilation. For instance:
>>>>
>>>> 1. First we compile sources A.java, B.java, Test.java presented below.
>>>>
>>>> A.java:
>>>> interface A {
>>>> default void same() {}
>>>> }
>>>>
>>>> B.java:
>>>> interface B extends A {
>>>> //private void same() {}
>>>> }
>>>>
>>>> Test.java:
>>>> class Test {
>>>> public static void main(String[] argv) {
>>>> B i = new B(){};
>>>> i.same();
>>>> }
>>>> }
>>>>
>>>> 2. Then we compile sources A.java, B.java presented below (toggle
>>>> commenting 'same' method in A and B):
>>>>
>>>> A.java:
>>>> interface A {
>>>> //default void same() {}
>>>> }
>>>>
>>>> B.java:
>>>> interface B extends A {
>>>> private void same() {}
>>>> }
>>>>
>>>>
>>>> 3. Then we compile source A.java presented below (returning back A
>>>> class
>>>> file as it resulted from step 1):
>>>>
>>>> A.java:
>>>> interface A {
>>>> default void same() {}
>>>> }
>>>>
>>>> 4. Run Test.main(), this results in a run-time error:
>>>>
>>>> Exception in thread "main" java.lang.IllegalAccessError: tried to
>>>> access method B.same()V from class Test
>>>>
>>>> So adding a private method seems to cause breaking binary
>>>> compatibility.
>>>> The change between binaries resulted from step 1 and step 3 is B class
>>>> file with a private method added, the rest of the class files are the
>>>> same.
>>>>
>>>> Should it be considered as a spec issue?
>>>>
>>>> [1]
>>>> https://bugs.openjdk.java.net/browse/JDK-8072872?focusedCommentId=13610992
>>>>
>>>>
>>>>
>>>> Thank you,
>>>> Georgiy.
>>
--
- DML
More information about the compiler-dev
mailing list