changeset 2860:4932bb04c4b8

7047734: javac, the LVT is not generated correctly in several scenarios Reviewed-by: jjg, mcimadamore
author vromero
date Sat, 14 Sep 2013 19:04:47 +0100
parents 03c26c60499c
children 8894cf49ae1e 4ce8148ffc4f
files src/share/classes/com/sun/tools/javac/code/Lint.java src/share/classes/com/sun/tools/javac/comp/Flow.java src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java src/share/classes/com/sun/tools/javac/comp/Lower.java src/share/classes/com/sun/tools/javac/comp/MemberEnter.java src/share/classes/com/sun/tools/javac/comp/TransTypes.java src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java src/share/classes/com/sun/tools/javac/jvm/Code.java src/share/classes/com/sun/tools/javac/jvm/Gen.java src/share/classes/com/sun/tools/javac/jvm/Items.java src/share/classes/com/sun/tools/javac/jvm/LVTRanges.java src/share/classes/com/sun/tools/javac/tree/TreeMaker.java src/share/classes/com/sun/tools/javac/util/Bits.java test/tools/javac/flow/AliveRanges.java test/tools/javac/flow/LVTHarness.java test/tools/javac/flow/tests/TestCaseConditional.java test/tools/javac/flow/tests/TestCaseDoLoop.java test/tools/javac/flow/tests/TestCaseFor.java test/tools/javac/flow/tests/TestCaseForEach.java test/tools/javac/flow/tests/TestCaseIf.java test/tools/javac/flow/tests/TestCaseIfElse.java test/tools/javac/flow/tests/TestCaseSwitch.java test/tools/javac/flow/tests/TestCaseTry.java test/tools/javac/flow/tests/TestCaseWhile.java
diffstat 24 files changed, 1889 insertions(+), 379 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/code/Lint.java	Sat Sep 14 15:23:21 2013 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Lint.java	Sat Sep 14 19:04:47 2013 +0100
@@ -33,9 +33,6 @@
 import com.sun.tools.javac.util.Options;
 import com.sun.tools.javac.util.Pair;
 
-import static com.sun.tools.javac.code.Flags.*;
-
-
 /**
  * A class for handling -Xlint suboptions and @SuppresssWarnings.
  *
@@ -81,7 +78,6 @@
         return l;
     }
 
-
     private final AugmentVisitor augmentor;
 
     private final EnumSet<LintCategory> values;
@@ -90,7 +86,6 @@
     private static final Map<String, LintCategory> map =
             new java.util.concurrent.ConcurrentHashMap<String, LintCategory>(20);
 
-
     protected Lint(Context context) {
         // initialize values according to the lint options
         Options options = Options.instance(context);
--- a/src/share/classes/com/sun/tools/javac/comp/Flow.java	Sat Sep 14 15:23:21 2013 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Flow.java	Sat Sep 14 19:04:47 2013 +0100
@@ -207,7 +207,7 @@
 
     public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
         new AliveAnalyzer().analyzeTree(env, make);
-        new AssignAnalyzer().analyzeTree(env, make);
+        new AssignAnalyzer(log, syms, lint, names).analyzeTree(env);
         new FlowAnalyzer().analyzeTree(env, make);
         new CaptureAnalyzer().analyzeTree(env, make);
     }
@@ -239,7 +239,7 @@
         //related errors, which will allow for more errors to be detected
         Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
         try {
-            new AssignAnalyzer().analyzeTree(env, that, make);
+            new AssignAnalyzer(log, syms, lint, names).analyzeTree(env);
             LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer();
             flowAnalyzer.analyzeTree(env, that, make);
             return flowAnalyzer.inferredThrownTypes;
@@ -292,15 +292,6 @@
     }
 
     /**
-     * Utility method to reset several Bits instances.
-     */
-    private void resetBits(Bits... bits) {
-        for (Bits b : bits) {
-            b.reset();
-        }
-    }
-
-    /**
      * Base visitor class for all visitors implementing dataflow analysis logic.
      * This class define the shared logic for handling jumps (break/continue statements).
      */
@@ -347,17 +338,17 @@
                 this.tree = tree;
             }
 
-            void resolveJump() {
+            void resolveJump(JCTree tree) {
                 //do nothing
             }
         }
 
-        abstract void markDead();
+        abstract void markDead(JCTree tree);
 
         /** Record an outward transfer of control. */
         void recordExit(JCTree tree, P pe) {
             pendingExits.append(pe);
-            markDead();
+            markDead(tree);
         }
 
         /** Resolve all jumps of this statement. */
@@ -371,7 +362,7 @@
                 P exit = exits.head;
                 if (exit.tree.hasTag(jk.treeTag) &&
                         jk.getTarget(exit.tree) == tree) {
-                    exit.resolveJump();
+                    exit.resolveJump(tree);
                     resolved = true;
                 } else {
                     pendingExits.append(exit);
@@ -380,12 +371,12 @@
             return resolved;
         }
 
-        /** Resolve all breaks of this statement. */
+        /** Resolve all continues of this statement. */
         boolean resolveContinues(JCTree tree) {
             return resolveJump(tree, new ListBuffer<P>(), JumpKind.CONTINUE);
         }
 
-        /** Resolve all continues of this statement. */
+        /** Resolve all breaks of this statement. */
         boolean resolveBreaks(JCTree tree, ListBuffer<P> oldPendingExits) {
             return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
         }
@@ -414,7 +405,7 @@
         private boolean alive;
 
         @Override
