Bug 23075 - Wrong compiling of inner classes
Summary: Wrong compiling of inner classes
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 2.0   Edit
Hardware: PC Windows 2000
: P3 normal (vote)
Target Milestone: 2.1 M1   Edit
Assignee: Philipe Mulet CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 290791 (view as bug list)
Depends on:
Blocks:
 
Reported: 2002-09-02 02:50 EDT by hiddel CLA
Modified: 2009-09-29 15:15 EDT (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description hiddel CLA 2002-09-02 02:50:58 EDT
Eclipse compiler has a bug and produces wrong bytecode for inner classes. The
point is that reference to enclosing instance in constructor is assigned AFTER
calling constructor of superclass. The result is null pointer exception when you
overriding in the inner class a method called by constructor of superclass. Example:

public class A {
  public int m;
  public void pp() {
     C c = new C(4);
     System.out.println(c.get());
  }
  public static void main(String[] args) {
     A a = new A();
     a.pp();
  }

  class C extends B {
    public C(int x1) {
      super(x1);    
    }
    protected void init(int x1) {
       x = m * x1; // <- NULL POINTER EXCEPTION because of m
    }  
  }
}

class B {
  int x;
  public B(int x1) {
    init(x1);
  }
  protected void init(int x1) {
    x  = x1;
  }
  public int get() {
    return x;
  }
}
Comment 1 Philipe Mulet CLA 2002-09-02 07:27:06 EDT
This is not a compiler bug, but rather a VM limitation since innerclasses have 
existed. The bytecode verification process enforces the first instruction 
inside a constructor to be a constructor invocation (super(...) or this(...)). 
Therefore, internals cannot be initialized for virtual calls which may occur 
indirectly through a super constructor invocation.

This is a limitation in innerclass usage due to a VM constraint.
Javac has the same behavior as we do, there is nothing we can do unfortunately, 
unless the VM specs was to change (which isn't the case).
Comment 2 hiddel CLA 2002-09-02 09:20:11 EDT
It is not true that javac has the same behavior as you do actually. When you use
"-source 1.4" option reference to enclosing instance is initialized BEFORE
constructor of superclass is called. 

This is the difference. In 1.3:

Method A. C(A,int)
   0 aload_0
   1 iload_2
   2 invokespecial #1 <Method B(int)>
   5 aload_0
   6 aload_1
   7 putfield #2 <Field A this$0>
  10 return

In 1.4:

Method A. C(A,int)
   0 aload_0
   1 aload_1
   2 putfield #1 <Field A this$0>
   5 aload_0
   6 iload_2
   7 invokespecial #2 <Method B(int)>
  10 return
Comment 3 Philipe Mulet CLA 2002-09-02 10:00:14 EDT
You are right, this seems to have changed recently (-source 1.4). I even see 
the VM spec mentionning it ($4.8.2).

Thanks for pointing this out, we will move accordingly for 1.4 source mode.
Comment 4 Philipe Mulet CLA 2002-09-02 10:44:23 EDT
Actually, javac -target 1.4 is enough to trigger this behavior, note that 
pre1.4 vms would not accept such bytecodes.
Comment 5 Philipe Mulet CLA 2002-09-02 12:06:15 EDT
Fixed in latest
Comment 6 hiddel CLA 2002-09-02 12:21:00 EDT
The fact that <1.4 vms don't accept this bytecode doesn't mean that 1.4 
compliant compiler shouldn't produce such bytecode. This is the way I 
undestand "1.4 compliant" in Eclipse - use only on >=1.4 vms.
Comment 7 Philipe Mulet CLA 2002-09-03 09:32:42 EDT
This is only partially true, you may toggle the compiler for general 1.4 
compliance, but still manually targeting a 1.1 VM (if you turn off assertions -
source 1.3).

Comment 8 David Audel CLA 2002-09-19 06:31:07 EDT
Verified.
Comment 9 Olivier Thomann CLA 2009-09-29 15:15:13 EDT
*** Bug 290791 has been marked as a duplicate of this bug. ***