blob: 2b439a6b33a50d12ed6cfdb03245ab03677b4315 [file] [log] [blame]
// Copyright (c) 2018, 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;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.SubtypingInfo;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.MethodSignatureEquivalence;
import com.google.common.base.Predicates;
import java.util.function.Predicate;
// Per-class collection of method signatures.
//
// Example use cases:
// *) in publicizer,
// to determine if a private method does not collide with methods in that class hierarchy.
// *) in vertical class merger,
// before moving a default interface method to its subtype, check if it does not collide with one
// in the given class hierarchy.
// *) in uninstantiated type optimizer,
// to avoid signature collisions while discarding unused return type or parameters.
// *) in unused argument removal,
// to avoid removing unused arguments from a virtual method if it is overriding another method or
// being overridden by a method in a subtype, and to check that a virtual method after unused
// argument removal does not collide with one in the existing class hierarchy.
// TODO(b/66369976): to determine if a certain method can be made `final`.
public class MethodPoolCollection extends MemberPoolCollection<DexMethod> {
private final Predicate<DexEncodedMethod> methodTester;
public MethodPoolCollection(AppView<AppInfoWithLiveness> appView) {
this(appView, appView.appInfo().computeSubtypingInfo());
}
public MethodPoolCollection(AppView<AppInfoWithLiveness> appView, SubtypingInfo subtypingInfo) {
this(appView, subtypingInfo, Predicates.alwaysTrue());
}
public MethodPoolCollection(
AppView<AppInfoWithLiveness> appView,
SubtypingInfo subtypingInfo,
Predicate<DexEncodedMethod> methodTester) {
super(appView, MethodSignatureEquivalence.get(), subtypingInfo);
this.methodTester = methodTester;
}
public static boolean excludesPrivateInstanceMethod(DexEncodedMethod method) {
return !method.isPrivateMethod() || method.isStatic();
}
@Override
Runnable computeMemberPoolForClass(DexClass clazz) {
return () -> {
MemberPool<DexMethod> methodPool =
memberPools.computeIfAbsent(clazz, k -> new MemberPool<>(equivalence, k));
clazz.forEachMethod(
encodedMethod -> {
if (methodTester.test(encodedMethod)) {
methodPool.seen(equivalence.wrap(encodedMethod.getReference()));
}
});
if (clazz.superType != null) {
DexClass superClazz = appView.definitionFor(clazz.superType);
if (superClazz != null) {
MemberPool<DexMethod> superPool =
memberPools.computeIfAbsent(
superClazz, k -> new MemberPool<>(equivalence, superClazz));
superPool.linkSubtype(methodPool);
methodPool.linkSupertype(superPool);
}
}
if (clazz.isInterface()) {
for (DexType subtype : subtypingInfo.allImmediateSubtypes(clazz.type)) {
DexClass subClazz = appView.definitionFor(subtype);
if (subClazz != null) {
MemberPool<DexMethod> childPool =
memberPools.computeIfAbsent(subClazz, k -> new MemberPool<>(equivalence, subClazz));
methodPool.linkSubtype(childPool);
childPool.linkInterface(methodPool);
}
}
}
};
}
}