blob: 3b96a767f877f725178b40ea839b60c840fc433e [file] [log] [blame]
// Copyright (c) 2020, 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.horizontalclassmerging;
import com.android.tools.r8.utils.IterableUtils;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
/**
* This is a simple policy executor that ensures regular sequential execution of policies. It should
* primarily be readable and correct. The SimplePolicyExecutor should be a reference implementation,
* against which more efficient policy executors can be compared.
*/
public class SimplePolicyExecutor extends PolicyExecutor {
// TODO(b/165506334): if performing mutable operation ensure that linked lists are used
private LinkedList<MergeGroup> applySingleClassPolicy(
SingleClassPolicy policy, LinkedList<MergeGroup> groups) {
Iterator<MergeGroup> i = groups.iterator();
while (i.hasNext()) {
MergeGroup group = i.next();
int previousNumberOfClasses = group.size();
group.removeIf(clazz -> !policy.canMerge(clazz));
policy.numberOfRemovedClasses += previousNumberOfClasses - group.size();
if (group.size() < 2) {
i.remove();
}
}
return groups;
}
private LinkedList<MergeGroup> applyMultiClassPolicy(
MultiClassPolicy policy, LinkedList<MergeGroup> groups) {
// For each group apply the multi class policy and add all the new groups together.
LinkedList<MergeGroup> newGroups = new LinkedList<>();
groups.forEach(
group -> {
int previousNumberOfClasses = group.size();
Collection<MergeGroup> policyGroups = policy.apply(group);
policyGroups.forEach(newGroup -> newGroup.applyMetadataFrom(group));
policy.numberOfRemovedClasses +=
previousNumberOfClasses - IterableUtils.sumInt(policyGroups, MergeGroup::size);
newGroups.addAll(policyGroups);
});
return newGroups;
}
@Override
public Collection<MergeGroup> run(
Collection<MergeGroup> inputGroups, Collection<Policy> policies) {
LinkedList<MergeGroup> linkedGroups;
if (inputGroups instanceof LinkedList) {
linkedGroups = (LinkedList<MergeGroup>) inputGroups;
} else {
linkedGroups = new LinkedList<>(inputGroups);
}
for (Policy policy : policies) {
if (policy.shouldSkipPolicy()) {
continue;
}
if (policy instanceof SingleClassPolicy) {
linkedGroups = applySingleClassPolicy((SingleClassPolicy) policy, linkedGroups);
} else if (policy instanceof MultiClassPolicy) {
linkedGroups = applyMultiClassPolicy((MultiClassPolicy) policy, linkedGroups);
}
policy.clear();
if (linkedGroups.isEmpty()) {
break;
}
// Any policy should not return any trivial groups.
assert linkedGroups.stream().allMatch(group -> group.size() >= 2);
}
return linkedGroups;
}
}