blob: 590299905905510e7293ca2232fc1aacf172ebf4 [file] [log] [blame]
// 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.ir.optimize.info;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DefaultUseRegistryWithResult;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.ir.conversion.PostMethodProcessor;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ThreadUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
/**
* Finds the methods in the program that should be reprocessed due to non-trivial method resolution
* optimization info.
*/
class MethodResolutionOptimizationInfoReprocessingEnqueuer {
private final AppView<AppInfoWithLiveness> appView;
MethodResolutionOptimizationInfoReprocessingEnqueuer(AppView<AppInfoWithLiveness> appView) {
this.appView = appView;
}
public void enqueueMethodForReprocessing(
ExecutorService executorService, PostMethodProcessor.Builder postMethodProcessorBuilder)
throws ExecutionException {
// Bring the methods to reprocess set up-to-date with the current graph lens.
postMethodProcessorBuilder.rewrittenWithLens(appView);
enqueueAffectedCallers(postMethodProcessorBuilder, executorService);
}
private void enqueueAffectedCallers(
PostMethodProcessor.Builder postMethodProcessorBuilder, ExecutorService executorService)
throws ExecutionException {
GraphLens currentGraphLens = appView.graphLens();
InternalOptions options = appView.options();
Collection<List<ProgramMethod>> methodsToReprocess =
ThreadUtils.processItemsWithResults(
appView.appInfo().classes(),
clazz -> {
List<ProgramMethod> methodsToReprocessInClass = new ArrayList<>();
clazz.forEachProgramMethodMatching(
DexEncodedMethod::hasCode,
method -> {
if (!postMethodProcessorBuilder.contains(method, currentGraphLens)
&& appView.getKeepInfo(method).isReprocessingAllowed(options, method)) {
AffectedMethodUseRegistry registry =
new AffectedMethodUseRegistry(appView, method);
if (method.registerCodeReferencesWithResult(registry)) {
methodsToReprocessInClass.add(method);
}
}
});
return methodsToReprocessInClass;
},
options.getThreadingModule(),
executorService);
methodsToReprocess.forEach(
methodsToReprocessInClass ->
postMethodProcessorBuilder.addAll(methodsToReprocessInClass, currentGraphLens));
}
static class AffectedMethodUseRegistry
extends DefaultUseRegistryWithResult<Boolean, ProgramMethod> {
private final AppView<AppInfoWithLiveness> appViewWithLiveness;
AffectedMethodUseRegistry(
AppView<AppInfoWithLiveness> appViewWithLiveness, ProgramMethod context) {
super(appViewWithLiveness, context, false);
this.appViewWithLiveness = appViewWithLiveness;
}
private void markAffected() {
setResult(Boolean.TRUE);
}
@Override
public void registerInvokeDirect(DexMethod method) {
DexMethod rewrittenMethod =
appViewWithLiveness.graphLens().lookupInvokeDirect(method, getContext()).getReference();
registerInvokeMethod(rewrittenMethod);
}
@Override
public void registerInvokeInterface(DexMethod method) {
DexMethod rewrittenMethod =
appViewWithLiveness
.graphLens()
.lookupInvokeInterface(method, getContext())
.getReference();
registerInvokeMethod(rewrittenMethod);
}
@Override
public void registerInvokeStatic(DexMethod method) {
DexMethod rewrittenMethod =
appViewWithLiveness.graphLens().lookupInvokeStatic(method, getContext()).getReference();
registerInvokeMethod(rewrittenMethod);
}
@Override
public void registerInvokeSuper(DexMethod method) {
DexMethod rewrittenMethod =
appViewWithLiveness.graphLens().lookupInvokeSuper(method, getContext()).getReference();
registerInvokeMethod(rewrittenMethod);
}
@Override
public void registerInvokeVirtual(DexMethod method) {
DexMethod rewrittenMethod =
appViewWithLiveness.graphLens().lookupInvokeVirtual(method, getContext()).getReference();
registerInvokeMethod(rewrittenMethod);
}
private void registerInvokeMethod(DexMethod method) {
SingleResolutionResult<?> resolutionResult =
appViewWithLiveness
.appInfo()
.unsafeResolveMethodDueToDexFormatLegacy(method)
.asSingleResolution();
if (resolutionResult == null) {
return;
}
MethodResolutionOptimizationInfoCollection methodResolutionOptimizationInfoCollection =
appViewWithLiveness.getMethodResolutionOptimizationInfoCollection();
MethodOptimizationInfo optimizationInfo =
methodResolutionOptimizationInfoCollection.get(
resolutionResult.getResolvedMethod(), resolutionResult.getResolvedHolder());
if (!optimizationInfo.isDefault()) {
markAffected();
}
}
}
}