-        void markDead() {
+        void markDead(JCTree tree) {
             alive = false;
         }
 
@@ -696,7 +687,7 @@
 
         public void visitThrow(JCThrow tree) {
             scan(tree.expr);
-            markDead();
+            markDead(tree);
         }
 
         public void visitApply(JCMethodInvocation tree) {
@@ -797,7 +788,7 @@
         }
 
         @Override
-        void markDead() {
+        void markDead(JCTree tree) {
             //do nothing
         }
 
@@ -1222,7 +1213,7 @@
             else {
                 markThrown(tree, tree.expr.type);
             }
-            markDead();
+            markDead(tree);
         }
 
         public void visitApply(JCMethodInvocation tree) {
@@ -1372,11 +1363,13 @@
      * depends on the results of the liveliness analyzer. This pass is also used to mark
      * effectively-final local variables/parameters.
      */
-    class AssignAnalyzer extends BaseAnalyzer<AssignAnalyzer.AssignPendingExit> {
+
+    public abstract static class AbstractAssignAnalyzer<P extends AbstractAssignAnalyzer.AbstractAssignPendingExit>
+        extends BaseAnalyzer<P> {
 
         /** The set of definitely assigned variables.
          */
-        final Bits inits;
+        protected final Bits inits;
 
         /** The set of definitely unassigned variables.
          */
@@ -1402,7 +1395,7 @@
 
         /** A mapping from addresses to variable symbols.
          */
-        JCVariableDecl[] vardecls;
+        protected JCVariableDecl[] vardecls;
 
         /** The current class being defined.
          */
@@ -1414,11 +1407,11 @@
 
         /** The next available variable sequence number.
          */
-        int nextadr;
+        protected int nextadr;
 
         /** The first variable sequence number in a block that can return.
          */
-        int returnadr;
+        protected int returnadr;
 
         /** The list of unreferenced automatic resources.
          */
@@ -1430,35 +1423,46 @@
         /** The starting position of the analysed tree */
         int startPos;
 
-        AssignAnalyzer() {
-            inits = new Bits();
+        final Symtab syms;
+
+        protected Names names;
+
+        public static class AbstractAssignPendingExit extends BaseAnalyzer.PendingExit {
+
+            final Bits inits;
+            final Bits uninits;
+            final Bits exit_inits = new Bits(true);
+            final Bits exit_uninits = new Bits(true);
+
+            public AbstractAssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
+                super(tree);
+                this.inits = inits;
+                this.uninits = uninits;
+                this.exit_inits.assign(inits);
+                this.exit_uninits.assign(uninits);
+            }
+
+            @Override
+            public void resolveJump(JCTree tree) {
+                inits.andSet(exit_inits);
+                uninits.andSet(exit_uninits);
+            }
+        }
+
+        public AbstractAssignAnalyzer(Bits inits, Symtab syms, Names names) {
+            this.inits = inits;
             uninits = new Bits();
             uninitsTry = new Bits();
             initsWhenTrue = new Bits(true);
             initsWhenFalse = new Bits(true);
             uninitsWhenTrue = new Bits(true);
             uninitsWhenFalse = new Bits(true);
-        }
-
-        class AssignPendingExit extends BaseAnalyzer.PendingExit {
-
-            final Bits exit_inits = new Bits(true);
-            final Bits exit_uninits = new Bits(true);
-
-            AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
-                super(tree);
-                this.exit_inits.assign(inits);
-                this.exit_uninits.assign(uninits);
-            }
-
-            void resolveJump() {
-                inits.andSet(exit_inits);
-                uninits.andSet(exit_uninits);
-            }
+            this.syms = syms;
+            this.names = names;
         }
 
         @Override
-        void markDead() {
+        protected void markDead(JCTree tree) {
             inits.inclRange(returnadr, nextadr);
             uninits.inclRange(returnadr, nextadr);
         }
@@ -1468,7 +1472,7 @@
         /** Do we need to track init/uninit state of this symbol?
          *  I.e. is symbol either a local or a blank final variable?
          */
-        boolean trackable(VarSymbol sym) {
+        protected boolean trackable(VarSymbol sym) {
             return
                 sym.pos >= startPos &&
                 ((sym.owner.kind == MTH ||
@@ -1488,44 +1492,35 @@
             }
             sym.adr = nextadr;
             vardecls[nextadr] = varDecl;
-            inits.excl(nextadr);
+            exclVarFromInits(varDecl, nextadr);
             uninits.incl(nextadr);
             nextadr++;
         }
 
+        protected void exclVarFromInits(JCTree tree, int adr) {
+            inits.excl(adr);
+        }
+
+        protected void assignToInits(JCTree tree, Bits bits) {
+            inits.assign(bits);
+        }
+
+        protected void andSetInits(JCTree tree, Bits bits) {
+            inits.andSet(bits);
+        }
+
+        protected void orSetInits(JCTree tree, Bits bits) {
+            inits.orSet(bits);
+        }
+
         /** Record an initialization of a trackable variable.
          */
         void letInit(DiagnosticPosition pos, VarSymbol sym) {
             if (sym.adr >= firstadr && trackable(sym)) {
-                if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {
-                    if (!uninits.isMember(sym.adr)) {
-                        //assignment targeting an effectively final variable
-                        //makes the variable lose its status of effectively final
-                        //if the variable is _not_ definitively unassigned
-                        sym.flags_field &= ~EFFECTIVELY_FINAL;
-                    } else {
-                        uninit(sym);
-                    }
-                }
-                else if ((sym.flags() & FINAL) != 0) {
-                    if ((sym.flags() & PARAMETER) != 0) {
-                        if ((sym.flags() & UNION) != 0) { //multi-catch parameter
-                            log.error(pos, "multicatch.parameter.may.not.be.assigned",
-                                      sym);
-                        }
-                        else {
-                            log.error(pos, "final.parameter.may.not.be.assigned",
-                                  sym);
-                        }
-                    } else if (!uninits.isMember(sym.adr)) {
-                        log.error(pos, flowKind.errKey, sym);
-                    } else {
-                        uninit(sym);
-                    }
+                if (uninits.isMember(sym.adr)) {
+                    uninit(sym);
                 }
                 inits.incl(sym.adr);
-            } else if ((sym.flags() & FINAL) != 0) {
-                log.error(pos, "var.might.already.be.assigned", sym);
             }
         }
         //where
@@ -1559,12 +1554,14 @@
         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
             checkInit(pos, sym, "var.might.not.have.been.initialized");
         }
-        void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {
-            if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
-                trackable(sym) &&
-                !inits.isMember(sym.adr)) {
-                log.error(pos, errkey, sym);
-                inits.incl(sym.adr);
+
+        void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {}
+
+        /** Utility method to reset several Bits instances.
+         */
+        private void resetBits(Bits... bits) {
+            for (Bits b : bits) {
+                b.reset();
             }
         }
 
@@ -1582,7 +1579,7 @@
 
         /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
          */
-        void merge() {
+        protected void merge(JCTree tree) {
             inits.assign(initsWhenFalse.andSet(initsWhenTrue));
             uninits.assign(uninitsWhenFalse.andSet(uninitsWhenTrue));
         }
@@ -1597,7 +1594,9 @@
         void scanExpr(JCTree tree) {
             if (tree != null) {
                 scan(tree);
-                if (inits.isReset()) merge();
+                if (inits.isReset()) {
+                    merge(tree);
+                }
             }
         }
 
@@ -1614,7 +1613,7 @@
          */
         void scanCond(JCTree tree) {
             if (tree.type.isFalse()) {
-                if (inits.isReset()) merge();
+                if (inits.isReset()) merge(tree);
                 initsWhenTrue.assign(inits);
                 initsWhenTrue.inclRange(firstadr, nextadr);
                 uninitsWhenTrue.assign(uninits);
@@ -1622,7 +1621,7 @@
                 initsWhenFalse.assign(inits);
                 uninitsWhenFalse.assign(uninits);
             } else if (tree.type.isTrue()) {
-                if (inits.isReset()) merge();
+                if (inits.isReset()) merge(tree);
                 initsWhenFalse.assign(inits);
                 initsWhenFalse.inclRange(firstadr, nextadr);
                 uninitsWhenFalse.assign(uninits);
@@ -1641,22 +1640,22 @@
 
         /* ------------ Visitor methods for various sorts of trees -------------*/
 
+        @Override
         public void visitClassDef(JCClassDecl tree) {
-            if (tree.sym == null) return;
+            if (tree.sym == null) {
+                return;
+            }
 
             JCClassDecl classDefPrev = classDef;
             int firstadrPrev = firstadr;
             int nextadrPrev = nextadr;
-            ListBuffer<AssignPendingExit> pendingExitsPrev = pendingExits;
-            Lint lintPrev = lint;
+            ListBuffer<P> pendingExitsPrev = pendingExits;
 
-            pendingExits = new ListBuffer<AssignPendingExit>();
+            pendingExits = new ListBuffer<P>();
             if (tree.name != names.empty) {
                 firstadr = nextadr;
             }
             classDef = tree;
-            lint = lint.augment(tree.sym);
-
             try {
                 // define all the static fields
                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
@@ -1664,8 +1663,9 @@
                         JCVariableDecl def = (JCVariableDecl)l.head;
                         if ((def.mods.flags & STATIC) != 0) {
                             VarSymbol sym = def.sym;
-                            if (trackable(sym))
+                            if (trackable(sym)) {
                                 newVar(def);
+                            }
                         }
                     }
                 }
@@ -1684,8 +1684,9 @@
                         JCVariableDecl def = (JCVariableDecl)l.head;
                         if ((def.mods.flags & STATIC) == 0) {
                             VarSymbol sym = def.sym;
-                            if (trackable(sym))
+                            if (trackable(sym)) {
                                 newVar(def);
+                            }
                         }
                     }
                 }
@@ -1709,21 +1710,25 @@
                 nextadr = nextadrPrev;
                 firstadr = firstadrPrev;
                 classDef = classDefPrev;
-                lint = lintPrev;
             }
         }
 
+        @Override
         public void visitMethodDef(JCMethodDecl tree) {
-            if (tree.body == null) return;
+            if (tree.body == null) {
+                return;
+            }
+            /*  MemberEnter can generate synthetic methods, ignore them
+             */
+            if ((tree.sym.flags() & SYNTHETIC) != 0) {
+                return;
+            }
 
             final Bits initsPrev = new Bits(inits);
             final Bits uninitsPrev = new Bits(uninits);
             int nextadrPrev = nextadr;
             int firstadrPrev = firstadr;
             int returnadrPrev = returnadr;
-            Lint lintPrev = lint;
-
-            lint = lint.augment(tree.sym);
 
             Assert.check(pendingExits.isEmpty());
 
@@ -1731,13 +1736,17 @@
                 boolean isInitialConstructor =
                     TreeInfo.isInitialConstructor(tree);
 
-                if (!isInitialConstructor)
+                if (!isInitialConstructor) {
                     firstadr = nextadr;
+                }
                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
                     JCVariableDecl def = l.head;
                     scan(def);
-                    inits.incl(def.sym.adr);
-                    uninits.excl(def.sym.adr);
+                    Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
+                    /*  If we are executing the code from Gen, then there can be
+                     *  synthetic or mandated variables, ignore them.
+                     */
+                    initParam(def);
                 }
                 // else we are in an instance initializer block;
                 // leave caught unchanged.
@@ -1761,39 +1770,42 @@
                         }
                     }
                 }
-                List<AssignPendingExit> exits = pendingExits.toList();
-                pendingExits = new ListBuffer<AssignPendingExit>();
+                List<P> exits = pendingExits.toList();
+                pendingExits = new ListBuffer<>();
                 while (exits.nonEmpty()) {
-                    AssignPendingExit exit = exits.head;
+                    P exit = exits.head;
                     exits = exits.tail;
                     Assert.check(exit.tree.hasTag(RETURN), exit.tree);
                     if (isInitialConstructor) {
-                        inits.assign(exit.exit_inits);
-                        for (int i = firstadr; i < nextadr; i++)
+                        assignToInits(exit.tree, exit.exit_inits);
+                        for (int i = firstadr; i < nextadr; i++) {
                             checkInit(exit.tree.pos(), vardecls[i].sym);
+                        }
                     }
                 }
             } finally {
-                inits.assign(initsPrev);
+                assignToInits(tree, initsPrev);
                 uninits.assign(uninitsPrev);
                 nextadr = nextadrPrev;
                 firstadr = firstadrPrev;
                 returnadr = returnadrPrev;
-                lint = lintPrev;
             }
         }
 
+        protected void initParam(JCVariableDecl def) {
+            inits.incl(def.sym.adr);
+            uninits.excl(def.sym.adr);
+        }
+
         public void visitVarDef(JCVariableDecl tree) {
             boolean track = trackable(tree.sym);
-            if (track && tree.sym.owner.kind == MTH) newVar(tree);
+            if (track && tree.sym.owner.kind == MTH) {
+                newVar(tree);
+            }
             if (tree.init != null) {
-                Lint lintPrev = lint;
-                lint = lint.augment(tree.sym);
-                try{
-                    scanExpr(tree.init);
-                    if (track) letInit(tree.pos(), tree.sym);
-                } finally {
-                    lint = lintPrev;
+                scanExpr(tree.init);
+                if (track) {
+                    letInit(tree.pos(), tree.sym);
                 }
             }
         }
@@ -1804,14 +1816,18 @@
             nextadr = nextadrPrev;
         }
 
+        int getLogNumberOfErrors() {
+            return 0;
+        }
+
         public void visitDoLoop(JCDoWhileLoop tree) {
-            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
+            ListBuffer<P> prevPendingExits = pendingExits;
             FlowKind prevFlowKind = flowKind;
             flowKind = FlowKind.NORMAL;
             final Bits initsSkip = new Bits(true);
             final Bits uninitsSkip = new Bits(true);
-            pendingExits = new ListBuffer<AssignPendingExit>();
-            int prevErrors = log.nerrors;
+            pendingExits = new ListBuffer<P>();
+            int prevErrors = getLogNumberOfErrors();
             do {
                 final Bits uninitsEntry = new Bits(uninits);
                 uninitsEntry.excludeFrom(nextadr);
@@ -1822,28 +1838,28 @@
                     initsSkip.assign(initsWhenFalse);
                     uninitsSkip.assign(uninitsWhenFalse);
                 }
-                if (log.nerrors !=  prevErrors ||
+                if (getLogNumberOfErrors() !=  prevErrors ||
                     flowKind.isFinal() ||
                     new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
                     break;
-                inits.assign(initsWhenTrue);
+                assignToInits(tree.cond, initsWhenTrue);
                 uninits.assign(uninitsEntry.andSet(uninitsWhenTrue));
                 flowKind = FlowKind.SPECULATIVE_LOOP;
             } while (true);
             flowKind = prevFlowKind;
-            inits.assign(initsSkip);
+            assignToInits(tree, initsSkip);
             uninits.assign(uninitsSkip);
             resolveBreaks(tree, prevPendingExits);
         }
 
         public void visitWhileLoop(JCWhileLoop tree) {
-            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
+            ListBuffer<P> prevPendingExits = pendingExits;
             FlowKind prevFlowKind = flowKind;
             flowKind = FlowKind.NORMAL;
             final Bits initsSkip = new Bits(true);
             final Bits uninitsSkip = new Bits(true);
-            pendingExits = new ListBuffer<AssignPendingExit>();
-            int prevErrors = log.nerrors;
+            pendingExits = new ListBuffer<>();
+            int prevErrors = getLogNumberOfErrors();
             final Bits uninitsEntry = new Bits(uninits);
             uninitsEntry.excludeFrom(nextadr);
             do {
@@ -1852,35 +1868,36 @@
                     initsSkip.assign(initsWhenFalse) ;
                     uninitsSkip.assign(uninitsWhenFalse);
                 }
-                inits.assign(initsWhenTrue);
+                assignToInits(tree, initsWhenTrue);
                 uninits.assign(uninitsWhenTrue);
                 scan(tree.body);
                 resolveContinues(tree);
-                if (log.nerrors != prevErrors ||
+                if (getLogNumberOfErrors() != prevErrors ||
                     flowKind.isFinal() ||
-                    new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
+                    new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) {
                     break;
+                }
                 uninits.assign(uninitsEntry.andSet(uninits));
                 flowKind = FlowKind.SPECULATIVE_LOOP;
             } while (true);
             flowKind = prevFlowKind;
             //a variable is DA/DU after the while statement, if it's DA/DU assuming the
             //branch is not taken AND if it's DA/DU before any break statement
-            inits.assign(initsSkip);
+            assignToInits(tree.body, initsSkip);
             uninits.assign(uninitsSkip);
             resolveBreaks(tree, prevPendingExits);
         }
 
         public void visitForLoop(JCForLoop tree) {
-            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
+            ListBuffer<P> prevPendingExits = pendingExits;
             FlowKind prevFlowKind = flowKind;
             flowKind = FlowKind.NORMAL;
             int nextadrPrev = nextadr;
             scan(tree.init);
             final Bits initsSkip = new Bits(true);
             final Bits uninitsSkip = new Bits(true);
-            pendingExits = new ListBuffer<AssignPendingExit>();
-            int prevErrors = log.nerrors;
+            pendingExits = new ListBuffer<P>();
+            int prevErrors = getLogNumberOfErrors();
             do {
                 final Bits uninitsEntry = new Bits(uninits);
                 uninitsEntry.excludeFrom(nextadr);
@@ -1890,7 +1907,7 @@
                         initsSkip.assign(initsWhenFalse);
                         uninitsSkip.assign(uninitsWhenFalse);
                     }
-                    inits.assign(initsWhenTrue);
+                    assignToInits(tree.body, initsWhenTrue);
                     uninits.assign(uninitsWhenTrue);
                 } else if (!flowKind.isFinal()) {
                     initsSkip.assign(inits);
@@ -1901,7 +1918,7 @@
                 scan(tree.body);
                 resolveContinues(tree);
                 scan(tree.step);
-                if (log.nerrors != prevErrors ||
+                if (getLogNumberOfErrors() != prevErrors ||
                     flowKind.isFinal() ||
                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
                     break;
@@ -1911,7 +1928,7 @@
             flowKind = prevFlowKind;
             //a variable is DA/DU after a for loop, if it's DA/DU assuming the
             //branch is not taken AND if it's DA/DU before any break statement
-            inits.assign(initsSkip);
+            assignToInits(tree.body, initsSkip);
             uninits.assign(uninitsSkip);
             resolveBreaks(tree, prevPendingExits);
             nextadr = nextadrPrev;
@@ -1920,7 +1937,7 @@
         public void visitForeachLoop(JCEnhancedForLoop tree) {
             visitVarDef(tree.var);
 
-            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
+            ListBuffer<P> prevPendingExits = pendingExits;
             FlowKind prevFlowKind = flowKind;
             flowKind = FlowKind.NORMAL;
             int nextadrPrev = nextadr;
@@ -1929,14 +1946,14 @@
             final Bits uninitsStart = new Bits(uninits);
 
             letInit(tree.pos(), tree.var.sym);
-            pendingExits = new ListBuffer<AssignPendingExit>();
-            int prevErrors = log.nerrors;
+            pendingExits = new ListBuffer<P>();
+            int prevErrors = getLogNumberOfErrors();
             do {
                 final Bits uninitsEntry = new Bits(uninits);
                 uninitsEntry.excludeFrom(nextadr);
                 scan(tree.body);
                 resolveContinues(tree);
-                if (log.nerrors != prevErrors ||
+                if (getLogNumberOfErrors() != prevErrors ||
                     flowKind.isFinal() ||
                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
                     break;
@@ -1944,41 +1961,50 @@
                 flowKind = FlowKind.SPECULATIVE_LOOP;
             } while (true);
             flowKind = prevFlowKind;
-            inits.assign(initsStart);
+            assignToInits(tree.body, initsStart);
             uninits.assign(uninitsStart.andSet(uninits));
             resolveBreaks(tree, prevPendingExits);
             nextadr = nextadrPrev;
         }
 
         public void visitLabelled(JCLabeledStatement tree) {
-            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
-            pendingExits = new ListBuffer<AssignPendingExit>();
+            ListBuffer<P> prevPendingExits = pendingExits;
+            pendingExits = new ListBuffer<P>();
             scan(tree.body);
             resolveBreaks(tree, prevPendingExits);
         }
 
         public void visitSwitch(JCSwitch tree) {
-            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
-            pendingExits = new ListBuffer<AssignPendingExit>();
+            ListBuffer<P> prevPendingExits = pendingExits;
+            pendingExits = new ListBuffer<>();
             int nextadrPrev = nextadr;
             scanExpr(tree.selector);
             final Bits initsSwitch = new Bits(inits);
             final Bits uninitsSwitch = new Bits(uninits);
             boolean hasDefault = false;
             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
-                inits.assign(initsSwitch);
+                assignToInits(l.head, initsSwitch);
                 uninits.assign(uninits.andSet(uninitsSwitch));
                 JCCase c = l.head;
-                if (c.pat == null)
+                if (c.pat == null) {
                     hasDefault = true;
-                else
+                } else {
                     scanExpr(c.pat);
+                }
+                if (hasDefault) {
+                    assignToInits(null, initsSwitch);
+                    uninits.assign(uninits.andSet(uninitsSwitch));
+                }
                 scan(c.stats);
                 addVars(c.stats, initsSwitch, uninitsSwitch);
+                if (!hasDefault) {
+                    assignToInits(l.head.stats.last(), initsSwitch);
+                    uninits.assign(uninits.andSet(uninitsSwitch));
+                }
                 // Warn about fall-through if lint switch fallthrough enabled.
             }
             if (!hasDefault) {
-                inits.andSet(initsSwitch);
+                andSetInits(null, initsSwitch);
             }
             resolveBreaks(tree, prevPendingExits);
             nextadr = nextadrPrev;
@@ -1997,11 +2023,17 @@
                 }
             }
 
+        boolean isEnabled(Lint.LintCategory lc) {
+            return false;
+        }
+
+        void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos, String key, Object ... args) {}
+
         public void visitTry(JCTry tree) {
             ListBuffer<JCVariableDecl> resourceVarDecls = ListBuffer.lb();
             final Bits uninitsTryPrev = new Bits(uninitsTry);
-            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
-            pendingExits = new ListBuffer<AssignPendingExit>();
+            ListBuffer<P> prevPendingExits = pendingExits;
+            pendingExits = new ListBuffer<>();
             final Bits initsTry = new Bits(inits);
             uninitsTry.assign(uninits);
             for (JCTree resource : tree.resources) {
@@ -2023,10 +2055,10 @@
             int nextadrCatch = nextadr;
 
             if (!resourceVarDecls.isEmpty() &&
-                    lint.isEnabled(Lint.LintCategory.TRY)) {
+                    isEnabled(Lint.LintCategory.TRY)) {
                 for (JCVariableDecl resVar : resourceVarDecls) {
                     if (unrefdResources.includes(resVar.sym)) {
-                        log.warning(Lint.LintCategory.TRY, resVar.pos(),
+                        reportWarning(Lint.LintCategory.TRY, resVar.pos(),
                                     "try.resource.not.referenced", resVar.sym);
                         unrefdResources.remove(resVar.sym);
                     }
@@ -2042,20 +2074,22 @@
 
             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
                 JCVariableDecl param = l.head.param;
-                inits.assign(initsCatchPrev);
+                assignToInits(tree.body, initsCatchPrev);
                 uninits.assign(uninitsCatchPrev);
                 scan(param);
-                inits.incl(param.sym.adr);
-                uninits.excl(param.sym.adr);
+                /* If this is a TWR and we are executing the code from Gen,
+                 * then there can be synthetic variables, ignore them.
+                 */
+                initParam(param);
                 scan(l.head.body);
                 initsEnd.andSet(inits);
                 uninitsEnd.andSet(uninits);
                 nextadr = nextadrCatch;
             }
             if (tree.finalizer != null) {
-                inits.assign(initsTry);
+                assignToInits(tree.finalizer, initsTry);
                 uninits.assign(uninitsTry);
-                ListBuffer<AssignPendingExit> exits = pendingExits;
+                ListBuffer<P> exits = pendingExits;
                 pendingExits = prevPendingExits;
                 scan(tree.finalizer);
                 if (!tree.finallyCanCompleteNormally) {
@@ -2065,19 +2099,19 @@
                     // FIX: this doesn't preserve source order of exits in catch
                     // versus finally!
                     while (exits.nonEmpty()) {
-                        AssignPendingExit exit = exits.next();
+                        P exit = exits.next();
                         if (exit.exit_inits != null) {
                             exit.exit_inits.orSet(inits);
                             exit.exit_uninits.andSet(uninits);
                         }
                         pendingExits.append(exit);
                     }
-                    inits.orSet(initsEnd);
+                    orSetInits(tree, initsEnd);
                 }
             } else {
-                inits.assign(initsEnd);
+                assignToInits(tree, initsEnd);
                 uninits.assign(uninitsEnd);
-                ListBuffer<AssignPendingExit> exits = pendingExits;
+                ListBuffer<P> exits = pendingExits;
                 pendingExits = prevPendingExits;
                 while (exits.nonEmpty()) pendingExits.append(exits.next());
             }
@@ -2088,7 +2122,7 @@
             scanCond(tree.cond);
             final Bits initsBeforeElse = new Bits(initsWhenFalse);
             final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
-            inits.assign(initsWhenTrue);
+            assignToInits(tree.cond, initsWhenTrue);
             uninits.assign(uninitsWhenTrue);
             if (tree.truepart.type.hasTag(BOOLEAN) &&
                 tree.falsepart.type.hasTag(BOOLEAN)) {
@@ -2101,7 +2135,7 @@
                 final Bits initsAfterThenWhenFalse = new Bits(initsWhenFalse);
                 final Bits uninitsAfterThenWhenTrue = new Bits(uninitsWhenTrue);
                 final Bits uninitsAfterThenWhenFalse = new Bits(uninitsWhenFalse);
-                inits.assign(initsBeforeElse);
+                assignToInits(tree.truepart, initsBeforeElse);
                 uninits.assign(uninitsBeforeElse);
                 scanCond(tree.falsepart);
                 initsWhenTrue.andSet(initsAfterThenWhenTrue);
@@ -2112,10 +2146,10 @@
                 scanExpr(tree.truepart);
                 final Bits initsAfterThen = new Bits(inits);
                 final Bits uninitsAfterThen = new Bits(uninits);
-                inits.assign(initsBeforeElse);
+                assignToInits(tree.truepart, initsBeforeElse);
                 uninits.assign(uninitsBeforeElse);
                 scanExpr(tree.falsepart);
-                inits.andSet(initsAfterThen);
+                andSetInits(tree.falsepart, initsAfterThen);
                 uninits.andSet(uninitsAfterThen);
             }
         }
@@ -2124,39 +2158,46 @@
             scanCond(tree.cond);
             final Bits initsBeforeElse = new Bits(initsWhenFalse);
             final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
-            inits.assign(initsWhenTrue);
+            assignToInits(tree.cond, initsWhenTrue);
             uninits.assign(uninitsWhenTrue);
             scan(tree.thenpart);
             if (tree.elsepart != null) {
                 final Bits initsAfterThen = new Bits(inits);
                 final Bits uninitsAfterThen = new Bits(uninits);
-                inits.assign(initsBeforeElse);
+                assignToInits(tree.thenpart, initsBeforeElse);
                 uninits.assign(uninitsBeforeElse);
                 scan(tree.elsepart);
-                inits.andSet(initsAfterThen);
+                andSetInits(tree.elsepart, initsAfterThen);
                 uninits.andSet(uninitsAfterThen);
             } else {
-                inits.andSet(initsBeforeElse);
+                andSetInits(tree.thenpart, initsBeforeElse);
                 uninits.andSet(uninitsBeforeElse);
             }
         }
 
-        public void visitBreak(JCBreak tree) {
-            recordExit(tree, new AssignPendingExit(tree, inits, uninits));
+        protected P createNewPendingExit(JCTree tree, Bits inits, Bits uninits) {
+            return null;
         }
 
-        public void visitContinue(JCContinue tree) {
-            recordExit(tree, new AssignPendingExit(tree, inits, uninits));
+        @Override
+        public void visitBreak(JCBreak tree) {
+            recordExit(tree, createNewPendingExit(tree, inits, uninits));
         }
 
+        @Override
+        public void visitContinue(JCContinue tree) {
+            recordExit(tree, createNewPendingExit(tree, inits, uninits));
+        }
+
+        @Override
         public void visitReturn(JCReturn tree) {
             scanExpr(tree.expr);
-            recordExit(tree, new AssignPendingExit(tree, inits, uninits));
+            recordExit(tree, createNewPendingExit(tree, inits, uninits));
         }
 
         public void visitThrow(JCThrow tree) {
             scanExpr(tree.expr);
-            markDead();
+            markDead(tree.expr);
         }
 
         public void visitApply(JCMethodInvocation tree) {
@@ -2175,10 +2216,10 @@
             final Bits prevUninits = new Bits(uninits);
             final Bits prevInits = new Bits(inits);
             int returnadrPrev = returnadr;
-            ListBuffer<AssignPendingExit> prevPending = pendingExits;
+            ListBuffer<P> prevPending = pendingExits;
             try {
                 returnadr = nextadr;
-                pendingExits = new ListBuffer<AssignPendingExit>();
+                pendingExits = new ListBuffer<P>();
                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
                     JCVariableDecl def = l.head;
                     scan(def);
@@ -2194,7 +2235,7 @@
             finally {
                 returnadr = returnadrPrev;
                 uninits.assign(prevUninits);
-                inits.assign(prevInits);
+                assignToInits(tree, prevInits);
                 pendingExits = prevPending;
             }
         }
@@ -2210,11 +2251,11 @@
             scanCond(tree.cond);
             uninitsExit.andSet(uninitsWhenTrue);
             if (tree.detail != null) {
-                inits.assign(initsWhenFalse);
+                assignToInits(tree, initsWhenFalse);
                 uninits.assign(uninitsWhenFalse);
                 scanExpr(tree.detail);
             }
-            inits.assign(initsExit);
+            assignToInits(tree, initsExit);
             uninits.assign(uninitsExit);
         }
 
@@ -2260,7 +2301,7 @@
                 scanCond(tree.lhs);
                 final Bits initsWhenFalseLeft = new Bits(initsWhenFalse);
                 final Bits uninitsWhenFalseLeft = new Bits(uninitsWhenFalse);
-                inits.assign(initsWhenTrue);
+                assignToInits(tree.lhs, initsWhenTrue);
                 uninits.assign(uninitsWhenTrue);
                 scanCond(tree.rhs);
                 initsWhenFalse.andSet(initsWhenFalseLeft);
@@ -2270,7 +2311,7 @@
                 scanCond(tree.lhs);
                 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
                 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
-                inits.assign(initsWhenFalse);
+                assignToInits(tree.lhs, initsWhenFalse);
                 uninits.assign(uninitsWhenFalse);
                 scanCond(tree.rhs);
                 initsWhenTrue.andSet(initsWhenTrueLeft);
@@ -2308,14 +2349,12 @@
 
         /** Perform definite assignment/unassignment analysis on a tree.
          */
-        public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
-            analyzeTree(env, env.tree, make);
-        }
+        public void analyzeTree(Env<?> env) {
+            analyzeTree(env, env.tree);
+         }
 
-        public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
+        public void analyzeTree(Env<?> env, JCTree tree) {
             try {
-                attrEnv = env;
-                Flow.this.make = make;
                 startPos = tree.pos().getStartPosition();
 
                 if (vardecls == null)
@@ -2325,7 +2364,7 @@
                         vardecls[i] = null;
                 firstadr = 0;
                 nextadr = 0;
-                pendingExits = new ListBuffer<AssignPendingExit>();
+                pendingExits = new ListBuffer<>();
                 this.classDef = null;
                 unrefdResources = new Scope(env.enclClass.sym);
                 scan(tree);
@@ -2334,18 +2373,160 @@
                 startPos = -1;
                 resetBits(inits, uninits, uninitsTry, initsWhenTrue,
                         initsWhenFalse, uninitsWhenTrue, uninitsWhenFalse);
-                if (vardecls != null) for (int i=0; i<vardecls.length; i++)
-                    vardecls[i] = null;
+                if (vardecls != null) {
+                    for (int i=0; i<vardecls.length; i++)
+                        vardecls[i] = null;
+                }
                 firstadr = 0;
                 nextadr = 0;
                 pendingExits = null;
-                Flow.this.make = null;
                 this.classDef = null;
                 unrefdResources = null;
             }
         }
     }
 
+    public static class AssignAnalyzer
+        extends AbstractAssignAnalyzer<AssignAnalyzer.AssignPendingExit> {
+
+        Log log;
+        Lint lint;
+
+        public static class AssignPendingExit
+            extends AbstractAssignAnalyzer.AbstractAssignPendingExit {
+
+            public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
+                super(tree, inits, uninits);
+            }
+        }
+
+        public AssignAnalyzer(Log log, Symtab syms, Lint lint, Names names) {
+            super(new Bits(), syms, names);
+            this.log = log;
+            this.lint = lint;
+        }
+
+        @Override
+        protected AssignPendingExit createNewPendingExit(JCTree tree,
+            Bits inits, Bits uninits) {
+            return new AssignPendingExit(tree, inits, uninits);
+        }
+
+        /** Record an initialization of a trackable variable.
+         */
+        @Override
+        void letInit(DiagnosticPosition pos, VarSymbol sym) {
+            if (sym.adr >= firstadr && trackable(sym)) {
+                if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {
+                    if (!uninits.isMember(sym.adr)) {
+                        //assignment targeting an effectively final variable
+                        //makes the variable lose its status of effectively final
+                        //if the variable is _not_ definitively unassigned
+                        sym.flags_field &= ~EFFECTIVELY_FINAL;
+                    } else {
+                        uninit(sym);
+                    }
+                }
+                else if ((sym.flags() & FINAL) != 0) {
+                    if ((sym.flags() & PARAMETER) != 0) {
+                        if ((sym.flags() & UNION) != 0) { //multi-catch parameter
+                            log.error(pos, "multicatch.parameter.may.not.be.assigned", sym);
+                        }
+                        else {
+                            log.error(pos, "final.parameter.may.not.be.assigned",
+                                  sym);
+                        }
+                    } else if (!uninits.isMember(sym.adr)) {
+                        log.error(pos, flowKind.errKey, sym);
+                    } else {
+                        uninit(sym);
+                    }
+                }
+                inits.incl(sym.adr);
+            } else if ((sym.flags() & FINAL) != 0) {
+                log.error(pos, "var.might.already.be.assigned", sym);
+            }
+        }
+
+        @Override
+        void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {
+            if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
+                trackable(sym) &&
+                !inits.isMember(sym.adr)) {
+                log.error(pos, errkey, sym);
+                inits.incl(sym.adr);
+            }
+        }
+
+        @Override
+        void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos,
+            String key, Object ... args) {
+            log.warning(lc, pos, key, args);
+        }
+
+        @Override
+        int getLogNumberOfErrors() {
+            return log.nerrors;
+        }
+
+        @Override
+        boolean isEnabled(Lint.LintCategory lc) {
+            return lint.isEnabled(lc);
+        }
+
+        @Override
+        public void visitClassDef(JCClassDecl tree) {
+            if (tree.sym == null) {
+                return;
+            }
+
+            Lint lintPrev = lint;
+            lint = lint.augment(tree.sym);
+            try {
+                super.visitClassDef(tree);
+            } finally {
+                lint = lintPrev;
+            }
+        }
+
+        @Override
+        public void visitMethodDef(JCMethodDecl tree) {
+            if (tree.body == null) {
+                return;
+            }
+
+            /*  MemberEnter can generate synthetic methods ignore them
+             */
+            if ((tree.sym.flags() & SYNTHETIC) != 0) {
+                return;
+            }
+
+            Lint lintPrev = lint;
+            lint = lint.augment(tree.sym);
+            try {
+                super.visitMethodDef(tree);
+            } finally {
+                lint = lintPrev;
+            }
+        }
+
+        @Override
+        public void visitVarDef(JCVariableDecl tree) {
+            if (tree.init == null) {
+                super.visitVarDef(tree);
+            } else {
+                Lint lintPrev = lint;
+                lint = lint.augment(tree.sym);
+                try{
+                    super.visitVarDef(tree);
+                } finally {
+                    lint = lintPrev;
+                }
+            }
+        }
+
+    }
+
     /**
      * This pass implements the last step of the dataflow analysis, namely
      * the effectively-final analysis check. This checks that every local variable
@@ -2358,7 +2539,7 @@
         JCTree currentTree; //local class or lambda
 
         @Override
-        void markDead() {
+        void markDead(JCTree tree) {
             //do nothing
         }
 
--- a/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Sat Sep 14 15:23:21 2013 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Sat Sep 14 19:04:47 2013 +0100
@@ -1745,6 +1745,11 @@
                         // Just erase the type var
                         ret = new VarSymbol(sym.flags(), name,
                                 types.erasure(sym.type), sym.owner);
+
+                        /* this information should also be kept for LVT generation at Gen
+                         * a Symbol with pos < startPos won't be tracked.
+                         */
+                        ((VarSymbol)ret).pos = ((VarSymbol)sym).pos;
                         break;
                     case CAPTURED_VAR:
                         ret = new VarSymbol(SYNTHETIC | FINAL, name, types.erasure(sym.type), translatedSym) {
--- a/src/share/classes/com/sun/tools/javac/comp/Lower.java	Sat Sep 14 15:23:21 2013 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Lower.java	Sat Sep 14 19:04:47 2013 +0100
@@ -1479,7 +1479,12 @@
      *  @param owner      The class in which the definitions go.
      */
     List<JCVariableDecl> freevarDefs(int pos, List<VarSymbol> freevars, Symbol owner) {
-        long flags = FINAL | SYNTHETIC;
+        return freevarDefs(pos, freevars, owner, 0);
+    }
+
+    List<JCVariableDecl> freevarDefs(int pos, List<VarSymbol> freevars, Symbol owner,
+            long additionalFlags) {
+        long flags = FINAL | SYNTHETIC | additionalFlags;
         if (owner.kind == TYP &&
             target.usePrivateSyntheticFields())
             flags |= PRIVATE;
@@ -1542,7 +1547,7 @@
             (owner.isConstructor() && c.isInner() &&
              !c.isPrivate() && !c.isStatic());
         long flags =
-            FINAL | (isMandated ? MANDATED : SYNTHETIC);
+            FINAL | (isMandated ? MANDATED : SYNTHETIC) | PARAMETER;
         VarSymbol outerThis = makeOuterThisVarSymbol(owner, flags);
         owner.extraParams = owner.extraParams.prepend(outerThis);
         return makeOuterThisVarDecl(pos, outerThis);
@@ -1626,7 +1631,8 @@
     JCTree makeTwrTry(JCTry tree) {
         make_at(tree.pos());
         twrVars = twrVars.dup();
-        JCBlock twrBlock = makeTwrBlock(tree.resources, tree.body, 0);
+        JCBlock twrBlock = makeTwrBlock(tree.resources, tree.body,
+                tree.finallyCanCompleteNormally, 0);
         if (tree.catchers.isEmpty() && tree.finalizer == null)
             result = translate(twrBlock);
         else
@@ -1635,7 +1641,8 @@
         return result;
     }
 
-    private JCBlock makeTwrBlock(List<JCTree> resources, JCBlock block, int depth) {
+    private JCBlock makeTwrBlock(List<JCTree> resources, JCBlock block,
+            boolean finallyCanCompleteNormally, int depth) {
         if (resources.isEmpty())
             return block;
 
@@ -1691,17 +1698,20 @@
         make.at(TreeInfo.endPos(block));
         JCBlock finallyClause = makeTwrFinallyClause(primaryException, expr);
         make.at(oldPos);
-        JCTry outerTry = make.Try(makeTwrBlock(resources.tail, block, depth + 1),
+        JCTry outerTry = make.Try(makeTwrBlock(resources.tail, block,
+                                    finallyCanCompleteNormally, depth + 1),
                                   List.<JCCatch>of(catchClause),
                                   finallyClause);
+        outerTry.finallyCanCompleteNormally = finallyCanCompleteNormally;
         stats.add(outerTry);
-        return make.Block(0L, stats.toList());
+        JCBlock newBlock = make.Block(0L, stats.toList());
+        return newBlock;
     }
 
     private JCBlock makeTwrFinallyClause(Symbol primaryException, JCExpression resource) {
         // primaryException.addSuppressed(catchException);
         VarSymbol catchException =
-            new VarSymbol(0, make.paramName(2),
+            new VarSymbol(SYNTHETIC, make.paramName(2),
                           syms.throwableType,
                           currentMethodSym);
         JCStatement addSuppressionStatement =
@@ -1716,6 +1726,7 @@
         JCBlock catchBlock = make.Block(0L, List.<JCStatement>of(addSuppressionStatement));
         List<JCCatch> catchClauses = List.<JCCatch>of(make.Catch(catchExceptionDecl, catchBlock));
         JCTry tryTree = make.Try(tryBlock, catchClauses, null);
+        tryTree.finallyCanCompleteNormally = true;
 
         // if (primaryException != null) {try...} else resourceClose;
         JCIf closeIfStatement = make.If(makeNonNullCheck(make.Ident(primaryException)),
@@ -2016,7 +2027,7 @@
 
         // catchParam := ClassNotFoundException e1
         VarSymbol catchParam =
-            new VarSymbol(0, make.paramName(1),
+            new VarSymbol(SYNTHETIC, make.paramName(1),
                           syms.classNotFoundExceptionType,
                           classDollarSym);
 
@@ -2704,7 +2715,7 @@
             JCVariableDecl otdef = null;
             if (currentClass.hasOuterInstance())
                 otdef = outerThisDef(tree.pos, m);
-            List<JCVariableDecl> fvdefs = freevarDefs(tree.pos, fvs, m);
+            List<JCVariableDecl> fvdefs = freevarDefs(tree.pos, fvs, m, PARAMETER);
 
             // Recursively translate result type, parameters and thrown list.
             tree.restype = translate(tree.restype);
@@ -3363,18 +3374,18 @@
          */
         private void visitArrayForeachLoop(JCEnhancedForLoop tree) {
             make_at(tree.expr.pos());
-            VarSymbol arraycache = new VarSymbol(0,
+            VarSymbol arraycache = new VarSymbol(SYNTHETIC,
                                                  names.fromString("arr" + target.syntheticNameChar()),
                                                  tree.expr.type,
                                                  currentMethodSym);
             JCStatement arraycachedef = make.VarDef(arraycache, tree.expr);
-            VarSymbol lencache = new VarSymbol(0,
+            VarSymbol lencache = new VarSymbol(SYNTHETIC,
                                                names.fromString("len" + target.syntheticNameChar()),
                                                syms.intType,
                                                currentMethodSym);
             JCStatement lencachedef = make.
                 VarDef(lencache, make.Select(make.Ident(arraycache), syms.lengthVar));
-            VarSymbol index = new VarSymbol(0,
+            VarSymbol index = new VarSymbol(SYNTHETIC,
                                             names.fromString("i" + target.syntheticNameChar()),
                                             syms.intType,
                                             currentMethodSym);
@@ -3456,7 +3467,7 @@
                                            names.iterator,
                                            eType,
                                            List.<Type>nil());
-            VarSymbol itvar = new VarSymbol(0, names.fromString("i" + target.syntheticNameChar()),
+            VarSymbol itvar = new VarSymbol(SYNTHETIC, names.fromString("i" + target.syntheticNameChar()),
                                             types.erasure(types.asSuper(iterator.type.getReturnType(), syms.iteratorType.tsym)),
                                             currentMethodSym);
 
--- a/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Sat Sep 14 15:23:21 2013 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Sat Sep 14 19:04:47 2013 +0100
@@ -1532,7 +1532,7 @@
              *  parameters from baseInit.
              */
             initParams = List.nil();
-            VarSymbol param = new VarSymbol(0, make.paramName(0), argtypes.head, init);
+            VarSymbol param = new VarSymbol(PARAMETER, make.paramName(0), argtypes.head, init);
             initParams = initParams.append(param);
             argTypesList = argTypesList.tail;
         }
@@ -1541,7 +1541,7 @@
             initParams = (initParams == null) ? List.<VarSymbol>nil() : initParams;
             List<VarSymbol> baseInitParams = baseInit.params;
             while (baseInitParams.nonEmpty() && argTypesList.nonEmpty()) {
-                VarSymbol param = new VarSymbol(baseInitParams.head.flags(),
+                VarSymbol param = new VarSymbol(baseInitParams.head.flags() | PARAMETER,
                         baseInitParams.head.name, argTypesList.head, init);
                 initParams = initParams.append(param);
                 baseInitParams = baseInitParams.tail;
--- a/src/share/classes/com/sun/tools/javac/comp/TransTypes.java	Sat Sep 14 15:23:21 2013 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/TransTypes.java	Sat Sep 14 19:04:47 2013 +0100
@@ -310,7 +310,7 @@
             Type.MethodType mType = (Type.MethodType)bridgeType;
             List<Type> argTypes = mType.argtypes;
             while (implParams.nonEmpty() && argTypes.nonEmpty()) {
-                VarSymbol param = new VarSymbol(implParams.head.flags() | SYNTHETIC,
+                VarSymbol param = new VarSymbol(implParams.head.flags() | SYNTHETIC | PARAMETER,
                         implParams.head.name, argTypes.head, bridge);
                 param.setAttributes(implParams.head);
                 bridgeParams = bridgeParams.append(param);
--- a/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Sat Sep 14 15:23:21 2013 +0100
+++ b/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Sat Sep 14 19:04:47 2013 +0100
@@ -37,7 +37,6 @@
 
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Attribute.RetentionPolicy;
-import com.sun.tools.javac.code.Attribute.TypeCompound;
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.code.Type.*;
 import com.sun.tools.javac.code.Types.UniqueType;
@@ -55,7 +54,6 @@
 import static com.sun.tools.javac.main.Option.*;
 import static javax.tools.StandardLocation.CLASS_OUTPUT;
 
-
 /** This class provides operations to map an internal symbol table graph
  *  rooted in a ClassSymbol into a classfile.
  *
@@ -1180,25 +1178,26 @@
 
         if (code.varBufferSize > 0) {
             int alenIdx = writeAttr(names.LocalVariableTable);
-            databuf.appendChar(code.varBufferSize);
-
+            databuf.appendChar(code.getLVTSize());
             for (int i=0; i<code.varBufferSize; i++) {
                 Code.LocalVar var = code.varBuffer[i];
 
-                // write variable info
-                Assert.check(var.start_pc >= 0
-                        && var.start_pc <= code.cp);
-                databuf.appendChar(var.start_pc);
-                Assert.check(var.length >= 0
-                        && (var.start_pc + var.length) <= code.cp);
-                databuf.appendChar(var.length);
-                VarSymbol sym = var.sym;
-                databuf.appendChar(pool.put(sym.name));
-                Type vartype = sym.erasure(types);
-                if (needsLocalVariableTypeEntry(sym.type))
-                    nGenericVars++;
-                databuf.appendChar(pool.put(typeSig(vartype)));
-                databuf.appendChar(var.reg);
+                for (Code.LocalVar.Range r: var.aliveRanges) {
+                    // write variable info
+                    Assert.check(r.start_pc >= 0
+                            && r.start_pc <= code.cp);
+                    databuf.appendChar(r.start_pc);
+                    Assert.check(r.length >= 0
+                            && (r.start_pc + r.length) <= code.cp);
+                    databuf.appendChar(r.length);
+                    VarSymbol sym = var.sym;
+                    databuf.appendChar(pool.put(sym.name));
+                    Type vartype = sym.erasure(types);
+                    databuf.appendChar(pool.put(typeSig(vartype)));
+                    databuf.appendChar(var.reg);
+                    if (needsLocalVariableTypeEntry(var.sym.type))
+                        nGenericVars++;
+                }
             }
             endAttr(alenIdx);
             acount++;
@@ -1214,13 +1213,15 @@
                 VarSymbol sym = var.sym;
                 if (!needsLocalVariableTypeEntry(sym.type))
                     continue;
-                count++;
-                // write variable info
-                databuf.appendChar(var.start_pc);
-                databuf.appendChar(var.length);
-                databuf.appendChar(pool.put(sym.name));
-                databuf.appendChar(pool.put(typeSig(sym.type)));
-                databuf.appendChar(var.reg);
+                for (Code.LocalVar.Range r : var.aliveRanges) {
+                    // write variable info
+                    databuf.appendChar(r.start_pc);
+                    databuf.appendChar(r.length);
+                    databuf.appendChar(pool.put(sym.name));
+                    databuf.appendChar(pool.put(typeSig(sym.type)));
+                    databuf.appendChar(var.reg);
+                    count++;
+                }
             }
             Assert.check(count == nGenericVars);
             endAttr(alenIdx);
--- a/src/share/classes/com/sun/tools/javac/jvm/Code.java	Sat Sep 14 15:23:21 2013 +0100
+++ b/src/share/classes/com/sun/tools/javac/jvm/Code.java	Sat Sep 14 19:04:47 2013 +0100
@@ -28,6 +28,7 @@
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.code.Types.UniqueType;
+import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 
@@ -181,6 +182,8 @@
 
     final MethodSymbol meth;
 
+    final LVTRanges lvtRanges;
+
     /** Construct a code object, given the settings of the fatcode,
      *  debugging info switches and the CharacterRangeTable.
      */
@@ -193,7 +196,8 @@
                 CRTable crt,
                 Symtab syms,
                 Types types,
-                Pool pool) {
+                Pool pool,
+                LVTRanges lvtRanges) {
         this.meth = meth;
         this.fatcode = fatcode;
         this.lineMap = lineMap;
@@ -215,6 +219,7 @@
         state = new State();
         lvar = new LocalVar[20];
         this.pool = pool;
+        this.lvtRanges = lvtRanges;
     }
 
 
@@ -305,9 +310,19 @@
 
     /** The current output code pointer.
      */
-    public int curPc() {
-        if (pendingJumps != null) resolvePending();
-        if (pendingStatPos != Position.NOPOS) markStatBegin();
+    public int curCP() {
+        /*
+         * This method has side-effects because calling it can indirectly provoke
+         *  extra code generation, like goto instructions, depending on the context
+         *  where it's called.
+         *  Use with care or even better avoid using it.
+         */
+        if (pendingJumps != null) {
+            resolvePending();
+        }
+        if (pendingStatPos != Position.NOPOS) {
+            markStatBegin();
+        }
         fixedPc = true;
         return cp;
     }
@@ -1175,7 +1190,7 @@
     /** Declare an entry point; return current code pointer
      */
     public int entryPoint() {
-        int pc = curPc();
+        int pc = curCP();
         alive = true;
         pendingStackMap = needStackMap;
         return pc;
@@ -1185,7 +1200,7 @@
      *  return current code pointer
      */
     public int entryPoint(State state) {
-        int pc = curPc();
+        int pc = curCP();
         alive = true;
         this.state = state.dup();
         Assert.check(state.stacksize <= max_stack);
@@ -1198,7 +1213,7 @@
      *  return current code pointer
      */
     public int entryPoint(State state, Type pushed) {
-        int pc = curPc();
+        int pc = curCP();
         alive = true;
         this.state = state.dup();
         Assert.check(state.stacksize <= max_stack);
@@ -1238,7 +1253,7 @@
 
     /** Emit a stack map entry.  */
     public void emitStackMap() {
-        int pc = curPc();
+        int pc = curCP();
         if (!needStackMap) return;
 
 
@@ -1482,6 +1497,9 @@
                 chain.pc + 3 == target && target == cp && !fixedPc) {
                 // If goto the next instruction, the jump is not needed:
                 // compact the code.
+                if (varDebugInfo) {
+                    adjustAliveRanges(cp, -3);
+                }
                 cp = cp - 3;
                 target = target - 3;
                 if (chain.next == null) {
@@ -1781,8 +1799,7 @@
                     sym = sym.clone(sym.owner);
                     sym.type = newtype;
                     LocalVar newlv = lvar[i] = new LocalVar(sym);
-                    // should the following be initialized to cp?
-                    newlv.start_pc = lv.start_pc;
+                    newlv.aliveRanges = lv.aliveRanges;
                 }
             }
         }
@@ -1870,8 +1887,36 @@
     static class LocalVar {
         final VarSymbol sym;
         final char reg;
-        char start_pc = Character.MAX_VALUE;
-        char length = Character.MAX_VALUE;
+
+        class Range {
+            char start_pc = Character.MAX_VALUE;
+            char length = Character.MAX_VALUE;
+
+            Range() {}
+
+            Range(char start) {
+                this.start_pc = start;
+            }
+
+            Range(char start, char length) {
+                this.start_pc = start;
+                this.length = length;
+            }
+
+            boolean closed() {
+                return start_pc != Character.MAX_VALUE && length != Character.MAX_VALUE;
+            }
+
+            @Override
+            public String toString() {
+                int currentStartPC = start_pc;
+                int currentLength = length;
+                return "startpc = " + currentStartPC + " length " + currentLength;
+            }
+        }
+
+        java.util.List<Range> aliveRanges = new java.util.ArrayList<>();
+
         LocalVar(VarSymbol v) {
             this.sym = v;
             this.reg = (char)v.adr;
@@ -1879,9 +1924,78 @@
         public LocalVar dup() {
             return new LocalVar(sym);
         }
+
+        Range firstRange() {
+            return aliveRanges.isEmpty() ? null : aliveRanges.get(0);
+        }
+
+        Range lastRange() {
+            return aliveRanges.isEmpty() ? null : aliveRanges.get(aliveRanges.size() - 1);
+        }
+
+        @Override
         public String toString() {
-            return "" + sym + " in register " + ((int)reg) + " starts at pc=" + ((int)start_pc) + " length=" + ((int)length);
+            if (aliveRanges == null) {
+                return "empty local var";
+            }
+            StringBuilder sb = new StringBuilder().append(sym)
+                    .append(" in register ").append((int)reg).append(" \n");
+            for (Range r : aliveRanges) {
+                sb.append(" starts at pc=").append(Integer.toString(((int)r.start_pc)))
+                    .append(" length=").append(Integer.toString(((int)r.length)))
+                    .append("\n");
+            }
+            return sb.toString();
         }
+
+        public void openRange(char start) {
+            if (!hasOpenRange()) {
+                aliveRanges.add(new Range(start));
+            }
+        }
+
+        public void closeRange(char end) {
+            if (isLastRangeInitialized()) {
+                Range range = lastRange();
+                if (range != null) {
+                    if (range.length == Character.MAX_VALUE) {
+                        range.length = end;
+                    }
+                }
+            } else {
+                if (!aliveRanges.isEmpty()) {
+                    aliveRanges.remove(aliveRanges.size() - 1);
+                }
+            }
+        }
+
+        public boolean hasOpenRange() {
+            if (aliveRanges.isEmpty()) {
+                return false;
+            }
+            Range range = lastRange();
+            return range.length == Character.MAX_VALUE;
+        }
+
+        public boolean isLastRangeInitialized() {
+            if (aliveRanges.isEmpty()) {
+                return false;
+            }
+            Range range = lastRange();
+            return range.start_pc != Character.MAX_VALUE;
+        }
+
+        public Range getWidestRange() {
+            if (aliveRanges.isEmpty()) {
+                return new Range();
+            } else {
+                Range firstRange = firstRange();
+                Range lastRange = lastRange();
+                char length = (char)(lastRange.length + (lastRange.start_pc - firstRange.start_pc));
+                return new Range(firstRange.start_pc, length);
+            }
+         }
+
     };
 
     /** Local variables, indexed by register. */
@@ -1892,11 +2006,60 @@
         int adr = v.adr;
         lvar = ArrayUtils.ensureCapacity(lvar, adr+1);
         Assert.checkNull(lvar[adr]);
-        if (pendingJumps != null) resolvePending();
+        if (pendingJumps != null) {
+            resolvePending();
+        }
         lvar[adr] = new LocalVar(v);
         state.defined.excl(adr);
     }
 
+
+    public void closeAliveRanges(JCTree tree) {
+        closeAliveRanges(tree, cp);
+    }
+
+    public void closeAliveRanges(JCTree tree, int closingCP) {
+        List<VarSymbol> locals = lvtRanges.getVars(meth, tree);
+        for (LocalVar localVar: lvar) {
+            for (VarSymbol aliveLocal : locals) {
+                if (localVar == null) {
+                    return;
+                }
+                if (localVar.sym == aliveLocal && localVar.lastRange() != null) {
+                    char length = (char)(closingCP - localVar.lastRange().start_pc);
+                    if (length > 0 && length < Character.MAX_VALUE) {
+                        localVar.closeRange(length);
+                    }
+                }
+            }
+        }
+    }
+
+    void adjustAliveRanges(int oldCP, int delta) {
+        for (LocalVar localVar: lvar) {
+            if (localVar == null) {
+                return;
+            }
+            for (LocalVar.Range range: localVar.aliveRanges) {
+                if (range.closed() && range.start_pc + range.length >= oldCP) {
+                    range.length += delta;
+                }
+            }
+        }
+    }
+
+    /**
+     * Calculates the size of the LocalVariableTable.
+     */
+    public int getLVTSize() {
+        int result = varBufferSize;
+        for (int i = 0; i < varBufferSize; i++) {
+            LocalVar var = varBuffer[i];
+            result += var.aliveRanges.size() - 1;
+        }
+        return result;
+    }
+
     /** Set the current variable defined state. */
     public void setDefined(Bits newDefined) {
         if (alive && newDefined != state.defined) {
@@ -1922,8 +2085,7 @@
         } else {
             state.defined.incl(adr);
             if (cp < Character.MAX_VALUE) {
-                if (v.start_pc == Character.MAX_VALUE)
-                    v.start_pc = (char)cp;
+                v.openRange((char)cp);
             }
         }
     }
@@ -1933,15 +2095,15 @@
         state.defined.excl(adr);
         if (adr < lvar.length &&
             lvar[adr] != null &&
-            lvar[adr].start_pc != Character.MAX_VALUE) {
+            lvar[adr].isLastRangeInitialized()) {
             LocalVar v = lvar[adr];
-            char length = (char)(curPc() - v.start_pc);
+            char length = (char)(curCP() - v.lastRange().start_pc);
             if (length > 0 && length < Character.MAX_VALUE) {
                 lvar[adr] = v.dup();
-                v.length = length;
+                v.closeRange(length);
                 putVar(v);
             } else {
-                v.start_pc = Character.MAX_VALUE;
+                v.lastRange().start_pc = Character.MAX_VALUE;
             }
         }
     }
@@ -1951,10 +2113,10 @@
         LocalVar v = lvar[adr];
         if (v != null) {
             lvar[adr] = null;
-            if (v.start_pc != Character.MAX_VALUE) {
-                char length = (char)(curPc() - v.start_pc);
+            if (v.isLastRangeInitialized()) {
+                char length = (char)(curCP() - v.lastRange().start_pc);
                 if (length < Character.MAX_VALUE) {
-                    v.length = length;
+                    v.closeRange(length);
                     putVar(v);
                     fillLocalVarPosition(v);
                 }
@@ -1968,8 +2130,9 @@
             return;
         for (Attribute.TypeCompound ta : lv.sym.getRawTypeAttributes()) {
             TypeAnnotationPosition p = ta.position;
-            p.lvarOffset = new int[] { (int)lv.start_pc };
-            p.lvarLength = new int[] { (int)lv.length };
+            LocalVar.Range widestRange = lv.getWidestRange();
+            p.lvarOffset = new int[] { (int)widestRange.start_pc };
+            p.lvarLength = new int[] { (int)widestRange.length };
             p.lvarIndex = new int[] { (int)lv.reg };
             p.isValidOffset = true;
         }
--- a/src/share/classes/com/sun/tools/javac/jvm/Gen.java	Sat Sep 14 15:23:21 2013 +0100
+++ b/src/share/classes/com/sun/tools/javac/jvm/Gen.java	Sat Sep 14 19:04:47 2013 +0100
@@ -24,6 +24,7 @@
  */
 
 package com.sun.tools.javac.jvm;
+
 import java.util.*;
 
 import com.sun.tools.javac.util.*;
@@ -95,10 +96,14 @@
         return instance;
     }
 
-    /* Constant pool, reset by genClass.
+    /** Constant pool, reset by genClass.
      */
     private Pool pool;
 
+    /** LVTRanges info.
+     */
+    private LVTRanges lvtRanges;
+
     protected Gen(Context context) {
         context.put(genKey, this);
 
@@ -128,6 +133,9 @@
             options.isUnset(G_CUSTOM)
             ? options.isSet(G)
             : options.isSet(G_CUSTOM, "vars");
+        if (varDebugInfo) {
+            lvtRanges = LVTRanges.instance(context);
+        }
         genCrt = options.isSet(XJCOV);
         debugCode = options.isSet("debugcode");
         allowInvokedynamic = target.hasInvokedynamic() || options.isSet("invokedynamic");
@@ -423,7 +431,7 @@
      */
     void endFinalizerGap(Env<GenContext> env) {
         if (env.info.gaps != null && env.info.gaps.length() % 2 == 1)
-            env.info.gaps.append(code.curPc());
+            env.info.gaps.append(code.curCP());
     }
 
     /** Mark end of all gaps in catch-all ranges for finalizers of environments
@@ -743,10 +751,10 @@
             genStat(tree, env);
             return;
         }
-        int startpc = code.curPc();
+        int startpc = code.curCP();
         genStat(tree, env);
         if (tree.hasTag(Tag.BLOCK)) crtFlags |= CRT_BLOCK;
-        code.crt.put(tree, crtFlags, startpc, code.curPc());
+        code.crt.put(tree, crtFlags, startpc, code.curCP());
     }
 
     /** Derived visitor method: generate code for a statement.
@@ -781,9 +789,9 @@
         if (trees.length() == 1) {        // mark one statement with the flags
             genStat(trees.head, env, crtFlags | CRT_STATEMENT);
         } else {
-            int startpc = code.curPc();
+            int startpc = code.curCP();
             genStats(trees, env);
-            code.crt.put(trees, crtFlags, startpc, code.curPc());
+            code.crt.put(trees, crtFlags, startpc, code.curCP());
         }
     }
 
@@ -806,9 +814,9 @@
      */
     public CondItem genCond(JCTree tree, int crtFlags) {
         if (!genCrt) return genCond(tree, false);
-        int startpc = code.curPc();
+        int startpc = code.curCP();
         CondItem item = genCond(tree, (crtFlags & CRT_FLOW_CONTROLLER) != 0);
-        code.crt.put(tree, crtFlags, startpc, code.curPc());
+        code.crt.put(tree, crtFlags, startpc, code.curCP());
         return item;
     }
 
@@ -971,7 +979,6 @@
         // definition.
         Env<GenContext> localEnv = env.dup(tree);
         localEnv.enclMethod = tree;
-
         // The expected type of every return statement in this method
         // is the method's return type.
         this.pt = tree.sym.erasure(types).getReturnType();
@@ -1045,7 +1052,7 @@
                     code.crt.put(tree.body,
                                  CRT_BLOCK,
                                  startpcCrt,
-                                 code.curPc());
+                                 code.curCP());
 
                 code.endScopes(0);
 
@@ -1087,10 +1094,12 @@
                                                : null,
                                         syms,
                                         types,
-                                        pool);
+                                        pool,
+                                        varDebugInfo ? lvtRanges : null);
             items = new Items(pool, code, syms, types);
-            if (code.debugCode)
+            if (code.debugCode) {
                 System.err.println(meth + " for body " + tree);
+            }
 
             // If method is not static, create a new local variable address
             // for `this'.
@@ -1111,7 +1120,7 @@
             }
 
             // Get ready to generate code for method body.
-            int startpcCrt = genCrt ? code.curPc() : 0;
+            int startpcCrt = genCrt ? code.curCP() : 0;
             code.entryPoint();
 
             // Suppress initial stackmap
@@ -1189,14 +1198,30 @@
                 Chain loopDone = c.jumpFalse();
                 code.resolve(c.trueJumps);
                 genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET);
+                if (varDebugInfo) {
+                    checkLoopLocalVarRangeEnding(loop, body,
+                            LoopLocalVarRangeEndingPoint.BEFORE_STEPS);
+                }
                 code.resolve(loopEnv.info.cont);
                 genStats(step, loopEnv);
+                if (varDebugInfo) {
+                    checkLoopLocalVarRangeEnding(loop, body,
+                            LoopLocalVarRangeEndingPoint.AFTER_STEPS);
+                }
                 code.resolve(code.branch(goto_), startpc);
                 code.resolve(loopDone);
             } else {
                 genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET);
+                if (varDebugInfo) {
+                    checkLoopLocalVarRangeEnding(loop, body,
+                            LoopLocalVarRangeEndingPoint.BEFORE_STEPS);
+                }
                 code.resolve(loopEnv.info.cont);
                 genStats(step, loopEnv);
+                if (varDebugInfo) {
+                    checkLoopLocalVarRangeEnding(loop, body,
+                            LoopLocalVarRangeEndingPoint.AFTER_STEPS);
+                }
                 CondItem c;
                 if (cond != null) {
                     code.statBegin(cond.pos);
@@ -1210,6 +1235,44 @@
             code.resolve(loopEnv.info.exit);
         }
 
+        private enum LoopLocalVarRangeEndingPoint {
+            BEFORE_STEPS,
+            AFTER_STEPS,
+        }
+
+        /**
+         *  Checks whether we have reached an alive range ending point for local
+         *  variables after a loop.
+         *
+         *  Local variables alive range ending point for loops varies depending
+         *  on the loop type. The range can be closed before or after the code
+         *  for the steps sentences has been generated.
+         *
+         *  - While loops has no steps so in that case the range is closed just
+         *  after the body of the loop.
+         *
+         *  - For-like loops may have steps so as long as the steps sentences
+         *  can possibly contain non-synthetic local variables, the alive range
+         *  for local variables must be closed after the steps in this case.
+        */
+        private void checkLoopLocalVarRangeEnding(JCTree loop, JCTree body,
+                LoopLocalVarRangeEndingPoint endingPoint) {
+            if (varDebugInfo && lvtRanges.containsKey(code.meth, body)) {
+                switch (endingPoint) {
+                    case BEFORE_STEPS:
+                        if (!loop.hasTag(FORLOOP)) {
+                            code.closeAliveRanges(body);
+                        }
+                        break;
+                    case AFTER_STEPS:
+                        if (loop.hasTag(FORLOOP)) {
+                            code.closeAliveRanges(body);
+                        }
+                        break;
+                }
+            }
+        }
+
     public void visitForeachLoop(JCEnhancedForLoop tree) {
         throw new AssertionError(); // should have been removed by Lower.
     }
@@ -1223,7 +1286,7 @@
     public void visitSwitch(JCSwitch tree) {
         int limit = code.nextreg;
         Assert.check(!tree.selector.type.hasTag(CLASS));
-        int startpcCrt = genCrt ? code.curPc() : 0;
+        int startpcCrt = genCrt ? code.curCP() : 0;
         Item sel = genExpr(tree.selector, syms.intType);
         List<JCCase> cases = tree.cases;
         if (cases.isEmpty()) {
@@ -1231,13 +1294,13 @@
             sel.load().drop();
             if (genCrt)
                 code.crt.put(TreeInfo.skipParens(tree.selector),
-                             CRT_FLOW_CONTROLLER, startpcCrt, code.curPc());
+                             CRT_FLOW_CONTROLLER, startpcCrt, code.curCP());
         } else {
             // We are seeing a nonempty switch.
             sel.load();
             if (genCrt)
                 code.crt.put(TreeInfo.skipParens(tree.selector),
-                             CRT_FLOW_CONTROLLER, startpcCrt, code.curPc());
+                             CRT_FLOW_CONTROLLER, startpcCrt, code.curCP());
             Env<GenContext> switchEnv = env.dup(tree, new GenContext());
             switchEnv.info.isSwitch = true;
 
@@ -1278,10 +1341,10 @@
                 ?
                 tableswitch : lookupswitch;
 
-            int startpc = code.curPc();    // the position of the selector operation
+            int startpc = code.curCP();    // the position of the selector operation
             code.emitop0(opcode);
             code.align(4);
-            int tableBase = code.curPc();  // the start of the jump table
+            int tableBase = code.curCP();  // the start of the jump table
             int[] offsets = null;          // a table of offsets for a lookupswitch
             code.emit4(-1);                // leave space for default offset
             if (opcode == tableswitch) {
@@ -1323,6 +1386,9 @@
 
                 // Generate code for the statements in this case.
                 genStats(c.stats, switchEnv, CRT_FLOW_TARGET);
+                if (varDebugInfo && lvtRanges.containsKey(code.meth, c.stats.last())) {
+                    code.closeAliveRanges(c.stats.last());
+                }
             }
 
             // Resolve all breaks.
@@ -1402,7 +1468,7 @@
             void gen() {
                 genLast();
                 Assert.check(syncEnv.info.gaps.length() % 2 == 0);
-                syncEnv.info.gaps.append(code.curPc());
+                syncEnv.info.gaps.append(code.curCP());
             }
             void genLast() {
                 if (code.isAlive()) {
@@ -1441,10 +1507,10 @@
                                       jsrState);
                     }
                     Assert.check(tryEnv.info.gaps.length() % 2 == 0);
-                    tryEnv.info.gaps.append(code.curPc());
+                    tryEnv.info.gaps.append(code.curCP());
                 } else {
                     Assert.check(tryEnv.info.gaps.length() % 2 == 0);
-                    tryEnv.info.gaps.append(code.curPc());
+                    tryEnv.info.gaps.append(code.curCP());
                     genLast();
                 }
             }
@@ -1467,10 +1533,10 @@
          */
         void genTry(JCTree body, List<JCCatch> catchers, Env<GenContext> env) {
             int limit = code.nextreg;
-            int startpc = code.curPc();
+            int startpc = code.curCP();
             Code.State stateTry = code.state.dup();
             genStat(body, env, CRT_BLOCK);
-            int endpc = code.curPc();
+            int endpc = code.curCP();
             boolean hasFinalizer =
                 env.info.finalize != null &&
                 env.info.finalize.hasFinalizer();
@@ -1479,6 +1545,9 @@
             genFinalizer(env);
             code.statBegin(TreeInfo.endPos(env.tree));
             Chain exitChain = code.branch(goto_);
+            if (varDebugInfo && lvtRanges.containsKey(code.meth, body)) {
+                code.closeAliveRanges(body);
+            }
             endFinalizerGap(env);
             if (startpc != endpc) for (List<JCCatch> l = catchers; l.nonEmpty(); l = l.tail) {
                 // start off with exception on stack
@@ -1573,7 +1642,7 @@
                         int catchType = makeRef(tree.pos(), subCatch.type);
                         int end = gaps.head.intValue();
                         registerCatch(tree.pos(),
-                                      startpc,  end, code.curPc(),
+                                      startpc,  end, code.curCP(),
                                       catchType);
                         if (subCatch.type.isAnnotated()) {
                             // All compounds share the same position, simply update the
@@ -1589,7 +1658,7 @@
                     for (JCExpression subCatch : subClauses) {
                         int catchType = makeRef(tree.pos(), subCatch.type);
                         registerCatch(tree.pos(),
-                                      startpc, endpc, code.curPc(),
+                                      startpc, endpc, code.curCP(),
                                       catchType);
                         if (subCatch.type.isAnnotated()) {
                             // All compounds share the same position, simply update the
@@ -1732,11 +1801,19 @@
             code.resolve(c.trueJumps);
             genStat(tree.thenpart, env, CRT_STATEMENT | CRT_FLOW_TARGET);
             thenExit = code.branch(goto_);
+            if (varDebugInfo && lvtRanges.containsKey(code.meth, tree.thenpart)) {
+                code.closeAliveRanges(tree.thenpart,
+                        thenExit != null && tree.elsepart == null ? thenExit.pc : code.cp);
+            }
         }
         if (elseChain != null) {
             code.resolve(elseChain);
-            if (tree.elsepart != null)
+            if (tree.elsepart != null) {
                 genStat(tree.elsepart, env,CRT_STATEMENT | CRT_FLOW_TARGET);
+                if (varDebugInfo && lvtRanges.containsKey(code.meth, tree.elsepart)) {
+                    code.closeAliveRanges(tree.elsepart);
+                }
+            }
         }
         code.resolve(thenExit);
         code.endScopes(limit);
@@ -1830,20 +1907,20 @@
         Chain elseChain = c.jumpFalse();
         if (!c.isFalse()) {
             code.resolve(c.trueJumps);
-            int startpc = genCrt ? code.curPc() : 0;
+            int startpc = genCrt ? code.curCP() : 0;
             genExpr(tree.truepart, pt).load();
             code.state.forceStackTop(tree.type);
             if (genCrt) code.crt.put(tree.truepart, CRT_FLOW_TARGET,
-                                     startpc, code.curPc());
+                                     startpc, code.curCP());
             thenExit = code.branch(goto_);
         }
         if (elseChain != null) {
             code.resolve(elseChain);
-            int startpc = genCrt ? code.curPc() : 0;
+            int startpc = genCrt ? code.curCP() : 0;
             genExpr(tree.falsepart, pt).load();
             code.state.forceStackTop(tree.type);
             if (genCrt) code.crt.put(tree.falsepart, CRT_FLOW_TARGET,
-                                     startpc, code.curPc());
+                                     startpc, code.curCP());
         }
         code.resolve(thenExit);
         result = items.makeStackItem(pt);
@@ -2423,6 +2500,19 @@
                 new Env<GenContext>(cdef, new GenContext());
             localEnv.toplevel = env.toplevel;
             localEnv.enclClass = cdef;
+
+            /*  We must not analyze synthetic methods
+             */
+            if (varDebugInfo && (cdef.sym.flags() & SYNTHETIC) == 0) {
+                try {
+                    LVTAssignAnalyzer lvtAssignAnalyzer = LVTAssignAnalyzer.make(
+                            lvtRanges, syms, names);
+                    lvtAssignAnalyzer.analyzeTree(localEnv);
+                } catch (Throwable e) {
+                    throw e;
+                }
+            }
+
             for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
                 genDef(l.head, localEnv);
             }
@@ -2507,4 +2597,311 @@
             cont = Code.mergeChains(c, cont);
         }
     }
+
+    static class LVTAssignAnalyzer
+        extends Flow.AbstractAssignAnalyzer<LVTAssignAnalyzer.LVTAssignPendingExit> {
+
+        final LVTBits lvtInits;
+        final LVTRanges lvtRanges;
+
+        /*  This class is anchored to a context dependent tree. The tree can
+         *  vary inside the same instruction for example in the switch instruction
+         *  the same FlowBits instance can be anchored to the whole tree, or
+         *  to a given case. The aim is to always anchor the bits to the tree
+         *  capable of closing a DA range.
+         */
+        static class LVTBits extends Bits {
+
+            enum BitsOpKind {
+                INIT,
+                CLEAR,
+                INCL_BIT,
+                EXCL_BIT,
+                ASSIGN,
+                AND_SET,
+                OR_SET,
+                DIFF_SET,
+                XOR_SET,
+                INCL_RANGE,
+                EXCL_RANGE,
+            }
+
+            JCTree currentTree;
+            LVTAssignAnalyzer analyzer;
+            private int[] oldBits = null;
+            BitsState stateBeforeOp;
+
+            LVTBits() {
+                super(false);
+            }
+
+            LVTBits(int[] bits, BitsState initState) {
+                super(bits, initState);
+            }
+
+            @Override
+            public void clear() {
+                generalOp(null, -1, BitsOpKind.CLEAR);
+            }
+
+            @Override
+            protected void internalReset() {
+                super.internalReset();
+                oldBits = null;
+            }
+
+            @Override
+            public Bits assign(Bits someBits) {
+                // bits can be null
+                oldBits = bits;
+                stateBeforeOp = currentState;
+                super.assign(someBits);
+                changed();
+                return this;
+            }
+
+            @Override
+            public void excludeFrom(int start) {
+                generalOp(null, start, BitsOpKind.EXCL_RANGE);
+            }
+
+            @Override
+            public void excl(int x) {
+                Assert.check(x >= 0);
+                generalOp(null, x, BitsOpKind.EXCL_BIT);
+            }
+
+            @Override
+            public Bits andSet(Bits xs) {
+               return generalOp(xs, -1, BitsOpKind.AND_SET);
+            }
+
+            @Override
+            public Bits orSet(Bits xs) {
+                return generalOp(xs, -1, BitsOpKind.OR_SET);
+            }
+
+            @Override
+            public Bits diffSet(Bits xs) {
+                return generalOp(xs, -1, BitsOpKind.DIFF_SET);
+            }
+
+            @Override
+            public Bits xorSet(Bits xs) {
+                return generalOp(xs, -1, BitsOpKind.XOR_SET);
+            }
+
+            private Bits generalOp(Bits xs, int i, BitsOpKind opKind) {
+                Assert.check(currentState != BitsState.UNKNOWN);
+                oldBits = dupBits();
+                stateBeforeOp = currentState;
+                switch (opKind) {
+                    case AND_SET:
+                        super.andSet(xs);
+                        break;
+                    case OR_SET:
+                        super.orSet(xs);
+                        break;
+                    case XOR_SET:
+                        super.xorSet(xs);
+                        break;
+                    case DIFF_SET:
+                        super.diffSet(xs);
+                        break;
+                    case CLEAR:
+                        super.clear();
+                        break;
+                    case EXCL_BIT:
+                        super.excl(i);
+                        break;
+                    case EXCL_RANGE:
+                        super.excludeFrom(i);
+                        break;
+                }
+                changed();
+                return this;
+            }
+
+            /*  The tree we need to anchor the bits instance to.
+             */
+            LVTBits at(JCTree tree) {
+                this.currentTree = tree;
+                return this;
+            }
+
+            /*  If the instance should be changed but the tree is not a closing
+             *  tree then a reset is needed or the former tree can mistakingly be
+             *  used.
+             */
+            LVTBits resetTree() {
+                this.currentTree = null;
+                return this;
+            }
+
+            /** This method will be called after any operation that causes a change to
+             *  the bits. Subclasses can thus override it in order to extract information
+             *  from the changes produced to the bits by the given operation.
+             */
+            public void changed() {
+                if (currentTree != null &&
+                        stateBeforeOp != BitsState.UNKNOWN &&
+                        trackTree(currentTree)) {
+                    List<VarSymbol> locals =
+                            analyzer.lvtRanges
+                            .getVars(analyzer.currentMethod, currentTree);
+                    locals = locals != null ?
+                            locals : List.<VarSymbol>nil();
+                    for (JCVariableDecl vardecl : analyzer.vardecls) {
+                        //once the first is null, the rest will be so.
+                        if (vardecl == null) {
+                            break;
+                        }
+                        if (trackVar(vardecl.sym) && bitChanged(vardecl.sym.adr)) {
+                            locals = locals.prepend(vardecl.sym);
+                        }
+                    }
+                    if (!locals.isEmpty()) {
+                        analyzer.lvtRanges.setEntry(analyzer.currentMethod,
+                                currentTree, locals);
+                    }
+                }
+            }
+
+            boolean bitChanged(int x) {
+                boolean isMemberOfBits = isMember(x);
+                int[] tmp = bits;
+                bits = oldBits;
+                boolean isMemberOfOldBits = isMember(x);
+                bits = tmp;
+                return (!isMemberOfBits && isMemberOfOldBits);
+            }
+
+            boolean trackVar(VarSymbol var) {
+                return (var.owner.kind == MTH &&
+                        (var.flags() & (PARAMETER | HASINIT)) == 0 &&
+                        analyzer.trackable(var));
+            }
+
+            boolean trackTree(JCTree tree) {
+                switch (tree.getTag()) {
+                    // of course a method closes the alive range of a local variable.
+                    case METHODDEF:
+                    // for while loops we want only the body
+                    case WHILELOOP:
+                        return false;
+                }
+                return true;
+            }
+
+        }
+
+        public class LVTAssignPendingExit extends Flow.AssignAnalyzer.AssignPendingExit {
+
+            LVTAssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
+                super(tree, inits, uninits);
+            }
+
+            @Override
+            public void resolveJump(JCTree tree) {
+                lvtInits.at(tree);
+                super.resolveJump(tree);
+            }
+        }
+
+        private LVTAssignAnalyzer(LVTRanges lvtRanges, Symtab syms, Names names) {
+            super(new LVTBits(), syms, names);
+            lvtInits = (LVTBits)inits;
+            this.lvtRanges = lvtRanges;
+        }
+
+        public static LVTAssignAnalyzer make(LVTRanges lvtRanges, Symtab syms, Names names) {
+            LVTAssignAnalyzer result = new LVTAssignAnalyzer(lvtRanges, syms, names);
+            result.lvtInits.analyzer = result;
+            return result;
+        }
+
+        @Override
+        protected void markDead(JCTree tree) {
+            lvtInits.at(tree).inclRange(returnadr, nextadr);
+            super.markDead(tree);
+        }
+
+        @Override
+        protected void merge(JCTree tree) {
+            lvtInits.at(tree);
+            super.merge(tree);
+        }
+
+        boolean isSyntheticOrMandated(Symbol sym) {
+            return (sym.flags() & (SYNTHETIC | MANDATED)) != 0;
+        }
+
+        @Override
+        protected boolean trackable(VarSymbol sym) {
+            if (isSyntheticOrMandated(sym)) {
+                //fast check to avoid tracking synthetic or mandated variables
+                return false;
+            }
+            return super.trackable(sym);
+        }
+
+        @Override
+        protected void initParam(JCVariableDecl def) {
+            if (!isSyntheticOrMandated(def.sym)) {
+                super.initParam(def);
+            }
+        }
+
+        @Override
+        protected void assignToInits(JCTree tree, Bits bits) {
+            lvtInits.at(tree);
+            lvtInits.assign(bits);
+        }
+
+        @Override
+        protected void andSetInits(JCTree tree, Bits bits) {
+            lvtInits.at(tree);
+            lvtInits.andSet(bits);
+        }
+
+        @Override
+        protected void orSetInits(JCTree tree, Bits bits) {
+            lvtInits.at(tree);
+            lvtInits.orSet(bits);
+        }
+
+        @Override
+        protected void exclVarFromInits(JCTree tree, int adr) {
+            lvtInits.at(tree);
+            lvtInits.excl(adr);
+        }
+
+        @Override
+        protected LVTAssignPendingExit createNewPendingExit(JCTree tree, Bits inits, Bits uninits) {
+            return new LVTAssignPendingExit(tree, inits, uninits);
+        }
+
+        MethodSymbol currentMethod;
+
+        @Override
+        public void visitMethodDef(JCMethodDecl tree) {
+            if ((tree.sym.flags() & (SYNTHETIC | GENERATEDCONSTR)) != 0) {
+                return;
+            }
+            if (tree.name.equals(names.clinit)) {
+                return;
+            }
+            boolean enumClass = (tree.sym.owner.flags() & ENUM) != 0;
+            if (enumClass &&
+                    (tree.name.equals(names.valueOf) ||
+                    tree.name.equals(names.values) ||
+                    tree.name.equals(names.init))) {
+                return;
+            }
+            currentMethod = tree.sym;
+            super.visitMethodDef(tree);
+        }
+
+    }
+
 }
--- a/src/share/classes/com/sun/tools/javac/jvm/Items.java	Sat Sep 14 15:23:21 2013 +0100
+++ b/src/share/classes/com/sun/tools/javac/jvm/Items.java	Sat Sep 14 19:04:47 2013 +0100
@@ -789,18 +789,18 @@
         Chain jumpTrue() {
             if (tree == null) return Code.mergeChains(trueJumps, code.branch(opcode));
             // we should proceed further in -Xjcov mode only
-            int startpc = code.curPc();
+            int startpc = code.curCP();
             Chain c = Code.mergeChains(trueJumps, code.branch(opcode));
-            code.crt.put(tree, CRTable.CRT_BRANCH_TRUE, startpc, code.curPc());
+            code.crt.put(tree, CRTable.CRT_BRANCH_TRUE, startpc, code.curCP());
             return c;
         }
 
         Chain jumpFalse() {
             if (tree == null) return Code.mergeChains(falseJumps, code.branch(Code.negate(opcode)));
             // we should proceed further in -Xjcov mode only
-            int startpc = code.curPc();
+            int startpc = code.curCP();
             Chain c = Code.mergeChains(falseJumps, code.branch(Code.negate(opcode)));
-            code.crt.put(tree, CRTable.CRT_BRANCH_FALSE, startpc, code.curPc());
+            code.crt.put(tree, CRTable.CRT_BRANCH_FALSE, startpc, code.curCP());
             return c;
         }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/tools/javac/jvm/LVTRanges.java	Sat Sep 14 19:04:47 2013 +0100
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.javac.jvm;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.WeakHashMap;
+
+import com.sun.tools.javac.code.Symbol.MethodSymbol;
+import com.sun.tools.javac.code.Symbol.VarSymbol;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.List;
+
+/** This class contains a one to many relation between a tree and a set of variables.
+ *  The relation implies that the given tree closes the DA (definite assignment)
+ *  range for the set of variables.
+ *
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ */
+public class LVTRanges {
+    /** The context key for the LVT ranges. */
+    protected static final Context.Key<LVTRanges> lvtRangesKey = new Context.Key<>();
+
+    /** Get the LVTRanges instance for this context. */
+    public static LVTRanges instance(Context context) {
+        LVTRanges instance = context.get(lvtRangesKey);
+        if (instance == null) {
+            instance = new LVTRanges(context);
+        }
+        return instance;
+    }
+
+    private static final long serialVersionUID = 1812267524140424433L;
+
+    protected Context context;
+
+    protected Map<MethodSymbol, Map<JCTree, List<VarSymbol>>>
+            aliveRangeClosingTrees = new WeakHashMap<>();
+
+    public LVTRanges(Context context) {
+        this.context = context;
+        context.put(lvtRangesKey, this);
+    }
+
+    public List<VarSymbol> getVars(MethodSymbol method, JCTree tree) {
+        Map<JCTree, List<VarSymbol>> varMap = aliveRangeClosingTrees.get(method);
+        return (varMap != null) ? varMap.get(tree) : null;
+    }
+
+    public boolean containsKey(MethodSymbol method, JCTree tree) {
+        Map<JCTree, List<VarSymbol>> varMap = aliveRangeClosingTrees.get(method);
+        if (varMap == null) {
+            return false;
+        }
+        return varMap.containsKey(tree);
+    }
+
+    public void setEntry(MethodSymbol method, JCTree tree, List<VarSymbol> vars) {
+        Map<JCTree, List<VarSymbol>> varMap = aliveRangeClosingTrees.get(method);
+        if (varMap != null) {
+            varMap.put(tree, vars);
+        } else {
+            varMap = new WeakHashMap<>();
+            varMap.put(tree, vars);
+            aliveRangeClosingTrees.put(method, varMap);
+        }
+    }
+
+    public List<VarSymbol> removeEntry(MethodSymbol method, JCTree tree) {
+        Map<JCTree, List<VarSymbol>> varMap = aliveRangeClosingTrees.get(method);
+        if (varMap != null) {
+            List<VarSymbol> result = varMap.remove(tree);
+            if (varMap.isEmpty()) {
+                aliveRangeClosingTrees.remove(method);
+            }
+            return result;
+        }
+        return null;
+    }
+
+    /* This method should be used for debugging LVT related issues.
+     */
+    @Override
+    public String toString() {
+        String result = "";
+        for (Entry<MethodSymbol, Map<JCTree, List<VarSymbol>>> mainEntry: aliveRangeClosingTrees.entrySet()) {
+            result += "Method: \n" + mainEntry.getKey().flatName() + "\n";
+            int i = 1;
+            for (Entry<JCTree, List<VarSymbol>> treeEntry: mainEntry.getValue().entrySet()) {
+                result += "    Tree " + i + ": \n" + treeEntry.getKey().toString() + "\n";
+                result += "        Variables closed:\n";
+                for (VarSymbol var: treeEntry.getValue()) {
+                    result += "            " + var.toString();
+                }
+                result += "\n";
+                i++;
+            }
+        }
+        return result;
+    }
+
+}
--- a/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Sat Sep 14 15:23:21 2013 +0100
+++ b/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Sat Sep 14 19:04:47 2013 +0100
@@ -890,7 +890,7 @@
     /** Create a value parameter tree from its name, type, and owner.
      */
     public JCVariableDecl Param(Name name, Type argtype, Symbol owner) {
-        return VarDef(new VarSymbol(0, name, argtype, owner), null);
+        return VarDef(new VarSymbol(PARAMETER, name, argtype, owner), null);
     }
 
     /** Create a a list of value parameter trees x0, ..., xn from a list of
--- a/src/share/classes/com/sun/tools/javac/util/Bits.java	Sat Sep 14 15:23:21 2013 +0100
+++ b/src/share/classes/com/sun/tools/javac/util/Bits.java	Sat Sep 14 19:04:47 2013 +0100
@@ -27,8 +27,6 @@
 
 import java.util.Arrays;
 
-import static com.sun.tools.javac.util.Bits.BitsOpKind.*;
-
 /** A class for extensible, mutable bit sets.
  *
  *  <p><b>This is NOT part of any supported API.
@@ -38,20 +36,6 @@
  */
 public class Bits {
 
-    public enum BitsOpKind {
-        INIT,
-        CLEAR,
-        INCL_BIT,
-        EXCL_BIT,
-        ASSIGN,
-        AND_SET,
-        OR_SET,
-        DIFF_SET,
-        XOR_SET,
-        INCL_RANGE,
-        EXCL_RANGE,
-    }
-
     //       ____________      reset    _________
     //      /  UNKNOWN   \   <-------- / UNINIT  \
     //      \____________/       |     \_________/
@@ -64,11 +48,14 @@
     //                            |         |
     //                            -----------
     //                               any
-    private enum BitsState {
+    protected enum BitsState {
         /*  A Bits instance is in UNKNOWN state if it has been explicitly reset.
          *  It is possible to get to this state from any other by calling the
          *  reset method. An instance in the UNKNOWN state can pass to the
          *  NORMAL state after being assigned another Bits instance.
+         *
+         *  Bits instances are final fields in Flow so the UNKNOWN state models
+         *  the null assignment.
          */
         UNKNOWN,
         /*  A Bits instance is in UNINIT when it is created with the default
@@ -103,13 +90,9 @@
 
     public int[] bits = null;
     // This field will store last version of bits after every change.
-    public int[] oldBits = null;
-
-    public BitsOpKind lastOperation = null;
-
     private static final int[] unassignedBits = new int[0];
 
-    private BitsState currentState;
+    protected BitsState currentState;
 
     /** Construct an initially empty set.
      */
@@ -127,27 +110,20 @@
 
     /** Construct a set consisting initially of given bit vector.
      */
-    private Bits(int[] bits, BitsState initState) {
+    protected Bits(int[] bits, BitsState initState) {
         this.bits = bits;
         this.currentState = initState;
         switch (initState) {
             case UNKNOWN:
-                reset(); //this will also set current state;
+                this.bits = null;
                 break;
             case NORMAL:
                 Assert.check(bits != unassignedBits);
-                lastOperation = INIT;
                 break;
         }
     }
 
-    /** This method will be called after any operation that causes a change to
-     *  the bits. Subclasses can thus override it in order to extract information
-     *  from the changes produced to the bits by the given operation.
-     */
-    public void changed() {}
-
-    private void sizeTo(int len) {
+    protected void sizeTo(int len) {
         if (bits.length < len) {
             bits = Arrays.copyOf(bits, len);
         }
@@ -157,16 +133,18 @@
      */
     public void clear() {
         Assert.check(currentState != BitsState.UNKNOWN);
-        oldBits = bits;
-        lastOperation = CLEAR;
-        for (int i = 0; i < bits.length; i++) bits[i] = 0;
-        changed();
+        for (int i = 0; i < bits.length; i++) {
+            bits[i] = 0;
+        }
         currentState = BitsState.NORMAL;
     }
 
     public void reset() {
+        internalReset();
+    }
+
+    protected void internalReset() {
         bits = null;
-        oldBits = null;
         currentState = BitsState.UNKNOWN;
     }
 
@@ -175,40 +153,40 @@
     }
 
     public Bits assign(Bits someBits) {
-        lastOperation = ASSIGN;
-        oldBits = bits;
         bits = someBits.dup().bits;
-        changed();
         currentState = BitsState.NORMAL;
         return this;
     }
 
     /** Return a copy of this set.
      */
-    private Bits dup() {
+    public Bits dup() {
         Assert.check(currentState != BitsState.UNKNOWN);
         Bits tmp = new Bits();
-        if (currentState != BitsState.NORMAL) {
-            tmp.bits = bits;
-        } else {
-            tmp.bits = new int[bits.length];
-            System.arraycopy(bits, 0, tmp.bits, 0, bits.length);
-        }
+        tmp.bits = dupBits();
         currentState = BitsState.NORMAL;
         return tmp;
     }
 
+    protected int[] dupBits() {
+        int [] result;
+        if (currentState != BitsState.NORMAL) {
+            result = bits;
+        } else {
+            result = new int[bits.length];
+            System.arraycopy(bits, 0, result, 0, bits.length);
+        }
+        return result;
+    }
+
     /** Include x in this set.
      */
     public void incl(int x) {
         Assert.check(currentState != BitsState.UNKNOWN);
-        Assert.check(x >= 0);
-        oldBits = bits;
-        lastOperation = INCL_BIT;
+        Assert.check(x >= 0, "Value of x " + x);
         sizeTo((x >>> wordshift) + 1);
         bits[x >>> wordshift] = bits[x >>> wordshift] |
             (1 << (x & wordmask));
-        changed();
         currentState = BitsState.NORMAL;
     }
 
@@ -217,14 +195,11 @@
      */
     public void inclRange(int start, int limit) {
         Assert.check(currentState != BitsState.UNKNOWN);
-        oldBits = bits;
-        lastOperation = INCL_RANGE;
         sizeTo((limit >>> wordshift) + 1);
         for (int x = start; x < limit; x++) {
             bits[x >>> wordshift] = bits[x >>> wordshift] |
                 (1 << (x & wordmask));
         }
-        changed();
         currentState = BitsState.NORMAL;
     }
 
@@ -232,13 +207,10 @@
      */
     public void excludeFrom(int start) {
         Assert.check(currentState != BitsState.UNKNOWN);
-        oldBits = bits;
-        lastOperation = EXCL_RANGE;
         Bits temp = new Bits();
         temp.sizeTo(bits.length);
         temp.inclRange(0, start);
         internalAndSet(temp);
-        changed();
         currentState = BitsState.NORMAL;
     }
 
@@ -247,12 +219,9 @@
     public void excl(int x) {
         Assert.check(currentState != BitsState.UNKNOWN);
         Assert.check(x >= 0);
-        oldBits = bits;
-        lastOperation = EXCL_BIT;
         sizeTo((x >>> wordshift) + 1);
         bits[x >>> wordshift] = bits[x >>> wordshift] &
             ~(1 << (x & wordmask));
-        changed();
         currentState = BitsState.NORMAL;
     }
 
@@ -269,15 +238,12 @@
      */
     public Bits andSet(Bits xs) {
         Assert.check(currentState != BitsState.UNKNOWN);
-        oldBits = bits;
-        lastOperation = AND_SET;
         internalAndSet(xs);
-        changed();
         currentState = BitsState.NORMAL;
         return this;
     }
 
-    private void internalAndSet(Bits xs) {
+    protected void internalAndSet(Bits xs) {
         Assert.check(currentState != BitsState.UNKNOWN);
         sizeTo(xs.bits.length);
         for (int i = 0; i < xs.bits.length; i++) {
@@ -289,13 +255,10 @@
      */
     public Bits orSet(Bits xs) {
         Assert.check(currentState != BitsState.UNKNOWN);
-        oldBits = bits;
-        lastOperation = OR_SET;
         sizeTo(xs.bits.length);
         for (int i = 0; i < xs.bits.length; i++) {
             bits[i] = bits[i] | xs.bits[i];
         }
-        changed();
         currentState = BitsState.NORMAL;
         return this;
     }
@@ -304,14 +267,11 @@
      */
     public Bits diffSet(Bits xs) {
         Assert.check(currentState != BitsState.UNKNOWN);
-        oldBits = bits;
-        lastOperation = DIFF_SET;
         for (int i = 0; i < bits.length; i++) {
             if (i < xs.bits.length) {
                 bits[i] = bits[i] & ~xs.bits[i];
             }
         }
-        changed();
         currentState = BitsState.NORMAL;
         return this;
     }
@@ -320,13 +280,10 @@
      */
     public Bits xorSet(Bits xs) {
         Assert.check(currentState != BitsState.UNKNOWN);
-        oldBits = bits;
-        lastOperation = XOR_SET;
         sizeTo(xs.bits.length);
         for (int i = 0; i < xs.bits.length; i++) {
             bits[i] = bits[i] ^ xs.bits[i];
         }
-        changed();
         currentState = BitsState.NORMAL;
         return this;
     }
@@ -336,7 +293,9 @@
      */
     private static int trailingZeroBits(int x) {
         Assert.check(wordlen == 32);
-        if (x == 0) return 32;
+        if (x == 0) {
+            return 32;
+        }
         int n = 1;
         if ((x & 0xffff) == 0) { n += 16; x >>>= 16; }
         if ((x & 0x00ff) == 0) { n +=  8; x >>>=  8; }
@@ -355,24 +314,31 @@
     public int nextBit(int x) {
         Assert.check(currentState != BitsState.UNKNOWN);
         int windex = x >>> wordshift;
-        if (windex >= bits.length) return -1;
+        if (windex >= bits.length) {
+            return -1;
+        }
         int word = bits[windex] & ~((1 << (x & wordmask))-1);
         while (true) {
-            if (word != 0)
+            if (word != 0) {
                 return (windex << wordshift) + trailingZeroBits(word);
+            }
             windex++;
-            if (windex >= bits.length) return -1;
+            if (windex >= bits.length) {
+                return -1;
+            }
             word = bits[windex];
         }
     }
 
     /** a string representation of this set.
      */
+    @Override
     public String toString() {
-        if (bits.length > 0) {
+        if (bits != null && bits.length > 0) {
             char[] digits = new char[bits.length * wordlen];
-            for (int i = 0; i < bits.length * wordlen; i++)
+            for (int i = 0; i < bits.length * wordlen; i++) {
                 digits[i] = isMember(i) ? '1' : '0';
+            }
             return new String(digits);
         } else {
             return "[]";
@@ -396,6 +362,8 @@
             System.out.println("found " + i);
             count ++;
         }
-        if (count != 125) throw new Error();
+        if (count != 125) {
+            throw new Error();
+        }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/flow/AliveRanges.java	Sat Sep 14 19:04:47 2013 +0100
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.lang.annotation.*;
+
+@Repeatable(AliveRanges.class)
+@Target({ElementType.METHOD})
+@interface AliveRange {
+    String varName();
+    int bytecodeStart();
+    int bytecodeLength();
+}
+
+@Target({ElementType.METHOD})
+@interface AliveRanges {AliveRange[] value();}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/flow/LVTHarness.java	Sat Sep 14 19:04:47 2013 +0100
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 7047734
+ * @summary The LVT is not generated correctly during some try/catch scenarios
+ * @library /tools/javac/lib
+ * @build JavacTestingAbstractProcessor LVTHarness
+ * @run main LVTHarness
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.util.Set;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+
+import com.sun.source.util.JavacTask;
+import com.sun.tools.classfile.Attribute;
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.ConstantPool;
+import com.sun.tools.classfile.ConstantPoolException;
+import com.sun.tools.classfile.Code_attribute;
+import com.sun.tools.classfile.ConstantPool.InvalidIndex;
+import com.sun.tools.classfile.ConstantPool.UnexpectedEntry;
+import com.sun.tools.classfile.Descriptor.InvalidDescriptor;
+import com.sun.tools.classfile.LocalVariableTable_attribute;
+import com.sun.tools.classfile.Method;
+
+import static javax.tools.StandardLocation.*;
+import static com.sun.tools.classfile.LocalVariableTable_attribute.Entry;
+
+public class LVTHarness {
+
+    static int nerrors = 0;
+
+    static final JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+    static final StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
+
+    public static void main(String[] args) throws Exception {
+        fm.setLocation(SOURCE_PATH,
+                Arrays.asList(new File(System.getProperty("test.src"), "tests")));
+        for (JavaFileObject jfo : fm.list(SOURCE_PATH, "",
+                Collections.singleton(JavaFileObject.Kind.SOURCE), true)) {
+            new LVTHarness(jfo).check();
+        }
+        if (nerrors > 0) {
+            throw new AssertionError("Errors were found");
+        }
+    }
+
+
+    JavaFileObject jfo;
+    Map<ElementKey, AliveRanges> aliveRangeMap =
+            new HashMap<ElementKey, AliveRanges>();
+    Set<String> declaredKeys = new HashSet<>();
+    List<ElementKey> seenAliveRanges = new ArrayList<>();
+
+    protected LVTHarness(JavaFileObject jfo) {
+        this.jfo = jfo;
+    }
+
+    protected void check() throws Exception {
+        JavacTask ct = (JavacTask)comp.getTask(null, fm, null, Arrays.asList("-g"),
+                null, Arrays.asList(jfo));
+        System.err.println("compiling code " + jfo.toString());
+        ct.setProcessors(Collections.singleton(new AliveRangeFinder()));
+        if (!ct.call()) {
+            throw new AssertionError("Error during compilation");
+        }
+
+        checkClassFile(new File(jfo.getName().replace(".java", ".class")));
+
+        //check all candidates have been used up
+        for (Map.Entry<ElementKey, AliveRanges> entry : aliveRangeMap.entrySet()) {
+            if (!seenAliveRanges.contains(entry.getKey())) {
+                error("Redundant @AliveRanges annotation on method " +
+                        entry.getKey().elem);
+            }
+        }
+    }
+
+    void checkClassFile(File file)
+            throws IOException, ConstantPoolException, InvalidDescriptor {
+        ClassFile classFile = ClassFile.read(file);
+        ConstantPool constantPool = classFile.constant_pool;
+
+        //lets get all the methods in the class file.
+        for (Method method : classFile.methods) {
+            for (ElementKey elementKey: aliveRangeMap.keySet()) {
+                String methodDesc = method.getName(constantPool) +
+                        method.descriptor.getParameterTypes(constantPool);
+                if (methodDesc.equals(elementKey.elem.toString())) {
+                    checkMethod(constantPool, method, aliveRangeMap.get(elementKey));
+                    seenAliveRanges.add(elementKey);
+                }
+            }
+        }
+    }
+
+    void checkMethod(ConstantPool constantPool, Method method, AliveRanges ranges)
+            throws InvalidIndex, UnexpectedEntry {
+        Code_attribute code = (Code_attribute) method.attributes.get(Attribute.Code);
+        LocalVariableTable_attribute lvt =
+            (LocalVariableTable_attribute) (code.attributes.get(Attribute.LocalVariableTable));
+        List<String> infoFromRanges = convertToStringList(ranges);
+        List<String> infoFromLVT = convertToStringList(constantPool, lvt);
+
+        // infoFromRanges most be contained in infoFromLVT
+        int i = 0;
+        int j = 0;
+        while (i < infoFromRanges.size() && j < infoFromLVT.size()) {
+            int comparison = infoFromRanges.get(i).compareTo(infoFromLVT.get(j));
+            if (comparison == 0) {
+                i++; j++;
+            } else if (comparison > 0) {
+                j++;
+            } else {
+                break;
+            }
+        }
+
+        if (i < infoFromRanges.size()) {
+            error(infoFromLVT, infoFromRanges);
+        }
+    }
+
+    List<String> convertToStringList(AliveRanges ranges) {
+        List<String> result = new ArrayList<>();
+        for (Annotation anno : ranges.value()) {
+            AliveRange range = (AliveRange)anno;
+            String str = formatLocalVariableData(range.varName(),
+                    range.bytecodeStart(), range.bytecodeLength());
+            result.add(str);
+        }
+        Collections.sort(result);
+        return result;
+    }
+
+    List<String> convertToStringList(ConstantPool constantPool,
+            LocalVariableTable_attribute lvt) throws InvalidIndex, UnexpectedEntry {
+        List<String> result = new ArrayList<>();
+        for (Entry entry : lvt.local_variable_table) {
+            String str = formatLocalVariableData(constantPool.getUTF8Value(entry.name_index),
+                    entry.start_pc, entry.length);
+            result.add(str);
+        }
+        Collections.sort(result);
+        return result;
+    }
+
+    String formatLocalVariableData(String varName, int start, int length) {
+        StringBuilder sb = new StringBuilder()
+                    .append("var name: ").append(varName)
+                    .append(" start: ").append(start)
+                    .append(" length: ").append(length);
+        return sb.toString();
+    }
+
+    protected void error(List<String> infoFromLVT, List<String> infoFromRanges) {
+        nerrors++;
+        System.err.printf("Error occurred while checking file: %s\n", jfo.getName());
+        System.err.println("The range info from the annotations is");
+        printStringListToErrOutput(infoFromRanges);
+        System.err.println();
+        System.err.println("And the range info from the class file is");
+        printStringListToErrOutput(infoFromLVT);
+        System.err.println();
+    }
+
+    void printStringListToErrOutput(List<String> list) {
+        for (String s : list) {
+            System.err.println("\t" + s);
+        }
+    }
+
+    protected void error(String msg) {
+        nerrors++;
+        System.err.printf("Error occurred while checking file: %s\nreason: %s\n",
+                jfo.getName(), msg);
+    }
+
+    class AliveRangeFinder extends JavacTestingAbstractProcessor {
+
+        @Override
+        public boolean process(Set<? extends TypeElement> annotations,
+            RoundEnvironment roundEnv) {
+            if (roundEnv.processingOver())
+                return true;
+
+            TypeElement aliveRangeAnno = elements.getTypeElement("AliveRanges");
+
+            if (!annotations.contains(aliveRangeAnno)) {
+                error("no @AliveRanges annotation found in test class");
+            }
+
+            for (Element elem: roundEnv.getElementsAnnotatedWith(aliveRangeAnno)) {
+                Annotation annotation = elem.getAnnotation(AliveRanges.class);
+                aliveRangeMap.put(new ElementKey(elem), (AliveRanges)annotation);
+            }
+            return true;
+        }
+    }
+
+    class ElementKey {
+
+        String key;
+        Element elem;
+
+        public ElementKey(Element elem) {
+            this.elem = elem;
+            this.key = computeKey(elem);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof ElementKey) {
+                ElementKey other = (ElementKey)obj;
+                return other.key.equals(key);
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return key.hashCode();
+        }
+
+        String computeKey(Element e) {
+            StringBuilder buf = new StringBuilder();
+            while (e != null) {
+                buf.append(e.toString());
+                e = e.getEnclosingElement();
+            }
+            buf.append(jfo.getName());
+            return buf.toString();
+        }
+
+        @Override
+        public String toString() {
+            return "Key{" + key + "}";
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/flow/tests/TestCaseConditional.java	Sat Sep 14 19:04:47 2013 +0100
@@ -0,0 +1,16 @@
+/* /nodynamiccopyright/ */
+
+public class TestCaseConditional {
+
+    @AliveRange(varName="o", bytecodeStart=5, bytecodeLength=33)
+    @AliveRange(varName="oo", bytecodeStart=23, bytecodeLength=15)
+    void m(String[] args) {
+        Boolean o;
+        Boolean oo = ((o = Boolean.TRUE).booleanValue()) ?
+                o = Boolean.TRUE :
+                Boolean.FALSE;
+        oo.hashCode();
+        o = Boolean.FALSE;
+        o.hashCode();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/flow/tests/TestCaseDoLoop.java	Sat Sep 14 19:04:47 2013 +0100
@@ -0,0 +1,15 @@
+/* /nodynamiccopyright/ */
+
+public class TestCaseDoLoop {
+
+    @AliveRange(varName="o", bytecodeStart=3, bytecodeLength=15)
+    @AliveRange(varName="args", bytecodeStart=0, bytecodeLength=18)
+    void m(String[] args) {
+        Object o;
+        do {
+            o = "";
+            o.hashCode();
+        } while (args[0] != null);
+        o = "";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/flow/tests/TestCaseFor.java	Sat Sep 14 19:04:47 2013 +0100
@@ -0,0 +1,27 @@
+/* /nodynamiccopyright/ */
+
+public class TestCaseFor {
+
+    @AliveRange(varName="o", bytecodeStart=10, bytecodeLength=8)
+    @AliveRange(varName="o", bytecodeStart=24, bytecodeLength=1)
+    void m1(String[] args) {
+        Object o;
+        for (int i = 0; i < 5; i++) {
+            o = "";
+            o.hashCode();
+        }
+        o = "";
+    }
+
+    @AliveRange(varName="o", bytecodeStart=10, bytecodeLength=8)
+    @AliveRange(varName="o", bytecodeStart=24, bytecodeLength=1)
+    void m2(String[] args) {
+        Object o;
+        for (int i = 0; i < 5; i++) {
+            o = "";
+            o.hashCode();
+            continue;
+        }
+        o = "";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/flow/tests/TestCaseForEach.java	Sat Sep 14 19:04:47 2013 +0100
@@ -0,0 +1,15 @@
+/* /nodynamiccopyright/ */
+
+public class TestCaseForEach {
+
+    @AliveRange(varName="o", bytecodeStart=25, bytecodeLength=8)
+    @AliveRange(varName="o", bytecodeStart=39, bytecodeLength=1)
+    void m(String[] args) {
+        Object o;
+        for (String s : args) {
+            o = "";
+            o.hashCode();
+        }
+        o = "";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/flow/tests/TestCaseIf.java	Sat Sep 14 19:04:47 2013 +0100
@@ -0,0 +1,61 @@
+/* /nodynamiccopyright/ */
+
+public class TestCaseIf {
+
+    @AliveRange(varName="o", bytecodeStart=9, bytecodeLength=5)
+    @AliveRange(varName="o", bytecodeStart=17, bytecodeLength=1)
+    void m0(String[] args) {
+        Object o;
+        if (args[0] != null) {
+            o = "";
+            o.hashCode();
+        }
+        o = "";
+    }
+
+    @AliveRange(varName="o", bytecodeStart=10, bytecodeLength=5)
+    @AliveRange(varName="o", bytecodeStart=18, bytecodeLength=1)
+    void m1() {
+        Object o;
+        int i = 5;
+        if (i == 5) {
+            o = "";
+            o.hashCode();
+        }
+        o = "";
+    }
+
+    @AliveRange(varName="o", bytecodeStart=10, bytecodeLength=5)
+    @AliveRange(varName="o", bytecodeStart=18, bytecodeLength=1)
+    void m2() {
+        Object o;
+        int i = 5;
+        if (!(i == 5)) {
+            o = "";
+            o.hashCode();
+        }
+        o = "";
+    }
+
+    @AliveRange(varName="o", bytecodeStart=15, bytecodeLength=5)
+    @AliveRange(varName="o", bytecodeStart=23, bytecodeLength=1)
+    void m3(String[] args) {
+        Object o;
+        if (args[0] != null && args[1] != null) {
+            o = "";
+            o.hashCode();
+        }
+        o = "";
+    }
+
+    @AliveRange(varName="o", bytecodeStart=15, bytecodeLength=5)
+    @AliveRange(varName="o", bytecodeStart=23, bytecodeLength=1)
+    void m4(String[] args) {
+        Object o;
+        if (args[0] != null || args[1] != null) {
+            o = "";
+            o.hashCode();
+        }
+        o = "";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/flow/tests/TestCaseIfElse.java	Sat Sep 14 19:04:47 2013 +0100
@@ -0,0 +1,48 @@
+/* /nodynamiccopyright/ */
+
+public class TestCaseIfElse {
+
+    @AliveRange(varName="o", bytecodeStart=9, bytecodeLength=8)
+    @AliveRange(varName="o", bytecodeStart=20, bytecodeLength=9)
+    void m0(String[] args) {
+        Object o;
+        if (args[0] != null) {
+            o = "then";
+            o.hashCode();
+        } else {
+            o = "else";
+            o.hashCode();
+        }
+        o = "finish";
+    }
+
+    @AliveRange(varName="o", bytecodeStart=10, bytecodeLength=8)
+    @AliveRange(varName="o", bytecodeStart=21, bytecodeLength=9)
+    void m1() {
+        Object o;
+        int i = 5;
+        if (i == 5) {
+            o = "then";
+            o.hashCode();
+        } else {
+            o = "else";
+            o.hashCode();
+        }
+        o = "finish";
+    }
+
+    @AliveRange(varName="o", bytecodeStart=10, bytecodeLength=8)
+    @AliveRange(varName="o", bytecodeStart=21, bytecodeLength=9)
+    void m2(String[] args) {
+        Object o;
+        int i = 5;
+        if (i != 5) {
+            o = "then";
+            o.hashCode();
+        } else {
+            o = "else";
+            o.hashCode();
+        }
+        o = "finish";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/flow/tests/TestCaseSwitch.java	Sat Sep 14 19:04:47 2013 +0100
@@ -0,0 +1,73 @@
+/* /nodynamiccopyright/ */
+
+public class TestCaseSwitch {
+
+    @AliveRange(varName="o", bytecodeStart=31, bytecodeLength=16)
+    @AliveRange(varName="o", bytecodeStart=50, bytecodeLength=15)
+    @AliveRange(varName="o", bytecodeStart=68, bytecodeLength=1)
+    @AliveRange(varName="oo", bytecodeStart=39, bytecodeLength=26)
+    @AliveRange(varName="uu", bytecodeStart=59, bytecodeLength=6)
+    void m1(String[] args) {
+        Object o;
+        switch (args.length) {
+            case 0:
+                    o = "0";
+                    o.hashCode();
+                    Object oo = "oo";
+                    oo.hashCode();
+                    break;
+            case 1:
+                    o = "1";
+                    o.hashCode();
+                    Object uu = "uu";
+                    uu.hashCode();
+                    break;
+        }
+        o = "return";
+    }
+
+    @AliveRange(varName="o", bytecodeStart=95, bytecodeLength=18)
+    @AliveRange(varName="o", bytecodeStart=116, bytecodeLength=15)
+    @AliveRange(varName="o", bytecodeStart=134, bytecodeLength=1)
+    @AliveRange(varName="oo", bytecodeStart=104, bytecodeLength=27)
+    @AliveRange(varName="uu", bytecodeStart=125, bytecodeLength=6)
+    void m2(String[] args) {
+        Object o;
+        switch (args[0]) {
+            case "string0":
+                    o = "0";
+                    o.hashCode();
+                    Object oo = "oo";
+                    oo.hashCode();
+                    break;
+            case "string1":
+                    o = "1";
+                    o.hashCode();
+                    Object uu = "uu";
+                    uu.hashCode();
+                    break;
+        }
+        o = "return";
+    }
+
+    @AliveRange(varName="o", bytecodeStart=31, bytecodeLength=8)
+    @AliveRange(varName="o", bytecodeStart=42, bytecodeLength=8)
+    @AliveRange(varName="o", bytecodeStart=53, bytecodeLength=9)
+    void m3(String[] args) {
+        Object o;
+        switch (args.length) {
+            case 0:
+                    o = "0";
+                    o.hashCode();
+                    break;
+            case 1:
+                    o = "1";
+                    o.hashCode();
+                    break;
+            default:
+                    o = "default";
+                    o.hashCode();
+        }
+        o = "finish";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/flow/tests/TestCaseTry.java	Sat Sep 14 19:04:47 2013 +0100
@@ -0,0 +1,76 @@
+/* /nodynamiccopyright/ */
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+
+public class TestCaseTry {
+
+    @AliveRange(varName="o", bytecodeStart=3, bytecodeLength=8)
+    @AliveRange(varName="o", bytecodeStart=15, bytecodeLength=1)
+    void m0(String[] args) {
+        Object o;
+        try {
+            o = "";
+            o.hashCode();
+        } catch (RuntimeException e) {}
+        o = "";
+    }
+
+    @AliveRange(varName="o", bytecodeStart=3, bytecodeLength=16)
+    @AliveRange(varName="o", bytecodeStart=23, bytecodeLength=23)
+    void m1() {
+        Object o;
+        try {
+            o = "";
+            o.hashCode();
+        } catch (RuntimeException e) {
+        }
+        finally {
+            o = "finally";
+            o.hashCode();
+        }
+        o = "";
+    }
+
+    @AliveRange(varName="o", bytecodeStart=3, bytecodeLength=16)
+    @AliveRange(varName="o", bytecodeStart=23, bytecodeLength=31)
+    void m2() {
+        Object o;
+        try {
+            o = "";
+            o.hashCode();
+        } catch (RuntimeException e) {
+            o = "catch";
+            o.hashCode();
+        }
+        finally {
+            o = "finally";
+            o.hashCode();
+        }
+        o = "";
+    }
+
+    @AliveRange(varName="o", bytecodeStart=22, bytecodeLength=38)
+    @AliveRange(varName="o", bytecodeStart=103, bytecodeLength=8)
+    void m3() {
+        Object o;
+        try (BufferedReader br =
+                  new BufferedReader(new FileReader("aFile"))) {
+            o = "inside try";
+            o.hashCode();
+        } catch (Exception e) {}
+        o = "";
+    }
+
+    @AliveRange(varName="o", bytecodeStart=12, bytecodeLength=96)
+    @AliveRange(varName="o", bytecodeStart=112, bytecodeLength=1)
+    void m4() {
+        String o;
+        try (BufferedReader br =
+                  new BufferedReader(new FileReader(o = "aFile"))) {
+            o = "inside try";
+            o.hashCode();
+        } catch (Exception e) {}
+        o = "";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/flow/tests/TestCaseWhile.java	Sat Sep 14 19:04:47 2013 +0100
@@ -0,0 +1,15 @@
+/* /nodynamiccopyright/ */
+
+public class TestCaseWhile {
+
+    @AliveRange(varName="o", bytecodeStart=9, bytecodeLength=5)
+    @AliveRange(varName="o", bytecodeStart=20, bytecodeLength=1)
+    void m(String[] args) {
+        Object o;
+        while (args[0] != null) {
+            o = "";
+            o.hashCode();
+        }
+        o = "";
+    }
+}