Bug 25174 - Wrong code generation of the eclipse java compiler
Summary: Wrong code generation of the eclipse java compiler
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 2.0.1   Edit
Hardware: PC Windows NT
: P3 major (vote)
Target Milestone: 2.1 M3   Edit
Assignee: Philipe Mulet CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2002-10-22 08:02 EDT by Michael Lupp CLA
Modified: 2002-11-14 07:08 EST (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Michael Lupp CLA 2002-10-22 08:02:32 EDT
Hi,

we have a class with this code:

-----------
protected javax.swing.tree.TreeCellEditor createTreeCellEditor() {
	javax.swing.border.Border oBorder =
			javax.swing.UIManager.getBorder("Tree.editorBorder");
	ZFavoriteTree.CellEditor oEditor = ZFavoriteTree.this.new CellEditor(
			TreeCellEditor.this.new DefaultTextField(oBorder)
	) {
		public boolean shouldSelectCell(java.util.EventObject oEvent) {
			boolean retValue = super.shouldSelectCell(oEvent);
			getComponent().requestFocus();
			return retValue;
		}
	};
	return oEditor;
};
-----------

The method is part of an inner protected class 'TreeCellEditor' of the class
'ZFavoriteTree'. The class 'CellEditor' is an inner protected class of the
'ZFavoriteTree', too.

If we compile this with the sun jdk 1.3.1_03 it works. But compiled with the
eclipse compiler we get a NullPointerException in the line where the CellEditor
is being created. If we change the code to

-----------
protected javax.swing.tree.TreeCellEditor createTreeCellEditor() {
	javax.swing.border.Border oBorder =
			javax.swing.UIManager.getBorder("Tree.editorBorder");
	ZFavoriteTree.CellEditor oEditor = new CellEditor(
			new DefaultTextField(oBorder)
	) {
		public boolean shouldSelectCell(java.util.EventObject oEvent) {
			boolean retValue = super.shouldSelectCell(oEvent);
			getComponent().requestFocus();
			return retValue;
		}
	};
	return oEditor;
};
-----------

and compile it then with the eclipse compiler, it works. It seems to be a
problem with the code generation of the eclipse compiler.

BTW: The bug is in build M2 too.

Best,

Michael
Comment 1 Philipe Mulet CLA 2002-10-23 05:08:24 EDT
Could you provide a complete test case with all sources for types involved 
here ? Trying to reproduce I actually found another defect (bug 25229), but 
could not reproduce yours.
Comment 2 Philipe Mulet CLA 2002-10-23 06:11:14 EDT
I am guessing this has to do with the fact that the offending code is run 
dynamically through a constructor invocation.

The enclosing instance (ZFavoriteTree.this) isn't bound yet (remember it is 
accessible through synthetic instance slot this$N). 

Our codegen is ensuring a null check is performed on the enclosing instance 
when it is passed to an allocation expression.

Can you for instance print the value of ZFavoriteTree.this prior to perform the 
call and see whether it is null at that stage ?

We ensure the enclosing instance is non null, as expected by the spec (javac 
1.4 also checks for this). However, once 1.4 compliance is enabled, our 
compiler will ensure the enclosing instance is non null at that point (since 
1.4 VMs are no longer blocking us from doing the right thing - initialize 
synthetic slots before super constructor invocation; 1.3 VMs were incorrectly 
reporting a verification error).

Now, we might want to be a little more resilient for backward compatibility 
reason... 

Comment 3 Philipe Mulet CLA 2002-10-23 06:31:58 EDT
If my guess is right, then this small test case should reproduce what you are 
seeing:

public class X {
	public static void main(String[] arguments) {
		new X().new X2();
	}
	class X1 {
		X1(){
			this.baz();
		}
		void baz() {
			System.out.println("X1.baz()");
		}
	}
	class X2 extends X1 {
		void baz() {
			System.out.println("X.this="+X.this);
			X1 x1 = X.this.new X1(){
				void baz(){
					System.out.println("X$1.baz()");
				}
			};
		}		
	}
}

- using Eclipse compiler in 1.3 compliant mode
X.this=null
Exception in thread "main" java.lang.NullPointerException
        at X$X2.baz(Unknown Source)
        at X$X1.<init>(Unknown Source)
        at X$X2.<init>(Unknown Source)
        at X.main(Unknown Source)
   --> non-initialized, ensure enclosing instance is non-null as spec'ed.

- using Javac 1.3.1
X.this=null
X$1.baz()
   --> non-initialized, but no NPE until actually used

- using Javac 1.4.1b18
X.this=null
Exception in thread "main" java.lang.NullPointerException
        at X$1.<init>(X.java:19)
        at X$X2.baz(X.java:18)
        at X$X1.<init>(X.java:8)
        at X$X2.<init>(X.java:15)
        at X.main(X.java:4)
   --> they added the null check, but did not fix the codegen to initialize
       correctly synthetics yet (same behavior as our 1.3 mode)

- using Eclipse compiler in 1.3 compliant mode
X.this=X@17182c1
X$1.baz()

   --> synthetic is correctly initialized, null check is in, but now it is fine.
       (could verify null check is in by using a null enclosing instance 
instead).


Will ensure our 1.3 mode is compliant with javac 1.3. Indeed, this behavior is 
sound given the VM constraint can make this happen legitimately.

Please confirm this is what you are experiencing.
Comment 4 Philipe Mulet CLA 2002-10-23 07:27:09 EDT
Last test case should have read "using Eclipse compiler in 1.4 compliant mode"
Comment 5 Philipe Mulet CLA 2002-10-25 05:25:10 EDT
Posted patch did solve the reporter's problem.

Fixed (by no longer doing the null check in 1.3 compliant mode).
Comment 6 David Audel CLA 2002-11-14 07:08:07 EST
Verified.