JDK-8061778 : Wrong LineNumberTable for default constructors
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 7-pool,8,9
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2014-10-22
  • Updated: 2015-09-29
  • Resolved: 2014-10-24
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9
8u60Fixed 9 b37Fixed
Description
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).

$ 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

   [...]
}
Comments
Minimal 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.
22-10-2014