| // Copyright (c) 2023, 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.verticalclassmerging; |
| |
| import com.android.tools.r8.classmerging.Policy; |
| import com.android.tools.r8.classmerging.PolicyExecutor; |
| import com.android.tools.r8.graph.AppView; |
| import com.android.tools.r8.graph.DexProgramClass; |
| import com.android.tools.r8.graph.ImmediateProgramSubtypingInfo; |
| import com.android.tools.r8.shaking.AppInfoWithLiveness; |
| import com.android.tools.r8.utils.ListUtils; |
| import com.android.tools.r8.utils.Timing; |
| import com.android.tools.r8.verticalclassmerging.policies.VerticalClassMergerPolicyWithPreprocessing; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Set; |
| import java.util.concurrent.ExecutionException; |
| import java.util.concurrent.ExecutorService; |
| |
| public class VerticalClassMergerPolicyExecutor extends PolicyExecutor<VerticalMergeGroup> { |
| |
| private final AppView<AppInfoWithLiveness> appView; |
| private final ImmediateProgramSubtypingInfo immediateSubtypingInfo; |
| |
| VerticalClassMergerPolicyExecutor( |
| AppView<AppInfoWithLiveness> appView, ImmediateProgramSubtypingInfo immediateSubtypingInfo) { |
| this.appView = appView; |
| this.immediateSubtypingInfo = immediateSubtypingInfo; |
| } |
| |
| ConnectedComponentVerticalClassMerger run( |
| Set<DexProgramClass> connectedComponent, |
| Collection<Policy> policies, |
| ExecutorService executorService, |
| Timing timing) |
| throws ExecutionException { |
| Collection<VerticalMergeGroup> groups = |
| createInitialMergeGroupsWithDeterministicOrder(connectedComponent); |
| groups = run(groups, policies, executorService, timing); |
| return new ConnectedComponentVerticalClassMerger(appView, groups); |
| } |
| |
| private Collection<VerticalMergeGroup> createInitialMergeGroupsWithDeterministicOrder( |
| Set<DexProgramClass> connectedComponent) { |
| List<VerticalMergeGroup> groups = new ArrayList<>(); |
| for (DexProgramClass mergeCandidate : connectedComponent) { |
| List<DexProgramClass> subclasses = immediateSubtypingInfo.getSubclasses(mergeCandidate); |
| if (subclasses.size() == 1) { |
| groups.add(new VerticalMergeGroup(mergeCandidate, ListUtils.first(subclasses))); |
| } |
| } |
| return ListUtils.destructiveSort( |
| groups, Comparator.comparing(group -> group.getSource().getType())); |
| } |
| |
| @Override |
| protected LinkedList<VerticalMergeGroup> apply( |
| Policy policy, LinkedList<VerticalMergeGroup> linkedGroups, ExecutorService executorService) |
| throws ExecutionException { |
| assert policy.isVerticalClassMergerPolicy(); |
| return apply(policy.asVerticalClassMergerPolicy(), linkedGroups); |
| } |
| |
| private <T> LinkedList<VerticalMergeGroup> apply( |
| VerticalClassMergerPolicyWithPreprocessing<T> policy, |
| LinkedList<VerticalMergeGroup> linkedGroups) { |
| T data = policy.preprocess(linkedGroups); |
| linkedGroups.removeIf( |
| group -> { |
| if (policy.canMerge(group, data)) { |
| return false; |
| } |
| assert policy.recordRemovedClassesForDebugging( |
| group.getSource().isInterface(), group.size(), Collections.emptyList()); |
| return true; |
| }); |
| return linkedGroups; |
| } |
| } |