8008562: javac, a refactoring to Bits is necessary in order to provide a change history

Reviewed-by: mcimadamore
This commit is contained in:
Vicente Romero 2013-04-26 10:17:01 +01:00
parent 625f8df5f5
commit a20460d6cb
3 changed files with 365 additions and 180 deletions

View File

@ -35,7 +35,6 @@ import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.comp.Resolve;
import com.sun.tools.javac.tree.JCTree.*;
import static com.sun.tools.javac.code.Flags.*;
@ -276,6 +275,15 @@ public class Flow {
allowEffectivelyFinalInInnerClasses = source.allowEffectivelyFinalInInnerClasses();
}
/**
* Utility method to reset several Bits instances.
*/
private void resetBits(Bits... bits) {
for (Bits b : bits) {
b.reset();
}
}
/**
* Base visitor class for all visitors implementing dataflow analysis logic.
* This class define the shared logic for handling jumps (break/continue statements).
@ -1294,11 +1302,11 @@ public class Flow {
/** The set of definitely assigned variables.
*/
Bits inits;
final Bits inits;
/** The set of definitely unassigned variables.
*/
Bits uninits;
final Bits uninits;
/** The set of variables that are definitely unassigned everywhere
* in current try block. This variable is maintained lazily; it is
@ -1308,15 +1316,15 @@ public class Flow {
* anywhere in current try block, intersect uninitsTry and
* uninits.
*/
Bits uninitsTry;
final Bits uninitsTry;
/** When analyzing a condition, inits and uninits are null.
* Instead we have:
*/
Bits initsWhenTrue;
Bits initsWhenFalse;
Bits uninitsWhenTrue;
Bits uninitsWhenFalse;
final Bits initsWhenTrue;
final Bits initsWhenFalse;
final Bits uninitsWhenTrue;
final Bits uninitsWhenFalse;
/** A mapping from addresses to variable symbols.
*/
@ -1348,15 +1356,25 @@ public class Flow {
/** The starting position of the analysed tree */
int startPos;
AssignAnalyzer() {
inits = new Bits();
uninits = new Bits();
uninitsTry = new Bits();
initsWhenTrue = new Bits(true);
initsWhenFalse = new Bits(true);
uninitsWhenTrue = new Bits(true);
uninitsWhenFalse = new Bits(true);
}
class AssignPendingExit extends BaseAnalyzer.PendingExit {
Bits exit_inits;
Bits exit_uninits;
final Bits exit_inits = new Bits(true);
final Bits exit_uninits = new Bits(true);
AssignPendingExit(JCTree tree, Bits inits, Bits uninits) {
AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
super(tree);
this.exit_inits = inits.dup();
this.exit_uninits = uninits.dup();
this.exit_inits.assign(inits);
this.exit_uninits.assign(uninits);
}
void resolveJump() {
@ -1476,19 +1494,20 @@ public class Flow {
/** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
*/
void split(boolean setToNull) {
initsWhenFalse = inits.dup();
uninitsWhenFalse = uninits.dup();
initsWhenTrue = inits;
uninitsWhenTrue = uninits;
if (setToNull)
inits = uninits = null;
initsWhenFalse.assign(inits);
uninitsWhenFalse.assign(uninits);
initsWhenTrue.assign(inits);
uninitsWhenTrue.assign(uninits);
if (setToNull) {
resetBits(inits, uninits);
}
}
/** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
*/
void merge() {
inits = initsWhenFalse.andSet(initsWhenTrue);
uninits = uninitsWhenFalse.andSet(uninitsWhenTrue);
inits.assign(initsWhenFalse.andSet(initsWhenTrue));
uninits.assign(uninitsWhenFalse.andSet(uninitsWhenTrue));
}
/* ************************************************************************
@ -1501,7 +1520,7 @@ public class Flow {
void scanExpr(JCTree tree) {
if (tree != null) {
scan(tree);
if (inits == null) merge();
if (inits.isReset()) merge();
}
}
@ -1518,28 +1537,29 @@ public class Flow {
*/
void scanCond(JCTree tree) {
if (tree.type.isFalse()) {
if (inits == null) merge();
initsWhenTrue = inits.dup();
if (inits.isReset()) merge();
initsWhenTrue.assign(inits);
initsWhenTrue.inclRange(firstadr, nextadr);
uninitsWhenTrue = uninits.dup();
uninitsWhenTrue.assign(uninits);
uninitsWhenTrue.inclRange(firstadr, nextadr);
initsWhenFalse = inits;
uninitsWhenFalse = uninits;
initsWhenFalse.assign(inits);
uninitsWhenFalse.assign(uninits);
} else if (tree.type.isTrue()) {
if (inits == null) merge();
initsWhenFalse = inits.dup();
if (inits.isReset()) merge();
initsWhenFalse.assign(inits);
initsWhenFalse.inclRange(firstadr, nextadr);
uninitsWhenFalse = uninits.dup();
uninitsWhenFalse.assign(uninits);
uninitsWhenFalse.inclRange(firstadr, nextadr);
initsWhenTrue = inits;
uninitsWhenTrue = uninits;
initsWhenTrue.assign(inits);
uninitsWhenTrue.assign(uninits);
} else {
scan(tree);
if (inits != null)
if (!inits.isReset())
split(tree.type != syms.unknownType);
}
if (tree.type != syms.unknownType)
inits = uninits = null;
if (tree.type != syms.unknownType) {
resetBits(inits, uninits);
}
}
/* ------------ Visitor methods for various sorts of trees -------------*/
@ -1619,8 +1639,8 @@ public class Flow {
public void visitMethodDef(JCMethodDecl tree) {
if (tree.body == null) return;
Bits initsPrev = inits.dup();
Bits uninitsPrev = uninits.dup();
final Bits initsPrev = new Bits(inits);
final Bits uninitsPrev = new Bits(uninits);
int nextadrPrev = nextadr;
int firstadrPrev = firstadr;
int returnadrPrev = returnadr;
@ -1658,14 +1678,14 @@ public class Flow {
exits = exits.tail;
Assert.check(exit.tree.hasTag(RETURN), exit.tree);
if (isInitialConstructor) {
inits = exit.exit_inits;
inits.assign(exit.exit_inits);
for (int i = firstadr; i < nextadr; i++)
checkInit(exit.tree.pos(), vars[i]);
}
}
} finally {
inits = initsPrev;
uninits = uninitsPrev;
inits.assign(initsPrev);
uninits.assign(uninitsPrev);
nextadr = nextadrPrev;
firstadr = firstadrPrev;
returnadr = returnadrPrev;
@ -1698,31 +1718,31 @@ public class Flow {
ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
FlowKind prevFlowKind = flowKind;
flowKind = FlowKind.NORMAL;
Bits initsSkip = null;
Bits uninitsSkip = null;
final Bits initsSkip = new Bits(true);
final Bits uninitsSkip = new Bits(true);
pendingExits = new ListBuffer<AssignPendingExit>();
int prevErrors = log.nerrors;
do {
Bits uninitsEntry = uninits.dup();
final Bits uninitsEntry = new Bits(uninits);
uninitsEntry.excludeFrom(nextadr);
scan(tree.body);
resolveContinues(tree);
scanCond(tree.cond);
if (!flowKind.isFinal()) {
initsSkip = initsWhenFalse;
uninitsSkip = uninitsWhenFalse;
initsSkip.assign(initsWhenFalse);
uninitsSkip.assign(uninitsWhenFalse);
}
if (log.nerrors != prevErrors ||
flowKind.isFinal() ||
uninitsEntry.dup().diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
break;
inits = initsWhenTrue;
uninits = uninitsEntry.andSet(uninitsWhenTrue);
inits.assign(initsWhenTrue);
uninits.assign(uninitsEntry.andSet(uninitsWhenTrue));
flowKind = FlowKind.SPECULATIVE_LOOP;
} while (true);
flowKind = prevFlowKind;
inits = initsSkip;
uninits = uninitsSkip;
inits.assign(initsSkip);
uninits.assign(uninitsSkip);
resolveBreaks(tree, prevPendingExits);
}
@ -1730,34 +1750,34 @@ public class Flow {
ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
FlowKind prevFlowKind = flowKind;
flowKind = FlowKind.NORMAL;
Bits initsSkip = null;
Bits uninitsSkip = null;
final Bits initsSkip = new Bits(true);
final Bits uninitsSkip = new Bits(true);
pendingExits = new ListBuffer<AssignPendingExit>();
int prevErrors = log.nerrors;
Bits uninitsEntry = uninits.dup();
final Bits uninitsEntry = new Bits(uninits);
uninitsEntry.excludeFrom(nextadr);
do {
scanCond(tree.cond);
if (!flowKind.isFinal()) {
initsSkip = initsWhenFalse;
uninitsSkip = uninitsWhenFalse;
initsSkip.assign(initsWhenFalse) ;
uninitsSkip.assign(uninitsWhenFalse);
}
inits = initsWhenTrue;
uninits = uninitsWhenTrue;
inits.assign(initsWhenTrue);
uninits.assign(uninitsWhenTrue);
scan(tree.body);
resolveContinues(tree);
if (log.nerrors != prevErrors ||
flowKind.isFinal() ||
uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
break;
uninits = uninitsEntry.andSet(uninits);
uninits.assign(uninitsEntry.andSet(uninits));
flowKind = FlowKind.SPECULATIVE_LOOP;
} while (true);
flowKind = prevFlowKind;
//a variable is DA/DU after the while statement, if it's DA/DU assuming the
//branch is not taken AND if it's DA/DU before any break statement
inits = initsSkip;
uninits = uninitsSkip;
inits.assign(initsSkip);
uninits.assign(uninitsSkip);
resolveBreaks(tree, prevPendingExits);
}
@ -1767,25 +1787,25 @@ public class Flow {
flowKind = FlowKind.NORMAL;
int nextadrPrev = nextadr;
scan(tree.init);
Bits initsSkip = null;
Bits uninitsSkip = null;
final Bits initsSkip = new Bits(true);
final Bits uninitsSkip = new Bits(true);
pendingExits = new ListBuffer<AssignPendingExit>();
int prevErrors = log.nerrors;
do {
Bits uninitsEntry = uninits.dup();
final Bits uninitsEntry = new Bits(uninits);
uninitsEntry.excludeFrom(nextadr);
if (tree.cond != null) {
scanCond(tree.cond);
if (!flowKind.isFinal()) {
initsSkip = initsWhenFalse;
uninitsSkip = uninitsWhenFalse;
initsSkip.assign(initsWhenFalse);
uninitsSkip.assign(uninitsWhenFalse);
}
inits = initsWhenTrue;
uninits = uninitsWhenTrue;
inits.assign(initsWhenTrue);
uninits.assign(uninitsWhenTrue);
} else if (!flowKind.isFinal()) {
initsSkip = inits.dup();
initsSkip.assign(inits);
initsSkip.inclRange(firstadr, nextadr);
uninitsSkip = uninits.dup();
uninitsSkip.assign(uninits);
uninitsSkip.inclRange(firstadr, nextadr);
}
scan(tree.body);
@ -1793,16 +1813,16 @@ public class Flow {
scan(tree.step);
if (log.nerrors != prevErrors ||
flowKind.isFinal() ||
uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
break;
uninits = uninitsEntry.andSet(uninits);
uninits.assign(uninitsEntry.andSet(uninits));
flowKind = FlowKind.SPECULATIVE_LOOP;
} while (true);
flowKind = prevFlowKind;
//a variable is DA/DU after a for loop, if it's DA/DU assuming the
//branch is not taken AND if it's DA/DU before any break statement
inits = initsSkip;
uninits = uninitsSkip;
inits.assign(initsSkip);
uninits.assign(uninitsSkip);
resolveBreaks(tree, prevPendingExits);
nextadr = nextadrPrev;
}
@ -1815,27 +1835,27 @@ public class Flow {
flowKind = FlowKind.NORMAL;
int nextadrPrev = nextadr;
scan(tree.expr);
Bits initsStart = inits.dup();
Bits uninitsStart = uninits.dup();
final Bits initsStart = new Bits(inits);
final Bits uninitsStart = new Bits(uninits);
letInit(tree.pos(), tree.var.sym);
pendingExits = new ListBuffer<AssignPendingExit>();
int prevErrors = log.nerrors;
do {
Bits uninitsEntry = uninits.dup();
final Bits uninitsEntry = new Bits(uninits);
uninitsEntry.excludeFrom(nextadr);
scan(tree.body);
resolveContinues(tree);
if (log.nerrors != prevErrors ||
flowKind.isFinal() ||
uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
break;
uninits = uninitsEntry.andSet(uninits);
uninits.assign(uninitsEntry.andSet(uninits));
flowKind = FlowKind.SPECULATIVE_LOOP;
} while (true);
flowKind = prevFlowKind;
inits = initsStart;
uninits = uninitsStart.andSet(uninits);
inits.assign(initsStart);
uninits.assign(uninitsStart.andSet(uninits));
resolveBreaks(tree, prevPendingExits);
nextadr = nextadrPrev;
}
@ -1852,12 +1872,12 @@ public class Flow {
pendingExits = new ListBuffer<AssignPendingExit>();
int nextadrPrev = nextadr;
scanExpr(tree.selector);
Bits initsSwitch = inits;
Bits uninitsSwitch = uninits.dup();
final Bits initsSwitch = new Bits(inits);
final Bits uninitsSwitch = new Bits(uninits);
boolean hasDefault = false;
for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
inits = initsSwitch.dup();
uninits = uninits.andSet(uninitsSwitch);
inits.assign(initsSwitch);
uninits.assign(uninits.andSet(uninitsSwitch));
JCCase c = l.head;
if (c.pat == null)
hasDefault = true;
@ -1875,8 +1895,8 @@ public class Flow {
}
// where
/** Add any variables defined in stats to inits and uninits. */
private void addVars(List<JCStatement> stats, Bits inits,
Bits uninits) {
private void addVars(List<JCStatement> stats, final Bits inits,
final Bits uninits) {
for (;stats.nonEmpty(); stats = stats.tail) {
JCTree stat = stats.head;
if (stat.hasTag(VARDEF)) {
@ -1889,11 +1909,11 @@ public class Flow {
public void visitTry(JCTry tree) {
ListBuffer<JCVariableDecl> resourceVarDecls = ListBuffer.lb();
Bits uninitsTryPrev = uninitsTry;
final Bits uninitsTryPrev = new Bits(uninitsTry);
ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
pendingExits = new ListBuffer<AssignPendingExit>();
Bits initsTry = inits.dup();
uninitsTry = uninits.dup();
final Bits initsTry = new Bits(inits);
uninitsTry.assign(uninits);
for (JCTree resource : tree.resources) {
if (resource instanceof JCVariableDecl) {
JCVariableDecl vdecl = (JCVariableDecl) resource;
@ -1908,8 +1928,8 @@ public class Flow {
}
scan(tree.body);
uninitsTry.andSet(uninits);
Bits initsEnd = inits;
Bits uninitsEnd = uninits;
final Bits initsEnd = new Bits(inits);
final Bits uninitsEnd = new Bits(uninits);
int nextadrCatch = nextadr;
if (!resourceVarDecls.isEmpty() &&
@ -1925,8 +1945,8 @@ public class Flow {
for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
JCVariableDecl param = l.head.param;
inits = initsTry.dup();
uninits = uninitsTry.dup();
inits.assign(initsTry);
uninits.assign(uninitsTry);
scan(param);
inits.incl(param.sym.adr);
uninits.excl(param.sym.adr);
@ -1936,8 +1956,8 @@ public class Flow {
nextadr = nextadrCatch;
}
if (tree.finalizer != null) {
inits = initsTry.dup();
uninits = uninitsTry.dup();
inits.assign(initsTry);
uninits.assign(uninitsTry);
ListBuffer<AssignPendingExit> exits = pendingExits;
pendingExits = prevPendingExits;
scan(tree.finalizer);
@ -1958,8 +1978,8 @@ public class Flow {
inits.orSet(initsEnd);
}
} else {
inits = initsEnd;
uninits = uninitsEnd;
inits.assign(initsEnd);
uninits.assign(uninitsEnd);
ListBuffer<AssignPendingExit> exits = pendingExits;
pendingExits = prevPendingExits;
while (exits.nonEmpty()) pendingExits.append(exits.next());
@ -1969,10 +1989,10 @@ public class Flow {
public void visitConditional(JCConditional tree) {
scanCond(tree.cond);
Bits initsBeforeElse = initsWhenFalse;
Bits uninitsBeforeElse = uninitsWhenFalse;
inits = initsWhenTrue;
uninits = uninitsWhenTrue;
final Bits initsBeforeElse = new Bits(initsWhenFalse);
final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
inits.assign(initsWhenTrue);
uninits.assign(uninitsWhenTrue);
if (tree.truepart.type.hasTag(BOOLEAN) &&
tree.falsepart.type.hasTag(BOOLEAN)) {
// if b and c are boolean valued, then
@ -1980,12 +2000,12 @@ public class Flow {
// v is (un)assigned after b when true and
// v is (un)assigned after c when true
scanCond(tree.truepart);
Bits initsAfterThenWhenTrue = initsWhenTrue.dup();
Bits initsAfterThenWhenFalse = initsWhenFalse.dup();
Bits uninitsAfterThenWhenTrue = uninitsWhenTrue.dup();
Bits uninitsAfterThenWhenFalse = uninitsWhenFalse.dup();
inits = initsBeforeElse;
uninits = uninitsBeforeElse;
final Bits initsAfterThenWhenTrue = new Bits(initsWhenTrue);
final Bits initsAfterThenWhenFalse = new Bits(initsWhenFalse);
final Bits uninitsAfterThenWhenTrue = new Bits(uninitsWhenTrue);
final Bits uninitsAfterThenWhenFalse = new Bits(uninitsWhenFalse);
inits.assign(initsBeforeElse);
uninits.assign(uninitsBeforeElse);
scanCond(tree.falsepart);
initsWhenTrue.andSet(initsAfterThenWhenTrue);
initsWhenFalse.andSet(initsAfterThenWhenFalse);
@ -1993,10 +2013,10 @@ public class Flow {
uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse);
} else {
scanExpr(tree.truepart);
Bits initsAfterThen = inits.dup();
Bits uninitsAfterThen = uninits.dup();
inits = initsBeforeElse;
uninits = uninitsBeforeElse;
final Bits initsAfterThen = new Bits(inits);
final Bits uninitsAfterThen = new Bits(uninits);
inits.assign(initsBeforeElse);
uninits.assign(uninitsBeforeElse);
scanExpr(tree.falsepart);
inits.andSet(initsAfterThen);
uninits.andSet(uninitsAfterThen);
@ -2005,16 +2025,16 @@ public class Flow {
public void visitIf(JCIf tree) {
scanCond(tree.cond);
Bits initsBeforeElse = initsWhenFalse;
Bits uninitsBeforeElse = uninitsWhenFalse;
inits = initsWhenTrue;
uninits = uninitsWhenTrue;
final Bits initsBeforeElse = new Bits(initsWhenFalse);
final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
inits.assign(initsWhenTrue);
uninits.assign(uninitsWhenTrue);
scan(tree.thenpart);
if (tree.elsepart != null) {
Bits initsAfterThen = inits.dup();
Bits uninitsAfterThen = uninits.dup();
inits = initsBeforeElse;
uninits = uninitsBeforeElse;
final Bits initsAfterThen = new Bits(inits);
final Bits uninitsAfterThen = new Bits(uninits);
inits.assign(initsBeforeElse);
uninits.assign(uninitsBeforeElse);
scan(tree.elsepart);
inits.andSet(initsAfterThen);
uninits.andSet(uninitsAfterThen);
@ -2055,8 +2075,8 @@ public class Flow {
@Override
public void visitLambda(JCLambda tree) {
Bits prevUninits = uninits;
Bits prevInits = inits;
final Bits prevUninits = new Bits(uninits);
final Bits prevInits = new Bits(inits);
int returnadrPrev = returnadr;
ListBuffer<AssignPendingExit> prevPending = pendingExits;
try {
@ -2076,8 +2096,8 @@ public class Flow {
}
finally {
returnadr = returnadrPrev;
uninits = prevUninits;
inits = prevInits;
uninits.assign(prevUninits);
inits.assign(prevInits);
pendingExits = prevPending;
}
}
@ -2088,17 +2108,17 @@ public class Flow {
}
public void visitAssert(JCAssert tree) {
Bits initsExit = inits.dup();
Bits uninitsExit = uninits.dup();
final Bits initsExit = new Bits(inits);
final Bits uninitsExit = new Bits(uninits);
scanCond(tree.cond);
uninitsExit.andSet(uninitsWhenTrue);
if (tree.detail != null) {
inits = initsWhenFalse;
uninits = uninitsWhenFalse;
inits.assign(initsWhenFalse);
uninits.assign(uninitsWhenFalse);
scanExpr(tree.detail);
}
inits = initsExit;
uninits = uninitsExit;
inits.assign(initsExit);
uninits.assign(uninitsExit);
}
public void visitAssign(JCAssign tree) {
@ -2120,12 +2140,12 @@ public class Flow {
switch (tree.getTag()) {
case NOT:
scanCond(tree.arg);
Bits t = initsWhenFalse;
initsWhenFalse = initsWhenTrue;
initsWhenTrue = t;
t = uninitsWhenFalse;
uninitsWhenFalse = uninitsWhenTrue;
uninitsWhenTrue = t;
final Bits t = new Bits(initsWhenFalse);
initsWhenFalse.assign(initsWhenTrue);
initsWhenTrue.assign(t);
t.assign(uninitsWhenFalse);
uninitsWhenFalse.assign(uninitsWhenTrue);
uninitsWhenTrue.assign(t);
break;
case PREINC: case POSTINC:
case PREDEC: case POSTDEC:
@ -2141,20 +2161,20 @@ public class Flow {
switch (tree.getTag()) {
case AND:
scanCond(tree.lhs);
Bits initsWhenFalseLeft = initsWhenFalse;
Bits uninitsWhenFalseLeft = uninitsWhenFalse;
inits = initsWhenTrue;
uninits = uninitsWhenTrue;
final Bits initsWhenFalseLeft = new Bits(initsWhenFalse);
final Bits uninitsWhenFalseLeft = new Bits(uninitsWhenFalse);
inits.assign(initsWhenTrue);
uninits.assign(uninitsWhenTrue);
scanCond(tree.rhs);
initsWhenFalse.andSet(initsWhenFalseLeft);
uninitsWhenFalse.andSet(uninitsWhenFalseLeft);
break;
case OR:
scanCond(tree.lhs);
Bits initsWhenTrueLeft = initsWhenTrue;
Bits uninitsWhenTrueLeft = uninitsWhenTrue;
inits = initsWhenFalse;
uninits = uninitsWhenFalse;
final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
inits.assign(initsWhenFalse);
uninits.assign(uninitsWhenFalse);
scanCond(tree.rhs);
initsWhenTrue.andSet(initsWhenTrueLeft);
uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
@ -2200,11 +2220,7 @@ public class Flow {
attrEnv = env;
Flow.this.make = make;
startPos = tree.pos().getStartPosition();
inits = new Bits();
uninits = new Bits();
uninitsTry = new Bits();
initsWhenTrue = initsWhenFalse =
uninitsWhenTrue = uninitsWhenFalse = null;
if (vars == null)
vars = new VarSymbol[32];
else
@ -2219,9 +2235,8 @@ public class Flow {
} finally {
// note that recursive invocations of this method fail hard
startPos = -1;
inits = uninits = uninitsTry = null;
initsWhenTrue = initsWhenFalse =
uninitsWhenTrue = uninitsWhenFalse = null;
resetBits(inits, uninits, uninitsTry, initsWhenTrue,
initsWhenFalse, uninitsWhenTrue, uninitsWhenFalse);
if (vars != null) for (int i=0; i<vars.length; i++)
vars[i] = null;
firstadr = 0;

View File

@ -1647,7 +1647,7 @@ public class Code {
State dup() {
try {
State state = (State)super.clone();
state.defined = defined.dup();
state.defined = new Bits(defined);
state.stack = stack.clone();
if (locks != null) state.locks = locks.clone();
if (debugCode) {
@ -1775,7 +1775,7 @@ public class Code {
}
State join(State other) {
defined = defined.andSet(other.defined);
defined.andSet(other.defined);
Assert.check(stacksize == other.stacksize
&& nlocks == other.nlocks);
for (int i=0; i<stacksize; ) {
@ -1887,7 +1887,7 @@ public class Code {
/** Set the current variable defined state. */
public void setDefined(Bits newDefined) {
if (alive && newDefined != state.defined) {
Bits diff = state.defined.dup().xorSet(newDefined);
Bits diff = new Bits(state.defined).xorSet(newDefined);
for (int adr = diff.nextBit(0);
adr >= 0;
adr = diff.nextBit(adr+1)) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,6 +27,8 @@ package com.sun.tools.javac.util;
import java.util.Arrays;
import static com.sun.tools.javac.util.Bits.BitsOpKind.*;
/** A class for extensible, mutable bit sets.
*
* <p><b>This is NOT part of any supported API.
@ -36,31 +38,114 @@ import java.util.Arrays;
*/
public class Bits {
public enum BitsOpKind {
INIT,
CLEAR,
INCL_BIT,
EXCL_BIT,
ASSIGN,
AND_SET,
OR_SET,
DIFF_SET,
XOR_SET,
INCL_RANGE,
EXCL_RANGE,
}
// ____________ reset _________
// / UNKNOWN \ <-------- / UNINIT \
// \____________/ | \_________/
// | | |
// |assign | | any
// | ___________ |
// ------> / NORMAL \ <----
// \___________/ |
// | |
// | |
// -----------
// any
private enum BitsState {
/* A Bits instance is in UNKNOWN state if it has been explicitly reset.
* It is possible to get to this state from any other by calling the
* reset method. An instance in the UNKNOWN state can pass to the
* NORMAL state after being assigned another Bits instance.
*/
UNKNOWN,
/* A Bits instance is in UNINIT when it is created with the default
* constructor but it isn't explicitly reset. The main objective of this
* internal state is to save some memory.
*/
UNINIT,
/* The normal state is reached after creating a Bits instance from an
* existing one or after applying any operation to an instance on UNINIT
* or NORMAL state. From this state a bits instance can pass to the
* UNKNOWN state by calling the reset method.
*/
NORMAL;
static BitsState getState(int[] someBits, boolean reset) {
if (reset) {
return UNKNOWN;
} else {
if (someBits != unassignedBits) {
return NORMAL;
} else {
return UNINIT;
}
}
}
}
private final static int wordlen = 32;
private final static int wordshift = 5;
private final static int wordmask = wordlen - 1;
private int[] bits;
public int[] bits = null;
// This field will store last version of bits after every change.
public int[] oldBits = null;
public BitsOpKind lastOperation = null;
private static final int[] unassignedBits = new int[0];
private BitsState currentState;
/** Construct an initially empty set.
*/
public Bits() {
this(new int[1]);
this(false);
}
public Bits(Bits someBits) {
this(someBits.dup().bits, BitsState.getState(someBits.bits, false));
}
public Bits(boolean reset) {
this(unassignedBits, BitsState.getState(unassignedBits, reset));
}
/** Construct a set consisting initially of given bit vector.
*/
public Bits(int[] bits) {
private Bits(int[] bits, BitsState initState) {
this.bits = bits;
this.currentState = initState;
switch (initState) {
case UNKNOWN:
reset(); //this will also set current state;
break;
case NORMAL:
Assert.check(bits != unassignedBits);
lastOperation = INIT;
break;
}
}
/** Construct a set consisting initially of given range.
/** This method will be called after any operation that causes a change to
* the bits. Subclasses can thus override it in order to extract information
* from the changes produced to the bits by the given operation.
*/
public Bits(int start, int limit) {
this();
inclRange(start, limit);
}
public void changed() {}
private void sizeTo(int len) {
if (bits.length < len) {
@ -71,57 +156,110 @@ public class Bits {
/** This set = {}.
*/
public void clear() {
Assert.check(currentState != BitsState.UNKNOWN);
oldBits = bits;
lastOperation = CLEAR;
for (int i = 0; i < bits.length; i++) bits[i] = 0;
changed();
currentState = BitsState.NORMAL;
}
public void reset() {
bits = null;
oldBits = null;
currentState = BitsState.UNKNOWN;
}
public boolean isReset() {
return currentState == BitsState.UNKNOWN;
}
public Bits assign(Bits someBits) {
lastOperation = ASSIGN;
oldBits = bits;
bits = someBits.dup().bits;
changed();
currentState = BitsState.NORMAL;
return this;
}
/** Return a copy of this set.
*/
public Bits dup() {
int[] newbits = new int[bits.length];
System.arraycopy(bits, 0, newbits, 0, bits.length);
return new Bits(newbits);
private Bits dup() {
Assert.check(currentState != BitsState.UNKNOWN);
Bits tmp = new Bits();
if (currentState != BitsState.NORMAL) {
tmp.bits = bits;
} else {
tmp.bits = new int[bits.length];
System.arraycopy(bits, 0, tmp.bits, 0, bits.length);
}
currentState = BitsState.NORMAL;
return tmp;
}
/** Include x in this set.
*/
public void incl(int x) {
Assert.check(currentState != BitsState.UNKNOWN);
Assert.check(x >= 0);
oldBits = bits;
lastOperation = INCL_BIT;
sizeTo((x >>> wordshift) + 1);
bits[x >>> wordshift] = bits[x >>> wordshift] |
(1 << (x & wordmask));
changed();
currentState = BitsState.NORMAL;
}
/** Include [start..limit) in this set.
*/
public void inclRange(int start, int limit) {
Assert.check(currentState != BitsState.UNKNOWN);
oldBits = bits;
lastOperation = INCL_RANGE;
sizeTo((limit >>> wordshift) + 1);
for (int x = start; x < limit; x++)
for (int x = start; x < limit; x++) {
bits[x >>> wordshift] = bits[x >>> wordshift] |
(1 << (x & wordmask));
}
changed();
currentState = BitsState.NORMAL;
}
/** Exclude [start...end] from this set.
*/
public void excludeFrom(int start) {
Assert.check(currentState != BitsState.UNKNOWN);
oldBits = bits;
lastOperation = EXCL_RANGE;
Bits temp = new Bits();
temp.sizeTo(bits.length);
temp.inclRange(0, start);
andSet(temp);
internalAndSet(temp);
changed();
currentState = BitsState.NORMAL;
}
/** Exclude x from this set.
*/
public void excl(int x) {
Assert.check(currentState != BitsState.UNKNOWN);
Assert.check(x >= 0);
oldBits = bits;
lastOperation = EXCL_BIT;
sizeTo((x >>> wordshift) + 1);
bits[x >>> wordshift] = bits[x >>> wordshift] &
~(1 << (x & wordmask));
changed();
currentState = BitsState.NORMAL;
}
/** Is x an element of this set?
*/
public boolean isMember(int x) {
Assert.check(currentState != BitsState.UNKNOWN);
return
0 <= x && x < (bits.length << wordshift) &&
(bits[x >>> wordshift] & (1 << (x & wordmask))) != 0;
@ -130,38 +268,66 @@ public class Bits {
/** {@literal this set = this set & xs}.
*/
public Bits andSet(Bits xs) {
sizeTo(xs.bits.length);
for (int i = 0; i < xs.bits.length; i++)
bits[i] = bits[i] & xs.bits[i];
Assert.check(currentState != BitsState.UNKNOWN);
oldBits = bits;
lastOperation = AND_SET;
internalAndSet(xs);
changed();
currentState = BitsState.NORMAL;
return this;
}
private void internalAndSet(Bits xs) {
Assert.check(currentState != BitsState.UNKNOWN);
sizeTo(xs.bits.length);
for (int i = 0; i < xs.bits.length; i++) {
bits[i] = bits[i] & xs.bits[i];
}
}
/** this set = this set | xs.
*/
public Bits orSet(Bits xs) {
Assert.check(currentState != BitsState.UNKNOWN);
oldBits = bits;
lastOperation = OR_SET;
sizeTo(xs.bits.length);
for (int i = 0; i < xs.bits.length; i++)
for (int i = 0; i < xs.bits.length; i++) {
bits[i] = bits[i] | xs.bits[i];
}
changed();
currentState = BitsState.NORMAL;
return this;
}
/** this set = this set \ xs.
*/
public Bits diffSet(Bits xs) {
Assert.check(currentState != BitsState.UNKNOWN);
oldBits = bits;
lastOperation = DIFF_SET;
for (int i = 0; i < bits.length; i++) {
if (i < xs.bits.length) {
bits[i] = bits[i] & ~xs.bits[i];
}
}
changed();
currentState = BitsState.NORMAL;
return this;
}
/** this set = this set ^ xs.
*/
public Bits xorSet(Bits xs) {
Assert.check(currentState != BitsState.UNKNOWN);
oldBits = bits;
lastOperation = XOR_SET;
sizeTo(xs.bits.length);
for (int i = 0; i < xs.bits.length; i++)
for (int i = 0; i < xs.bits.length; i++) {
bits[i] = bits[i] ^ xs.bits[i];
}
changed();
currentState = BitsState.NORMAL;
return this;
}
@ -187,6 +353,7 @@ public class Bits {
* }</pre>
*/
public int nextBit(int x) {
Assert.check(currentState != BitsState.UNKNOWN);
int windex = x >>> wordshift;
if (windex >= bits.length) return -1;
int word = bits[windex] & ~((1 << (x & wordmask))-1);
@ -202,17 +369,20 @@ public class Bits {
/** a string representation of this set.
*/
public String toString() {
char[] digits = new char[bits.length * wordlen];
for (int i = 0; i < bits.length * wordlen; i++)
digits[i] = isMember(i) ? '1' : '0';
return new String(digits);
if (bits.length > 0) {
char[] digits = new char[bits.length * wordlen];
for (int i = 0; i < bits.length * wordlen; i++)
digits[i] = isMember(i) ? '1' : '0';
return new String(digits);
} else {
return "[]";
}
}
/** Test Bits.nextBit(int). */
public static void main(String[] args) {
java.util.Random r = new java.util.Random();
Bits bits = new Bits();
int dupCount = 0;
for (int i=0; i<125; i++) {
int k;
do {