United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6679509 The compiler generates non-erased code when translating enhanced for loops
JDK-6679509 : The compiler generates non-erased code when translating enhanced for loops

Details
Type:
Bug
Submit Date:
2008-03-25
Status:
Closed
Updated Date:
2011-05-13
Project Name:
JDK
Resolved Date:
2008-04-18
Component:
tools
OS:
linux
Sub-Component:
javac
CPU:
x86
Priority:
P2
Resolution:
Duplicate
Affected Versions:
7
Fixed Versions:
7

Related Reports
Duplicate:

Sub Tasks

Description
An AssertionError occurs while compiling the following code using "javac -target 1.5 Main.java":
--------------------------------------------------------------------------
import java.util.List;

public class Main {

    public static void main(String[] args) {
        try {
        } finally {
            List<List<?>> l = null;
            for (List<?> textRegion : l) {
            }
        }
    }

}
--------------------------------------------------------------------------

Please note that "-target 1.5" is required on JDK6 and JDK7, can be omitted on JDK5.

I can reproduce on:
$ java -version
java version "1.5.0_12"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_12-b04)
Java HotSpot(TM) Server VM (build 1.5.0_12-b04, mixed mode)

$ java -version
java version "1.7.0-ea"
Java(TM) SE Runtime Environment (build 1.7.0-ea-b22)
Java HotSpot(TM) Server VM (build 11.0-b08, mixed mode)

$ java -version
java version "1.6.0_10-ea"
Java(TM) SE Runtime Environment (build 1.6.0_10-ea-b12)
Java HotSpot(TM) Server VM (build 11.0-b11, mixed mode)

Stack trace (from 1.7.0-ea-b22):
An exception has occurred in the compiler (1.7.0-ea). Please file a bug at the Java Developer Connection (http://java.sun.com/webapps/bugreport)  after checking the Bug Parade for duplicates. Include your program and the following diagnostic in your report.  Thank you.
java.lang.AssertionError: com.sun.tools.javac.jvm.Gen$1ComplexityScanner
        at com.sun.tools.javac.jvm.Gen$1ComplexityScanner.visitWildcard(Gen.java:1587)
        at com.sun.tools.javac.tree.JCTree$JCWildcard.accept(JCTree.java:1896)
        at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
        at com.sun.tools.javac.jvm.Gen$1ComplexityScanner.scan(Gen.java:1517)
        at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:57)
        at com.sun.tools.javac.tree.TreeScanner.visitTypeApply(TreeScanner.java:268)
        at com.sun.tools.javac.tree.JCTree$JCTypeApply.accept(JCTree.java:1840)
        at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
        at com.sun.tools.javac.jvm.Gen$1ComplexityScanner.scan(Gen.java:1517)
        at com.sun.tools.javac.tree.TreeScanner.visitVarDef(TreeScanner.java:94)
        at com.sun.tools.javac.tree.JCTree$JCVariableDecl.accept(JCTree.java:709)
        at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
        at com.sun.tools.javac.jvm.Gen$1ComplexityScanner.scan(Gen.java:1517)
        at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:57)
        at com.sun.tools.javac.tree.TreeScanner.visitBlock(TreeScanner.java:102)
        at com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:765)
        at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
        at com.sun.tools.javac.jvm.Gen$1ComplexityScanner.scan(Gen.java:1517)
        at com.sun.tools.javac.tree.TreeScanner.visitForLoop(TreeScanner.java:119)
        at com.sun.tools.javac.jvm.Gen$1ComplexityScanner.visitForLoop(Gen.java:1525)
        at com.sun.tools.javac.tree.JCTree$JCForLoop.accept(JCTree.java:856)
        at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49)
        at com.sun.tools.javac.jvm.Gen$1ComplexityScanner.scan(Gen.java:1517)
        at com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:57)
        at com.sun.tools.javac.tree.TreeScanner.visitBlock(TreeScanner.java:102)
        at com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:765)
        at com.sun.tools.javac.jvm.Gen.estimateCodeComplexity(Gen.java:1591)
        at com.sun.tools.javac.jvm.Gen.visitTry(Gen.java:1311)
        at com.sun.tools.javac.tree.JCTree$JCTry.accept(JCTree.java:1023)
        at com.sun.tools.javac.jvm.Gen.genDef(Gen.java:679)
        at com.sun.tools.javac.jvm.Gen.genStat(Gen.java:714)
        at com.sun.tools.javac.jvm.Gen.genStat(Gen.java:700)
        at com.sun.tools.javac.jvm.Gen.genStats(Gen.java:751)
        at com.sun.tools.javac.jvm.Gen.visitBlock(Gen.java:1027)
        at com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:765)
        at com.sun.tools.javac.jvm.Gen.genDef(Gen.java:679)
        at com.sun.tools.javac.jvm.Gen.genStat(Gen.java:714)
        at com.sun.tools.javac.jvm.Gen.genMethod(Gen.java:907)
        at com.sun.tools.javac.jvm.Gen.visitMethodDef(Gen.java:880)
        at com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:653)
        at com.sun.tools.javac.jvm.Gen.genDef(Gen.java:679)
        at com.sun.tools.javac.jvm.Gen.genClass(Gen.java:2219)
        at com.sun.tools.javac.main.JavaCompiler.genCode(JavaCompiler.java:631)
        at com.sun.tools.javac.main.JavaCompiler.generate(JavaCompiler.java:1303)
        at com.sun.tools.javac.main.JavaCompiler.generate(JavaCompiler.java:1273)
        at com.sun.tools.javac.main.JavaCompiler.compile2(JavaCompiler.java:779)
        at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:744)
        at com.sun.tools.javac.main.Main.compile(Main.java:386)
        at com.sun.tools.javac.main.Main.compile(Main.java:312)
        at com.sun.tools.javac.main.Main.compile(Main.java:303)
        at com.sun.tools.javac.Main.compile(Main.java:82)
        at com.sun.tools.javac.Main.main(Main.java:67)

                                    

