mirror of
https://github.com/openjdk/jdk.git
synced 2026-07-13 12:38:07 +00:00
8008562: javac, a refactoring to Bits is necessary in order to provide a change history
Reviewed-by: mcimadamore
This commit is contained in:
parent
625f8df5f5
commit
a20460d6cb
@ -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;
|
||||
|
||||
@ -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)) {
|
||||
|
||||
@ -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 {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user