JDK-4255913 : code gen.: non-locals not copied into anon. class before base class construction
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 1.1.7
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_nt
  • CPU: x86
  • Submitted: 1999-07-21
  • Updated: 2000-12-15
  • Resolved: 2000-12-15
Related Reports
Duplicate :  

Name: wl91122			Date: 07/21/99

The compiler might have a bug in code generation for anonymous

Non-local variables referenced in an anonymous subclass are
not copied before the base class constructor is called.

(This might not be a compiler bug but might be a flaw in
how inner classes are defined.  That is, the language spec.
might define that non-local variables are defined to be copied
in during initialization of the anonymous subclass (instead of 
before construction of the base class even starts).  If
that's the case, then that definition should be reworked to
yield more intuitive (and useful) behavior.)

Here's my test case:

package test;

  Demonstrates possible code generation error in JDK 1.1.7B compiler.

  It appears that non-local variables that are referenced in an anonymous 
  class are not properly copied (or otherwise made accessible) before the 
  base class constructor is called.

  The output from the JDK 1.1.7B compiler is:

callingMethod.1: parameter = whatever
callingMethod.1: local_var = hello
calledByConstructor (constructor): parameter = null
calledByConstructor (constructor): local_var = null
<init>: parameter = whatever
<init>: local_var = hello
calledByConstructor (callingMethod): parameter = whatever
calledByConstructor (callingMethod): local_var = hello
callingMethod.2: parameter = whatever
callingMethod.2: local_var = hello

  Note how variables "parameter" and "local_var" are seen as null 
  from the anonymous subclass at the time the base class constructor 
  is active.

import java.util.Enumeration;
import java.util.Vector;

class Test

    public static void main( String[] args )
	callingMethod( "whatever" );
    } // main();

    protected static void callingMethod( final String parameter )
	final String local_var = "hello";

	System.err.println( "callingMethod.1: parameter = " + parameter );
	System.err.println( "callingMethod.1: local_var = " + local_var );

	BaseClass enum = new BaseClass()
		    System.err.println( "<init>: parameter = " + parameter );
		    System.err.println( "<init>: local_var = " + local_var );


		public void calledByConstructor( String caller )
		    System.err.println( "calledByConstructor (" + caller +  "): parameter = " + parameter );
		    System.err.println( "calledByConstructor (" + caller +  "): local_var = " + local_var );
	enum.calledByConstructor( "callingMethod" );
	System.err.println( "callingMethod.2: parameter = " + parameter );
	System.err.println( "callingMethod.2: local_var = " + local_var );
    } // callingMethod(...)

} // class Test

abstract class BaseClass 

    protected BaseClass()
	calledByConstructor( "constructor" );
    } // BaseClass()

    protected abstract void calledByConstructor( String caller );
} // class BaseClass

(Review ID: 54104) 

WORK AROUND Name: wl91122 Date: 07/21/99 no simple workaround ======================================================================

EVALUATION The val$parameter and val$local_var fields of the anonymous class are initialized during the execution of the constructor for the inner anonymous class. This constructor must first call the superclass constructor before assigning any fields, due to verification requirements. We admit that this behavior is anomalous and undesirable, but it cannot be done differently without a liberalization of the verification rules, a change that would break compatibility with all existing VM's. Most likely, such a change could be done only as a part of a major overhaul of the VM, which is not being planned at this time. There is a well-known analogous problem with the initializatio of the outer instance pointers, i.e., this$0. This is the reason for the following statement in the inner classes spec, which is misleading, because it applies to *all* Java compilers that correctly generate verifiable code: There is a limitation in some implementations of Java 1.1., under which the initialization of this$0 is delayed until after any superclass constructor is run. This means that up-level references made by a subclass method may fail if the method happens to be executed by the superclass constructor. The same problem exists in jdk1.3 as well. It is not a compiler problem per-se, but a compromise in the implementation required by the existing verification rules. william.maddox@Eng 1999-08-04