Skip to content

Commit

Permalink
Lazily remove invalid typesflows from analysis.
Browse files Browse the repository at this point in the history
  • Loading branch information
teshull committed Aug 9, 2023
1 parent d7db489 commit 337d381
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,9 @@ public void run(DebugContext ignored) {
PointsToStats.registerTypeFlowQueuedUpdate(PointsToAnalysis.this, operation);

operation.inQueue = false;
operation.update(PointsToAnalysis.this);
if (operation.isValid()) {
operation.update(PointsToAnalysis.this);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,15 @@ public String toString() {
*/
final void removeInternalFlows(PointsToAnalysis bb) {

// Invalidate internal flows which will be cleared
flowsIterator().forEachRemaining(typeFlow -> {
// param and return flows will not be cleared
boolean skipInvalidate = typeFlow instanceof FormalParamTypeFlow || typeFlow instanceof FormalReturnTypeFlow;
if (!skipInvalidate) {
typeFlow.invalidate();
}
});

// Clear out the parameter uses and observers
for (var param : getParameters()) {
if (param != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,14 @@ public abstract class TypeFlow<T> {
*/
private volatile boolean isSaturated;

/**
* A TypeFlow is invalidated when the flowsgraph it belongs to is updated due to
* {@link MethodTypeFlow#updateFlowsGraph}. Once a flow is invalided it no longer needs to be
* updated and its links can be removed. Note delaying the removal of invalid flows does not
* affect correctness, so they can be removed lazily.
*/
private boolean isValid = true;

@SuppressWarnings("rawtypes")//
private static final AtomicReferenceFieldUpdater<TypeFlow, TypeState> STATE_UPDATER = AtomicReferenceFieldUpdater.newUpdater(TypeFlow.class, TypeState.class, "state");

Expand Down Expand Up @@ -258,6 +266,20 @@ public int getSlot() {
return this.slot;
}

/**
* Return true is the flow is valid and should be updated.
*/
public boolean isValid() {
return isValid;
}

/**
* Invalidating the typeflow will cause the flow to be lazily removed in the future.
*/
public void invalidate() {
isValid = false;
}

/**
* Return true if this flow is saturated. When an observer becomes saturated it doesn't
* immediately remove itself from all its inputs. The inputs lazily remove it on next update.
Expand Down Expand Up @@ -392,6 +414,9 @@ protected boolean doAddUse(PointsToAnalysis bb, TypeFlow<?> use) {
if (use.equals(this)) {
return false;
}
if (!use.isValid()) {
return false;
}
/* Input is always tracked. */
registerInput(bb, use);
if (use.isSaturated()) {
Expand Down Expand Up @@ -473,6 +498,10 @@ private boolean doAddObserver(PointsToAnalysis bb, TypeFlow<?> observer) {
if (observer.equals(this)) {
return false;
}
if (!observer.isValid()) {
return false;
}

registerObservee(bb, observer);
return ConcurrentLightHashSet.addElement(this, OBSERVERS_UPDATER, observer);
}
Expand Down Expand Up @@ -579,15 +608,19 @@ public static AnalysisType filterUncheckedInterface(AnalysisType type) {
public void update(PointsToAnalysis bb) {
TypeState curState = getState();
for (TypeFlow<?> use : getUses()) {
if (use.isSaturated()) {
if (!use.isValid() || use.isSaturated()) {
removeUse(use);
} else {
use.addState(bb, curState);
}
}

for (TypeFlow<?> observer : getObservers()) {
observer.onObservedUpdate(bb);
if (observer.isValid()) {
observer.onObservedUpdate(bb);
} else {
removeObserver(observer);
}
}
}

Expand Down

0 comments on commit 337d381

Please sign in to comment.