blob: 205cf71ca801ed97bdf17d088c2c3ca46c81c155 [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.shaking;
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexMethodHandle;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.utils.BooleanBox;
import java.util.Set;
import java.util.function.Consumer;
public class MainDexDirectReferenceTracer {
private final AnnotationDirectReferenceCollector annotationDirectReferenceCollector =
new AnnotationDirectReferenceCollector();
private final DirectReferencesCollector codeDirectReferenceCollector;
private final AppInfoWithClassHierarchy appInfo;
private final Consumer<DexType> consumer;
public MainDexDirectReferenceTracer(
AppInfoWithClassHierarchy appInfo, Consumer<DexType> consumer) {
this.codeDirectReferenceCollector = new DirectReferencesCollector(appInfo.dexItemFactory());
this.appInfo = appInfo;
this.consumer = consumer;
}
public void run(Set<DexType> roots) {
for (DexType type : roots) {
DexProgramClass clazz = asProgramClassOrNull(appInfo.definitionFor(type));
// Should only happen for library classes, which are filtered out.
assert clazz != null;
consumer.accept(type);
// Super and interfaces are live, no need to add them.
traceAnnotationsDirectDependencies(clazz.annotations());
clazz.forEachField(field -> consumer.accept(field.field.type));
clazz.forEachProgramMethodMatching(
definition -> {
traceMethodDirectDependencies(definition.getReference(), consumer);
return definition.hasCode();
},
method -> method.registerCodeReferences(codeDirectReferenceCollector));
}
}
public void runOnCode(ProgramMethod method) {
method.registerCodeReferences(codeDirectReferenceCollector);
}
public static boolean hasReferencesOutsideFromCode(
AppInfoWithClassHierarchy appInfo, ProgramMethod method, Set<DexType> classes) {
BooleanBox result = new BooleanBox();
new MainDexDirectReferenceTracer(
appInfo,
type -> {
DexType baseType = type.toBaseType(appInfo.dexItemFactory());
if (baseType.isClassType() && !classes.contains(baseType)) {
DexClass cls = appInfo.definitionFor(baseType);
if (cls != null && cls.isProgramClass()) {
result.set(true);
}
}
})
.runOnCode(method);
return result.get();
}
private void traceAnnotationsDirectDependencies(DexAnnotationSet annotations) {
annotations.collectIndexedItems(annotationDirectReferenceCollector);
}
private void traceMethodDirectDependencies(DexMethod method, Consumer<DexType> consumer) {
DexProto proto = method.proto;
consumer.accept(proto.returnType);
for (DexType parameterType : proto.parameters.values) {
consumer.accept(parameterType);
}
}
private class DirectReferencesCollector extends UseRegistry {
private DirectReferencesCollector(DexItemFactory factory) {
super(factory);
}
@Override
public boolean registerInitClass(DexType clazz) {
consumer.accept(clazz);
return true;
}
@Override
public boolean registerInvokeVirtual(DexMethod method) {
return registerInvoke(method);
}
@Override
public boolean registerInvokeDirect(DexMethod method) {
return registerInvoke(method);
}
@Override
public boolean registerInvokeStatic(DexMethod method) {
return registerInvoke(method);
}
@Override
public boolean registerInvokeInterface(DexMethod method) {
return registerInvoke(method);
}
@Override
public boolean registerInvokeSuper(DexMethod method) {
return registerInvoke(method);
}
protected boolean registerInvoke(DexMethod method) {
consumer.accept(method.holder);
traceMethodDirectDependencies(method, consumer);
return true;
}
@Override
public boolean registerInstanceFieldWrite(DexField field) {
return registerFieldAccess(field);
}
@Override
public boolean registerInstanceFieldRead(DexField field) {
return registerFieldAccess(field);
}
@Override
public boolean registerStaticFieldRead(DexField field) {
return registerFieldAccess(field);
}
@Override
public boolean registerStaticFieldWrite(DexField field) {
return registerFieldAccess(field);
}
protected boolean registerFieldAccess(DexField field) {
consumer.accept(field.holder);
consumer.accept(field.type);
return true;
}
@Override
public boolean registerNewInstance(DexType type) {
consumer.accept(type);
return true;
}
@Override
public boolean registerTypeReference(DexType type) {
consumer.accept(type);
return true;
}
}
private class AnnotationDirectReferenceCollector implements IndexedItemCollection {
@Override
public boolean addClass(DexProgramClass dexProgramClass) {
consumer.accept(dexProgramClass.type);
return false;
}
@Override
public boolean addField(DexField field) {
consumer.accept(field.holder);
consumer.accept(field.type);
return false;
}
@Override
public boolean addMethod(DexMethod method) {
consumer.accept(method.holder);
addProto(method.proto);
return false;
}
@Override
public boolean addString(DexString string) {
return false;
}
@Override
public boolean addProto(DexProto proto) {
consumer.accept(proto.returnType);
for (DexType parameterType : proto.parameters.values) {
consumer.accept(parameterType);
}
return false;
}
@Override
public boolean addType(DexType type) {
consumer.accept(type);
return false;
}
@Override
public boolean addCallSite(DexCallSite callSite) {
throw new AssertionError("CallSite are not supported when tracing for legacy multi dex");
}
@Override
public boolean addMethodHandle(DexMethodHandle methodHandle) {
throw new AssertionError(
"DexMethodHandle are not supported when tracing for legacy multi dex");
}
}
}