immutable DfaVariableState, for faster copying and less memory usage

This commit is contained in:
peter
2013-09-23 16:30:25 +02:00
parent 666ed529c0
commit e8dbc2135e
7 changed files with 147 additions and 111 deletions
@@ -45,12 +45,14 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
private final Stack<DfaValue> myStack = new Stack<DfaValue>();
private TIntStack myOffsetStack = new TIntStack(1);
private final TLongHashSet myDistinctClasses = new TLongHashSet();
private final THashMap<DfaVariableValue,DfaVariableState> myVariableStates = new THashMap<DfaVariableValue, DfaVariableState>();
private final THashMap<DfaVariableValue,DfaVariableState> myVariableStates = ContainerUtil.newTroveMap();
private THashMap<DfaVariableValue,DfaVariableState> myDefaultVariableStates; // shared between all states
private final THashSet<DfaVariableValue> myUnknownVariables = new THashSet<DfaVariableValue>();
private boolean myEphemeral;
public DfaMemoryStateImpl(final DfaValueFactory factory) {
myFactory = factory;
myDefaultVariableStates = ContainerUtil.newTroveMap();
}
public DfaValueFactory getFactory() {
@@ -65,6 +67,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
public DfaMemoryStateImpl createCopy() {
DfaMemoryStateImpl newState = createNew();
newState.myDefaultVariableStates = myDefaultVariableStates;
newState.myEphemeral = myEphemeral;
newState.myStack.addAll(myStack);
newState.myDistinctClasses.addAll(myDistinctClasses.toArray());
@@ -76,9 +79,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
newState.myEqClasses.add(aClass != null ? new EqClass(aClass) : null);
}
for (DfaVariableValue dfaVariableValue : myVariableStates.keySet()) {
newState.myVariableStates.put(dfaVariableValue, myVariableStates.get(dfaVariableValue).clone());
}
newState.myVariableStates.putAll(myVariableStates);
return newState;
}
@@ -98,19 +99,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
if (myDistinctClasses.size() != that.myDistinctClasses.size()) return false;
if (!getNonTrivialEqClasses().equals(that.getNonTrivialEqClasses())) return false;
if (!getDistinctClassPairs().equals(that.getDistinctClassPairs())) return false;
for (DfaVariableValue var : myVariableStates.keySet()) {
DfaVariableState thatState = that.myVariableStates.get(var);
if (!myVariableStates.get(var).equals(thatState != null ? thatState : createVariableState(var))) {
return false;
}
}
for (DfaVariableValue var : that.myVariableStates.keySet()) {
if (!myVariableStates.containsKey(var) && !that.myVariableStates.get(var).equals(createVariableState(var))) {
return false;
}
}
if (!myVariableStates.equals(that.myVariableStates)) return false;
return true;
}
@@ -142,7 +131,11 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
}
public int hashCode() {
return ((getNonTrivialEqClasses().hashCode() * 31 + getDistinctClassPairs().hashCode()) * 31 + myStack.hashCode()) * 31 + myUnknownVariables.hashCode();
return (((getNonTrivialEqClasses().hashCode() * 31 +
getDistinctClassPairs().hashCode()) * 31 +
myStack.hashCode()) * 31 +
myUnknownVariables.hashCode()) * 31 +
myVariableStates.hashCode();
}
@SuppressWarnings({"HardCodedStringLiteral"})
@@ -218,15 +211,14 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
if (var == value) return;
flushVariable(var);
DfaVariableState varState = getVariableState(var);
if (value instanceof DfaUnknownValue) {
varState.setNullable(false);
setVariableState(var, getVariableState(var).withNullable(false));
return;
}
varState.setValue(value);
setVariableState(var, getVariableState(var).withValue(value));
if (value instanceof DfaTypeValue) {
varState.setNullable(((DfaTypeValue)value).isNullable());
setVariableState(var, getVariableState(var).withNullable(((DfaTypeValue)value).isNullable()));
DfaRelationValue dfaInstanceof = myFactory.getRelationFactory().createRelation(var, value, JavaTokenType.INSTANCEOF_KEYWORD, false);
if (((DfaTypeValue)value).isNotNull()) {
applyCondition(dfaInstanceof);
@@ -240,15 +232,15 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
applyCondition(dfaEqual);
if (value instanceof DfaVariableValue) {
myVariableStates.put(var, varState = getVariableState((DfaVariableValue)value).clone());
setVariableState(var, getVariableState((DfaVariableValue)value));
}
else if (value instanceof DfaBoxedValue) {
varState.setNullable(false);
setVariableState(var, getVariableState(var).withNullable(false));
applyCondition(compareToNull(var, true));
}
}
if (varState.isNotNull()) {
if (getVariableState(var).isNotNull()) {
applyCondition(compareToNull(var, true));
}
}
@@ -448,7 +440,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
public boolean isNull(DfaValue dfaValue) {
if (dfaValue instanceof DfaTypeValue && ((DfaTypeValue)dfaValue).isNotNull()) return false;
if (dfaValue instanceof DfaConstValue) return ((DfaConstValue)dfaValue).getConstant() == null;
if (dfaValue instanceof DfaConstValue) return ((DfaConstValue)dfaValue).getValue() == null;
if (dfaValue instanceof DfaVariableValue) {
int c1Index = getEqClassIndex(dfaValue);
@@ -509,7 +501,13 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
DfaVariableValue dfaVar = (DfaVariableValue)left;
DfaTypeValue dfaType = (DfaTypeValue)dfaCond.getRightOperand();
return isNull(dfaVar) || getVariableState(dfaVar).setInstanceofValue(dfaType);
if (isUnknownState(dfaVar) || isNull(dfaVar)) return true;
DfaVariableState newState = getVariableState(dfaVar).withInstanceofValue(dfaType);
if (newState != null) {
setVariableState(dfaVar, newState);
return true;
}
return false;
}
static DfaValue unwrap(DfaValue value) {
@@ -561,12 +559,25 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
if (dfaRight instanceof DfaTypeValue) {
if (dfaLeft instanceof DfaVariableValue) {
DfaVariableState varState = getVariableState((DfaVariableValue)dfaLeft);
DfaVariableValue dfaVar = (DfaVariableValue)dfaLeft;
if (isUnknownState(dfaVar)) return true;
if (isNegated) {
return varState.addNotInstanceofValue((DfaTypeValue)dfaRight) || applyCondition(compareToNull(dfaVar, false));
DfaVariableState newState = getVariableState(dfaVar).withNotInstanceofValue((DfaTypeValue)dfaRight);
if (newState != null) {
setVariableState(dfaVar, newState);
return true;
}
return applyCondition(compareToNull(dfaVar, false));
}
return applyCondition(compareToNull(dfaVar, true)) && varState.setInstanceofValue((DfaTypeValue)dfaRight);
if (applyCondition(compareToNull(dfaVar, true))) {
DfaVariableState newState = getVariableState(dfaVar).withInstanceofValue((DfaTypeValue)dfaRight);
if (newState != null) {
setVariableState(dfaVar, newState);
return true;
}
}
return false;
}
return true;
}
@@ -593,7 +604,9 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
if (isNotNull(dfaVar)) {
return true;
}
getVariableState(dfaVar).setNullable(true);
if (!isUnknownState(dfaVar)) {
setVariableState(dfaVar, getVariableState(dfaVar).withNullability(Nullness.NULLABLE));
}
}
return false;
}
@@ -734,17 +747,33 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
return myFactory.getRelationFactory().createRelation(dfaVar, dfaNull, JavaTokenType.EQEQ, negated);
}
void setVariableState(DfaVariableValue dfaVar, DfaVariableState state) {
assert !myUnknownVariables.contains(dfaVar);
if (state.equals(myDefaultVariableStates.get(dfaVar))) {
myVariableStates.remove(dfaVar);
} else {
myVariableStates.put(dfaVar, state);
}
}
public DfaVariableState getVariableState(DfaVariableValue dfaVar) {
DfaVariableState state = myVariableStates.get(dfaVar);
if (state == null) {
state = createVariableState(dfaVar);
state = myDefaultVariableStates.get(dfaVar);
if (state == null) {
state = createVariableState(dfaVar);
DfaTypeValue initialType = dfaVar.getTypeValue();
if (initialType != null) {
state = state.withInstanceofValue(initialType);
assert state != null;
}
myDefaultVariableStates.put(dfaVar, state);
}
if (isUnknownState(dfaVar)) {
state.setNullable(false);
return state;
return state.withNullable(false);
}
myVariableStates.put(dfaVar, state);
}
return state;
@@ -760,16 +789,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
@Override
public void flushFields(DfaVariableValue[] fields) {
Set<DfaVariableValue> allVars = new HashSet<DfaVariableValue>(myVariableStates.keySet());
Collections.addAll(allVars, fields);
Set<DfaVariableValue> dependencies = new HashSet<DfaVariableValue>();
for (DfaVariableValue variableValue : allVars) {
dependencies.addAll(myFactory.getVarFactory().getAllQualifiedBy(variableValue));
}
allVars.addAll(dependencies);
for (DfaVariableValue value : allVars) {
for (DfaVariableValue value : myFactory.getVarFactory().getAllVariables()) {
if (myVariableStates.containsKey(value) || getEqClassIndex(value) >= 0) {
if (value.isFlushableByCalls()) {
doFlush(value, true);