Generated constructor returns from line number of other method

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Wed Oct 22 09:52:56 UTC 2014


Hi Eirik,
this is definitively a javac issue; I isolated the problem to the 
following test case:

class Test {
      static class Empty { }
}

which generates the following LineNumberTable for the default constructor:

LineNumberTable:
         line 1: 0
         line 2: 4

However, if the static nested class is commented out, the following 
LineNumberTable is obtained:

LineNumberTable:
         line 1: 0

The problem seems to be caused by the fact that, during code translation 
(Lower), javac replaces nested class declarations with empty blocks 
which are then mistakenly confused by a subsequent code generation step 
for instance initializers (!!) - this means that the generated code 
would look like:

class Test {
      { } //  <-------------

       Test() {
            super();
       }
}

And then, after initializer normalization, it becomes:

class Test {
       Test() {
            super();
            {  } <------------
       }
}

That's wrong, as the empty block does not correspond to a static 
instance initializer, but, rather, to a compile-time artifact and should 
therefore be skipped.

I filed this:

https://bugs.openjdk.java.net/browse/JDK-8061778

to keep track of this issue.

Thanks for the report.

Maurizio


On 22/10/14 07:31, Eirik Bjørsnøs wrote:
> If it's even more odd that rather odd, might we even call it a bug? :-)
>
> I noticed that javac also generates a class
> WeirdConstructorLinenumber$1 containing a <clinit> which initialises
> an int[] switch map:
>
> class no.kantega.labs.revoc.demo.WeirdConstructorLinenumber$1 {
>    static final int[] $SwitchMap$java$math$RoundingMode;
>
>    static {};
>      Code:
>         0: invokestatic  #1                  // Method
> java/math/RoundingMode.values:()[Ljava/math/RoundingMode;
>         3: arraylength
>         4: newarray       int
>         6: putstatic     #2                  // Field
> $SwitchMap$java$math$RoundingMode:[I
>         9: return
>      LineNumberTable:
>        line 8: 0
> }
>
> Looks like for some reason the line number for the <clinit> "leaks"
> over to the <init> of the enclosing class.
>
> I first noticed this issue when working on a code coverage tool. For
> performance reasons, the tool instruments line number instructions not
> by their actual line numbers, but with the count of the first time a
> line number occurs in the byte code for that class. The odd line
> number in <init> shifted the line count by one which caused line
> counts for a method to spill over to the next method in the class.
>
> I imagine other source-aware tools such as code coverage tools, static
> analysis tools or even debuggers might be affected by this.
>
> Eirik.
>
>
>
> On Wed, Oct 22, 2014 at 12:52 AM, Alex Buckley <alex.buckley at oracle.com> wrote:
>> It's rather odd that an <init> method corresponding to a default constructor has a LineNumberTable attribute in the first place. After all, the default constructor doesn't correspond to any lines of code in the original source file.
>>
>> The fact that <init>'s LineNumberTable attribute changes based on the body of another method is even more odd.
>>
>> Alex
>>
>>
>> On 10/21/2014 3:19 PM, Eirik Bjørsnøs wrote:
>>> Hi,
>>>
>>> Given a class containing a method switching on an enum, like this:
>>>
>>> 1:  public class WeirdConstructorLinenumber
>>> 2:  {
>>> 3:     public void consider(java.math.RoundingMode mode) {
>>> 4:         switch ( mode ) {}
>>> 5:     }
>>> 6:  }
>>>
>>> javac generates a default constructor as expected.
>>>
>>> But the generated constructor returns from line 4 (which really belongs
>>> to the "consider" method).
>>>
>>> I could only make this happen by having my consider method switc on an
>>> enum. If I remove the switch or switch on something different, like an
>>> int, the constructor is generated with a single line and returns at line
>>> 1 as expected.
>>>
>>> Could this be a javac bug? Or is there something I'm just completely
>>> missing?
>>>
>>> $ javac WeirdConstructorLinenumber.java
>>> $ javap -c -l -classpath . WeirdConstructorLinenumber
>>> Compiled from "WeirdConstructorLinenumber.java"
>>> public class WeirdConstructorLinenumber {
>>>     public WeirdConstructorLinenumber();
>>>       Code:
>>>          0: aload_0
>>>          1: invokespecial #1                  // Method
>>> java/lang/Object."<init>":()V
>>>          4: return
>>>       LineNumberTable:
>>>         line 1: 0
>>>         line 4: 4
>>>
>>>      [...]
>>> }
>>>
>>>
>>> Thanks,
>>> Eirik Bjørsnøs
>>>



More information about the compiler-dev mailing list