Add process and run to worklist
Change-Id: I7cca65fd683bf4dfd537d7188a171819270d15a0
diff --git a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
index 8bbfcfd..c42f8c6 100644
--- a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
+++ b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
@@ -139,24 +139,25 @@
if (!type.isClassType() || isJavaType(type)) {
return;
}
- WorkList<DexType> workList = WorkList.newIdentityWorkList(type, seenTypes);
- while (workList.hasNext()) {
- DexClass clazz = appView.definitionFor(workList.next());
- if (clazz == null || !clazz.isLibraryClass()) {
- continue;
- }
- ComputedApiLevel androidApiLevel =
- apiLevelCompute.computeApiLevelForLibraryReference(
- clazz.type, ComputedApiLevel.unknown());
- if (androidApiLevel.isGreaterThan(appView.computedMinApiLevel())
- && androidApiLevel.isKnownApiLevel()) {
- workList.addIfNotSeen(clazz.allImmediateSupertypes());
- libraryClassesToMock.add(clazz.asLibraryClass());
- referencingContexts
- .computeIfAbsent(clazz.asLibraryClass(), ignoreKey(Sets::newConcurrentHashSet))
- .add(context);
- }
- }
+ WorkList.newIdentityWorkList(type, seenTypes)
+ .process(
+ (classType, workList) -> {
+ DexClass clazz = appView.definitionFor(classType);
+ if (clazz == null || !clazz.isLibraryClass()) {
+ return;
+ }
+ ComputedApiLevel androidApiLevel =
+ apiLevelCompute.computeApiLevelForLibraryReference(
+ clazz.type, ComputedApiLevel.unknown());
+ if (androidApiLevel.isGreaterThan(appView.computedMinApiLevel())
+ && androidApiLevel.isKnownApiLevel()) {
+ workList.addIfNotSeen(clazz.allImmediateSupertypes());
+ libraryClassesToMock.add(clazz.asLibraryClass());
+ referencingContexts
+ .computeIfAbsent(clazz.asLibraryClass(), ignoreKey(Sets::newConcurrentHashSet))
+ .add(context);
+ }
+ });
}
private boolean isJavaType(DexType type) {
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignatureContextBuilder.java b/src/main/java/com/android/tools/r8/graph/GenericSignatureContextBuilder.java
index 3492c06..b761eb99b 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignatureContextBuilder.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignatureContextBuilder.java
@@ -182,20 +182,26 @@
public static GenericSignatureContextBuilder createForSingleClass(
AppView<?> appView, DexProgramClass clazz) {
- WorkList<DexProgramClass> workList = WorkList.newIdentityWorkList(clazz);
- while (workList.hasNext()) {
- DexProgramClass current = workList.next();
- DexClass outer = null;
- if (current.getEnclosingMethodAttribute() != null) {
- outer = appView.definitionFor(current.getEnclosingMethodAttribute().getEnclosingType());
- } else if (current.getInnerClassAttributeForThisClass() != null) {
- outer = appView.definitionFor(current.getInnerClassAttributeForThisClass().getOuter());
- }
- if (outer != null && outer.isProgramClass()) {
- workList.addIfNotSeen(outer.asProgramClass());
- }
- }
- return create(appView, workList.getSeenSet());
+ return create(
+ appView,
+ WorkList.newIdentityWorkList(clazz)
+ .process(
+ (current, workList) -> {
+ DexClass outer = null;
+ if (current.getEnclosingMethodAttribute() != null) {
+ outer =
+ appView.definitionFor(
+ current.getEnclosingMethodAttribute().getEnclosingType());
+ } else if (current.getInnerClassAttributeForThisClass() != null) {
+ outer =
+ appView.definitionFor(
+ current.getInnerClassAttributeForThisClass().getOuter());
+ }
+ if (outer != null && outer.isProgramClass()) {
+ workList.addIfNotSeen(outer.asProgramClass());
+ }
+ })
+ .getSeenSet());
}
public TypeParameterContext computeTypeParameterContext(
diff --git a/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java b/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java
index 1aa8117..98eab7f 100644
--- a/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java
+++ b/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java
@@ -217,26 +217,27 @@
}
}
- while (worklist.hasNext()) {
- DexClass clazz = worklist.next();
- if (clazz.isProgramClass()) {
- DexProgramClass programClass = clazz.asProgramClass();
- if (isInstantiatedDirectly(programClass)
- || isInterfaceWithUnknownSubtypeHierarchy(programClass)) {
- if (onClass.apply(programClass).shouldBreak()) {
- return TraversalContinuation.doBreak();
+ return worklist.run(
+ clazz -> {
+ if (clazz.isProgramClass()) {
+ DexProgramClass programClass = clazz.asProgramClass();
+ if (isInstantiatedDirectly(programClass)
+ || isInterfaceWithUnknownSubtypeHierarchy(programClass)) {
+ if (onClass.apply(programClass).shouldBreak()) {
+ return TraversalContinuation.doBreak();
+ }
+ }
}
- }
- }
- worklist.addIfNotSeen(instantiatedHierarchy.getOrDefault(clazz.type, Collections.emptySet()));
- for (LambdaDescriptor lambda :
- instantiatedLambdas.getOrDefault(clazz.type, Collections.emptyList())) {
- if (onLambda.apply(lambda).shouldBreak()) {
- return TraversalContinuation.doBreak();
- }
- }
- }
- return TraversalContinuation.doContinue();
+ worklist.addIfNotSeen(
+ instantiatedHierarchy.getOrDefault(clazz.type, Collections.emptySet()));
+ for (LambdaDescriptor lambda :
+ instantiatedLambdas.getOrDefault(clazz.type, Collections.emptyList())) {
+ if (onLambda.apply(lambda).shouldBreak()) {
+ return TraversalContinuation.doBreak();
+ }
+ }
+ return TraversalContinuation.doContinue();
+ });
}
public Set<DexType> getInstantiatedLambdaInterfaces() {
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoConstructorCollisions.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoConstructorCollisions.java
index e77b31a..6e94908 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoConstructorCollisions.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoConstructorCollisions.java
@@ -79,33 +79,33 @@
// Find the set of types that must not be merged, because they could lead to a constructor
// collision.
Set<DexType> collisionResolution = Sets.newIdentityHashSet();
- WorkList<DexProgramClass> workList = WorkList.newIdentityWorkList(appView.appInfo().classes());
- while (workList.hasNext()) {
- // Iterate over all the instance initializers of the current class. If the current class is in
- // a merge group, we must include all constructors of the entire merge group.
- DexProgramClass current = workList.next();
- Iterable<DexProgramClass> group =
- groupsByType.containsKey(current.getType())
- ? groupsByType.get(current.getType())
- : IterableUtils.singleton(current);
- Set<DexMethod> seen = Sets.newIdentityHashSet();
- for (DexProgramClass clazz : group) {
- for (DexEncodedMethod method :
- clazz.directMethods(DexEncodedMethod::isInstanceInitializer)) {
- // Rewrite the constructor reference using the current merge groups.
- DexMethod newReference = rewriteReference(method.getReference(), groupsByType);
- if (!seen.add(newReference)) {
- // Found a collision. Block all referenced types from being merged.
- for (DexType type : method.getProto().getBaseTypes(dexItemFactory)) {
- if (type.isClassType() && groupsByType.containsKey(type)) {
- collisionResolution.add(type);
+ // Iterate over all the instance initializers of the current class. If the current class is in
+ // a merge group, we must include all constructors of the entire merge group.
+ WorkList.newIdentityWorkList(appView.appInfo().classes())
+ .process(
+ (current, workList) -> {
+ Iterable<DexProgramClass> group =
+ groupsByType.containsKey(current.getType())
+ ? groupsByType.get(current.getType())
+ : IterableUtils.singleton(current);
+ Set<DexMethod> seen = Sets.newIdentityHashSet();
+ for (DexProgramClass clazz : group) {
+ for (DexEncodedMethod method :
+ clazz.directMethods(DexEncodedMethod::isInstanceInitializer)) {
+ // Rewrite the constructor reference using the current merge groups.
+ DexMethod newReference = rewriteReference(method.getReference(), groupsByType);
+ if (!seen.add(newReference)) {
+ // Found a collision. Block all referenced types from being merged.
+ for (DexType type : method.getProto().getBaseTypes(dexItemFactory)) {
+ if (type.isClassType() && groupsByType.containsKey(type)) {
+ collisionResolution.add(type);
+ }
+ }
+ }
+ }
}
- }
- }
- }
- }
- workList.markAsSeen(group);
- }
+ workList.markAsSeen(group);
+ });
return collisionResolution;
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/OnlyDirectlyConnectedOrUnrelatedInterfaces.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/OnlyDirectlyConnectedOrUnrelatedInterfaces.java
index fd24d1f..a64402a 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/OnlyDirectlyConnectedOrUnrelatedInterfaces.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/OnlyDirectlyConnectedOrUnrelatedInterfaces.java
@@ -133,21 +133,21 @@
WorkList<DexProgramClass> workList = WorkList.newWorkList(new LinkedHashSet<>());
// Intentionally not marking `clazz` as seen, since we only want the strict sub/super types.
workList.addIgnoringSeenSet(clazz);
- while (workList.hasNext()) {
- DexProgramClass interfaceDefinition = workList.next();
- MergeGroup group = committed.get(interfaceDefinition);
- if (group != null) {
- workList.addIfNotSeen(group);
- }
- for (DexType immediateSubOrSuperInterfaceType :
- immediateSubOrSuperInterfacesProvider.apply(interfaceDefinition)) {
- DexProgramClass immediateSubOrSuperInterface =
- asProgramClassOrNull(appView.definitionFor(immediateSubOrSuperInterfaceType));
- if (immediateSubOrSuperInterface != null) {
- workList.addIfNotSeen(immediateSubOrSuperInterface);
- }
- }
- }
+ workList.process(
+ interfaceDefinition -> {
+ MergeGroup group = committed.get(interfaceDefinition);
+ if (group != null) {
+ workList.addIfNotSeen(group);
+ }
+ for (DexType immediateSubOrSuperInterfaceType :
+ immediateSubOrSuperInterfacesProvider.apply(interfaceDefinition)) {
+ DexProgramClass immediateSubOrSuperInterface =
+ asProgramClassOrNull(appView.definitionFor(immediateSubOrSuperInterfaceType));
+ if (immediateSubOrSuperInterface != null) {
+ workList.addIfNotSeen(immediateSubOrSuperInterface);
+ }
+ }
+ });
assert !workList.isSeen(clazz);
return workList.getMutableSeenSet();
}
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
index 808913a..1a2d82b 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
@@ -258,20 +258,22 @@
if (originalClass.isLibraryClass()) {
return originalClass;
}
- WorkList<DexClass> workList = WorkList.newIdentityWorkList(originalClass);
- while (workList.hasNext()) {
- DexClass clazz = workList.next();
- if (clazz.isLibraryClass()) {
- return clazz;
- } else if (clazz.lookupMember(reference) != null) {
- return clazz;
- } else if (clazz.getSuperType() != null) {
- appInfo
- .contextIndependentDefinitionForWithResolutionResult(clazz.getSuperType())
- .forEachClassResolutionResult(workList::addIfNotSeen);
- }
- }
- return null;
+ return WorkList.newIdentityWorkList(originalClass)
+ .run(
+ (clazz, workList) -> {
+ if (clazz.isLibraryClass()) {
+ return TraversalContinuation.doBreak(clazz);
+ } else if (clazz.lookupMember(reference) != null) {
+ return TraversalContinuation.doBreak(clazz);
+ } else if (clazz.getSuperType() != null) {
+ appInfo
+ .contextIndependentDefinitionForWithResolutionResult(clazz.getSuperType())
+ .forEachClassResolutionResult(workList::addIfNotSeen);
+ }
+ return TraversalContinuation.doContinue();
+ })
+ .asBreakOrDefault(null)
+ .getValue();
}
private static Set<DexClass> findAllFirstLibraryInterfacesOrProgramClassWithDefinition(
diff --git a/src/main/java/com/android/tools/r8/utils/TraversalContinuation.java b/src/main/java/com/android/tools/r8/utils/TraversalContinuation.java
index c33d020..f2b96f3 100644
--- a/src/main/java/com/android/tools/r8/utils/TraversalContinuation.java
+++ b/src/main/java/com/android/tools/r8/utils/TraversalContinuation.java
@@ -18,6 +18,11 @@
return null;
}
+ public Break<TB, TC> asBreakOrDefault(TB defaultValue) {
+ Break<TB, TC> breakValue = asBreak();
+ return breakValue == null ? doBreak(defaultValue) : breakValue;
+ }
+
public boolean isContinue() {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/utils/WorkList.java b/src/main/java/com/android/tools/r8/utils/WorkList.java
index 79c2ed7..5aa700a 100644
--- a/src/main/java/com/android/tools/r8/utils/WorkList.java
+++ b/src/main/java/com/android/tools/r8/utils/WorkList.java
@@ -10,6 +10,10 @@
import java.util.Deque;
import java.util.HashSet;
import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
public class WorkList<T> {
@@ -100,6 +104,32 @@
return false;
}
+ public WorkList<T> process(Consumer<T> consumer) {
+ return process((item, ignored) -> consumer.accept(item));
+ }
+
+ public WorkList<T> process(BiConsumer<T, WorkList<T>> consumer) {
+ while (hasNext()) {
+ consumer.accept(next(), this);
+ }
+ return this;
+ }
+
+ public <TB, TC> TraversalContinuation<TB, TC> run(Function<T, TraversalContinuation<TB, TC>> fn) {
+ return run((item, ignored) -> fn.apply(item));
+ }
+
+ public <TB, TC> TraversalContinuation<TB, TC> run(
+ BiFunction<T, WorkList<T>, TraversalContinuation<TB, TC>> fn) {
+ while (hasNext()) {
+ TraversalContinuation<TB, TC> result = fn.apply(next(), this);
+ if (result.shouldBreak()) {
+ return result;
+ }
+ }
+ return TraversalContinuation.doContinue();
+ }
+
public void addFirstIgnoringSeenSet(T item) {
workingList.addFirst(item);
}