7047734: javac, the LVT is not generated correctly in several scenarios

Sat, 14 Sep 2013 19:04:47 +0100

author
vromero
date
Sat, 14 Sep 2013 19:04:47 +0100
changeset 2027
4932bb04c4b8
parent 2026
03c26c60499c
child 2028
4ce8148ffc4f

7047734: javac, the LVT is not generated correctly in several scenarios
Reviewed-by: jjg, mcimadamore

src/share/classes/com/sun/tools/javac/code/Lint.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/comp/Flow.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/comp/Lower.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/comp/MemberEnter.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/comp/TransTypes.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/jvm/Code.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/jvm/Gen.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/jvm/Items.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/jvm/LVTRanges.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/tree/TreeMaker.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/util/Bits.java file | annotate | diff | comparison | revisions
test/tools/javac/flow/AliveRanges.java file | annotate | diff | comparison | revisions
test/tools/javac/flow/LVTHarness.java file | annotate | diff | comparison | revisions
test/tools/javac/flow/tests/TestCaseConditional.java file | annotate | diff | comparison | revisions
test/tools/javac/flow/tests/TestCaseDoLoop.java file | annotate | diff | comparison | revisions
test/tools/javac/flow/tests/TestCaseFor.java file | annotate | diff | comparison | revisions
test/tools/javac/flow/tests/TestCaseForEach.java file | annotate | diff | comparison | revisions
test/tools/javac/flow/tests/TestCaseIf.java file | annotate | diff | comparison | revisions
test/tools/javac/flow/tests/TestCaseIfElse.java file | annotate | diff | comparison | revisions
test/tools/javac/flow/tests/TestCaseSwitch.java file | annotate | diff | comparison | revisions
test/tools/javac/flow/tests/TestCaseTry.java file | annotate | diff | comparison | revisions
test/tools/javac/flow/tests/TestCaseWhile.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/classes/com/sun/tools/javac/code/Lint.java	Sat Sep 14 15:23:21 2013 +0100
     1.2 +++ b/src/share/classes/com/sun/tools/javac/code/Lint.java	Sat Sep 14 19:04:47 2013 +0100
     1.3 @@ -33,9 +33,6 @@
     1.4  import com.sun.tools.javac.util.Options;
     1.5  import com.sun.tools.javac.util.Pair;
     1.6  
     1.7 -import static com.sun.tools.javac.code.Flags.*;
     1.8 -
     1.9 -
    1.10  /**
    1.11   * A class for handling -Xlint suboptions and @SuppresssWarnings.
    1.12   *
    1.13 @@ -81,7 +78,6 @@
    1.14          return l;
    1.15      }
    1.16  
    1.17 -
    1.18      private final AugmentVisitor augmentor;
    1.19  
    1.20      private final EnumSet<LintCategory> values;
    1.21 @@ -90,7 +86,6 @@
    1.22      private static final Map<String, LintCategory> map =
    1.23              new java.util.concurrent.ConcurrentHashMap<String, LintCategory>(20);
    1.24  
    1.25 -
    1.26      protected Lint(Context context) {
    1.27          // initialize values according to the lint options
    1.28          Options options = Options.instance(context);
     2.1 --- a/src/share/classes/com/sun/tools/javac/comp/Flow.java	Sat Sep 14 15:23:21 2013 +0100
     2.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Flow.java	Sat Sep 14 19:04:47 2013 +0100
     2.3 @@ -207,7 +207,7 @@
     2.4  
     2.5      public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
     2.6          new AliveAnalyzer().analyzeTree(env, make);
     2.7 -        new AssignAnalyzer().analyzeTree(env, make);
     2.8 +        new AssignAnalyzer(log, syms, lint, names).analyzeTree(env);
     2.9          new FlowAnalyzer().analyzeTree(env, make);
    2.10          new CaptureAnalyzer().analyzeTree(env, make);
    2.11      }
    2.12 @@ -239,7 +239,7 @@
    2.13          //related errors, which will allow for more errors to be detected
    2.14          Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
    2.15          try {
    2.16 -            new AssignAnalyzer().analyzeTree(env, that, make);
    2.17 +            new AssignAnalyzer(log, syms, lint, names).analyzeTree(env);
    2.18              LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer();
    2.19              flowAnalyzer.analyzeTree(env, that, make);
    2.20              return flowAnalyzer.inferredThrownTypes;
    2.21 @@ -292,15 +292,6 @@
    2.22      }
    2.23  
    2.24      /**
    2.25 -     * Utility method to reset several Bits instances.
    2.26 -     */
    2.27 -    private void resetBits(Bits... bits) {
    2.28 -        for (Bits b : bits) {
    2.29 -            b.reset();
    2.30 -        }
    2.31 -    }
    2.32 -
    2.33 -    /**
    2.34       * Base visitor class for all visitors implementing dataflow analysis logic.
    2.35       * This class define the shared logic for handling jumps (break/continue statements).
    2.36       */
    2.37 @@ -347,17 +338,17 @@
    2.38                  this.tree = tree;
    2.39              }
    2.40  
    2.41 -            void resolveJump() {
    2.42 +            void resolveJump(JCTree tree) {
    2.43                  //do nothing
    2.44              }
    2.45          }
    2.46  
    2.47 -        abstract void markDead();
    2.48 +        abstract void markDead(JCTree tree);
    2.49  
    2.50          /** Record an outward transfer of control. */
    2.51          void recordExit(JCTree tree, P pe) {
    2.52              pendingExits.append(pe);
    2.53 -            markDead();
    2.54 +            markDead(tree);
    2.55          }
    2.56  
    2.57          /** Resolve all jumps of this statement. */
    2.58 @@ -371,7 +362,7 @@
    2.59                  P exit = exits.head;
    2.60                  if (exit.tree.hasTag(jk.treeTag) &&
    2.61                          jk.getTarget(exit.tree) == tree) {
    2.62 -                    exit.resolveJump();
    2.63 +                    exit.resolveJump(tree);
    2.64                      resolved = true;
    2.65                  } else {
    2.66                      pendingExits.append(exit);
    2.67 @@ -380,12 +371,12 @@
    2.68              return resolved;
    2.69          }
    2.70  
    2.71 -        /** Resolve all breaks of this statement. */
    2.72 +        /** Resolve all continues of this statement. */
    2.73          boolean resolveContinues(JCTree tree) {
    2.74              return resolveJump(tree, new ListBuffer<P>(), JumpKind.CONTINUE);
    2.75          }
    2.76  
    2.77 -        /** Resolve all continues of this statement. */
    2.78 +        /** Resolve all breaks of this statement. */
    2.79          boolean resolveBreaks(JCTree tree, ListBuffer<P> oldPendingExits) {
    2.80              return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
    2.81          }
    2.82 @@ -414,7 +405,7 @@
    2.83          private boolean alive;
    2.84  
    2.85          @Override
    2.86 -        void markDead() {
    2.87 +        void markDead(JCTree tree) {
    2.88              alive = false;
    2.89          }
    2.90  
    2.91 @@ -696,7 +687,7 @@
    2.92  
    2.93          public void visitThrow(JCThrow tree) {
    2.94              scan(tree.expr);
    2.95 -            markDead();
    2.96 +            markDead(tree);
    2.97          }
    2.98  
    2.99          public void visitApply(JCMethodInvocation tree) {
   2.100 @@ -797,7 +788,7 @@
   2.101          }
   2.102  
   2.103          @Override
   2.104 -        void markDead() {
   2.105 +        void markDead(JCTree tree) {
   2.106              //do nothing
   2.107          }
   2.108  
   2.109 @@ -1222,7 +1213,7 @@
   2.110              else {
   2.111                  markThrown(tree, tree.expr.type);
   2.112              }
   2.113 -            markDead();
   2.114 +            markDead(tree);
   2.115          }
   2.116  
   2.117          public void visitApply(JCMethodInvocation tree) {
   2.118 @@ -1372,11 +1363,13 @@
   2.119       * depends on the results of the liveliness analyzer. This pass is also used to mark
   2.120       * effectively-final local variables/parameters.
   2.121       */
   2.122 -    class AssignAnalyzer extends BaseAnalyzer<AssignAnalyzer.AssignPendingExit> {
   2.123 +
   2.124 +    public abstract static class AbstractAssignAnalyzer<P extends AbstractAssignAnalyzer.AbstractAssignPendingExit>
   2.125 +        extends BaseAnalyzer<P> {
   2.126  
   2.127          /** The set of definitely assigned variables.
   2.128           */
   2.129 -        final Bits inits;
   2.130 +        protected final Bits inits;
   2.131  
   2.132          /** The set of definitely unassigned variables.
   2.133           */
   2.134 @@ -1402,7 +1395,7 @@
   2.135  
   2.136          /** A mapping from addresses to variable symbols.
   2.137           */
   2.138 -        JCVariableDecl[] vardecls;
   2.139 +        protected JCVariableDecl[] vardecls;
   2.140  
   2.141          /** The current class being defined.
   2.142           */
   2.143 @@ -1414,11 +1407,11 @@
   2.144  
   2.145          /** The next available variable sequence number.
   2.146           */
   2.147 -        int nextadr;
   2.148 +        protected int nextadr;
   2.149  
   2.150          /** The first variable sequence number in a block that can return.
   2.151           */
   2.152 -        int returnadr;
   2.153 +        protected int returnadr;
   2.154  
   2.155          /** The list of unreferenced automatic resources.
   2.156           */
   2.157 @@ -1430,35 +1423,46 @@
   2.158          /** The starting position of the analysed tree */
   2.159          int startPos;
   2.160  
   2.161 -        AssignAnalyzer() {
   2.162 -            inits = new Bits();
   2.163 +        final Symtab syms;
   2.164 +
   2.165 +        protected Names names;
   2.166 +
   2.167 +        public static class AbstractAssignPendingExit extends BaseAnalyzer.PendingExit {
   2.168 +
   2.169 +            final Bits inits;
   2.170 +            final Bits uninits;
   2.171 +            final Bits exit_inits = new Bits(true);
   2.172 +            final Bits exit_uninits = new Bits(true);
   2.173 +
   2.174 +            public AbstractAssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
   2.175 +                super(tree);
   2.176 +                this.inits = inits;
   2.177 +                this.uninits = uninits;
   2.178 +                this.exit_inits.assign(inits);
   2.179 +                this.exit_uninits.assign(uninits);
   2.180 +            }
   2.181 +
   2.182 +            @Override
   2.183 +            public void resolveJump(JCTree tree) {
   2.184 +                inits.andSet(exit_inits);
   2.185 +                uninits.andSet(exit_uninits);
   2.186 +            }
   2.187 +        }
   2.188 +
   2.189 +        public AbstractAssignAnalyzer(Bits inits, Symtab syms, Names names) {
   2.190 +            this.inits = inits;
   2.191              uninits = new Bits();
   2.192              uninitsTry = new Bits();
   2.193              initsWhenTrue = new Bits(true);
   2.194              initsWhenFalse = new Bits(true);
   2.195              uninitsWhenTrue = new Bits(true);
   2.196              uninitsWhenFalse = new Bits(true);
   2.197 -        }
   2.198 -
   2.199 -        class AssignPendingExit extends BaseAnalyzer.PendingExit {
   2.200 -
   2.201 -            final Bits exit_inits = new Bits(true);
   2.202 -            final Bits exit_uninits = new Bits(true);
   2.203 -
   2.204 -            AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
   2.205 -                super(tree);
   2.206 -                this.exit_inits.assign(inits);
   2.207 -                this.exit_uninits.assign(uninits);
   2.208 -            }
   2.209 -
   2.210 -            void resolveJump() {
   2.211 -                inits.andSet(exit_inits);
   2.212 -                uninits.andSet(exit_uninits);
   2.213 -            }
   2.214 +            this.syms = syms;
   2.215 +            this.names = names;
   2.216          }
   2.217  
   2.218          @Override
   2.219 -        void markDead() {
   2.220 +        protected void markDead(JCTree tree) {
   2.221              inits.inclRange(returnadr, nextadr);
   2.222              uninits.inclRange(returnadr, nextadr);
   2.223          }
   2.224 @@ -1468,7 +1472,7 @@
   2.225          /** Do we need to track init/uninit state of this symbol?
   2.226           *  I.e. is symbol either a local or a blank final variable?
   2.227           */
   2.228 -        boolean trackable(VarSymbol sym) {
   2.229 +        protected boolean trackable(VarSymbol sym) {
   2.230              return
   2.231                  sym.pos >= startPos &&
   2.232                  ((sym.owner.kind == MTH ||
   2.233 @@ -1488,44 +1492,35 @@
   2.234              }
   2.235              sym.adr = nextadr;
   2.236              vardecls[nextadr] = varDecl;
   2.237 -            inits.excl(nextadr);
   2.238 +            exclVarFromInits(varDecl, nextadr);
   2.239              uninits.incl(nextadr);
   2.240              nextadr++;
   2.241          }
   2.242  
   2.243 +        protected void exclVarFromInits(JCTree tree, int adr) {
   2.244 +            inits.excl(adr);
   2.245 +        }
   2.246 +
   2.247 +        protected void assignToInits(JCTree tree, Bits bits) {
   2.248 +            inits.assign(bits);
   2.249 +        }
   2.250 +
   2.251 +        protected void andSetInits(JCTree tree, Bits bits) {
   2.252 +            inits.andSet(bits);
   2.253 +        }
   2.254 +
   2.255 +        protected void orSetInits(JCTree tree, Bits bits) {
   2.256 +            inits.orSet(bits);
   2.257 +        }
   2.258 +
   2.259          /** Record an initialization of a trackable variable.
   2.260           */
   2.261          void letInit(DiagnosticPosition pos, VarSymbol sym) {
   2.262              if (sym.adr >= firstadr && trackable(sym)) {
   2.263 -                if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {
   2.264 -                    if (!uninits.isMember(sym.adr)) {
   2.265 -                        //assignment targeting an effectively final variable
   2.266 -                        //makes the variable lose its status of effectively final
   2.267 -                        //if the variable is _not_ definitively unassigned
   2.268 -                        sym.flags_field &= ~EFFECTIVELY_FINAL;
   2.269 -                    } else {
   2.270 -                        uninit(sym);
   2.271 -                    }
   2.272 -                }
   2.273 -                else if ((sym.flags() & FINAL) != 0) {
   2.274 -                    if ((sym.flags() & PARAMETER) != 0) {
   2.275 -                        if ((sym.flags() & UNION) != 0) { //multi-catch parameter
   2.276 -                            log.error(pos, "multicatch.parameter.may.not.be.assigned",
   2.277 -                                      sym);
   2.278 -                        }
   2.279 -                        else {
   2.280 -                            log.error(pos, "final.parameter.may.not.be.assigned",
   2.281 -                                  sym);
   2.282 -                        }
   2.283 -                    } else if (!uninits.isMember(sym.adr)) {
   2.284 -                        log.error(pos, flowKind.errKey, sym);
   2.285 -                    } else {
   2.286 -                        uninit(sym);
   2.287 -                    }
   2.288 +                if (uninits.isMember(sym.adr)) {
   2.289 +                    uninit(sym);
   2.290                  }
   2.291                  inits.incl(sym.adr);
   2.292 -            } else if ((sym.flags() & FINAL) != 0) {
   2.293 -                log.error(pos, "var.might.already.be.assigned", sym);
   2.294              }
   2.295          }
   2.296          //where
   2.297 @@ -1559,12 +1554,14 @@
   2.298          void checkInit(DiagnosticPosition pos, VarSymbol sym) {
   2.299              checkInit(pos, sym, "var.might.not.have.been.initialized");
   2.300          }
   2.301 -        void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {
   2.302 -            if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
   2.303 -                trackable(sym) &&
   2.304 -                !inits.isMember(sym.adr)) {
   2.305 -                log.error(pos, errkey, sym);
   2.306 -                inits.incl(sym.adr);
   2.307 +
   2.308 +        void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {}
   2.309 +
   2.310 +        /** Utility method to reset several Bits instances.
   2.311 +         */
   2.312 +        private void resetBits(Bits... bits) {
   2.313 +            for (Bits b : bits) {
   2.314 +                b.reset();
   2.315              }
   2.316          }
   2.317  
   2.318 @@ -1582,7 +1579,7 @@
   2.319  
   2.320          /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
   2.321           */
   2.322 -        void merge() {
   2.323 +        protected void merge(JCTree tree) {
   2.324              inits.assign(initsWhenFalse.andSet(initsWhenTrue));
   2.325              uninits.assign(uninitsWhenFalse.andSet(uninitsWhenTrue));
   2.326          }
   2.327 @@ -1597,7 +1594,9 @@
   2.328          void scanExpr(JCTree tree) {
   2.329              if (tree != null) {
   2.330                  scan(tree);
   2.331 -                if (inits.isReset()) merge();
   2.332 +                if (inits.isReset()) {
   2.333 +                    merge(tree);
   2.334 +                }
   2.335              }
   2.336          }
   2.337  
   2.338 @@ -1614,7 +1613,7 @@
   2.339           */
   2.340          void scanCond(JCTree tree) {
   2.341              if (tree.type.isFalse()) {
   2.342 -                if (inits.isReset()) merge();
   2.343 +                if (inits.isReset()) merge(tree);
   2.344                  initsWhenTrue.assign(inits);
   2.345                  initsWhenTrue.inclRange(firstadr, nextadr);
   2.346                  uninitsWhenTrue.assign(uninits);
   2.347 @@ -1622,7 +1621,7 @@
   2.348                  initsWhenFalse.assign(inits);
   2.349                  uninitsWhenFalse.assign(uninits);
   2.350              } else if (tree.type.isTrue()) {
   2.351 -                if (inits.isReset()) merge();
   2.352 +                if (inits.isReset()) merge(tree);
   2.353                  initsWhenFalse.assign(inits);
   2.354                  initsWhenFalse.inclRange(firstadr, nextadr);
   2.355                  uninitsWhenFalse.assign(uninits);
   2.356 @@ -1641,22 +1640,22 @@
   2.357  
   2.358          /* ------------ Visitor methods for various sorts of trees -------------*/
   2.359  
   2.360 +        @Override
   2.361          public void visitClassDef(JCClassDecl tree) {
   2.362 -            if (tree.sym == null) return;
   2.363 +            if (tree.sym == null) {
   2.364 +                return;
   2.365 +            }
   2.366  
   2.367              JCClassDecl classDefPrev = classDef;
   2.368              int firstadrPrev = firstadr;
   2.369              int nextadrPrev = nextadr;
   2.370 -            ListBuffer<AssignPendingExit> pendingExitsPrev = pendingExits;
   2.371 -            Lint lintPrev = lint;
   2.372 +            ListBuffer<P> pendingExitsPrev = pendingExits;
   2.373  
   2.374 -            pendingExits = new ListBuffer<AssignPendingExit>();
   2.375 +            pendingExits = new ListBuffer<P>();
   2.376              if (tree.name != names.empty) {
   2.377                  firstadr = nextadr;
   2.378              }
   2.379              classDef = tree;
   2.380 -            lint = lint.augment(tree.sym);
   2.381 -
   2.382              try {
   2.383                  // define all the static fields
   2.384                  for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   2.385 @@ -1664,8 +1663,9 @@
   2.386                          JCVariableDecl def = (JCVariableDecl)l.head;
   2.387                          if ((def.mods.flags & STATIC) != 0) {
   2.388                              VarSymbol sym = def.sym;
   2.389 -                            if (trackable(sym))
   2.390 +                            if (trackable(sym)) {
   2.391                                  newVar(def);
   2.392 +                            }
   2.393                          }
   2.394                      }
   2.395                  }
   2.396 @@ -1684,8 +1684,9 @@
   2.397                          JCVariableDecl def = (JCVariableDecl)l.head;
   2.398                          if ((def.mods.flags & STATIC) == 0) {
   2.399                              VarSymbol sym = def.sym;
   2.400 -                            if (trackable(sym))
   2.401 +                            if (trackable(sym)) {
   2.402                                  newVar(def);
   2.403 +                            }
   2.404                          }
   2.405                      }
   2.406                  }
   2.407 @@ -1709,21 +1710,25 @@
   2.408                  nextadr = nextadrPrev;
   2.409                  firstadr = firstadrPrev;
   2.410                  classDef = classDefPrev;
   2.411 -                lint = lintPrev;
   2.412              }
   2.413          }
   2.414  
   2.415 +        @Override
   2.416          public void visitMethodDef(JCMethodDecl tree) {
   2.417 -            if (tree.body == null) return;
   2.418 +            if (tree.body == null) {
   2.419 +                return;
   2.420 +            }
   2.421 +            /*  MemberEnter can generate synthetic methods, ignore them
   2.422 +             */
   2.423 +            if ((tree.sym.flags() & SYNTHETIC) != 0) {
   2.424 +                return;
   2.425 +            }
   2.426  
   2.427              final Bits initsPrev = new Bits(inits);
   2.428              final Bits uninitsPrev = new Bits(uninits);
   2.429              int nextadrPrev = nextadr;
   2.430              int firstadrPrev = firstadr;
   2.431              int returnadrPrev = returnadr;
   2.432 -            Lint lintPrev = lint;
   2.433 -
   2.434 -            lint = lint.augment(tree.sym);
   2.435  
   2.436              Assert.check(pendingExits.isEmpty());
   2.437  
   2.438 @@ -1731,13 +1736,17 @@
   2.439                  boolean isInitialConstructor =
   2.440                      TreeInfo.isInitialConstructor(tree);
   2.441  
   2.442 -                if (!isInitialConstructor)
   2.443 +                if (!isInitialConstructor) {
   2.444                      firstadr = nextadr;
   2.445 +                }
   2.446                  for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
   2.447                      JCVariableDecl def = l.head;
   2.448                      scan(def);
   2.449 -                    inits.incl(def.sym.adr);
   2.450 -                    uninits.excl(def.sym.adr);
   2.451 +                    Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
   2.452 +                    /*  If we are executing the code from Gen, then there can be
   2.453 +                     *  synthetic or mandated variables, ignore them.
   2.454 +                     */
   2.455 +                    initParam(def);
   2.456                  }
   2.457                  // else we are in an instance initializer block;
   2.458                  // leave caught unchanged.
   2.459 @@ -1761,39 +1770,42 @@
   2.460                          }
   2.461                      }
   2.462                  }
   2.463 -                List<AssignPendingExit> exits = pendingExits.toList();
   2.464 -                pendingExits = new ListBuffer<AssignPendingExit>();
   2.465 +                List<P> exits = pendingExits.toList();
   2.466 +                pendingExits = new ListBuffer<>();
   2.467                  while (exits.nonEmpty()) {
   2.468 -                    AssignPendingExit exit = exits.head;
   2.469 +                    P exit = exits.head;
   2.470                      exits = exits.tail;
   2.471                      Assert.check(exit.tree.hasTag(RETURN), exit.tree);
   2.472                      if (isInitialConstructor) {
   2.473 -                        inits.assign(exit.exit_inits);
   2.474 -                        for (int i = firstadr; i < nextadr; i++)
   2.475 +                        assignToInits(exit.tree, exit.exit_inits);
   2.476 +                        for (int i = firstadr; i < nextadr; i++) {
   2.477                              checkInit(exit.tree.pos(), vardecls[i].sym);
   2.478 +                        }
   2.479                      }
   2.480                  }
   2.481              } finally {
   2.482 -                inits.assign(initsPrev);
   2.483 +                assignToInits(tree, initsPrev);
   2.484                  uninits.assign(uninitsPrev);
   2.485                  nextadr = nextadrPrev;
   2.486                  firstadr = firstadrPrev;
   2.487                  returnadr = returnadrPrev;
   2.488 -                lint = lintPrev;
   2.489              }
   2.490          }
   2.491  
   2.492 +        protected void initParam(JCVariableDecl def) {
   2.493 +            inits.incl(def.sym.adr);
   2.494 +            uninits.excl(def.sym.adr);
   2.495 +        }
   2.496 +
   2.497          public void visitVarDef(JCVariableDecl tree) {
   2.498              boolean track = trackable(tree.sym);
   2.499 -            if (track && tree.sym.owner.kind == MTH) newVar(tree);
   2.500 +            if (track && tree.sym.owner.kind == MTH) {
   2.501 +                newVar(tree);
   2.502 +            }
   2.503              if (tree.init != null) {
   2.504 -                Lint lintPrev = lint;
   2.505 -                lint = lint.augment(tree.sym);
   2.506 -                try{
   2.507 -                    scanExpr(tree.init);
   2.508 -                    if (track) letInit(tree.pos(), tree.sym);
   2.509 -                } finally {
   2.510 -                    lint = lintPrev;
   2.511 +                scanExpr(tree.init);
   2.512 +                if (track) {
   2.513 +                    letInit(tree.pos(), tree.sym);
   2.514                  }
   2.515              }
   2.516          }
   2.517 @@ -1804,14 +1816,18 @@
   2.518              nextadr = nextadrPrev;
   2.519          }
   2.520  
   2.521 +        int getLogNumberOfErrors() {
   2.522 +            return 0;
   2.523 +        }
   2.524 +
   2.525          public void visitDoLoop(JCDoWhileLoop tree) {
   2.526 -            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
   2.527 +            ListBuffer<P> prevPendingExits = pendingExits;
   2.528              FlowKind prevFlowKind = flowKind;
   2.529              flowKind = FlowKind.NORMAL;
   2.530              final Bits initsSkip = new Bits(true);
   2.531              final Bits uninitsSkip = new Bits(true);
   2.532 -            pendingExits = new ListBuffer<AssignPendingExit>();
   2.533 -            int prevErrors = log.nerrors;
   2.534 +            pendingExits = new ListBuffer<P>();
   2.535 +            int prevErrors = getLogNumberOfErrors();
   2.536              do {
   2.537                  final Bits uninitsEntry = new Bits(uninits);
   2.538                  uninitsEntry.excludeFrom(nextadr);
   2.539 @@ -1822,28 +1838,28 @@
   2.540                      initsSkip.assign(initsWhenFalse);
   2.541                      uninitsSkip.assign(uninitsWhenFalse);
   2.542                  }
   2.543 -                if (log.nerrors !=  prevErrors ||
   2.544 +                if (getLogNumberOfErrors() !=  prevErrors ||
   2.545                      flowKind.isFinal() ||
   2.546                      new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
   2.547                      break;
   2.548 -                inits.assign(initsWhenTrue);
   2.549 +                assignToInits(tree.cond, initsWhenTrue);
   2.550                  uninits.assign(uninitsEntry.andSet(uninitsWhenTrue));
   2.551                  flowKind = FlowKind.SPECULATIVE_LOOP;
   2.552              } while (true);
   2.553              flowKind = prevFlowKind;
   2.554 -            inits.assign(initsSkip);
   2.555 +            assignToInits(tree, initsSkip);
   2.556              uninits.assign(uninitsSkip);
   2.557              resolveBreaks(tree, prevPendingExits);
   2.558          }
   2.559  
   2.560          public void visitWhileLoop(JCWhileLoop tree) {
   2.561 -            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
   2.562 +            ListBuffer<P> prevPendingExits = pendingExits;
   2.563              FlowKind prevFlowKind = flowKind;
   2.564              flowKind = FlowKind.NORMAL;
   2.565              final Bits initsSkip = new Bits(true);
   2.566              final Bits uninitsSkip = new Bits(true);
   2.567 -            pendingExits = new ListBuffer<AssignPendingExit>();
   2.568 -            int prevErrors = log.nerrors;
   2.569 +            pendingExits = new ListBuffer<>();
   2.570 +            int prevErrors = getLogNumberOfErrors();
   2.571              final Bits uninitsEntry = new Bits(uninits);
   2.572              uninitsEntry.excludeFrom(nextadr);
   2.573              do {
   2.574 @@ -1852,35 +1868,36 @@
   2.575                      initsSkip.assign(initsWhenFalse) ;
   2.576                      uninitsSkip.assign(uninitsWhenFalse);
   2.577                  }
   2.578 -                inits.assign(initsWhenTrue);
   2.579 +                assignToInits(tree, initsWhenTrue);
   2.580                  uninits.assign(uninitsWhenTrue);
   2.581                  scan(tree.body);
   2.582                  resolveContinues(tree);
   2.583 -                if (log.nerrors != prevErrors ||
   2.584 +                if (getLogNumberOfErrors() != prevErrors ||
   2.585                      flowKind.isFinal() ||
   2.586 -                    new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
   2.587 +                    new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) {
   2.588                      break;
   2.589 +                }
   2.590                  uninits.assign(uninitsEntry.andSet(uninits));
   2.591                  flowKind = FlowKind.SPECULATIVE_LOOP;
   2.592              } while (true);
   2.593              flowKind = prevFlowKind;
   2.594              //a variable is DA/DU after the while statement, if it's DA/DU assuming the
   2.595              //branch is not taken AND if it's DA/DU before any break statement
   2.596 -            inits.assign(initsSkip);
   2.597 +            assignToInits(tree.body, initsSkip);
   2.598              uninits.assign(uninitsSkip);
   2.599              resolveBreaks(tree, prevPendingExits);
   2.600          }
   2.601  
   2.602          public void visitForLoop(JCForLoop tree) {
   2.603 -            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
   2.604 +            ListBuffer<P> prevPendingExits = pendingExits;
   2.605              FlowKind prevFlowKind = flowKind;
   2.606              flowKind = FlowKind.NORMAL;
   2.607              int nextadrPrev = nextadr;
   2.608              scan(tree.init);
   2.609              final Bits initsSkip = new Bits(true);
   2.610              final Bits uninitsSkip = new Bits(true);
   2.611 -            pendingExits = new ListBuffer<AssignPendingExit>();
   2.612 -            int prevErrors = log.nerrors;
   2.613 +            pendingExits = new ListBuffer<P>();
   2.614 +            int prevErrors = getLogNumberOfErrors();
   2.615              do {
   2.616                  final Bits uninitsEntry = new Bits(uninits);
   2.617                  uninitsEntry.excludeFrom(nextadr);
   2.618 @@ -1890,7 +1907,7 @@
   2.619                          initsSkip.assign(initsWhenFalse);
   2.620                          uninitsSkip.assign(uninitsWhenFalse);
   2.621                      }
   2.622 -                    inits.assign(initsWhenTrue);
   2.623 +                    assignToInits(tree.body, initsWhenTrue);
   2.624                      uninits.assign(uninitsWhenTrue);
   2.625                  } else if (!flowKind.isFinal()) {
   2.626                      initsSkip.assign(inits);
   2.627 @@ -1901,7 +1918,7 @@
   2.628                  scan(tree.body);
   2.629                  resolveContinues(tree);
   2.630                  scan(tree.step);
   2.631 -                if (log.nerrors != prevErrors ||
   2.632 +                if (getLogNumberOfErrors() != prevErrors ||
   2.633                      flowKind.isFinal() ||
   2.634                      new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
   2.635                      break;
   2.636 @@ -1911,7 +1928,7 @@
   2.637              flowKind = prevFlowKind;
   2.638              //a variable is DA/DU after a for loop, if it's DA/DU assuming the
   2.639              //branch is not taken AND if it's DA/DU before any break statement
   2.640 -            inits.assign(initsSkip);
   2.641 +            assignToInits(tree.body, initsSkip);
   2.642              uninits.assign(uninitsSkip);
   2.643              resolveBreaks(tree, prevPendingExits);
   2.644              nextadr = nextadrPrev;
   2.645 @@ -1920,7 +1937,7 @@
   2.646          public void visitForeachLoop(JCEnhancedForLoop tree) {
   2.647              visitVarDef(tree.var);
   2.648  
   2.649 -            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
   2.650 +            ListBuffer<P> prevPendingExits = pendingExits;
   2.651              FlowKind prevFlowKind = flowKind;
   2.652              flowKind = FlowKind.NORMAL;
   2.653              int nextadrPrev = nextadr;
   2.654 @@ -1929,14 +1946,14 @@
   2.655              final Bits uninitsStart = new Bits(uninits);
   2.656  
   2.657              letInit(tree.pos(), tree.var.sym);
   2.658 -            pendingExits = new ListBuffer<AssignPendingExit>();
   2.659 -            int prevErrors = log.nerrors;
   2.660 +            pendingExits = new ListBuffer<P>();
   2.661 +            int prevErrors = getLogNumberOfErrors();
   2.662              do {
   2.663                  final Bits uninitsEntry = new Bits(uninits);
   2.664                  uninitsEntry.excludeFrom(nextadr);
   2.665                  scan(tree.body);
   2.666                  resolveContinues(tree);
   2.667 -                if (log.nerrors != prevErrors ||
   2.668 +                if (getLogNumberOfErrors() != prevErrors ||
   2.669                      flowKind.isFinal() ||
   2.670                      new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
   2.671                      break;
   2.672 @@ -1944,41 +1961,50 @@
   2.673                  flowKind = FlowKind.SPECULATIVE_LOOP;
   2.674              } while (true);
   2.675              flowKind = prevFlowKind;
   2.676 -            inits.assign(initsStart);
   2.677 +            assignToInits(tree.body, initsStart);
   2.678              uninits.assign(uninitsStart.andSet(uninits));
   2.679              resolveBreaks(tree, prevPendingExits);
   2.680              nextadr = nextadrPrev;
   2.681          }
   2.682  
   2.683          public void visitLabelled(JCLabeledStatement tree) {
   2.684 -            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
   2.685 -            pendingExits = new ListBuffer<AssignPendingExit>();
   2.686 +            ListBuffer<P> prevPendingExits = pendingExits;
   2.687 +            pendingExits = new ListBuffer<P>();
   2.688              scan(tree.body);
   2.689              resolveBreaks(tree, prevPendingExits);
   2.690          }
   2.691  
   2.692          public void visitSwitch(JCSwitch tree) {
   2.693 -            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
   2.694 -            pendingExits = new ListBuffer<AssignPendingExit>();
   2.695 +            ListBuffer<P> prevPendingExits = pendingExits;
   2.696 +            pendingExits = new ListBuffer<>();
   2.697              int nextadrPrev = nextadr;
   2.698              scanExpr(tree.selector);
   2.699              final Bits initsSwitch = new Bits(inits);
   2.700              final Bits uninitsSwitch = new Bits(uninits);
   2.701              boolean hasDefault = false;
   2.702              for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
   2.703 -                inits.assign(initsSwitch);
   2.704 +                assignToInits(l.head, initsSwitch);
   2.705                  uninits.assign(uninits.andSet(uninitsSwitch));
   2.706                  JCCase c = l.head;
   2.707 -                if (c.pat == null)
   2.708 +                if (c.pat == null) {
   2.709                      hasDefault = true;
   2.710 -                else
   2.711 +                } else {
   2.712                      scanExpr(c.pat);
   2.713 +                }
   2.714 +                if (hasDefault) {
   2.715 +                    assignToInits(null, initsSwitch);
   2.716 +                    uninits.assign(uninits.andSet(uninitsSwitch));
   2.717 +                }
   2.718                  scan(c.stats);
   2.719                  addVars(c.stats, initsSwitch, uninitsSwitch);
   2.720 +                if (!hasDefault) {
   2.721 +                    assignToInits(l.head.stats.last(), initsSwitch);
   2.722 +                    uninits.assign(uninits.andSet(uninitsSwitch));
   2.723 +                }
   2.724                  // Warn about fall-through if lint switch fallthrough enabled.
   2.725              }
   2.726              if (!hasDefault) {
   2.727 -                inits.andSet(initsSwitch);
   2.728 +                andSetInits(null, initsSwitch);
   2.729              }
   2.730              resolveBreaks(tree, prevPendingExits);
   2.731              nextadr = nextadrPrev;
   2.732 @@ -1997,11 +2023,17 @@
   2.733                  }
   2.734              }
   2.735  
   2.736 +        boolean isEnabled(Lint.LintCategory lc) {
   2.737 +            return false;
   2.738 +        }
   2.739 +
   2.740 +        void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos, String key, Object ... args) {}
   2.741 +
   2.742          public void visitTry(JCTry tree) {
   2.743              ListBuffer<JCVariableDecl> resourceVarDecls = ListBuffer.lb();
   2.744              final Bits uninitsTryPrev = new Bits(uninitsTry);
   2.745 -            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
   2.746 -            pendingExits = new ListBuffer<AssignPendingExit>();
   2.747 +            ListBuffer<P> prevPendingExits = pendingExits;
   2.748 +            pendingExits = new ListBuffer<>();
   2.749              final Bits initsTry = new Bits(inits);
   2.750              uninitsTry.assign(uninits);
   2.751              for (JCTree resource : tree.resources) {
   2.752 @@ -2023,10 +2055,10 @@
   2.753              int nextadrCatch = nextadr;
   2.754  
   2.755              if (!resourceVarDecls.isEmpty() &&
   2.756 -                    lint.isEnabled(Lint.LintCategory.TRY)) {
   2.757 +                    isEnabled(Lint.LintCategory.TRY)) {
   2.758                  for (JCVariableDecl resVar : resourceVarDecls) {
   2.759                      if (unrefdResources.includes(resVar.sym)) {
   2.760 -                        log.warning(Lint.LintCategory.TRY, resVar.pos(),
   2.761 +                        reportWarning(Lint.LintCategory.TRY, resVar.pos(),
   2.762                                      "try.resource.not.referenced", resVar.sym);
   2.763                          unrefdResources.remove(resVar.sym);
   2.764                      }
   2.765 @@ -2042,20 +2074,22 @@
   2.766  
   2.767              for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
   2.768                  JCVariableDecl param = l.head.param;
   2.769 -                inits.assign(initsCatchPrev);
   2.770 +                assignToInits(tree.body, initsCatchPrev);
   2.771                  uninits.assign(uninitsCatchPrev);
   2.772                  scan(param);
   2.773 -                inits.incl(param.sym.adr);
   2.774 -                uninits.excl(param.sym.adr);
   2.775 +                /* If this is a TWR and we are executing the code from Gen,
   2.776 +                 * then there can be synthetic variables, ignore them.
   2.777 +                 */
   2.778 +                initParam(param);
   2.779                  scan(l.head.body);
   2.780                  initsEnd.andSet(inits);
   2.781                  uninitsEnd.andSet(uninits);
   2.782                  nextadr = nextadrCatch;
   2.783              }
   2.784              if (tree.finalizer != null) {
   2.785 -                inits.assign(initsTry);
   2.786 +                assignToInits(tree.finalizer, initsTry);
   2.787                  uninits.assign(uninitsTry);
   2.788 -                ListBuffer<AssignPendingExit> exits = pendingExits;
   2.789 +                ListBuffer<P> exits = pendingExits;
   2.790                  pendingExits = prevPendingExits;
   2.791                  scan(tree.finalizer);
   2.792                  if (!tree.finallyCanCompleteNormally) {
   2.793 @@ -2065,19 +2099,19 @@
   2.794                      // FIX: this doesn't preserve source order of exits in catch
   2.795                      // versus finally!
   2.796                      while (exits.nonEmpty()) {
   2.797 -                        AssignPendingExit exit = exits.next();
   2.798 +                        P exit = exits.next();
   2.799                          if (exit.exit_inits != null) {
   2.800                              exit.exit_inits.orSet(inits);
   2.801                              exit.exit_uninits.andSet(uninits);
   2.802                          }
   2.803                          pendingExits.append(exit);
   2.804                      }
   2.805 -                    inits.orSet(initsEnd);
   2.806 +                    orSetInits(tree, initsEnd);
   2.807                  }
   2.808              } else {
   2.809 -                inits.assign(initsEnd);
   2.810 +                assignToInits(tree, initsEnd);
   2.811                  uninits.assign(uninitsEnd);
   2.812 -                ListBuffer<AssignPendingExit> exits = pendingExits;
   2.813 +                ListBuffer<P> exits = pendingExits;
   2.814                  pendingExits = prevPendingExits;
   2.815                  while (exits.nonEmpty()) pendingExits.append(exits.next());
   2.816              }
   2.817 @@ -2088,7 +2122,7 @@
   2.818              scanCond(tree.cond);
   2.819              final Bits initsBeforeElse = new Bits(initsWhenFalse);
   2.820              final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
   2.821 -            inits.assign(initsWhenTrue);
   2.822 +            assignToInits(tree.cond, initsWhenTrue);
   2.823              uninits.assign(uninitsWhenTrue);
   2.824              if (tree.truepart.type.hasTag(BOOLEAN) &&
   2.825                  tree.falsepart.type.hasTag(BOOLEAN)) {
   2.826 @@ -2101,7 +2135,7 @@
   2.827                  final Bits initsAfterThenWhenFalse = new Bits(initsWhenFalse);
   2.828                  final Bits uninitsAfterThenWhenTrue = new Bits(uninitsWhenTrue);
   2.829                  final Bits uninitsAfterThenWhenFalse = new Bits(uninitsWhenFalse);
   2.830 -                inits.assign(initsBeforeElse);
   2.831 +                assignToInits(tree.truepart, initsBeforeElse);
   2.832                  uninits.assign(uninitsBeforeElse);
   2.833                  scanCond(tree.falsepart);
   2.834                  initsWhenTrue.andSet(initsAfterThenWhenTrue);
   2.835 @@ -2112,10 +2146,10 @@
   2.836                  scanExpr(tree.truepart);
   2.837                  final Bits initsAfterThen = new Bits(inits);
   2.838                  final Bits uninitsAfterThen = new Bits(uninits);
   2.839 -                inits.assign(initsBeforeElse);
   2.840 +                assignToInits(tree.truepart, initsBeforeElse);
   2.841                  uninits.assign(uninitsBeforeElse);
   2.842                  scanExpr(tree.falsepart);
   2.843 -                inits.andSet(initsAfterThen);
   2.844 +                andSetInits(tree.falsepart, initsAfterThen);
   2.845                  uninits.andSet(uninitsAfterThen);
   2.846              }
   2.847          }
   2.848 @@ -2124,39 +2158,46 @@
   2.849              scanCond(tree.cond);
   2.850              final Bits initsBeforeElse = new Bits(initsWhenFalse);
   2.851              final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
   2.852 -            inits.assign(initsWhenTrue);
   2.853 +            assignToInits(tree.cond, initsWhenTrue);
   2.854              uninits.assign(uninitsWhenTrue);
   2.855              scan(tree.thenpart);
   2.856              if (tree.elsepart != null) {
   2.857                  final Bits initsAfterThen = new Bits(inits);
   2.858                  final Bits uninitsAfterThen = new Bits(uninits);
   2.859 -                inits.assign(initsBeforeElse);
   2.860 +                assignToInits(tree.thenpart, initsBeforeElse);
   2.861                  uninits.assign(uninitsBeforeElse);
   2.862                  scan(tree.elsepart);
   2.863 -                inits.andSet(initsAfterThen);
   2.864 +                andSetInits(tree.elsepart, initsAfterThen);
   2.865                  uninits.andSet(uninitsAfterThen);
   2.866              } else {
   2.867 -                inits.andSet(initsBeforeElse);
   2.868 +                andSetInits(tree.thenpart, initsBeforeElse);
   2.869                  uninits.andSet(uninitsBeforeElse);
   2.870              }
   2.871          }
   2.872  
   2.873 -        public void visitBreak(JCBreak tree) {
   2.874 -            recordExit(tree, new AssignPendingExit(tree, inits, uninits));
   2.875 +        protected P createNewPendingExit(JCTree tree, Bits inits, Bits uninits) {
   2.876 +            return null;
   2.877          }
   2.878  
   2.879 -        public void visitContinue(JCContinue tree) {
   2.880 -            recordExit(tree, new AssignPendingExit(tree, inits, uninits));
   2.881 +        @Override
   2.882 +        public void visitBreak(JCBreak tree) {
   2.883 +            recordExit(tree, createNewPendingExit(tree, inits, uninits));
   2.884          }
   2.885  
   2.886 +        @Override
   2.887 +        public void visitContinue(JCContinue tree) {
   2.888 +            recordExit(tree, createNewPendingExit(tree, inits, uninits));
   2.889 +        }
   2.890 +
   2.891 +        @Override
   2.892          public void visitReturn(JCReturn tree) {
   2.893              scanExpr(tree.expr);
   2.894 -            recordExit(tree, new AssignPendingExit(tree, inits, uninits));
   2.895 +            recordExit(tree, createNewPendingExit(tree, inits, uninits));
   2.896          }
   2.897  
   2.898          public void visitThrow(JCThrow tree) {
   2.899              scanExpr(tree.expr);
   2.900 -            markDead();
   2.901 +            markDead(tree.expr);
   2.902          }
   2.903  
   2.904          public void visitApply(JCMethodInvocation tree) {
   2.905 @@ -2175,10 +2216,10 @@
   2.906              final Bits prevUninits = new Bits(uninits);
   2.907              final Bits prevInits = new Bits(inits);
   2.908              int returnadrPrev = returnadr;
   2.909 -            ListBuffer<AssignPendingExit> prevPending = pendingExits;
   2.910 +            ListBuffer<P> prevPending = pendingExits;
   2.911              try {
   2.912                  returnadr = nextadr;
   2.913 -                pendingExits = new ListBuffer<AssignPendingExit>();
   2.914 +                pendingExits = new ListBuffer<P>();
   2.915                  for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
   2.916                      JCVariableDecl def = l.head;
   2.917                      scan(def);
   2.918 @@ -2194,7 +2235,7 @@
   2.919              finally {
   2.920                  returnadr = returnadrPrev;
   2.921                  uninits.assign(prevUninits);
   2.922 -                inits.assign(prevInits);
   2.923 +                assignToInits(tree, prevInits);
   2.924                  pendingExits = prevPending;
   2.925              }
   2.926          }
   2.927 @@ -2210,11 +2251,11 @@
   2.928              scanCond(tree.cond);
   2.929              uninitsExit.andSet(uninitsWhenTrue);
   2.930              if (tree.detail != null) {
   2.931 -                inits.assign(initsWhenFalse);
   2.932 +                assignToInits(tree, initsWhenFalse);
   2.933                  uninits.assign(uninitsWhenFalse);
   2.934                  scanExpr(tree.detail);
   2.935              }
   2.936 -            inits.assign(initsExit);
   2.937 +            assignToInits(tree, initsExit);
   2.938              uninits.assign(uninitsExit);
   2.939          }
   2.940  
   2.941 @@ -2260,7 +2301,7 @@
   2.942                  scanCond(tree.lhs);
   2.943                  final Bits initsWhenFalseLeft = new Bits(initsWhenFalse);
   2.944                  final Bits uninitsWhenFalseLeft = new Bits(uninitsWhenFalse);
   2.945 -                inits.assign(initsWhenTrue);
   2.946 +                assignToInits(tree.lhs, initsWhenTrue);
   2.947                  uninits.assign(uninitsWhenTrue);
   2.948                  scanCond(tree.rhs);
   2.949                  initsWhenFalse.andSet(initsWhenFalseLeft);
   2.950 @@ -2270,7 +2311,7 @@
   2.951                  scanCond(tree.lhs);
   2.952                  final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
   2.953                  final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
   2.954 -                inits.assign(initsWhenFalse);
   2.955 +                assignToInits(tree.lhs, initsWhenFalse);
   2.956                  uninits.assign(uninitsWhenFalse);
   2.957                  scanCond(tree.rhs);
   2.958                  initsWhenTrue.andSet(initsWhenTrueLeft);
   2.959 @@ -2308,14 +2349,12 @@
   2.960  
   2.961          /** Perform definite assignment/unassignment analysis on a tree.
   2.962           */
   2.963 -        public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
   2.964 -            analyzeTree(env, env.tree, make);
   2.965 -        }
   2.966 +        public void analyzeTree(Env<?> env) {
   2.967 +            analyzeTree(env, env.tree);
   2.968 +         }
   2.969  
   2.970 -        public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
   2.971 +        public void analyzeTree(Env<?> env, JCTree tree) {
   2.972              try {
   2.973 -                attrEnv = env;
   2.974 -                Flow.this.make = make;
   2.975                  startPos = tree.pos().getStartPosition();
   2.976  
   2.977                  if (vardecls == null)
   2.978 @@ -2325,7 +2364,7 @@
   2.979                          vardecls[i] = null;
   2.980                  firstadr = 0;
   2.981                  nextadr = 0;
   2.982 -                pendingExits = new ListBuffer<AssignPendingExit>();
   2.983 +                pendingExits = new ListBuffer<>();
   2.984                  this.classDef = null;
   2.985                  unrefdResources = new Scope(env.enclClass.sym);
   2.986                  scan(tree);
   2.987 @@ -2334,18 +2373,160 @@
   2.988                  startPos = -1;
   2.989                  resetBits(inits, uninits, uninitsTry, initsWhenTrue,
   2.990                          initsWhenFalse, uninitsWhenTrue, uninitsWhenFalse);
   2.991 -                if (vardecls != null) for (int i=0; i<vardecls.length; i++)
   2.992 -                    vardecls[i] = null;
   2.993 +                if (vardecls != null) {
   2.994 +                    for (int i=0; i<vardecls.length; i++)
   2.995 +                        vardecls[i] = null;
   2.996 +                }
   2.997                  firstadr = 0;
   2.998                  nextadr = 0;
   2.999                  pendingExits = null;
  2.1000 -                Flow.this.make = null;
  2.1001                  this.classDef = null;
  2.1002                  unrefdResources = null;
  2.1003              }
  2.1004          }
  2.1005      }
  2.1006  
  2.1007 +    public static class AssignAnalyzer
  2.1008 +        extends AbstractAssignAnalyzer<AssignAnalyzer.AssignPendingExit> {
  2.1009 +
  2.1010 +        Log log;
  2.1011 +        Lint lint;
  2.1012 +
  2.1013 +        public static class AssignPendingExit
  2.1014 +            extends AbstractAssignAnalyzer.AbstractAssignPendingExit {
  2.1015 +
  2.1016 +            public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
  2.1017 +                super(tree, inits, uninits);
  2.1018 +            }
  2.1019 +        }
  2.1020 +
  2.1021 +        public AssignAnalyzer(Log log, Symtab syms, Lint lint, Names names) {
  2.1022 +            super(new Bits(), syms, names);
  2.1023 +            this.log = log;
  2.1024 +            this.lint = lint;
  2.1025 +        }
  2.1026 +
  2.1027 +        @Override
  2.1028 +        protected AssignPendingExit createNewPendingExit(JCTree tree,
  2.1029 +            Bits inits, Bits uninits) {
  2.1030 +            return new AssignPendingExit(tree, inits, uninits);
  2.1031 +        }
  2.1032 +
  2.1033 +        /** Record an initialization of a trackable variable.
  2.1034 +         */
  2.1035 +        @Override
  2.1036 +        void letInit(DiagnosticPosition pos, VarSymbol sym) {
  2.1037 +            if (sym.adr >= firstadr && trackable(sym)) {
  2.1038 +                if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {
  2.1039 +                    if (!uninits.isMember(sym.adr)) {
  2.1040 +                        //assignment targeting an effectively final variable
  2.1041 +                        //makes the variable lose its status of effectively final
  2.1042 +                        //if the variable is _not_ definitively unassigned
  2.1043 +                        sym.flags_field &= ~EFFECTIVELY_FINAL;
  2.1044 +                    } else {
  2.1045 +                        uninit(sym);
  2.1046 +                    }
  2.1047 +                }
  2.1048 +                else if ((sym.flags() & FINAL) != 0) {
  2.1049 +                    if ((sym.flags() & PARAMETER) != 0) {
  2.1050 +                        if ((sym.flags() & UNION) != 0) { //multi-catch parameter
  2.1051 +                            log.error(pos, "multicatch.parameter.may.not.be.assigned", sym);
  2.1052 +                        }
  2.1053 +                        else {
  2.1054 +                            log.error(pos, "final.parameter.may.not.be.assigned",
  2.1055 +                                  sym);
  2.1056 +                        }
  2.1057 +                    } else if (!uninits.isMember(sym.adr)) {
  2.1058 +                        log.error(pos, flowKind.errKey, sym);
  2.1059 +                    } else {
  2.1060 +                        uninit(sym);
  2.1061 +                    }
  2.1062 +                }
  2.1063 +                inits.incl(sym.adr);
  2.1064 +            } else if ((sym.flags() & FINAL) != 0) {
  2.1065 +                log.error(pos, "var.might.already.be.assigned", sym);
  2.1066 +            }
  2.1067 +        }
  2.1068 +
  2.1069 +        @Override
  2.1070 +        void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {
  2.1071 +            if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
  2.1072 +                trackable(sym) &&
  2.1073 +                !inits.isMember(sym.adr)) {
  2.1074 +                log.error(pos, errkey, sym);
  2.1075 +                inits.incl(sym.adr);
  2.1076 +            }
  2.1077 +        }
  2.1078 +
  2.1079 +        @Override
  2.1080 +        void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos,
  2.1081 +            String key, Object ... args) {
  2.1082 +            log.warning(lc, pos, key, args);
  2.1083 +        }
  2.1084 +
  2.1085 +        @Override
  2.1086 +        int getLogNumberOfErrors() {
  2.1087 +            return log.nerrors;
  2.1088 +        }
  2.1089 +
  2.1090 +        @Override
  2.1091 +        boolean isEnabled(Lint.LintCategory lc) {
  2.1092 +            return lint.isEnabled(lc);
  2.1093 +        }
  2.1094 +
  2.1095 +        @Override
  2.1096 +        public void visitClassDef(JCClassDecl tree) {
  2.1097 +            if (tree.sym == null) {
  2.1098 +                return;
  2.1099 +            }
  2.1100 +
  2.1101 +            Lint lintPrev = lint;
  2.1102 +            lint = lint.augment(tree.sym);
  2.1103 +            try {
  2.1104 +                super.visitClassDef(tree);
  2.1105 +            } finally {
  2.1106 +                lint = lintPrev;
  2.1107 +            }
  2.1108 +        }
  2.1109 +
  2.1110 +        @Override
  2.1111 +        public void visitMethodDef(JCMethodDecl tree) {
  2.1112 +            if (tree.body == null) {
  2.1113 +                return;
  2.1114 +            }
  2.1115 +
  2.1116 +            /*  MemberEnter can generate synthetic methods ignore them
  2.1117 +             */
  2.1118 +            if ((tree.sym.flags() & SYNTHETIC) != 0) {
  2.1119 +                return;
  2.1120 +            }
  2.1121 +
  2.1122 +            Lint lintPrev = lint;
  2.1123 +            lint = lint.augment(tree.sym);
  2.1124 +            try {
  2.1125 +                super.visitMethodDef(tree);
  2.1126 +            } finally {
  2.1127 +                lint = lintPrev;
  2.1128 +            }
  2.1129 +        }
  2.1130 +
  2.1131 +        @Override
  2.1132 +        public void visitVarDef(JCVariableDecl tree) {
  2.1133 +            if (tree.init == null) {
  2.1134 +                super.visitVarDef(tree);
  2.1135 +            } else {
  2.1136 +                Lint lintPrev = lint;
  2.1137 +                lint = lint.augment(tree.sym);
  2.1138 +                try{
  2.1139 +                    super.visitVarDef(tree);
  2.1140 +                } finally {
  2.1141 +                    lint = lintPrev;
  2.1142 +                }
  2.1143 +            }
  2.1144 +        }
  2.1145 +
  2.1146 +    }
  2.1147 +
  2.1148      /**
  2.1149       * This pass implements the last step of the dataflow analysis, namely
  2.1150       * the effectively-final analysis check. This checks that every local variable
  2.1151 @@ -2358,7 +2539,7 @@
  2.1152          JCTree currentTree; //local class or lambda
  2.1153  
  2.1154          @Override
  2.1155 -        void markDead() {
  2.1156 +        void markDead(JCTree tree) {
  2.1157              //do nothing
  2.1158          }
  2.1159  
     3.1 --- a/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Sat Sep 14 15:23:21 2013 +0100
     3.2 +++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Sat Sep 14 19:04:47 2013 +0100
     3.3 @@ -1745,6 +1745,11 @@
     3.4                          // Just erase the type var
     3.5                          ret = new VarSymbol(sym.flags(), name,
     3.6                                  types.erasure(sym.type), sym.owner);
     3.7 +
     3.8 +                        /* this information should also be kept for LVT generation at Gen
     3.9 +                         * a Symbol with pos < startPos won't be tracked.
    3.10 +                         */
    3.11 +                        ((VarSymbol)ret).pos = ((VarSymbol)sym).pos;
    3.12                          break;
    3.13                      case CAPTURED_VAR:
    3.14                          ret = new VarSymbol(SYNTHETIC | FINAL, name, types.erasure(sym.type), translatedSym) {
     4.1 --- a/src/share/classes/com/sun/tools/javac/comp/Lower.java	Sat Sep 14 15:23:21 2013 +0100
     4.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Lower.java	Sat Sep 14 19:04:47 2013 +0100
     4.3 @@ -1479,7 +1479,12 @@
     4.4       *  @param owner      The class in which the definitions go.
     4.5       */
     4.6      List<JCVariableDecl> freevarDefs(int pos, List<VarSymbol> freevars, Symbol owner) {
     4.7 -        long flags = FINAL | SYNTHETIC;
     4.8 +        return freevarDefs(pos, freevars, owner, 0);
     4.9 +    }
    4.10 +
    4.11 +    List<JCVariableDecl> freevarDefs(int pos, List<VarSymbol> freevars, Symbol owner,
    4.12 +            long additionalFlags) {
    4.13 +        long flags = FINAL | SYNTHETIC | additionalFlags;
    4.14          if (owner.kind == TYP &&
    4.15              target.usePrivateSyntheticFields())
    4.16              flags |= PRIVATE;
    4.17 @@ -1542,7 +1547,7 @@
    4.18              (owner.isConstructor() && c.isInner() &&
    4.19               !c.isPrivate() && !c.isStatic());
    4.20          long flags =
    4.21 -            FINAL | (isMandated ? MANDATED : SYNTHETIC);
    4.22 +            FINAL | (isMandated ? MANDATED : SYNTHETIC) | PARAMETER;
    4.23          VarSymbol outerThis = makeOuterThisVarSymbol(owner, flags);
    4.24          owner.extraParams = owner.extraParams.prepend(outerThis);
    4.25          return makeOuterThisVarDecl(pos, outerThis);
    4.26 @@ -1626,7 +1631,8 @@
    4.27      JCTree makeTwrTry(JCTry tree) {
    4.28          make_at(tree.pos());
    4.29          twrVars = twrVars.dup();
    4.30 -        JCBlock twrBlock = makeTwrBlock(tree.resources, tree.body, 0);
    4.31 +        JCBlock twrBlock = makeTwrBlock(tree.resources, tree.body,
    4.32 +                tree.finallyCanCompleteNormally, 0);
    4.33          if (tree.catchers.isEmpty() && tree.finalizer == null)
    4.34              result = translate(twrBlock);
    4.35          else
    4.36 @@ -1635,7 +1641,8 @@
    4.37          return result;
    4.38      }
    4.39  
    4.40 -    private JCBlock makeTwrBlock(List<JCTree> resources, JCBlock block, int depth) {
    4.41 +    private JCBlock makeTwrBlock(List<JCTree> resources, JCBlock block,
    4.42 +            boolean finallyCanCompleteNormally, int depth) {
    4.43          if (resources.isEmpty())
    4.44              return block;
    4.45  
    4.46 @@ -1691,17 +1698,20 @@
    4.47          make.at(TreeInfo.endPos(block));
    4.48          JCBlock finallyClause = makeTwrFinallyClause(primaryException, expr);
    4.49          make.at(oldPos);
    4.50 -        JCTry outerTry = make.Try(makeTwrBlock(resources.tail, block, depth + 1),
    4.51 +        JCTry outerTry = make.Try(makeTwrBlock(resources.tail, block,
    4.52 +                                    finallyCanCompleteNormally, depth + 1),
    4.53                                    List.<JCCatch>of(catchClause),
    4.54                                    finallyClause);
    4.55 +        outerTry.finallyCanCompleteNormally = finallyCanCompleteNormally;
    4.56          stats.add(outerTry);
    4.57 -        return make.Block(0L, stats.toList());
    4.58 +        JCBlock newBlock = make.Block(0L, stats.toList());
    4.59 +        return newBlock;
    4.60      }
    4.61  
    4.62      private JCBlock makeTwrFinallyClause(Symbol primaryException, JCExpression resource) {
    4.63          // primaryException.addSuppressed(catchException);
    4.64          VarSymbol catchException =
    4.65 -            new VarSymbol(0, make.paramName(2),
    4.66 +            new VarSymbol(SYNTHETIC, make.paramName(2),
    4.67                            syms.throwableType,
    4.68                            currentMethodSym);
    4.69          JCStatement addSuppressionStatement =
    4.70 @@ -1716,6 +1726,7 @@
    4.71          JCBlock catchBlock = make.Block(0L, List.<JCStatement>of(addSuppressionStatement));
    4.72          List<JCCatch> catchClauses = List.<JCCatch>of(make.Catch(catchExceptionDecl, catchBlock));
    4.73          JCTry tryTree = make.Try(tryBlock, catchClauses, null);
    4.74 +        tryTree.finallyCanCompleteNormally = true;
    4.75  
    4.76          // if (primaryException != null) {try...} else resourceClose;
    4.77          JCIf closeIfStatement = make.If(makeNonNullCheck(make.Ident(primaryException)),
    4.78 @@ -2016,7 +2027,7 @@
    4.79  
    4.80          // catchParam := ClassNotFoundException e1
    4.81          VarSymbol catchParam =
    4.82 -            new VarSymbol(0, make.paramName(1),
    4.83 +            new VarSymbol(SYNTHETIC, make.paramName(1),
    4.84                            syms.classNotFoundExceptionType,
    4.85                            classDollarSym);
    4.86  
    4.87 @@ -2704,7 +2715,7 @@
    4.88              JCVariableDecl otdef = null;
    4.89              if (currentClass.hasOuterInstance())
    4.90                  otdef = outerThisDef(tree.pos, m);
    4.91 -            List<JCVariableDecl> fvdefs = freevarDefs(tree.pos, fvs, m);
    4.92 +            List<JCVariableDecl> fvdefs = freevarDefs(tree.pos, fvs, m, PARAMETER);
    4.93  
    4.94              // Recursively translate result type, parameters and thrown list.
    4.95              tree.restype = translate(tree.restype);
    4.96 @@ -3363,18 +3374,18 @@
    4.97           */
    4.98          private void visitArrayForeachLoop(JCEnhancedForLoop tree) {
    4.99              make_at(tree.expr.pos());
   4.100 -            VarSymbol arraycache = new VarSymbol(0,
   4.101 +            VarSymbol arraycache = new VarSymbol(SYNTHETIC,
   4.102                                                   names.fromString("arr" + target.syntheticNameChar()),
   4.103                                                   tree.expr.type,
   4.104                                                   currentMethodSym);
   4.105              JCStatement arraycachedef = make.VarDef(arraycache, tree.expr);
   4.106 -            VarSymbol lencache = new VarSymbol(0,
   4.107 +            VarSymbol lencache = new VarSymbol(SYNTHETIC,
   4.108                                                 names.fromString("len" + target.syntheticNameChar()),
   4.109                                                 syms.intType,
   4.110                                                 currentMethodSym);
   4.111              JCStatement lencachedef = make.
   4.112                  VarDef(lencache, make.Select(make.Ident(arraycache), syms.lengthVar));
   4.113 -            VarSymbol index = new VarSymbol(0,
   4.114 +            VarSymbol index = new VarSymbol(SYNTHETIC,
   4.115                                              names.fromString("i" + target.syntheticNameChar()),
   4.116                                              syms.intType,
   4.117                                              currentMethodSym);
   4.118 @@ -3456,7 +3467,7 @@
   4.119                                             names.iterator,
   4.120                                             eType,
   4.121                                             List.<Type>nil());
   4.122 -            VarSymbol itvar = new VarSymbol(0, names.fromString("i" + target.syntheticNameChar()),
   4.123 +            VarSymbol itvar = new VarSymbol(SYNTHETIC, names.fromString("i" + target.syntheticNameChar()),
   4.124                                              types.erasure(types.asSuper(iterator.type.getReturnType(), syms.iteratorType.tsym)),
   4.125                                              currentMethodSym);
   4.126  
     5.1 --- a/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Sat Sep 14 15:23:21 2013 +0100
     5.2 +++ b/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Sat Sep 14 19:04:47 2013 +0100
     5.3 @@ -1532,7 +1532,7 @@
     5.4               *  parameters from baseInit.
     5.5               */
     5.6              initParams = List.nil();
     5.7 -            VarSymbol param = new VarSymbol(0, make.paramName(0), argtypes.head, init);
     5.8 +            VarSymbol param = new VarSymbol(PARAMETER, make.paramName(0), argtypes.head, init);
     5.9              initParams = initParams.append(param);
    5.10              argTypesList = argTypesList.tail;
    5.11          }
    5.12 @@ -1541,7 +1541,7 @@
    5.13              initParams = (initParams == null) ? List.<VarSymbol>nil() : initParams;
    5.14              List<VarSymbol> baseInitParams = baseInit.params;
    5.15              while (baseInitParams.nonEmpty() && argTypesList.nonEmpty()) {
    5.16 -                VarSymbol param = new VarSymbol(baseInitParams.head.flags(),
    5.17 +                VarSymbol param = new VarSymbol(baseInitParams.head.flags() | PARAMETER,
    5.18                          baseInitParams.head.name, argTypesList.head, init);
    5.19                  initParams = initParams.append(param);
    5.20                  baseInitParams = baseInitParams.tail;
     6.1 --- a/src/share/classes/com/sun/tools/javac/comp/TransTypes.java	Sat Sep 14 15:23:21 2013 +0100
     6.2 +++ b/src/share/classes/com/sun/tools/javac/comp/TransTypes.java	Sat Sep 14 19:04:47 2013 +0100
     6.3 @@ -310,7 +310,7 @@
     6.4              Type.MethodType mType = (Type.MethodType)bridgeType;
     6.5              List<Type> argTypes = mType.argtypes;
     6.6              while (implParams.nonEmpty() && argTypes.nonEmpty()) {
     6.7 -                VarSymbol param = new VarSymbol(implParams.head.flags() | SYNTHETIC,
     6.8 +                VarSymbol param = new VarSymbol(implParams.head.flags() | SYNTHETIC | PARAMETER,
     6.9                          implParams.head.name, argTypes.head, bridge);
    6.10                  param.setAttributes(implParams.head);
    6.11                  bridgeParams = bridgeParams.append(param);
     7.1 --- a/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Sat Sep 14 15:23:21 2013 +0100
     7.2 +++ b/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Sat Sep 14 19:04:47 2013 +0100
     7.3 @@ -37,7 +37,6 @@
     7.4  
     7.5  import com.sun.tools.javac.code.*;
     7.6  import com.sun.tools.javac.code.Attribute.RetentionPolicy;
     7.7 -import com.sun.tools.javac.code.Attribute.TypeCompound;
     7.8  import com.sun.tools.javac.code.Symbol.*;
     7.9  import com.sun.tools.javac.code.Type.*;
    7.10  import com.sun.tools.javac.code.Types.UniqueType;
    7.11 @@ -55,7 +54,6 @@
    7.12  import static com.sun.tools.javac.main.Option.*;
    7.13  import static javax.tools.StandardLocation.CLASS_OUTPUT;
    7.14  
    7.15 -
    7.16  /** This class provides operations to map an internal symbol table graph
    7.17   *  rooted in a ClassSymbol into a classfile.
    7.18   *
    7.19 @@ -1180,25 +1178,26 @@
    7.20  
    7.21          if (code.varBufferSize > 0) {
    7.22              int alenIdx = writeAttr(names.LocalVariableTable);
    7.23 -            databuf.appendChar(code.varBufferSize);
    7.24 -
    7.25 +            databuf.appendChar(code.getLVTSize());
    7.26              for (int i=0; i<code.varBufferSize; i++) {
    7.27                  Code.LocalVar var = code.varBuffer[i];
    7.28  
    7.29 -                // write variable info
    7.30 -                Assert.check(var.start_pc >= 0
    7.31 -                        && var.start_pc <= code.cp);
    7.32 -                databuf.appendChar(var.start_pc);
    7.33 -                Assert.check(var.length >= 0
    7.34 -                        && (var.start_pc + var.length) <= code.cp);
    7.35 -                databuf.appendChar(var.length);
    7.36 -                VarSymbol sym = var.sym;
    7.37 -                databuf.appendChar(pool.put(sym.name));
    7.38 -                Type vartype = sym.erasure(types);
    7.39 -                if (needsLocalVariableTypeEntry(sym.type))
    7.40 -                    nGenericVars++;
    7.41 -                databuf.appendChar(pool.put(typeSig(vartype)));
    7.42 -                databuf.appendChar(var.reg);
    7.43 +                for (Code.LocalVar.Range r: var.aliveRanges) {
    7.44 +                    // write variable info
    7.45 +                    Assert.check(r.start_pc >= 0
    7.46 +                            && r.start_pc <= code.cp);
    7.47 +                    databuf.appendChar(r.start_pc);
    7.48 +                    Assert.check(r.length >= 0
    7.49 +                            && (r.start_pc + r.length) <= code.cp);
    7.50 +                    databuf.appendChar(r.length);
    7.51 +                    VarSymbol sym = var.sym;
    7.52 +                    databuf.appendChar(pool.put(sym.name));
    7.53 +                    Type vartype = sym.erasure(types);
    7.54 +                    databuf.appendChar(pool.put(typeSig(vartype)));
    7.55 +                    databuf.appendChar(var.reg);
    7.56 +                    if (needsLocalVariableTypeEntry(var.sym.type))
    7.57 +                        nGenericVars++;
    7.58 +                }
    7.59              }
    7.60              endAttr(alenIdx);
    7.61              acount++;
    7.62 @@ -1214,13 +1213,15 @@
    7.63                  VarSymbol sym = var.sym;
    7.64                  if (!needsLocalVariableTypeEntry(sym.type))
    7.65                      continue;
    7.66 -                count++;
    7.67 -                // write variable info
    7.68 -                databuf.appendChar(var.start_pc);
    7.69 -                databuf.appendChar(var.length);
    7.70 -                databuf.appendChar(pool.put(sym.name));
    7.71 -                databuf.appendChar(pool.put(typeSig(sym.type)));
    7.72 -                databuf.appendChar(var.reg);
    7.73 +                for (Code.LocalVar.Range r : var.aliveRanges) {
    7.74 +                    // write variable info
    7.75 +                    databuf.appendChar(r.start_pc);
    7.76 +                    databuf.appendChar(r.length);
    7.77 +                    databuf.appendChar(pool.put(sym.name));
    7.78 +                    databuf.appendChar(pool.put(typeSig(sym.type)));
    7.79 +                    databuf.appendChar(var.reg);
    7.80 +                    count++;
    7.81 +                }
    7.82              }
    7.83              Assert.check(count == nGenericVars);
    7.84              endAttr(alenIdx);
     8.1 --- a/src/share/classes/com/sun/tools/javac/jvm/Code.java	Sat Sep 14 15:23:21 2013 +0100
     8.2 +++ b/src/share/classes/com/sun/tools/javac/jvm/Code.java	Sat Sep 14 19:04:47 2013 +0100
     8.3 @@ -28,6 +28,7 @@
     8.4  import com.sun.tools.javac.code.*;
     8.5  import com.sun.tools.javac.code.Symbol.*;
     8.6  import com.sun.tools.javac.code.Types.UniqueType;
     8.7 +import com.sun.tools.javac.tree.JCTree;
     8.8  import com.sun.tools.javac.util.*;
     8.9  import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    8.10  
    8.11 @@ -181,6 +182,8 @@
    8.12  
    8.13      final MethodSymbol meth;
    8.14  
    8.15 +    final LVTRanges lvtRanges;
    8.16 +
    8.17      /** Construct a code object, given the settings of the fatcode,
    8.18       *  debugging info switches and the CharacterRangeTable.
    8.19       */
    8.20 @@ -193,7 +196,8 @@
    8.21                  CRTable crt,
    8.22                  Symtab syms,
    8.23                  Types types,
    8.24 -                Pool pool) {
    8.25 +                Pool pool,
    8.26 +                LVTRanges lvtRanges) {
    8.27          this.meth = meth;
    8.28          this.fatcode = fatcode;
    8.29          this.lineMap = lineMap;
    8.30 @@ -215,6 +219,7 @@
    8.31          state = new State();
    8.32          lvar = new LocalVar[20];
    8.33          this.pool = pool;
    8.34 +        this.lvtRanges = lvtRanges;
    8.35      }
    8.36  
    8.37  
    8.38 @@ -305,9 +310,19 @@
    8.39  
    8.40      /** The current output code pointer.
    8.41       */
    8.42 -    public int curPc() {
    8.43 -        if (pendingJumps != null) resolvePending();
    8.44 -        if (pendingStatPos != Position.NOPOS) markStatBegin();
    8.45 +    public int curCP() {
    8.46 +        /*
    8.47 +         * This method has side-effects because calling it can indirectly provoke
    8.48 +         *  extra code generation, like goto instructions, depending on the context
    8.49 +         *  where it's called.
    8.50 +         *  Use with care or even better avoid using it.
    8.51 +         */
    8.52 +        if (pendingJumps != null) {
    8.53 +            resolvePending();
    8.54 +        }
    8.55 +        if (pendingStatPos != Position.NOPOS) {
    8.56 +            markStatBegin();
    8.57 +        }
    8.58          fixedPc = true;
    8.59          return cp;
    8.60      }
    8.61 @@ -1175,7 +1190,7 @@
    8.62      /** Declare an entry point; return current code pointer
    8.63       */
    8.64      public int entryPoint() {
    8.65 -        int pc = curPc();
    8.66 +        int pc = curCP();
    8.67          alive = true;
    8.68          pendingStackMap = needStackMap;
    8.69          return pc;
    8.70 @@ -1185,7 +1200,7 @@
    8.71       *  return current code pointer
    8.72       */
    8.73      public int entryPoint(State state) {
    8.74 -        int pc = curPc();
    8.75 +        int pc = curCP();
    8.76          alive = true;
    8.77          this.state = state.dup();
    8.78          Assert.check(state.stacksize <= max_stack);
    8.79 @@ -1198,7 +1213,7 @@
    8.80       *  return current code pointer
    8.81       */
    8.82      public int entryPoint(State state, Type pushed) {
    8.83 -        int pc = curPc();
    8.84 +        int pc = curCP();
    8.85          alive = true;
    8.86          this.state = state.dup();
    8.87          Assert.check(state.stacksize <= max_stack);
    8.88 @@ -1238,7 +1253,7 @@
    8.89  
    8.90      /** Emit a stack map entry.  */
    8.91      public void emitStackMap() {
    8.92 -        int pc = curPc();
    8.93 +        int pc = curCP();
    8.94          if (!needStackMap) return;
    8.95  
    8.96  
    8.97 @@ -1482,6 +1497,9 @@
    8.98                  chain.pc + 3 == target && target == cp && !fixedPc) {
    8.99                  // If goto the next instruction, the jump is not needed:
   8.100                  // compact the code.
   8.101 +                if (varDebugInfo) {
   8.102 +                    adjustAliveRanges(cp, -3);
   8.103 +                }
   8.104                  cp = cp - 3;
   8.105                  target = target - 3;
   8.106                  if (chain.next == null) {
   8.107 @@ -1781,8 +1799,7 @@
   8.108                      sym = sym.clone(sym.owner);
   8.109                      sym.type = newtype;
   8.110                      LocalVar newlv = lvar[i] = new LocalVar(sym);
   8.111 -                    // should the following be initialized to cp?
   8.112 -                    newlv.start_pc = lv.start_pc;
   8.113 +                    newlv.aliveRanges = lv.aliveRanges;
   8.114                  }
   8.115              }
   8.116          }
   8.117 @@ -1870,8 +1887,36 @@
   8.118      static class LocalVar {
   8.119          final VarSymbol sym;
   8.120          final char reg;
   8.121 -        char start_pc = Character.MAX_VALUE;
   8.122 -        char length = Character.MAX_VALUE;
   8.123 +
   8.124 +        class Range {
   8.125 +            char start_pc = Character.MAX_VALUE;
   8.126 +            char length = Character.MAX_VALUE;
   8.127 +
   8.128 +            Range() {}
   8.129 +
   8.130 +            Range(char start) {
   8.131 +                this.start_pc = start;
   8.132 +            }
   8.133 +
   8.134 +            Range(char start, char length) {
   8.135 +                this.start_pc = start;
   8.136 +                this.length = length;
   8.137 +            }
   8.138 +
   8.139 +            boolean closed() {
   8.140 +                return start_pc != Character.MAX_VALUE && length != Character.MAX_VALUE;
   8.141 +            }
   8.142 +
   8.143 +            @Override
   8.144 +            public String toString() {
   8.145 +                int currentStartPC = start_pc;
   8.146 +                int currentLength = length;
   8.147 +                return "startpc = " + currentStartPC + " length " + currentLength;
   8.148 +            }
   8.149 +        }
   8.150 +
   8.151 +        java.util.List<Range> aliveRanges = new java.util.ArrayList<>();
   8.152 +
   8.153          LocalVar(VarSymbol v) {
   8.154              this.sym = v;
   8.155              this.reg = (char)v.adr;
   8.156 @@ -1879,9 +1924,78 @@
   8.157          public LocalVar dup() {
   8.158              return new LocalVar(sym);
   8.159          }
   8.160 +
   8.161 +        Range firstRange() {
   8.162 +            return aliveRanges.isEmpty() ? null : aliveRanges.get(0);
   8.163 +        }
   8.164 +
   8.165 +        Range lastRange() {
   8.166 +            return aliveRanges.isEmpty() ? null : aliveRanges.get(aliveRanges.size() - 1);
   8.167 +        }
   8.168 +
   8.169 +        @Override
   8.170          public String toString() {
   8.171 -            return "" + sym + " in register " + ((int)reg) + " starts at pc=" + ((int)start_pc) + " length=" + ((int)length);
   8.172 +            if (aliveRanges == null) {
   8.173 +                return "empty local var";
   8.174 +            }
   8.175 +            StringBuilder sb = new StringBuilder().append(sym)
   8.176 +                    .append(" in register ").append((int)reg).append(" \n");
   8.177 +            for (Range r : aliveRanges) {
   8.178 +                sb.append(" starts at pc=").append(Integer.toString(((int)r.start_pc)))
   8.179 +                    .append(" length=").append(Integer.toString(((int)r.length)))
   8.180 +                    .append("\n");
   8.181 +            }
   8.182 +            return sb.toString();
   8.183          }
   8.184 +
   8.185 +        public void openRange(char start) {
   8.186 +            if (!hasOpenRange()) {
   8.187 +                aliveRanges.add(new Range(start));
   8.188 +            }
   8.189 +        }
   8.190 +
   8.191 +        public void closeRange(char end) {
   8.192 +            if (isLastRangeInitialized()) {
   8.193 +                Range range = lastRange();
   8.194 +                if (range != null) {
   8.195 +                    if (range.length == Character.MAX_VALUE) {
   8.196 +                        range.length = end;
   8.197 +                    }
   8.198 +                }
   8.199 +            } else {
   8.200 +                if (!aliveRanges.isEmpty()) {
   8.201 +                    aliveRanges.remove(aliveRanges.size() - 1);
   8.202 +                }
   8.203 +            }
   8.204 +        }
   8.205 +
   8.206 +        public boolean hasOpenRange() {
   8.207 +            if (aliveRanges.isEmpty()) {
   8.208 +                return false;
   8.209 +            }
   8.210 +            Range range = lastRange();
   8.211 +            return range.length == Character.MAX_VALUE;
   8.212 +        }
   8.213 +
   8.214 +        public boolean isLastRangeInitialized() {
   8.215 +            if (aliveRanges.isEmpty()) {
   8.216 +                return false;
   8.217 +            }
   8.218 +            Range range = lastRange();
   8.219 +            return range.start_pc != Character.MAX_VALUE;
   8.220 +        }
   8.221 +
   8.222 +        public Range getWidestRange() {
   8.223 +            if (aliveRanges.isEmpty()) {
   8.224 +                return new Range();
   8.225 +            } else {
   8.226 +                Range firstRange = firstRange();
   8.227 +                Range lastRange = lastRange();
   8.228 +                char length = (char)(lastRange.length + (lastRange.start_pc - firstRange.start_pc));
   8.229 +                return new Range(firstRange.start_pc, length);
   8.230 +            }
   8.231 +         }
   8.232 +
   8.233      };
   8.234  
   8.235      /** Local variables, indexed by register. */
   8.236 @@ -1892,11 +2006,60 @@
   8.237          int adr = v.adr;
   8.238          lvar = ArrayUtils.ensureCapacity(lvar, adr+1);
   8.239          Assert.checkNull(lvar[adr]);
   8.240 -        if (pendingJumps != null) resolvePending();
   8.241 +        if (pendingJumps != null) {
   8.242 +            resolvePending();
   8.243 +        }
   8.244          lvar[adr] = new LocalVar(v);
   8.245          state.defined.excl(adr);
   8.246      }
   8.247  
   8.248 +
   8.249 +    public void closeAliveRanges(JCTree tree) {
   8.250 +        closeAliveRanges(tree, cp);
   8.251 +    }
   8.252 +
   8.253 +    public void closeAliveRanges(JCTree tree, int closingCP) {
   8.254 +        List<VarSymbol> locals = lvtRanges.getVars(meth, tree);
   8.255 +        for (LocalVar localVar: lvar) {
   8.256 +            for (VarSymbol aliveLocal : locals) {
   8.257 +                if (localVar == null) {
   8.258 +                    return;
   8.259 +                }
   8.260 +                if (localVar.sym == aliveLocal && localVar.lastRange() != null) {
   8.261 +                    char length = (char)(closingCP - localVar.lastRange().start_pc);
   8.262 +                    if (length > 0 && length < Character.MAX_VALUE) {
   8.263 +                        localVar.closeRange(length);
   8.264 +                    }
   8.265 +                }
   8.266 +            }
   8.267 +        }
   8.268 +    }
   8.269 +
   8.270 +    void adjustAliveRanges(int oldCP, int delta) {
   8.271 +        for (LocalVar localVar: lvar) {
   8.272 +            if (localVar == null) {
   8.273 +                return;
   8.274 +            }
   8.275 +            for (LocalVar.Range range: localVar.aliveRanges) {
   8.276 +                if (range.closed() && range.start_pc + range.length >= oldCP) {
   8.277 +                    range.length += delta;
   8.278 +                }
   8.279 +            }
   8.280 +        }
   8.281 +    }
   8.282 +
   8.283 +    /**
   8.284 +     * Calculates the size of the LocalVariableTable.
   8.285 +     */
   8.286 +    public int getLVTSize() {
   8.287 +        int result = varBufferSize;
   8.288 +        for (int i = 0; i < varBufferSize; i++) {
   8.289 +            LocalVar var = varBuffer[i];
   8.290 +            result += var.aliveRanges.size() - 1;
   8.291 +        }
   8.292 +        return result;
   8.293 +    }
   8.294 +
   8.295      /** Set the current variable defined state. */
   8.296      public void setDefined(Bits newDefined) {
   8.297          if (alive && newDefined != state.defined) {
   8.298 @@ -1922,8 +2085,7 @@
   8.299          } else {
   8.300              state.defined.incl(adr);
   8.301              if (cp < Character.MAX_VALUE) {
   8.302 -                if (v.start_pc == Character.MAX_VALUE)
   8.303 -                    v.start_pc = (char)cp;
   8.304 +                v.openRange((char)cp);
   8.305              }
   8.306          }
   8.307      }
   8.308 @@ -1933,15 +2095,15 @@
   8.309          state.defined.excl(adr);
   8.310          if (adr < lvar.length &&
   8.311              lvar[adr] != null &&
   8.312 -            lvar[adr].start_pc != Character.MAX_VALUE) {
   8.313 +            lvar[adr].isLastRangeInitialized()) {
   8.314              LocalVar v = lvar[adr];
   8.315 -            char length = (char)(curPc() - v.start_pc);
   8.316 +            char length = (char)(curCP() - v.lastRange().start_pc);
   8.317              if (length > 0 && length < Character.MAX_VALUE) {
   8.318                  lvar[adr] = v.dup();
   8.319 -                v.length = length;
   8.320 +                v.closeRange(length);
   8.321                  putVar(v);
   8.322              } else {
   8.323 -                v.start_pc = Character.MAX_VALUE;
   8.324 +                v.lastRange().start_pc = Character.MAX_VALUE;
   8.325              }
   8.326          }
   8.327      }
   8.328 @@ -1951,10 +2113,10 @@
   8.329          LocalVar v = lvar[adr];
   8.330          if (v != null) {
   8.331              lvar[adr] = null;
   8.332 -            if (v.start_pc != Character.MAX_VALUE) {
   8.333 -                char length = (char)(curPc() - v.start_pc);
   8.334 +            if (v.isLastRangeInitialized()) {
   8.335 +                char length = (char)(curCP() - v.lastRange().start_pc);
   8.336                  if (length < Character.MAX_VALUE) {
   8.337 -                    v.length = length;
   8.338 +                    v.closeRange(length);
   8.339                      putVar(v);
   8.340                      fillLocalVarPosition(v);
   8.341                  }
   8.342 @@ -1968,8 +2130,9 @@
   8.343              return;
   8.344          for (Attribute.TypeCompound ta : lv.sym.getRawTypeAttributes()) {
   8.345              TypeAnnotationPosition p = ta.position;
   8.346 -            p.lvarOffset = new int[] { (int)lv.start_pc };
   8.347 -            p.lvarLength = new int[] { (int)lv.length };
   8.348 +            LocalVar.Range widestRange = lv.getWidestRange();
   8.349 +            p.lvarOffset = new int[] { (int)widestRange.start_pc };
   8.350 +            p.lvarLength = new int[] { (int)widestRange.length };
   8.351              p.lvarIndex = new int[] { (int)lv.reg };
   8.352              p.isValidOffset = true;
   8.353          }
     9.1 --- a/src/share/classes/com/sun/tools/javac/jvm/Gen.java	Sat Sep 14 15:23:21 2013 +0100
     9.2 +++ b/src/share/classes/com/sun/tools/javac/jvm/Gen.java	Sat Sep 14 19:04:47 2013 +0100
     9.3 @@ -24,6 +24,7 @@
     9.4   */
     9.5  
     9.6  package com.sun.tools.javac.jvm;
     9.7 +
     9.8  import java.util.*;
     9.9  
    9.10  import com.sun.tools.javac.util.*;
    9.11 @@ -95,10 +96,14 @@
    9.12          return instance;
    9.13      }
    9.14  
    9.15 -    /* Constant pool, reset by genClass.
    9.16 +    /** Constant pool, reset by genClass.
    9.17       */
    9.18      private Pool pool;
    9.19  
    9.20 +    /** LVTRanges info.
    9.21 +     */
    9.22 +    private LVTRanges lvtRanges;
    9.23 +
    9.24      protected Gen(Context context) {
    9.25          context.put(genKey, this);
    9.26  
    9.27 @@ -128,6 +133,9 @@
    9.28              options.isUnset(G_CUSTOM)
    9.29              ? options.isSet(G)
    9.30              : options.isSet(G_CUSTOM, "vars");
    9.31 +        if (varDebugInfo) {
    9.32 +            lvtRanges = LVTRanges.instance(context);
    9.33 +        }
    9.34          genCrt = options.isSet(XJCOV);
    9.35          debugCode = options.isSet("debugcode");
    9.36          allowInvokedynamic = target.hasInvokedynamic() || options.isSet("invokedynamic");
    9.37 @@ -423,7 +431,7 @@
    9.38       */
    9.39      void endFinalizerGap(Env<GenContext> env) {
    9.40          if (env.info.gaps != null && env.info.gaps.length() % 2 == 1)
    9.41 -            env.info.gaps.append(code.curPc());
    9.42 +            env.info.gaps.append(code.curCP());
    9.43      }
    9.44  
    9.45      /** Mark end of all gaps in catch-all ranges for finalizers of environments
    9.46 @@ -743,10 +751,10 @@
    9.47              genStat(tree, env);
    9.48              return;
    9.49          }
    9.50 -        int startpc = code.curPc();
    9.51 +        int startpc = code.curCP();
    9.52          genStat(tree, env);
    9.53          if (tree.hasTag(Tag.BLOCK)) crtFlags |= CRT_BLOCK;
    9.54 -        code.crt.put(tree, crtFlags, startpc, code.curPc());
    9.55 +        code.crt.put(tree, crtFlags, startpc, code.curCP());
    9.56      }
    9.57  
    9.58      /** Derived visitor method: generate code for a statement.
    9.59 @@ -781,9 +789,9 @@
    9.60          if (trees.length() == 1) {        // mark one statement with the flags
    9.61              genStat(trees.head, env, crtFlags | CRT_STATEMENT);
    9.62          } else {
    9.63 -            int startpc = code.curPc();
    9.64 +            int startpc = code.curCP();
    9.65              genStats(trees, env);
    9.66 -            code.crt.put(trees, crtFlags, startpc, code.curPc());
    9.67 +            code.crt.put(trees, crtFlags, startpc, code.curCP());
    9.68          }
    9.69      }
    9.70  
    9.71 @@ -806,9 +814,9 @@
    9.72       */
    9.73      public CondItem genCond(JCTree tree, int crtFlags) {
    9.74          if (!genCrt) return genCond(tree, false);
    9.75 -        int startpc = code.curPc();
    9.76 +        int startpc = code.curCP();
    9.77          CondItem item = genCond(tree, (crtFlags & CRT_FLOW_CONTROLLER) != 0);
    9.78 -        code.crt.put(tree, crtFlags, startpc, code.curPc());
    9.79 +        code.crt.put(tree, crtFlags, startpc, code.curCP());
    9.80          return item;
    9.81      }
    9.82  
    9.83 @@ -971,7 +979,6 @@
    9.84          // definition.
    9.85          Env<GenContext> localEnv = env.dup(tree);
    9.86          localEnv.enclMethod = tree;
    9.87 -
    9.88          // The expected type of every return statement in this method
    9.89          // is the method's return type.
    9.90          this.pt = tree.sym.erasure(types).getReturnType();
    9.91 @@ -1045,7 +1052,7 @@
    9.92                      code.crt.put(tree.body,
    9.93                                   CRT_BLOCK,
    9.94                                   startpcCrt,
    9.95 -                                 code.curPc());
    9.96 +                                 code.curCP());
    9.97  
    9.98                  code.endScopes(0);
    9.99  
   9.100 @@ -1087,10 +1094,12 @@
   9.101                                                 : null,
   9.102                                          syms,
   9.103                                          types,
   9.104 -                                        pool);
   9.105 +                                        pool,
   9.106 +                                        varDebugInfo ? lvtRanges : null);
   9.107              items = new Items(pool, code, syms, types);
   9.108 -            if (code.debugCode)
   9.109 +            if (code.debugCode) {
   9.110                  System.err.println(meth + " for body " + tree);
   9.111 +            }
   9.112  
   9.113              // If method is not static, create a new local variable address
   9.114              // for `this'.
   9.115 @@ -1111,7 +1120,7 @@
   9.116              }
   9.117  
   9.118              // Get ready to generate code for method body.
   9.119 -            int startpcCrt = genCrt ? code.curPc() : 0;
   9.120 +            int startpcCrt = genCrt ? code.curCP() : 0;
   9.121              code.entryPoint();
   9.122  
   9.123              // Suppress initial stackmap
   9.124 @@ -1189,14 +1198,30 @@
   9.125                  Chain loopDone = c.jumpFalse();
   9.126                  code.resolve(c.trueJumps);
   9.127                  genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET);
   9.128 +                if (varDebugInfo) {
   9.129 +                    checkLoopLocalVarRangeEnding(loop, body,
   9.130 +                            LoopLocalVarRangeEndingPoint.BEFORE_STEPS);
   9.131 +                }
   9.132                  code.resolve(loopEnv.info.cont);
   9.133                  genStats(step, loopEnv);
   9.134 +                if (varDebugInfo) {
   9.135 +                    checkLoopLocalVarRangeEnding(loop, body,
   9.136 +                            LoopLocalVarRangeEndingPoint.AFTER_STEPS);
   9.137 +                }
   9.138                  code.resolve(code.branch(goto_), startpc);
   9.139                  code.resolve(loopDone);
   9.140              } else {
   9.141                  genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET);
   9.142 +                if (varDebugInfo) {
   9.143 +                    checkLoopLocalVarRangeEnding(loop, body,
   9.144 +                            LoopLocalVarRangeEndingPoint.BEFORE_STEPS);
   9.145 +                }
   9.146                  code.resolve(loopEnv.info.cont);
   9.147                  genStats(step, loopEnv);
   9.148 +                if (varDebugInfo) {
   9.149 +                    checkLoopLocalVarRangeEnding(loop, body,
   9.150 +                            LoopLocalVarRangeEndingPoint.AFTER_STEPS);
   9.151 +                }
   9.152                  CondItem c;
   9.153                  if (cond != null) {
   9.154                      code.statBegin(cond.pos);
   9.155 @@ -1210,6 +1235,44 @@
   9.156              code.resolve(loopEnv.info.exit);
   9.157          }
   9.158  
   9.159 +        private enum LoopLocalVarRangeEndingPoint {
   9.160 +            BEFORE_STEPS,
   9.161 +            AFTER_STEPS,
   9.162 +        }
   9.163 +
   9.164 +        /**
   9.165 +         *  Checks whether we have reached an alive range ending point for local
   9.166 +         *  variables after a loop.
   9.167 +         *
   9.168 +         *  Local variables alive range ending point for loops varies depending
   9.169 +         *  on the loop type. The range can be closed before or after the code
   9.170 +         *  for the steps sentences has been generated.
   9.171 +         *
   9.172 +         *  - While loops has no steps so in that case the range is closed just
   9.173 +         *  after the body of the loop.
   9.174 +         *
   9.175 +         *  - For-like loops may have steps so as long as the steps sentences
   9.176 +         *  can possibly contain non-synthetic local variables, the alive range
   9.177 +         *  for local variables must be closed after the steps in this case.
   9.178 +        */
   9.179 +        private void checkLoopLocalVarRangeEnding(JCTree loop, JCTree body,
   9.180 +                LoopLocalVarRangeEndingPoint endingPoint) {
   9.181 +            if (varDebugInfo && lvtRanges.containsKey(code.meth, body)) {
   9.182 +                switch (endingPoint) {
   9.183 +                    case BEFORE_STEPS:
   9.184 +                        if (!loop.hasTag(FORLOOP)) {
   9.185 +                            code.closeAliveRanges(body);
   9.186 +                        }
   9.187 +                        break;
   9.188 +                    case AFTER_STEPS:
   9.189 +                        if (loop.hasTag(FORLOOP)) {
   9.190 +                            code.closeAliveRanges(body);
   9.191 +                        }
   9.192 +                        break;
   9.193 +                }
   9.194 +            }
   9.195 +        }
   9.196 +
   9.197      public void visitForeachLoop(JCEnhancedForLoop tree) {
   9.198          throw new AssertionError(); // should have been removed by Lower.
   9.199      }
   9.200 @@ -1223,7 +1286,7 @@
   9.201      public void visitSwitch(JCSwitch tree) {
   9.202          int limit = code.nextreg;
   9.203          Assert.check(!tree.selector.type.hasTag(CLASS));
   9.204 -        int startpcCrt = genCrt ? code.curPc() : 0;
   9.205 +        int startpcCrt = genCrt ? code.curCP() : 0;
   9.206          Item sel = genExpr(tree.selector, syms.intType);
   9.207          List<JCCase> cases = tree.cases;
   9.208          if (cases.isEmpty()) {
   9.209 @@ -1231,13 +1294,13 @@
   9.210              sel.load().drop();
   9.211              if (genCrt)
   9.212                  code.crt.put(TreeInfo.skipParens(tree.selector),
   9.213 -                             CRT_FLOW_CONTROLLER, startpcCrt, code.curPc());
   9.214 +                             CRT_FLOW_CONTROLLER, startpcCrt, code.curCP());
   9.215          } else {
   9.216              // We are seeing a nonempty switch.
   9.217              sel.load();
   9.218              if (genCrt)
   9.219                  code.crt.put(TreeInfo.skipParens(tree.selector),
   9.220 -                             CRT_FLOW_CONTROLLER, startpcCrt, code.curPc());
   9.221 +                             CRT_FLOW_CONTROLLER, startpcCrt, code.curCP());
   9.222              Env<GenContext> switchEnv = env.dup(tree, new GenContext());
   9.223              switchEnv.info.isSwitch = true;
   9.224  
   9.225 @@ -1278,10 +1341,10 @@
   9.226                  ?
   9.227                  tableswitch : lookupswitch;
   9.228  
   9.229 -            int startpc = code.curPc();    // the position of the selector operation
   9.230 +            int startpc = code.curCP();    // the position of the selector operation
   9.231              code.emitop0(opcode);
   9.232              code.align(4);
   9.233 -            int tableBase = code.curPc();  // the start of the jump table
   9.234 +            int tableBase = code.curCP();  // the start of the jump table
   9.235              int[] offsets = null;          // a table of offsets for a lookupswitch
   9.236              code.emit4(-1);                // leave space for default offset
   9.237              if (opcode == tableswitch) {
   9.238 @@ -1323,6 +1386,9 @@
   9.239  
   9.240                  // Generate code for the statements in this case.
   9.241                  genStats(c.stats, switchEnv, CRT_FLOW_TARGET);
   9.242 +                if (varDebugInfo && lvtRanges.containsKey(code.meth, c.stats.last())) {
   9.243 +                    code.closeAliveRanges(c.stats.last());
   9.244 +                }
   9.245              }
   9.246  
   9.247              // Resolve all breaks.
   9.248 @@ -1402,7 +1468,7 @@
   9.249              void gen() {
   9.250                  genLast();
   9.251                  Assert.check(syncEnv.info.gaps.length() % 2 == 0);
   9.252 -                syncEnv.info.gaps.append(code.curPc());
   9.253 +                syncEnv.info.gaps.append(code.curCP());
   9.254              }
   9.255              void genLast() {
   9.256                  if (code.isAlive()) {
   9.257 @@ -1441,10 +1507,10 @@
   9.258                                        jsrState);
   9.259                      }
   9.260                      Assert.check(tryEnv.info.gaps.length() % 2 == 0);
   9.261 -                    tryEnv.info.gaps.append(code.curPc());
   9.262 +                    tryEnv.info.gaps.append(code.curCP());
   9.263                  } else {
   9.264                      Assert.check(tryEnv.info.gaps.length() % 2 == 0);
   9.265 -                    tryEnv.info.gaps.append(code.curPc());
   9.266 +                    tryEnv.info.gaps.append(code.curCP());
   9.267                      genLast();
   9.268                  }
   9.269              }
   9.270 @@ -1467,10 +1533,10 @@
   9.271           */
   9.272          void genTry(JCTree body, List<JCCatch> catchers, Env<GenContext> env) {
   9.273              int limit = code.nextreg;
   9.274 -            int startpc = code.curPc();
   9.275 +            int startpc = code.curCP();
   9.276              Code.State stateTry = code.state.dup();
   9.277              genStat(body, env, CRT_BLOCK);
   9.278 -            int endpc = code.curPc();
   9.279 +            int endpc = code.curCP();
   9.280              boolean hasFinalizer =
   9.281                  env.info.finalize != null &&
   9.282                  env.info.finalize.hasFinalizer();
   9.283 @@ -1479,6 +1545,9 @@
   9.284              genFinalizer(env);
   9.285              code.statBegin(TreeInfo.endPos(env.tree));
   9.286              Chain exitChain = code.branch(goto_);
   9.287 +            if (varDebugInfo && lvtRanges.containsKey(code.meth, body)) {
   9.288 +                code.closeAliveRanges(body);
   9.289 +            }
   9.290              endFinalizerGap(env);
   9.291              if (startpc != endpc) for (List<JCCatch> l = catchers; l.nonEmpty(); l = l.tail) {
   9.292                  // start off with exception on stack
   9.293 @@ -1573,7 +1642,7 @@
   9.294                          int catchType = makeRef(tree.pos(), subCatch.type);
   9.295                          int end = gaps.head.intValue();
   9.296                          registerCatch(tree.pos(),
   9.297 -                                      startpc,  end, code.curPc(),
   9.298 +                                      startpc,  end, code.curCP(),
   9.299                                        catchType);
   9.300                          if (subCatch.type.isAnnotated()) {
   9.301                              // All compounds share the same position, simply update the
   9.302 @@ -1589,7 +1658,7 @@
   9.303                      for (JCExpression subCatch : subClauses) {
   9.304                          int catchType = makeRef(tree.pos(), subCatch.type);
   9.305                          registerCatch(tree.pos(),
   9.306 -                                      startpc, endpc, code.curPc(),
   9.307 +                                      startpc, endpc, code.curCP(),
   9.308                                        catchType);
   9.309                          if (subCatch.type.isAnnotated()) {
   9.310                              // All compounds share the same position, simply update the
   9.311 @@ -1732,11 +1801,19 @@
   9.312              code.resolve(c.trueJumps);
   9.313              genStat(tree.thenpart, env, CRT_STATEMENT | CRT_FLOW_TARGET);
   9.314              thenExit = code.branch(goto_);
   9.315 +            if (varDebugInfo && lvtRanges.containsKey(code.meth, tree.thenpart)) {
   9.316 +                code.closeAliveRanges(tree.thenpart,
   9.317 +                        thenExit != null && tree.elsepart == null ? thenExit.pc : code.cp);
   9.318 +            }
   9.319          }
   9.320          if (elseChain != null) {
   9.321              code.resolve(elseChain);
   9.322 -            if (tree.elsepart != null)
   9.323 +            if (tree.elsepart != null) {
   9.324                  genStat(tree.elsepart, env,CRT_STATEMENT | CRT_FLOW_TARGET);
   9.325 +                if (varDebugInfo && lvtRanges.containsKey(code.meth, tree.elsepart)) {
   9.326 +                    code.closeAliveRanges(tree.elsepart);
   9.327 +                }
   9.328 +            }
   9.329          }
   9.330          code.resolve(thenExit);
   9.331          code.endScopes(limit);
   9.332 @@ -1830,20 +1907,20 @@
   9.333          Chain elseChain = c.jumpFalse();
   9.334          if (!c.isFalse()) {
   9.335              code.resolve(c.trueJumps);
   9.336 -            int startpc = genCrt ? code.curPc() : 0;
   9.337 +            int startpc = genCrt ? code.curCP() : 0;
   9.338              genExpr(tree.truepart, pt).load();
   9.339              code.state.forceStackTop(tree.type);
   9.340              if (genCrt) code.crt.put(tree.truepart, CRT_FLOW_TARGET,
   9.341 -                                     startpc, code.curPc());
   9.342 +                                     startpc, code.curCP());
   9.343              thenExit = code.branch(goto_);
   9.344          }
   9.345          if (elseChain != null) {
   9.346              code.resolve(elseChain);
   9.347 -            int startpc = genCrt ? code.curPc() : 0;
   9.348 +            int startpc = genCrt ? code.curCP() : 0;
   9.349              genExpr(tree.falsepart, pt).load();
   9.350              code.state.forceStackTop(tree.type);
   9.351              if (genCrt) code.crt.put(tree.falsepart, CRT_FLOW_TARGET,
   9.352 -                                     startpc, code.curPc());
   9.353 +                                     startpc, code.curCP());
   9.354          }
   9.355          code.resolve(thenExit);
   9.356          result = items.makeStackItem(pt);
   9.357 @@ -2423,6 +2500,19 @@
   9.358                  new Env<GenContext>(cdef, new GenContext());
   9.359              localEnv.toplevel = env.toplevel;
   9.360              localEnv.enclClass = cdef;
   9.361 +
   9.362 +            /*  We must not analyze synthetic methods
   9.363 +             */
   9.364 +            if (varDebugInfo && (cdef.sym.flags() & SYNTHETIC) == 0) {
   9.365 +                try {
   9.366 +                    LVTAssignAnalyzer lvtAssignAnalyzer = LVTAssignAnalyzer.make(
   9.367 +                            lvtRanges, syms, names);
   9.368 +                    lvtAssignAnalyzer.analyzeTree(localEnv);
   9.369 +                } catch (Throwable e) {
   9.370 +                    throw e;
   9.371 +                }
   9.372 +            }
   9.373 +
   9.374              for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
   9.375                  genDef(l.head, localEnv);
   9.376              }
   9.377 @@ -2507,4 +2597,311 @@
   9.378              cont = Code.mergeChains(c, cont);
   9.379          }
   9.380      }
   9.381 +
   9.382 +    static class LVTAssignAnalyzer
   9.383 +        extends Flow.AbstractAssignAnalyzer<LVTAssignAnalyzer.LVTAssignPendingExit> {
   9.384 +
   9.385 +        final LVTBits lvtInits;
   9.386 +        final LVTRanges lvtRanges;
   9.387 +
   9.388 +        /*  This class is anchored to a context dependent tree. The tree can
   9.389 +         *  vary inside the same instruction for example in the switch instruction
   9.390 +         *  the same FlowBits instance can be anchored to the whole tree, or
   9.391 +         *  to a given case. The aim is to always anchor the bits to the tree
   9.392 +         *  capable of closing a DA range.
   9.393 +         */
   9.394 +        static class LVTBits extends Bits {
   9.395 +
   9.396 +            enum BitsOpKind {
   9.397 +                INIT,
   9.398 +                CLEAR,
   9.399 +                INCL_BIT,
   9.400 +                EXCL_BIT,
   9.401 +                ASSIGN,
   9.402 +                AND_SET,
   9.403 +                OR_SET,
   9.404 +                DIFF_SET,
   9.405 +                XOR_SET,
   9.406 +                INCL_RANGE,
   9.407 +                EXCL_RANGE,
   9.408 +            }
   9.409 +
   9.410 +            JCTree currentTree;
   9.411 +            LVTAssignAnalyzer analyzer;
   9.412 +            private int[] oldBits = null;
   9.413 +            BitsState stateBeforeOp;
   9.414 +
   9.415 +            LVTBits() {
   9.416 +                super(false);
   9.417 +            }
   9.418 +
   9.419 +            LVTBits(int[] bits, BitsState initState) {
   9.420 +                super(bits, initState);
   9.421 +            }
   9.422 +
   9.423 +            @Override
   9.424 +            public void clear() {
   9.425 +                generalOp(null, -1, BitsOpKind.CLEAR);
   9.426 +            }
   9.427 +
   9.428 +            @Override
   9.429 +            protected void internalReset() {
   9.430 +                super.internalReset();
   9.431 +                oldBits = null;
   9.432 +            }
   9.433 +
   9.434 +            @Override
   9.435 +            public Bits assign(Bits someBits) {
   9.436 +                // bits can be null
   9.437 +                oldBits = bits;
   9.438 +                stateBeforeOp = currentState;
   9.439 +                super.assign(someBits);
   9.440 +                changed();
   9.441 +                return this;
   9.442 +            }
   9.443 +
   9.444 +            @Override
   9.445 +            public void excludeFrom(int start) {
   9.446 +                generalOp(null, start, BitsOpKind.EXCL_RANGE);
   9.447 +            }
   9.448 +
   9.449 +            @Override
   9.450 +            public void excl(int x) {
   9.451 +                Assert.check(x >= 0);
   9.452 +                generalOp(null, x, BitsOpKind.EXCL_BIT);
   9.453 +            }
   9.454 +
   9.455 +            @Override
   9.456 +            public Bits andSet(Bits xs) {
   9.457 +               return generalOp(xs, -1, BitsOpKind.AND_SET);
   9.458 +            }
   9.459 +
   9.460 +            @Override
   9.461 +            public Bits orSet(Bits xs) {
   9.462 +                return generalOp(xs, -1, BitsOpKind.OR_SET);
   9.463 +            }
   9.464 +
   9.465 +            @Override
   9.466 +            public Bits diffSet(Bits xs) {
   9.467 +                return generalOp(xs, -1, BitsOpKind.DIFF_SET);
   9.468 +            }
   9.469 +
   9.470 +            @Override
   9.471 +            public Bits xorSet(Bits xs) {
   9.472 +                return generalOp(xs, -1, BitsOpKind.XOR_SET);
   9.473 +            }
   9.474 +
   9.475 +            private Bits generalOp(Bits xs, int i, BitsOpKind opKind) {
   9.476 +                Assert.check(currentState != BitsState.UNKNOWN);
   9.477 +                oldBits = dupBits();
   9.478 +                stateBeforeOp = currentState;
   9.479 +                switch (opKind) {
   9.480 +                    case AND_SET:
   9.481 +                        super.andSet(xs);
   9.482 +                        break;
   9.483 +                    case OR_SET:
   9.484 +                        super.orSet(xs);
   9.485 +                        break;
   9.486 +                    case XOR_SET:
   9.487 +                        super.xorSet(xs);
   9.488 +                        break;
   9.489 +                    case DIFF_SET:
   9.490 +                        super.diffSet(xs);
   9.491 +                        break;
   9.492 +                    case CLEAR:
   9.493 +                        super.clear();
   9.494 +                        break;
   9.495 +                    case EXCL_BIT:
   9.496 +                        super.excl(i);
   9.497 +                        break;
   9.498 +                    case EXCL_RANGE:
   9.499 +                        super.excludeFrom(i);
   9.500 +                        break;
   9.501 +                }
   9.502 +                changed();
   9.503 +                return this;
   9.504 +            }
   9.505 +
   9.506 +            /*  The tree we need to anchor the bits instance to.
   9.507 +             */
   9.508 +            LVTBits at(JCTree tree) {
   9.509 +                this.currentTree = tree;
   9.510 +                return this;
   9.511 +            }
   9.512 +
   9.513 +            /*  If the instance should be changed but the tree is not a closing
   9.514 +             *  tree then a reset is needed or the former tree can mistakingly be
   9.515 +             *  used.
   9.516 +             */
   9.517 +            LVTBits resetTree() {
   9.518 +                this.currentTree = null;
   9.519 +                return this;
   9.520 +            }
   9.521 +
   9.522 +            /** This method will be called after any operation that causes a change to
   9.523 +             *  the bits. Subclasses can thus override it in order to extract information
   9.524 +             *  from the changes produced to the bits by the given operation.
   9.525 +             */
   9.526 +            public void changed() {
   9.527 +                if (currentTree != null &&
   9.528 +                        stateBeforeOp != BitsState.UNKNOWN &&
   9.529 +                        trackTree(currentTree)) {
   9.530 +                    List<VarSymbol> locals =
   9.531 +                            analyzer.lvtRanges
   9.532 +                            .getVars(analyzer.currentMethod, currentTree);
   9.533 +                    locals = locals != null ?
   9.534 +                            locals : List.<VarSymbol>nil();
   9.535 +                    for (JCVariableDecl vardecl : analyzer.vardecls) {
   9.536 +                        //once the first is null, the rest will be so.
   9.537 +                        if (vardecl == null) {
   9.538 +                            break;
   9.539 +                        }
   9.540 +                        if (trackVar(vardecl.sym) && bitChanged(vardecl.sym.adr)) {
   9.541 +                            locals = locals.prepend(vardecl.sym);
   9.542 +                        }
   9.543 +                    }
   9.544 +                    if (!locals.isEmpty()) {
   9.545 +                        analyzer.lvtRanges.setEntry(analyzer.currentMethod,
   9.546 +                                currentTree, locals);
   9.547 +                    }
   9.548 +                }
   9.549 +            }
   9.550 +
   9.551 +            boolean bitChanged(int x) {
   9.552 +                boolean isMemberOfBits = isMember(x);
   9.553 +                int[] tmp = bits;
   9.554 +                bits = oldBits;
   9.555 +                boolean isMemberOfOldBits = isMember(x);
   9.556 +                bits = tmp;
   9.557 +                return (!isMemberOfBits && isMemberOfOldBits);
   9.558 +            }
   9.559 +
   9.560 +            boolean trackVar(VarSymbol var) {
   9.561 +                return (var.owner.kind == MTH &&
   9.562 +                        (var.flags() & (PARAMETER | HASINIT)) == 0 &&
   9.563 +                        analyzer.trackable(var));
   9.564 +            }
   9.565 +
   9.566 +            boolean trackTree(JCTree tree) {
   9.567 +                switch (tree.getTag()) {
   9.568 +                    // of course a method closes the alive range of a local variable.
   9.569 +                    case METHODDEF:
   9.570 +                    // for while loops we want only the body
   9.571 +                    case WHILELOOP:
   9.572 +                        return false;
   9.573 +                }
   9.574 +                return true;
   9.575 +            }
   9.576 +
   9.577 +        }
   9.578 +
   9.579 +        public class LVTAssignPendingExit extends Flow.AssignAnalyzer.AssignPendingExit {
   9.580 +
   9.581 +            LVTAssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
   9.582 +                super(tree, inits, uninits);
   9.583 +            }
   9.584 +
   9.585 +            @Override
   9.586 +            public void resolveJump(JCTree tree) {
   9.587 +                lvtInits.at(tree);
   9.588 +                super.resolveJump(tree);
   9.589 +            }
   9.590 +        }
   9.591 +
   9.592 +        private LVTAssignAnalyzer(LVTRanges lvtRanges, Symtab syms, Names names) {
   9.593 +            super(new LVTBits(), syms, names);
   9.594 +            lvtInits = (LVTBits)inits;
   9.595 +            this.lvtRanges = lvtRanges;
   9.596 +        }
   9.597 +
   9.598 +        public static LVTAssignAnalyzer make(LVTRanges lvtRanges, Symtab syms, Names names) {
   9.599 +            LVTAssignAnalyzer result = new LVTAssignAnalyzer(lvtRanges, syms, names);
   9.600 +            result.lvtInits.analyzer = result;
   9.601 +            return result;
   9.602 +        }
   9.603 +
   9.604 +        @Override
   9.605 +        protected void markDead(JCTree tree) {
   9.606 +            lvtInits.at(tree).inclRange(returnadr, nextadr);
   9.607 +            super.markDead(tree);
   9.608 +        }
   9.609 +
   9.610 +        @Override
   9.611 +        protected void merge(JCTree tree) {
   9.612 +            lvtInits.at(tree);
   9.613 +            super.merge(tree);
   9.614 +        }
   9.615 +
   9.616 +        boolean isSyntheticOrMandated(Symbol sym) {
   9.617 +            return (sym.flags() & (SYNTHETIC | MANDATED)) != 0;
   9.618 +        }
   9.619 +
   9.620 +        @Override
   9.621 +        protected boolean trackable(VarSymbol sym) {
   9.622 +            if (isSyntheticOrMandated(sym)) {
   9.623 +                //fast check to avoid tracking synthetic or mandated variables
   9.624 +                return false;
   9.625 +            }
   9.626 +            return super.trackable(sym);
   9.627 +        }
   9.628 +
   9.629 +        @Override
   9.630 +        protected void initParam(JCVariableDecl def) {
   9.631 +            if (!isSyntheticOrMandated(def.sym)) {
   9.632 +                super.initParam(def);
   9.633 +            }
   9.634 +        }
   9.635 +
   9.636 +        @Override
   9.637 +        protected void assignToInits(JCTree tree, Bits bits) {
   9.638 +            lvtInits.at(tree);
   9.639 +            lvtInits.assign(bits);
   9.640 +        }
   9.641 +
   9.642 +        @Override
   9.643 +        protected void andSetInits(JCTree tree, Bits bits) {
   9.644 +            lvtInits.at(tree);
   9.645 +            lvtInits.andSet(bits);
   9.646 +        }
   9.647 +
   9.648 +        @Override
   9.649 +        protected void orSetInits(JCTree tree, Bits bits) {
   9.650 +            lvtInits.at(tree);
   9.651 +            lvtInits.orSet(bits);
   9.652 +        }
   9.653 +
   9.654 +        @Override
   9.655 +        protected void exclVarFromInits(JCTree tree, int adr) {
   9.656 +            lvtInits.at(tree);
   9.657 +            lvtInits.excl(adr);
   9.658 +        }
   9.659 +
   9.660 +        @Override
   9.661 +        protected LVTAssignPendingExit createNewPendingExit(JCTree tree, Bits inits, Bits uninits) {
   9.662 +            return new LVTAssignPendingExit(tree, inits, uninits);
   9.663 +        }
   9.664 +
   9.665 +        MethodSymbol currentMethod;
   9.666 +
   9.667 +        @Override
   9.668 +        public void visitMethodDef(JCMethodDecl tree) {
   9.669 +            if ((tree.sym.flags() & (SYNTHETIC | GENERATEDCONSTR)) != 0) {
   9.670 +                return;
   9.671 +            }
   9.672 +            if (tree.name.equals(names.clinit)) {
   9.673 +                return;
   9.674 +            }
   9.675 +            boolean enumClass = (tree.sym.owner.flags() & ENUM) != 0;
   9.676 +            if (enumClass &&
   9.677 +                    (tree.name.equals(names.valueOf) ||
   9.678 +                    tree.name.equals(names.values) ||
   9.679 +                    tree.name.equals(names.init))) {
   9.680 +                return;
   9.681 +            }
   9.682 +            currentMethod = tree.sym;
   9.683 +            super.visitMethodDef(tree);
   9.684 +        }
   9.685 +
   9.686 +    }
   9.687 +
   9.688  }
    10.1 --- a/src/share/classes/com/sun/tools/javac/jvm/Items.java	Sat Sep 14 15:23:21 2013 +0100
    10.2 +++ b/src/share/classes/com/sun/tools/javac/jvm/Items.java	Sat Sep 14 19:04:47 2013 +0100
    10.3 @@ -789,18 +789,18 @@
    10.4          Chain jumpTrue() {
    10.5              if (tree == null) return Code.mergeChains(trueJumps, code.branch(opcode));
    10.6              // we should proceed further in -Xjcov mode only
    10.7 -            int startpc = code.curPc();
    10.8 +            int startpc = code.curCP();
    10.9              Chain c = Code.mergeChains(trueJumps, code.branch(opcode));
   10.10 -            code.crt.put(tree, CRTable.CRT_BRANCH_TRUE, startpc, code.curPc());
   10.11 +            code.crt.put(tree, CRTable.CRT_BRANCH_TRUE, startpc, code.curCP());
   10.12              return c;
   10.13          }
   10.14  
   10.15          Chain jumpFalse() {
   10.16              if (tree == null) return Code.mergeChains(falseJumps, code.branch(Code.negate(opcode)));
   10.17              // we should proceed further in -Xjcov mode only
   10.18 -            int startpc = code.curPc();
   10.19 +            int startpc = code.curCP();
   10.20              Chain c = Code.mergeChains(falseJumps, code.branch(Code.negate(opcode)));
   10.21 -            code.crt.put(tree, CRTable.CRT_BRANCH_FALSE, startpc, code.curPc());
   10.22 +            code.crt.put(tree, CRTable.CRT_BRANCH_FALSE, startpc, code.curCP());
   10.23              return c;
   10.24          }
   10.25  
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/src/share/classes/com/sun/tools/javac/jvm/LVTRanges.java	Sat Sep 14 19:04:47 2013 +0100
    11.3 @@ -0,0 +1,129 @@
    11.4 +/*
    11.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
    11.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    11.7 + *
    11.8 + * This code is free software; you can redistribute it and/or modify it
    11.9 + * under the terms of the GNU General Public License version 2 only, as
   11.10 + * published by the Free Software Foundation.  Oracle designates this
   11.11 + * particular file as subject to the "Classpath" exception as provided
   11.12 + * by Oracle in the LICENSE file that accompanied this code.
   11.13 + *
   11.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   11.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   11.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   11.17 + * version 2 for more details (a copy is included in the LICENSE file that
   11.18 + * accompanied this code).
   11.19 + *
   11.20 + * You should have received a copy of the GNU General Public License version
   11.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   11.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   11.23 + *
   11.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   11.25 + * or visit www.oracle.com if you need additional information or have any
   11.26 + * questions.
   11.27 + */
   11.28 +
   11.29 +package com.sun.tools.javac.jvm;
   11.30 +
   11.31 +import java.util.Map;
   11.32 +import java.util.Map.Entry;
   11.33 +import java.util.WeakHashMap;
   11.34 +
   11.35 +import com.sun.tools.javac.code.Symbol.MethodSymbol;
   11.36 +import com.sun.tools.javac.code.Symbol.VarSymbol;
   11.37 +import com.sun.tools.javac.tree.JCTree;
   11.38 +import com.sun.tools.javac.util.Context;
   11.39 +import com.sun.tools.javac.util.List;
   11.40 +
   11.41 +/** This class contains a one to many relation between a tree and a set of variables.
   11.42 + *  The relation implies that the given tree closes the DA (definite assignment)
   11.43 + *  range for the set of variables.
   11.44 + *
   11.45 + *  <p><b>This is NOT part of any supported API.
   11.46 + *  If you write code that depends on this, you do so at your own risk.
   11.47 + *  This code and its internal interfaces are subject to change or
   11.48 + *  deletion without notice.</b>
   11.49 + */
   11.50 +public class LVTRanges {
   11.51 +    /** The context key for the LVT ranges. */
   11.52 +    protected static final Context.Key<LVTRanges> lvtRangesKey = new Context.Key<>();
   11.53 +
   11.54 +    /** Get the LVTRanges instance for this context. */
   11.55 +    public static LVTRanges instance(Context context) {
   11.56 +        LVTRanges instance = context.get(lvtRangesKey);
   11.57 +        if (instance == null) {
   11.58 +            instance = new LVTRanges(context);
   11.59 +        }
   11.60 +        return instance;
   11.61 +    }
   11.62 +
   11.63 +    private static final long serialVersionUID = 1812267524140424433L;
   11.64 +
   11.65 +    protected Context context;
   11.66 +
   11.67 +    protected Map<MethodSymbol, Map<JCTree, List<VarSymbol>>>
   11.68 +            aliveRangeClosingTrees = new WeakHashMap<>();
   11.69 +
   11.70 +    public LVTRanges(Context context) {
   11.71 +        this.context = context;
   11.72 +        context.put(lvtRangesKey, this);
   11.73 +    }
   11.74 +
   11.75 +    public List<VarSymbol> getVars(MethodSymbol method, JCTree tree) {
   11.76 +        Map<JCTree, List<VarSymbol>> varMap = aliveRangeClosingTrees.get(method);
   11.77 +        return (varMap != null) ? varMap.get(tree) : null;
   11.78 +    }
   11.79 +
   11.80 +    public boolean containsKey(MethodSymbol method, JCTree tree) {
   11.81 +        Map<JCTree, List<VarSymbol>> varMap = aliveRangeClosingTrees.get(method);
   11.82 +        if (varMap == null) {
   11.83 +            return false;
   11.84 +        }
   11.85 +        return varMap.containsKey(tree);
   11.86 +    }
   11.87 +
   11.88 +    public void setEntry(MethodSymbol method, JCTree tree, List<VarSymbol> vars) {
   11.89 +        Map<JCTree, List<VarSymbol>> varMap = aliveRangeClosingTrees.get(method);
   11.90 +        if (varMap != null) {
   11.91 +            varMap.put(tree, vars);
   11.92 +        } else {
   11.93 +            varMap = new WeakHashMap<>();
   11.94 +            varMap.put(tree, vars);
   11.95 +            aliveRangeClosingTrees.put(method, varMap);
   11.96 +        }
   11.97 +    }
   11.98 +
   11.99 +    public List<VarSymbol> removeEntry(MethodSymbol method, JCTree tree) {
  11.100 +        Map<JCTree, List<VarSymbol>> varMap = aliveRangeClosingTrees.get(method);
  11.101 +        if (varMap != null) {
  11.102 +            List<VarSymbol> result = varMap.remove(tree);
  11.103 +            if (varMap.isEmpty()) {
  11.104 +                aliveRangeClosingTrees.remove(method);
  11.105 +            }
  11.106 +            return result;
  11.107 +        }
  11.108 +        return null;
  11.109 +    }
  11.110 +
  11.111 +    /* This method should be used for debugging LVT related issues.
  11.112 +     */
  11.113 +    @Override
  11.114 +    public String toString() {
  11.115 +        String result = "";
  11.116 +        for (Entry<MethodSymbol, Map<JCTree, List<VarSymbol>>> mainEntry: aliveRangeClosingTrees.entrySet()) {
  11.117 +            result += "Method: \n" + mainEntry.getKey().flatName() + "\n";
  11.118 +            int i = 1;
  11.119 +            for (Entry<JCTree, List<VarSymbol>> treeEntry: mainEntry.getValue().entrySet()) {
  11.120 +                result += "    Tree " + i + ": \n" + treeEntry.getKey().toString() + "\n";
  11.121 +                result += "        Variables closed:\n";
  11.122 +                for (VarSymbol var: treeEntry.getValue()) {
  11.123 +                    result += "            " + var.toString();
  11.124 +                }
  11.125 +                result += "\n";
  11.126 +                i++;
  11.127 +            }
  11.128 +        }
  11.129 +        return result;
  11.130 +    }
  11.131 +
  11.132 +}
    12.1 --- a/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Sat Sep 14 15:23:21 2013 +0100
    12.2 +++ b/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Sat Sep 14 19:04:47 2013 +0100
    12.3 @@ -890,7 +890,7 @@
    12.4      /** Create a value parameter tree from its name, type, and owner.
    12.5       */
    12.6      public JCVariableDecl Param(Name name, Type argtype, Symbol owner) {
    12.7 -        return VarDef(new VarSymbol(0, name, argtype, owner), null);
    12.8 +        return VarDef(new VarSymbol(PARAMETER, name, argtype, owner), null);
    12.9      }
   12.10  
   12.11      /** Create a a list of value parameter trees x0, ..., xn from a list of
    13.1 --- a/src/share/classes/com/sun/tools/javac/util/Bits.java	Sat Sep 14 15:23:21 2013 +0100
    13.2 +++ b/src/share/classes/com/sun/tools/javac/util/Bits.java	Sat Sep 14 19:04:47 2013 +0100
    13.3 @@ -27,8 +27,6 @@
    13.4  
    13.5  import java.util.Arrays;
    13.6  
    13.7 -import static com.sun.tools.javac.util.Bits.BitsOpKind.*;
    13.8 -
    13.9  /** A class for extensible, mutable bit sets.
   13.10   *
   13.11   *  <p><b>This is NOT part of any supported API.
   13.12 @@ -38,20 +36,6 @@
   13.13   */
   13.14  public class Bits {
   13.15  
   13.16 -    public enum BitsOpKind {
   13.17 -        INIT,
   13.18 -        CLEAR,
   13.19 -        INCL_BIT,
   13.20 -        EXCL_BIT,
   13.21 -        ASSIGN,
   13.22 -        AND_SET,
   13.23 -        OR_SET,
   13.24 -        DIFF_SET,
   13.25 -        XOR_SET,
   13.26 -        INCL_RANGE,
   13.27 -        EXCL_RANGE,
   13.28 -    }
   13.29 -
   13.30      //       ____________      reset    _________
   13.31      //      /  UNKNOWN   \   <-------- / UNINIT  \
   13.32      //      \____________/       |     \_________/
   13.33 @@ -64,11 +48,14 @@
   13.34      //                            |         |
   13.35      //                            -----------
   13.36      //                               any
   13.37 -    private enum BitsState {
   13.38 +    protected enum BitsState {
   13.39          /*  A Bits instance is in UNKNOWN state if it has been explicitly reset.
   13.40           *  It is possible to get to this state from any other by calling the
   13.41           *  reset method. An instance in the UNKNOWN state can pass to the
   13.42           *  NORMAL state after being assigned another Bits instance.
   13.43 +         *
   13.44 +         *  Bits instances are final fields in Flow so the UNKNOWN state models
   13.45 +         *  the null assignment.
   13.46           */
   13.47          UNKNOWN,
   13.48          /*  A Bits instance is in UNINIT when it is created with the default
   13.49 @@ -103,13 +90,9 @@
   13.50  
   13.51      public int[] bits = null;
   13.52      // This field will store last version of bits after every change.
   13.53 -    public int[] oldBits = null;
   13.54 -
   13.55 -    public BitsOpKind lastOperation = null;
   13.56 -
   13.57      private static final int[] unassignedBits = new int[0];
   13.58  
   13.59 -    private BitsState currentState;
   13.60 +    protected BitsState currentState;
   13.61  
   13.62      /** Construct an initially empty set.
   13.63       */
   13.64 @@ -127,27 +110,20 @@
   13.65  
   13.66      /** Construct a set consisting initially of given bit vector.
   13.67       */
   13.68 -    private Bits(int[] bits, BitsState initState) {
   13.69 +    protected Bits(int[] bits, BitsState initState) {
   13.70          this.bits = bits;
   13.71          this.currentState = initState;
   13.72          switch (initState) {
   13.73              case UNKNOWN:
   13.74 -                reset(); //this will also set current state;
   13.75 +                this.bits = null;
   13.76                  break;
   13.77              case NORMAL:
   13.78                  Assert.check(bits != unassignedBits);
   13.79 -                lastOperation = INIT;
   13.80                  break;
   13.81          }
   13.82      }
   13.83  
   13.84 -    /** This method will be called after any operation that causes a change to
   13.85 -     *  the bits. Subclasses can thus override it in order to extract information
   13.86 -     *  from the changes produced to the bits by the given operation.
   13.87 -     */
   13.88 -    public void changed() {}
   13.89 -
   13.90 -    private void sizeTo(int len) {
   13.91 +    protected void sizeTo(int len) {
   13.92          if (bits.length < len) {
   13.93              bits = Arrays.copyOf(bits, len);
   13.94          }
   13.95 @@ -157,16 +133,18 @@
   13.96       */
   13.97      public void clear() {
   13.98          Assert.check(currentState != BitsState.UNKNOWN);
   13.99 -        oldBits = bits;
  13.100 -        lastOperation = CLEAR;
  13.101 -        for (int i = 0; i < bits.length; i++) bits[i] = 0;
  13.102 -        changed();
  13.103 +        for (int i = 0; i < bits.length; i++) {
  13.104 +            bits[i] = 0;
  13.105 +        }
  13.106          currentState = BitsState.NORMAL;
  13.107      }
  13.108  
  13.109      public void reset() {
  13.110 +        internalReset();
  13.111 +    }
  13.112 +
  13.113 +    protected void internalReset() {
  13.114          bits = null;
  13.115 -        oldBits = null;
  13.116          currentState = BitsState.UNKNOWN;
  13.117      }
  13.118  
  13.119 @@ -175,40 +153,40 @@
  13.120      }
  13.121  
  13.122      public Bits assign(Bits someBits) {
  13.123 -        lastOperation = ASSIGN;
  13.124 -        oldBits = bits;
  13.125          bits = someBits.dup().bits;
  13.126 -        changed();
  13.127          currentState = BitsState.NORMAL;
  13.128          return this;
  13.129      }
  13.130  
  13.131      /** Return a copy of this set.
  13.132       */
  13.133 -    private Bits dup() {
  13.134 +    public Bits dup() {
  13.135          Assert.check(currentState != BitsState.UNKNOWN);
  13.136          Bits tmp = new Bits();
  13.137 -        if (currentState != BitsState.NORMAL) {
  13.138 -            tmp.bits = bits;
  13.139 -        } else {
  13.140 -            tmp.bits = new int[bits.length];
  13.141 -            System.arraycopy(bits, 0, tmp.bits, 0, bits.length);
  13.142 -        }
  13.143 +        tmp.bits = dupBits();
  13.144          currentState = BitsState.NORMAL;
  13.145          return tmp;
  13.146      }
  13.147  
  13.148 +    protected int[] dupBits() {
  13.149 +        int [] result;
  13.150 +        if (currentState != BitsState.NORMAL) {
  13.151 +            result = bits;
  13.152 +        } else {
  13.153 +            result = new int[bits.length];
  13.154 +            System.arraycopy(bits, 0, result, 0, bits.length);
  13.155 +        }
  13.156 +        return result;
  13.157 +    }
  13.158 +
  13.159      /** Include x in this set.
  13.160       */
  13.161      public void incl(int x) {
  13.162          Assert.check(currentState != BitsState.UNKNOWN);
  13.163 -        Assert.check(x >= 0);
  13.164 -        oldBits = bits;
  13.165 -        lastOperation = INCL_BIT;
  13.166 +        Assert.check(x >= 0, "Value of x " + x);
  13.167          sizeTo((x >>> wordshift) + 1);
  13.168          bits[x >>> wordshift] = bits[x >>> wordshift] |
  13.169              (1 << (x & wordmask));
  13.170 -        changed();
  13.171          currentState = BitsState.NORMAL;
  13.172      }
  13.173  
  13.174 @@ -217,14 +195,11 @@
  13.175       */
  13.176      public void inclRange(int start, int limit) {
  13.177          Assert.check(currentState != BitsState.UNKNOWN);
  13.178 -        oldBits = bits;
  13.179 -        lastOperation = INCL_RANGE;
  13.180          sizeTo((limit >>> wordshift) + 1);
  13.181          for (int x = start; x < limit; x++) {
  13.182              bits[x >>> wordshift] = bits[x >>> wordshift] |
  13.183                  (1 << (x & wordmask));
  13.184          }
  13.185 -        changed();
  13.186          currentState = BitsState.NORMAL;
  13.187      }
  13.188  
  13.189 @@ -232,13 +207,10 @@
  13.190       */
  13.191      public void excludeFrom(int start) {
  13.192          Assert.check(currentState != BitsState.UNKNOWN);
  13.193 -        oldBits = bits;
  13.194 -        lastOperation = EXCL_RANGE;
  13.195          Bits temp = new Bits();
  13.196          temp.sizeTo(bits.length);
  13.197          temp.inclRange(0, start);
  13.198          internalAndSet(temp);
  13.199 -        changed();
  13.200          currentState = BitsState.NORMAL;
  13.201      }
  13.202  
  13.203 @@ -247,12 +219,9 @@
  13.204      public void excl(int x) {
  13.205          Assert.check(currentState != BitsState.UNKNOWN);
  13.206          Assert.check(x >= 0);
  13.207 -        oldBits = bits;
  13.208 -        lastOperation = EXCL_BIT;
  13.209          sizeTo((x >>> wordshift) + 1);
  13.210          bits[x >>> wordshift] = bits[x >>> wordshift] &
  13.211              ~(1 << (x & wordmask));
  13.212 -        changed();
  13.213          currentState = BitsState.NORMAL;
  13.214      }
  13.215  
  13.216 @@ -269,15 +238,12 @@
  13.217       */
  13.218      public Bits andSet(Bits xs) {
  13.219          Assert.check(currentState != BitsState.UNKNOWN);
  13.220 -        oldBits = bits;
  13.221 -        lastOperation = AND_SET;
  13.222          internalAndSet(xs);
  13.223 -        changed();
  13.224          currentState = BitsState.NORMAL;
  13.225          return this;
  13.226      }
  13.227  
  13.228 -    private void internalAndSet(Bits xs) {
  13.229 +    protected void internalAndSet(Bits xs) {
  13.230          Assert.check(currentState != BitsState.UNKNOWN);
  13.231          sizeTo(xs.bits.length);
  13.232          for (int i = 0; i < xs.bits.length; i++) {
  13.233 @@ -289,13 +255,10 @@
  13.234       */
  13.235      public Bits orSet(Bits xs) {
  13.236          Assert.check(currentState != BitsState.UNKNOWN);
  13.237 -        oldBits = bits;
  13.238 -        lastOperation = OR_SET;
  13.239          sizeTo(xs.bits.length);
  13.240          for (int i = 0; i < xs.bits.length; i++) {
  13.241              bits[i] = bits[i] | xs.bits[i];
  13.242          }
  13.243 -        changed();
  13.244          currentState = BitsState.NORMAL;
  13.245          return this;
  13.246      }
  13.247 @@ -304,14 +267,11 @@
  13.248       */
  13.249      public Bits diffSet(Bits xs) {
  13.250          Assert.check(currentState != BitsState.UNKNOWN);
  13.251 -        oldBits = bits;
  13.252 -        lastOperation = DIFF_SET;
  13.253          for (int i = 0; i < bits.length; i++) {
  13.254              if (i < xs.bits.length) {
  13.255                  bits[i] = bits[i] & ~xs.bits[i];
  13.256              }
  13.257          }
  13.258 -        changed();
  13.259          currentState = BitsState.NORMAL;
  13.260          return this;
  13.261      }
  13.262 @@ -320,13 +280,10 @@
  13.263       */
  13.264      public Bits xorSet(Bits xs) {
  13.265          Assert.check(currentState != BitsState.UNKNOWN);
  13.266 -        oldBits = bits;
  13.267 -        lastOperation = XOR_SET;
  13.268          sizeTo(xs.bits.length);
  13.269          for (int i = 0; i < xs.bits.length; i++) {
  13.270              bits[i] = bits[i] ^ xs.bits[i];
  13.271          }
  13.272 -        changed();
  13.273          currentState = BitsState.NORMAL;
  13.274          return this;
  13.275      }
  13.276 @@ -336,7 +293,9 @@
  13.277       */
  13.278      private static int trailingZeroBits(int x) {
  13.279          Assert.check(wordlen == 32);
  13.280 -        if (x == 0) return 32;
  13.281 +        if (x == 0) {
  13.282 +            return 32;
  13.283 +        }
  13.284          int n = 1;
  13.285          if ((x & 0xffff) == 0) { n += 16; x >>>= 16; }
  13.286          if ((x & 0x00ff) == 0) { n +=  8; x >>>=  8; }
  13.287 @@ -355,24 +314,31 @@
  13.288      public int nextBit(int x) {
  13.289          Assert.check(currentState != BitsState.UNKNOWN);
  13.290          int windex = x >>> wordshift;
  13.291 -        if (windex >= bits.length) return -1;
  13.292 +        if (windex >= bits.length) {
  13.293 +            return -1;
  13.294 +        }
  13.295          int word = bits[windex] & ~((1 << (x & wordmask))-1);
  13.296          while (true) {
  13.297 -            if (word != 0)
  13.298 +            if (word != 0) {
  13.299                  return (windex << wordshift) + trailingZeroBits(word);
  13.300 +            }
  13.301              windex++;
  13.302 -            if (windex >= bits.length) return -1;
  13.303 +            if (windex >= bits.length) {
  13.304 +                return -1;
  13.305 +            }
  13.306              word = bits[windex];
  13.307          }
  13.308      }
  13.309  
  13.310      /** a string representation of this set.
  13.311       */
  13.312 +    @Override
  13.313      public String toString() {
  13.314 -        if (bits.length > 0) {
  13.315 +        if (bits != null && bits.length > 0) {
  13.316              char[] digits = new char[bits.length * wordlen];
  13.317 -            for (int i = 0; i < bits.length * wordlen; i++)
  13.318 +            for (int i = 0; i < bits.length * wordlen; i++) {
  13.319                  digits[i] = isMember(i) ? '1' : '0';
  13.320 +            }
  13.321              return new String(digits);
  13.322          } else {
  13.323              return "[]";
  13.324 @@ -396,6 +362,8 @@
  13.325              System.out.println("found " + i);
  13.326              count ++;
  13.327          }
  13.328 -        if (count != 125) throw new Error();
  13.329 +        if (count != 125) {
  13.330 +            throw new Error();
  13.331 +        }
  13.332      }
  13.333  }
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/test/tools/javac/flow/AliveRanges.java	Sat Sep 14 19:04:47 2013 +0100
    14.3 @@ -0,0 +1,34 @@
    14.4 +/*
    14.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
    14.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    14.7 + *
    14.8 + * This code is free software; you can redistribute it and/or modify it
    14.9 + * under the terms of the GNU General Public License version 2 only, as
   14.10 + * published by the Free Software Foundation.
   14.11 + *
   14.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   14.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   14.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14.15 + * version 2 for more details (a copy is included in the LICENSE file that
   14.16 + * accompanied this code).
   14.17 + *
   14.18 + * You should have received a copy of the GNU General Public License version
   14.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   14.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   14.21 + *
   14.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   14.23 + * or visit www.oracle.com if you need additional information or have any
   14.24 + * questions.
   14.25 + */
   14.26 +import java.lang.annotation.*;
   14.27 +
   14.28 +@Repeatable(AliveRanges.class)
   14.29 +@Target({ElementType.METHOD})
   14.30 +@interface AliveRange {
   14.31 +    String varName();
   14.32 +    int bytecodeStart();
   14.33 +    int bytecodeLength();
   14.34 +}
   14.35 +
   14.36 +@Target({ElementType.METHOD})
   14.37 +@interface AliveRanges {AliveRange[] value();}
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/test/tools/javac/flow/LVTHarness.java	Sat Sep 14 19:04:47 2013 +0100
    15.3 @@ -0,0 +1,280 @@
    15.4 +/*
    15.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
    15.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    15.7 + *
    15.8 + * This code is free software; you can redistribute it and/or modify it
    15.9 + * under the terms of the GNU General Public License version 2 only, as
   15.10 + * published by the Free Software Foundation.
   15.11 + *
   15.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   15.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   15.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   15.15 + * version 2 for more details (a copy is included in the LICENSE file that
   15.16 + * accompanied this code).
   15.17 + *
   15.18 + * You should have received a copy of the GNU General Public License version
   15.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   15.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   15.21 + *
   15.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   15.23 + * or visit www.oracle.com if you need additional information or have any
   15.24 + * questions.
   15.25 + */
   15.26 +
   15.27 +/*
   15.28 + * @test
   15.29 + * @bug 7047734
   15.30 + * @summary The LVT is not generated correctly during some try/catch scenarios
   15.31 + * @library /tools/javac/lib
   15.32 + * @build JavacTestingAbstractProcessor LVTHarness
   15.33 + * @run main LVTHarness
   15.34 + */
   15.35 +
   15.36 +import java.io.File;
   15.37 +import java.io.IOException;
   15.38 +import java.lang.annotation.Annotation;
   15.39 +import java.util.Set;
   15.40 +import java.util.Arrays;
   15.41 +import java.util.ArrayList;
   15.42 +import java.util.Collections;
   15.43 +import java.util.HashMap;
   15.44 +import java.util.HashSet;
   15.45 +import java.util.List;
   15.46 +import java.util.Map;
   15.47 +
   15.48 +import javax.annotation.processing.RoundEnvironment;
   15.49 +import javax.lang.model.element.Element;
   15.50 +import javax.lang.model.element.TypeElement;
   15.51 +import javax.tools.JavaCompiler;
   15.52 +import javax.tools.JavaFileObject;
   15.53 +import javax.tools.StandardJavaFileManager;
   15.54 +import javax.tools.ToolProvider;
   15.55 +
   15.56 +import com.sun.source.util.JavacTask;
   15.57 +import com.sun.tools.classfile.Attribute;
   15.58 +import com.sun.tools.classfile.ClassFile;
   15.59 +import com.sun.tools.classfile.ConstantPool;
   15.60 +import com.sun.tools.classfile.ConstantPoolException;
   15.61 +import com.sun.tools.classfile.Code_attribute;
   15.62 +import com.sun.tools.classfile.ConstantPool.InvalidIndex;
   15.63 +import com.sun.tools.classfile.ConstantPool.UnexpectedEntry;
   15.64 +import com.sun.tools.classfile.Descriptor.InvalidDescriptor;
   15.65 +import com.sun.tools.classfile.LocalVariableTable_attribute;
   15.66 +import com.sun.tools.classfile.Method;
   15.67 +
   15.68 +import static javax.tools.StandardLocation.*;
   15.69 +import static com.sun.tools.classfile.LocalVariableTable_attribute.Entry;
   15.70 +
   15.71 +public class LVTHarness {
   15.72 +
   15.73 +    static int nerrors = 0;
   15.74 +
   15.75 +    static final JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
   15.76 +    static final StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
   15.77 +
   15.78 +    public static void main(String[] args) throws Exception {
   15.79 +        fm.setLocation(SOURCE_PATH,
   15.80 +                Arrays.asList(new File(System.getProperty("test.src"), "tests")));
   15.81 +        for (JavaFileObject jfo : fm.list(SOURCE_PATH, "",
   15.82 +                Collections.singleton(JavaFileObject.Kind.SOURCE), true)) {
   15.83 +            new LVTHarness(jfo).check();
   15.84 +        }
   15.85 +        if (nerrors > 0) {
   15.86 +            throw new AssertionError("Errors were found");
   15.87 +        }
   15.88 +    }
   15.89 +
   15.90 +
   15.91 +    JavaFileObject jfo;
   15.92 +    Map<ElementKey, AliveRanges> aliveRangeMap =
   15.93 +            new HashMap<ElementKey, AliveRanges>();
   15.94 +    Set<String> declaredKeys = new HashSet<>();
   15.95 +    List<ElementKey> seenAliveRanges = new ArrayList<>();
   15.96 +
   15.97 +    protected LVTHarness(JavaFileObject jfo) {
   15.98 +        this.jfo = jfo;
   15.99 +    }
  15.100 +
  15.101 +    protected void check() throws Exception {
  15.102 +        JavacTask ct = (JavacTask)comp.getTask(null, fm, null, Arrays.asList("-g"),
  15.103 +                null, Arrays.asList(jfo));
  15.104 +        System.err.println("compiling code " + jfo.toString());
  15.105 +        ct.setProcessors(Collections.singleton(new AliveRangeFinder()));
  15.106 +        if (!ct.call()) {
  15.107 +            throw new AssertionError("Error during compilation");
  15.108 +        }
  15.109 +
  15.110 +        checkClassFile(new File(jfo.getName().replace(".java", ".class")));
  15.111 +
  15.112 +        //check all candidates have been used up
  15.113 +        for (Map.Entry<ElementKey, AliveRanges> entry : aliveRangeMap.entrySet()) {
  15.114 +            if (!seenAliveRanges.contains(entry.getKey())) {
  15.115 +                error("Redundant @AliveRanges annotation on method " +
  15.116 +                        entry.getKey().elem);
  15.117 +            }
  15.118 +        }
  15.119 +    }
  15.120 +
  15.121 +    void checkClassFile(File file)
  15.122 +            throws IOException, ConstantPoolException, InvalidDescriptor {
  15.123 +        ClassFile classFile = ClassFile.read(file);
  15.124 +        ConstantPool constantPool = classFile.constant_pool;
  15.125 +
  15.126 +        //lets get all the methods in the class file.
  15.127 +        for (Method method : classFile.methods) {
  15.128 +            for (ElementKey elementKey: aliveRangeMap.keySet()) {
  15.129 +                String methodDesc = method.getName(constantPool) +
  15.130 +                        method.descriptor.getParameterTypes(constantPool);
  15.131 +                if (methodDesc.equals(elementKey.elem.toString())) {
  15.132 +                    checkMethod(constantPool, method, aliveRangeMap.get(elementKey));
  15.133 +                    seenAliveRanges.add(elementKey);
  15.134 +                }
  15.135 +            }
  15.136 +        }
  15.137 +    }
  15.138 +
  15.139 +    void checkMethod(ConstantPool constantPool, Method method, AliveRanges ranges)
  15.140 +            throws InvalidIndex, UnexpectedEntry {
  15.141 +        Code_attribute code = (Code_attribute) method.attributes.get(Attribute.Code);
  15.142 +        LocalVariableTable_attribute lvt =
  15.143 +            (LocalVariableTable_attribute) (code.attributes.get(Attribute.LocalVariableTable));
  15.144 +        List<String> infoFromRanges = convertToStringList(ranges);
  15.145 +        List<String> infoFromLVT = convertToStringList(constantPool, lvt);
  15.146 +
  15.147 +        // infoFromRanges most be contained in infoFromLVT
  15.148 +        int i = 0;
  15.149 +        int j = 0;
  15.150 +        while (i < infoFromRanges.size() && j < infoFromLVT.size()) {
  15.151 +            int comparison = infoFromRanges.get(i).compareTo(infoFromLVT.get(j));
  15.152 +            if (comparison == 0) {
  15.153 +                i++; j++;
  15.154 +            } else if (comparison > 0) {
  15.155 +                j++;
  15.156 +            } else {
  15.157 +                break;
  15.158 +            }
  15.159 +        }
  15.160 +
  15.161 +        if (i < infoFromRanges.size()) {
  15.162 +            error(infoFromLVT, infoFromRanges);
  15.163 +        }
  15.164 +    }
  15.165 +
  15.166 +    List<String> convertToStringList(AliveRanges ranges) {
  15.167 +        List<String> result = new ArrayList<>();
  15.168 +        for (Annotation anno : ranges.value()) {
  15.169 +            AliveRange range = (AliveRange)anno;
  15.170 +            String str = formatLocalVariableData(range.varName(),
  15.171 +                    range.bytecodeStart(), range.bytecodeLength());
  15.172 +            result.add(str);
  15.173 +        }
  15.174 +        Collections.sort(result);
  15.175 +        return result;
  15.176 +    }
  15.177 +
  15.178 +    List<String> convertToStringList(ConstantPool constantPool,
  15.179 +            LocalVariableTable_attribute lvt) throws InvalidIndex, UnexpectedEntry {
  15.180 +        List<String> result = new ArrayList<>();
  15.181 +        for (Entry entry : lvt.local_variable_table) {
  15.182 +            String str = formatLocalVariableData(constantPool.getUTF8Value(entry.name_index),
  15.183 +                    entry.start_pc, entry.length);
  15.184 +            result.add(str);
  15.185 +        }
  15.186 +        Collections.sort(result);
  15.187 +        return result;
  15.188 +    }
  15.189 +
  15.190 +    String formatLocalVariableData(String varName, int start, int length) {
  15.191 +        StringBuilder sb = new StringBuilder()
  15.192 +                    .append("var name: ").append(varName)
  15.193 +                    .append(" start: ").append(start)
  15.194 +                    .append(" length: ").append(length);
  15.195 +        return sb.toString();
  15.196 +    }
  15.197 +
  15.198 +    protected void error(List<String> infoFromLVT, List<String> infoFromRanges) {
  15.199 +        nerrors++;
  15.200 +        System.err.printf("Error occurred while checking file: %s\n", jfo.getName());
  15.201 +        System.err.println("The range info from the annotations is");
  15.202 +        printStringListToErrOutput(infoFromRanges);
  15.203 +        System.err.println();
  15.204 +        System.err.println("And the range info from the class file is");
  15.205 +        printStringListToErrOutput(infoFromLVT);
  15.206 +        System.err.println();
  15.207 +    }
  15.208 +
  15.209 +    void printStringListToErrOutput(List<String> list) {
  15.210 +        for (String s : list) {
  15.211 +            System.err.println("\t" + s);
  15.212 +        }
  15.213 +    }
  15.214 +
  15.215 +    protected void error(String msg) {
  15.216 +        nerrors++;
  15.217 +        System.err.printf("Error occurred while checking file: %s\nreason: %s\n",
  15.218 +                jfo.getName(), msg);
  15.219 +    }
  15.220 +
  15.221 +    class AliveRangeFinder extends JavacTestingAbstractProcessor {
  15.222 +
  15.223 +        @Override
  15.224 +        public boolean process(Set<? extends TypeElement> annotations,
  15.225 +            RoundEnvironment roundEnv) {
  15.226 +            if (roundEnv.processingOver())
  15.227 +                return true;
  15.228 +
  15.229 +            TypeElement aliveRangeAnno = elements.getTypeElement("AliveRanges");
  15.230 +
  15.231 +            if (!annotations.contains(aliveRangeAnno)) {
  15.232 +                error("no @AliveRanges annotation found in test class");
  15.233 +            }
  15.234 +
  15.235 +            for (Element elem: roundEnv.getElementsAnnotatedWith(aliveRangeAnno)) {
  15.236 +                Annotation annotation = elem.getAnnotation(AliveRanges.class);
  15.237 +                aliveRangeMap.put(new ElementKey(elem), (AliveRanges)annotation);
  15.238 +            }
  15.239 +            return true;
  15.240 +        }
  15.241 +    }
  15.242 +
  15.243 +    class ElementKey {
  15.244 +
  15.245 +        String key;
  15.246 +        Element elem;
  15.247 +
  15.248 +        public ElementKey(Element elem) {
  15.249 +            this.elem = elem;
  15.250 +            this.key = computeKey(elem);
  15.251 +        }
  15.252 +
  15.253 +        @Override
  15.254 +        public boolean equals(Object obj) {
  15.255 +            if (obj instanceof ElementKey) {
  15.256 +                ElementKey other = (ElementKey)obj;
  15.257 +                return other.key.equals(key);
  15.258 +            }
  15.259 +            return false;
  15.260 +        }
  15.261 +
  15.262 +        @Override
  15.263 +        public int hashCode() {
  15.264 +            return key.hashCode();
  15.265 +        }
  15.266 +
  15.267 +        String computeKey(Element e) {
  15.268 +            StringBuilder buf = new StringBuilder();
  15.269 +            while (e != null) {
  15.270 +                buf.append(e.toString());
  15.271 +                e = e.getEnclosingElement();
  15.272 +            }
  15.273 +            buf.append(jfo.getName());
  15.274 +            return buf.toString();
  15.275 +        }
  15.276 +
  15.277 +        @Override
  15.278 +        public String toString() {
  15.279 +            return "Key{" + key + "}";
  15.280 +        }
  15.281 +    }
  15.282 +
  15.283 +}
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/test/tools/javac/flow/tests/TestCaseConditional.java	Sat Sep 14 19:04:47 2013 +0100
    16.3 @@ -0,0 +1,16 @@
    16.4 +/* /nodynamiccopyright/ */
    16.5 +
    16.6 +public class TestCaseConditional {
    16.7 +
    16.8 +    @AliveRange(varName="o", bytecodeStart=5, bytecodeLength=33)
    16.9 +    @AliveRange(varName="oo", bytecodeStart=23, bytecodeLength=15)
   16.10 +    void m(String[] args) {
   16.11 +        Boolean o;
   16.12 +        Boolean oo = ((o = Boolean.TRUE).booleanValue()) ?
   16.13 +                o = Boolean.TRUE :
   16.14 +                Boolean.FALSE;
   16.15 +        oo.hashCode();
   16.16 +        o = Boolean.FALSE;
   16.17 +        o.hashCode();
   16.18 +    }
   16.19 +}
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/test/tools/javac/flow/tests/TestCaseDoLoop.java	Sat Sep 14 19:04:47 2013 +0100
    17.3 @@ -0,0 +1,15 @@
    17.4 +/* /nodynamiccopyright/ */
    17.5 +
    17.6 +public class TestCaseDoLoop {
    17.7 +
    17.8 +    @AliveRange(varName="o", bytecodeStart=3, bytecodeLength=15)
    17.9 +    @AliveRange(varName="args", bytecodeStart=0, bytecodeLength=18)
   17.10 +    void m(String[] args) {
   17.11 +        Object o;
   17.12 +        do {
   17.13 +            o = "";
   17.14 +            o.hashCode();
   17.15 +        } while (args[0] != null);
   17.16 +        o = "";
   17.17 +    }
   17.18 +}
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/test/tools/javac/flow/tests/TestCaseFor.java	Sat Sep 14 19:04:47 2013 +0100
    18.3 @@ -0,0 +1,27 @@
    18.4 +/* /nodynamiccopyright/ */
    18.5 +
    18.6 +public class TestCaseFor {
    18.7 +
    18.8 +    @AliveRange(varName="o", bytecodeStart=10, bytecodeLength=8)
    18.9 +    @AliveRange(varName="o", bytecodeStart=24, bytecodeLength=1)
   18.10 +    void m1(String[] args) {
   18.11 +        Object o;
   18.12 +        for (int i = 0; i < 5; i++) {
   18.13 +            o = "";
   18.14 +            o.hashCode();
   18.15 +        }
   18.16 +        o = "";
   18.17 +    }
   18.18 +
   18.19 +    @AliveRange(varName="o", bytecodeStart=10, bytecodeLength=8)
   18.20 +    @AliveRange(varName="o", bytecodeStart=24, bytecodeLength=1)
   18.21 +    void m2(String[] args) {
   18.22 +        Object o;
   18.23 +        for (int i = 0; i < 5; i++) {
   18.24 +            o = "";
   18.25 +            o.hashCode();
   18.26 +            continue;
   18.27 +        }
   18.28 +        o = "";
   18.29 +    }
   18.30 +}
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/test/tools/javac/flow/tests/TestCaseForEach.java	Sat Sep 14 19:04:47 2013 +0100
    19.3 @@ -0,0 +1,15 @@
    19.4 +/* /nodynamiccopyright/ */
    19.5 +
    19.6 +public class TestCaseForEach {
    19.7 +
    19.8 +    @AliveRange(varName="o", bytecodeStart=25, bytecodeLength=8)
    19.9 +    @AliveRange(varName="o", bytecodeStart=39, bytecodeLength=1)
   19.10 +    void m(String[] args) {
   19.11 +        Object o;
   19.12 +        for (String s : args) {
   19.13 +            o = "";
   19.14 +            o.hashCode();
   19.15 +        }
   19.16 +        o = "";
   19.17 +    }
   19.18 +}
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/test/tools/javac/flow/tests/TestCaseIf.java	Sat Sep 14 19:04:47 2013 +0100
    20.3 @@ -0,0 +1,61 @@
    20.4 +/* /nodynamiccopyright/ */
    20.5 +
    20.6 +public class TestCaseIf {
    20.7 +
    20.8 +    @AliveRange(varName="o", bytecodeStart=9, bytecodeLength=5)
    20.9 +    @AliveRange(varName="o", bytecodeStart=17, bytecodeLength=1)
   20.10 +    void m0(String[] args) {
   20.11 +        Object o;
   20.12 +        if (args[0] != null) {
   20.13 +            o = "";
   20.14 +            o.hashCode();
   20.15 +        }
   20.16 +        o = "";
   20.17 +    }
   20.18 +
   20.19 +    @AliveRange(varName="o", bytecodeStart=10, bytecodeLength=5)
   20.20 +    @AliveRange(varName="o", bytecodeStart=18, bytecodeLength=1)
   20.21 +    void m1() {
   20.22 +        Object o;
   20.23 +        int i = 5;
   20.24 +        if (i == 5) {
   20.25 +            o = "";
   20.26 +            o.hashCode();
   20.27 +        }
   20.28 +        o = "";
   20.29 +    }
   20.30 +
   20.31 +    @AliveRange(varName="o", bytecodeStart=10, bytecodeLength=5)
   20.32 +    @AliveRange(varName="o", bytecodeStart=18, bytecodeLength=1)
   20.33 +    void m2() {
   20.34 +        Object o;
   20.35 +        int i = 5;
   20.36 +        if (!(i == 5)) {
   20.37 +            o = "";
   20.38 +            o.hashCode();
   20.39 +        }
   20.40 +        o = "";
   20.41 +    }
   20.42 +
   20.43 +    @AliveRange(varName="o", bytecodeStart=15, bytecodeLength=5)
   20.44 +    @AliveRange(varName="o", bytecodeStart=23, bytecodeLength=1)
   20.45 +    void m3(String[] args) {
   20.46 +        Object o;
   20.47 +        if (args[0] != null && args[1] != null) {
   20.48 +            o = "";
   20.49 +            o.hashCode();
   20.50 +        }
   20.51 +        o = "";
   20.52 +    }
   20.53 +
   20.54 +    @AliveRange(varName="o", bytecodeStart=15, bytecodeLength=5)
   20.55 +    @AliveRange(varName="o", bytecodeStart=23, bytecodeLength=1)
   20.56 +    void m4(String[] args) {
   20.57 +        Object o;
   20.58 +        if (args[0] != null || args[1] != null) {
   20.59 +            o = "";
   20.60 +            o.hashCode();
   20.61 +        }
   20.62 +        o = "";
   20.63 +    }
   20.64 +}
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/test/tools/javac/flow/tests/TestCaseIfElse.java	Sat Sep 14 19:04:47 2013 +0100
    21.3 @@ -0,0 +1,48 @@
    21.4 +/* /nodynamiccopyright/ */
    21.5 +
    21.6 +public class TestCaseIfElse {
    21.7 +
    21.8 +    @AliveRange(varName="o", bytecodeStart=9, bytecodeLength=8)
    21.9 +    @AliveRange(varName="o", bytecodeStart=20, bytecodeLength=9)
   21.10 +    void m0(String[] args) {
   21.11 +        Object o;
   21.12 +        if (args[0] != null) {
   21.13 +            o = "then";
   21.14 +            o.hashCode();
   21.15 +        } else {
   21.16 +            o = "else";
   21.17 +            o.hashCode();
   21.18 +        }
   21.19 +        o = "finish";
   21.20 +    }
   21.21 +
   21.22 +    @AliveRange(varName="o", bytecodeStart=10, bytecodeLength=8)
   21.23 +    @AliveRange(varName="o", bytecodeStart=21, bytecodeLength=9)
   21.24 +    void m1() {
   21.25 +        Object o;
   21.26 +        int i = 5;
   21.27 +        if (i == 5) {
   21.28 +            o = "then";
   21.29 +            o.hashCode();
   21.30 +        } else {
   21.31 +            o = "else";
   21.32 +            o.hashCode();
   21.33 +        }
   21.34 +        o = "finish";
   21.35 +    }
   21.36 +
   21.37 +    @AliveRange(varName="o", bytecodeStart=10, bytecodeLength=8)
   21.38 +    @AliveRange(varName="o", bytecodeStart=21, bytecodeLength=9)
   21.39 +    void m2(String[] args) {
   21.40 +        Object o;
   21.41 +        int i = 5;
   21.42 +        if (i != 5) {
   21.43 +            o = "then";
   21.44 +            o.hashCode();
   21.45 +        } else {
   21.46 +            o = "else";
   21.47 +            o.hashCode();
   21.48 +        }
   21.49 +        o = "finish";
   21.50 +    }
   21.51 +}
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/test/tools/javac/flow/tests/TestCaseSwitch.java	Sat Sep 14 19:04:47 2013 +0100
    22.3 @@ -0,0 +1,73 @@
    22.4 +/* /nodynamiccopyright/ */
    22.5 +
    22.6 +public class TestCaseSwitch {
    22.7 +
    22.8 +    @AliveRange(varName="o", bytecodeStart=31, bytecodeLength=16)
    22.9 +    @AliveRange(varName="o", bytecodeStart=50, bytecodeLength=15)
   22.10 +    @AliveRange(varName="o", bytecodeStart=68, bytecodeLength=1)
   22.11 +    @AliveRange(varName="oo", bytecodeStart=39, bytecodeLength=26)
   22.12 +    @AliveRange(varName="uu", bytecodeStart=59, bytecodeLength=6)
   22.13 +    void m1(String[] args) {
   22.14 +        Object o;
   22.15 +        switch (args.length) {
   22.16 +            case 0:
   22.17 +                    o = "0";
   22.18 +                    o.hashCode();
   22.19 +                    Object oo = "oo";
   22.20 +                    oo.hashCode();
   22.21 +                    break;
   22.22 +            case 1:
   22.23 +                    o = "1";
   22.24 +                    o.hashCode();
   22.25 +                    Object uu = "uu";
   22.26 +                    uu.hashCode();
   22.27 +                    break;
   22.28 +        }
   22.29 +        o = "return";
   22.30 +    }
   22.31 +
   22.32 +    @AliveRange(varName="o", bytecodeStart=95, bytecodeLength=18)
   22.33 +    @AliveRange(varName="o", bytecodeStart=116, bytecodeLength=15)
   22.34 +    @AliveRange(varName="o", bytecodeStart=134, bytecodeLength=1)
   22.35 +    @AliveRange(varName="oo", bytecodeStart=104, bytecodeLength=27)
   22.36 +    @AliveRange(varName="uu", bytecodeStart=125, bytecodeLength=6)
   22.37 +    void m2(String[] args) {
   22.38 +        Object o;
   22.39 +        switch (args[0]) {
   22.40 +            case "string0":
   22.41 +                    o = "0";
   22.42 +                    o.hashCode();
   22.43 +                    Object oo = "oo";
   22.44 +                    oo.hashCode();
   22.45 +                    break;
   22.46 +            case "string1":
   22.47 +                    o = "1";
   22.48 +                    o.hashCode();
   22.49 +                    Object uu = "uu";
   22.50 +                    uu.hashCode();
   22.51 +                    break;
   22.52 +        }
   22.53 +        o = "return";
   22.54 +    }
   22.55 +
   22.56 +    @AliveRange(varName="o", bytecodeStart=31, bytecodeLength=8)
   22.57 +    @AliveRange(varName="o", bytecodeStart=42, bytecodeLength=8)
   22.58 +    @AliveRange(varName="o", bytecodeStart=53, bytecodeLength=9)
   22.59 +    void m3(String[] args) {
   22.60 +        Object o;
   22.61 +        switch (args.length) {
   22.62 +            case 0:
   22.63 +                    o = "0";
   22.64 +                    o.hashCode();
   22.65 +                    break;
   22.66 +            case 1:
   22.67 +                    o = "1";
   22.68 +                    o.hashCode();
   22.69 +                    break;
   22.70 +            default:
   22.71 +                    o = "default";
   22.72 +                    o.hashCode();
   22.73 +        }
   22.74 +        o = "finish";
   22.75 +    }
   22.76 +}
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/test/tools/javac/flow/tests/TestCaseTry.java	Sat Sep 14 19:04:47 2013 +0100
    23.3 @@ -0,0 +1,76 @@
    23.4 +/* /nodynamiccopyright/ */
    23.5 +
    23.6 +import java.io.BufferedReader;
    23.7 +import java.io.FileReader;
    23.8 +
    23.9 +public class TestCaseTry {
   23.10 +
   23.11 +    @AliveRange(varName="o", bytecodeStart=3, bytecodeLength=8)
   23.12 +    @AliveRange(varName="o", bytecodeStart=15, bytecodeLength=1)
   23.13 +    void m0(String[] args) {
   23.14 +        Object o;
   23.15 +        try {
   23.16 +            o = "";
   23.17 +            o.hashCode();
   23.18 +        } catch (RuntimeException e) {}
   23.19 +        o = "";
   23.20 +    }
   23.21 +
   23.22 +    @AliveRange(varName="o", bytecodeStart=3, bytecodeLength=16)
   23.23 +    @AliveRange(varName="o", bytecodeStart=23, bytecodeLength=23)
   23.24 +    void m1() {
   23.25 +        Object o;
   23.26 +        try {
   23.27 +            o = "";
   23.28 +            o.hashCode();
   23.29 +        } catch (RuntimeException e) {
   23.30 +        }
   23.31 +        finally {
   23.32 +            o = "finally";
   23.33 +            o.hashCode();
   23.34 +        }
   23.35 +        o = "";
   23.36 +    }
   23.37 +
   23.38 +    @AliveRange(varName="o", bytecodeStart=3, bytecodeLength=16)
   23.39 +    @AliveRange(varName="o", bytecodeStart=23, bytecodeLength=31)
   23.40 +    void m2() {
   23.41 +        Object o;
   23.42 +        try {
   23.43 +            o = "";
   23.44 +            o.hashCode();
   23.45 +        } catch (RuntimeException e) {
   23.46 +            o = "catch";
   23.47 +            o.hashCode();
   23.48 +        }
   23.49 +        finally {
   23.50 +            o = "finally";
   23.51 +            o.hashCode();
   23.52 +        }
   23.53 +        o = "";
   23.54 +    }
   23.55 +
   23.56 +    @AliveRange(varName="o", bytecodeStart=22, bytecodeLength=38)
   23.57 +    @AliveRange(varName="o", bytecodeStart=103, bytecodeLength=8)
   23.58 +    void m3() {
   23.59 +        Object o;
   23.60 +        try (BufferedReader br =
   23.61 +                  new BufferedReader(new FileReader("aFile"))) {
   23.62 +            o = "inside try";
   23.63 +            o.hashCode();
   23.64 +        } catch (Exception e) {}
   23.65 +        o = "";
   23.66 +    }
   23.67 +
   23.68 +    @AliveRange(varName="o", bytecodeStart=12, bytecodeLength=96)
   23.69 +    @AliveRange(varName="o", bytecodeStart=112, bytecodeLength=1)
   23.70 +    void m4() {
   23.71 +        String o;
   23.72 +        try (BufferedReader br =
   23.73 +                  new BufferedReader(new FileReader(o = "aFile"))) {
   23.74 +            o = "inside try";
   23.75 +            o.hashCode();
   23.76 +        } catch (Exception e) {}
   23.77 +        o = "";
   23.78 +    }
   23.79 +}
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/test/tools/javac/flow/tests/TestCaseWhile.java	Sat Sep 14 19:04:47 2013 +0100
    24.3 @@ -0,0 +1,15 @@
    24.4 +/* /nodynamiccopyright/ */
    24.5 +
    24.6 +public class TestCaseWhile {
    24.7 +
    24.8 +    @AliveRange(varName="o", bytecodeStart=9, bytecodeLength=5)
    24.9 +    @AliveRange(varName="o", bytecodeStart=20, bytecodeLength=1)
   24.10 +    void m(String[] args) {
   24.11 +        Object o;
   24.12 +        while (args[0] != null) {
   24.13 +            o = "";
   24.14 +            o.hashCode();
   24.15 +        }
   24.16 +        o = "";
   24.17 +    }
   24.18 +}

mercurial