Comments
WORK AROUND

Separate the code in the "finally" block into a method.
                                     
2008-03-25
SUGGESTED FIX

diff -r a1d1f335633f src/share/classes/com/sun/tools/javac/comp/Lower.java
--- a/src/share/classes/com/sun/tools/javac/comp/Lower.java     Wed Apr 09 15:30:44 2008 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Lower.java     Tue Apr 15 12:43:32 2008 +0100
@@ -2863,13 +2863,15 @@ public class Lower extends TreeTranslato
             JCExpressionStatement step = make.Exec(makeUnary(JCTree.PREINC, make.Ident(index)));
 
             Type elemtype = types.elemtype(tree.expr.type);
-            JCStatement loopvarinit = make.
-                VarDef(tree.var.sym,
-                       make.
-                       Indexed(make.Ident(arraycache), make.Ident(index)).
-                       setType(elemtype));
+            JCExpression loopvarinit = make.Indexed(make.Ident(arraycache),
+                                                    make.Ident(index)).setType(elemtype);
+            JCVariableDecl loopvardef = (JCVariableDecl)make.VarDef(tree.var.mods,
+                                                  tree.var.name,
+                                                  tree.var.vartype,
+                                                  loopvarinit).setType(tree.var.type);
+            loopvardef.sym = tree.var.sym;
             JCBlock body = make.
-                Block(0, List.of(loopvarinit, tree.body));
+                Block(0, List.of(loopvardef, tree.body));
 
             result = translate(make.
                                ForLoop(loopinit,
@@ -2944,7 +2946,11 @@ public class Lower extends TreeTranslato
             JCExpression vardefinit = make.App(make.Select(make.Ident(itvar), next));
             if (iteratorTarget != syms.objectType)
                 vardefinit = make.TypeCast(iteratorTarget, vardefinit);
-            JCVariableDecl indexDef = make.VarDef(tree.var.sym, vardefinit);
+            JCVariableDecl indexDef = (JCVariableDecl)make.VarDef(tree.var.mods,
+                                                  tree.var.name,
+                                                  tree.var.vartype,
+                                                  vardefinit).setType(tree.var.type);
+            indexDef.sym = tree.var.sym;
             JCBlock body = make.Block(0, List.of(indexDef, tree.body));
             result = translate(make.
                 ForLoop(List.of(init),
                                     
2008-04-15
EVALUATION

When Lower generates the trees corresponding to the foreach loops (namely within the two methods Lower.visitIterableForEachLoop() and Lower.visitArrayForEachLoop()) a synthetic variable declaration is  generated by the compiler with a non-erased type. In particular, the folowing enhanced for loop:

for (List<?> l : new ArrayList<List<?>>) {//code}

gets translated into the following ordinary for-loop:

for (java.util.Iterator i$ = l.iterator(); i$.hasNext(); ) {
    List<?> t = (List)i$.next();
    {//code}
}

As it can be noticed, the type of the variable i$ is List<?> instead of the erased type List. This has to do with javac exploiting a method (namely TreeMaker.VarDef) for emitting the variable declaration AST based on the info contained into the type of the symbol of the loop variable (namely tree.var.sym.type). This bit doesn't get erased during TransTypes (during that process only tree.var.type gets erased), as the full generic signature contained inside the symbol may be required for further processing during the lowering phase (that happen at a later point) - e.g. for emitting synthetic casts in case the type of the variable is a type-variable.

Even if this problem exists even without the command-line option -target 1.5, this option causes the AssertionError to be thrown. The reason has to do with the fact that starting from JDK 6, the compiler does not longer emit jsr/ret instructions for try/catch/finally blocks. That is, finally block are always inlined into the method exploiting them, thus making the check in Gen.ComplexityScanner pointless. However, if the compiler is run with the -target 1.5 option, the decision of whether the finally block has to be inlined or not method depends on Gen.estimateCodeComplexity; this method fails with the reported error when it encounters non-erased code (in this case the code in the finalizer had a wildcard in it).
                                     
2008-04-15



Hardware and Software, Engineered to Work Together