blob: 8ca2654cd2e390e3dbffd5e0695a23e556c1f912 [file] [log] [blame]
// Copyright (c) 2024, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking.rules;
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.shaking.Enqueuer;
import com.android.tools.r8.shaking.MinimumKeepInfoCollection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
public abstract class PendingConditionalRuleBase<T> {
private List<T> outstandingPreconditions;
private final List<T> satisfiedPreconditions;
private final MinimumKeepInfoCollection consequences;
PendingConditionalRuleBase(List<T> preconditions, MinimumKeepInfoCollection consequences) {
this.outstandingPreconditions = preconditions;
this.satisfiedPreconditions = new ArrayList<>(preconditions.size());
this.consequences = consequences;
}
public List<T> getSatisfiedPreconditions() {
return satisfiedPreconditions;
}
abstract List<DexReference> getReferences(List<T> items);
abstract boolean isSatisfied(T item, Enqueuer enqueuer);
MinimumKeepInfoCollection getConsequences() {
return consequences;
}
MaterializedConditionalRule asMaterialized() {
assert !isOutstanding();
return new MaterializedConditionalRule(getReferences(satisfiedPreconditions), consequences);
}
final boolean isOutstanding() {
return !outstandingPreconditions.isEmpty();
}
final boolean isSatisfiedAfterUpdate(Enqueuer enqueuer) {
assert isOutstanding();
int newlySatisfied = 0;
for (T precondition : outstandingPreconditions) {
if (isSatisfied(precondition, enqueuer)) {
++newlySatisfied;
satisfiedPreconditions.add(precondition);
}
}
// Not satisfied and nothing changed.
if (newlySatisfied == 0) {
return false;
}
// The rule is satisfied in full.
if (newlySatisfied == outstandingPreconditions.size()) {
outstandingPreconditions = Collections.emptyList();
return true;
}
// Partially satisfied.
// This is expected to be the uncommon case so the update to outstanding is delayed to here.
int newOutstandingSize = outstandingPreconditions.size() - newlySatisfied;
assert newOutstandingSize > 0;
List<DexReference> satisfied = getReferences(satisfiedPreconditions);
List<DexReference> outstanding = getReferences(outstandingPreconditions);
List<T> newOutstanding = new ArrayList<>();
Iterator<T> it = outstandingPreconditions.iterator();
for (DexReference reference : outstanding) {
T precondition = it.next();
if (!satisfied.contains(reference)) {
newOutstanding.add(precondition);
}
}
assert !it.hasNext();
assert newOutstanding.size() == newOutstandingSize;
outstandingPreconditions = newOutstanding;
assert isOutstanding();
return false;
}
}