Sat, 14 Sep 2013 19:04:47 +0100
7047734: javac, the LVT is not generated correctly in several scenarios
Reviewed-by: jjg, mcimadamore
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 +}