blob: df45e6b63417c33cd855214ad021c7d54d345943 [file] [log] [blame]
// Copyright (c) 2017, 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.graph;
import com.android.tools.r8.FeatureSplit;
import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.MainDexInfo;
import com.android.tools.r8.synthesis.CommittedItems;
import com.android.tools.r8.synthesis.SyntheticItems;
import com.android.tools.r8.utils.BooleanBox;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.IterableUtils;
import java.util.List;
import java.util.function.Consumer;
public class AppInfo implements DexDefinitionSupplier {
private final DexApplication app;
private final DexItemFactory dexItemFactory;
private final MainDexInfo mainDexInfo;
private final SyntheticItems syntheticItems;
// Set when a new AppInfo replaces a previous one. All public methods should verify that the
// current instance is not obsolete, to ensure that we almost use the most recent AppInfo.
private final BooleanBox obsolete;
public static AppInfo createInitialAppInfo(DexApplication application) {
return createInitialAppInfo(application, MainDexInfo.none());
}
public static AppInfo createInitialAppInfo(DexApplication application, MainDexInfo mainDexInfo) {
return new AppInfo(SyntheticItems.createInitialSyntheticItems(application), mainDexInfo);
}
public AppInfo(CommittedItems committedItems, MainDexInfo mainDexInfo) {
this(
committedItems.getApplication(),
committedItems.toSyntheticItems(),
mainDexInfo,
new BooleanBox());
}
// For desugaring.
// This is a view onto the app info and is the only place the pending synthetics are shared.
AppInfo(AppInfoWithClassHierarchy.CreateDesugaringViewOnAppInfo witness, AppInfo appInfo) {
this(appInfo.app, appInfo.syntheticItems, appInfo.mainDexInfo, appInfo.obsolete);
assert witness != null;
}
private AppInfo(
DexApplication application,
SyntheticItems syntheticItems,
MainDexInfo mainDexInfo,
BooleanBox obsolete) {
this.app = application;
this.dexItemFactory = application.dexItemFactory;
this.mainDexInfo = mainDexInfo;
this.syntheticItems = syntheticItems;
this.obsolete = obsolete;
}
public AppInfo prunedCopyFrom(PrunedItems prunedItems) {
assert getClass() == AppInfo.class;
assert checkIfObsolete();
assert prunedItems.getPrunedApp() == app();
if (prunedItems.isEmpty()) {
return this;
}
return new AppInfo(
getSyntheticItems().commitPrunedItems(prunedItems),
getMainDexInfo().withoutPrunedItems(prunedItems));
}
public AppInfo rebuildWithMainDexInfo(MainDexInfo mainDexInfo) {
assert checkIfObsolete();
return new AppInfo(app, syntheticItems, mainDexInfo, new BooleanBox());
}
protected InternalOptions options() {
return app.options;
}
public boolean isObsolete() {
return obsolete.get();
}
public void markObsolete() {
obsolete.set();
}
public void unsetObsolete() {
obsolete.unset();
}
public boolean checkIfObsolete() {
assert !isObsolete();
return true;
}
public DexApplication app() {
assert checkIfObsolete();
return app;
}
@Override
public DexItemFactory dexItemFactory() {
assert checkIfObsolete();
return dexItemFactory;
}
public MainDexInfo getMainDexInfo() {
assert checkIfObsolete();
return mainDexInfo;
}
public SyntheticItems getSyntheticItems() {
assert checkIfObsolete();
return syntheticItems;
}
public void addSynthesizedClassForLibraryDesugaring(DexProgramClass clazz) {
assert checkIfObsolete();
assert options().desugaredLibraryConfiguration != null;
syntheticItems.addLegacySyntheticClassForLibraryDesugaring(clazz);
}
public void addSynthesizedClass(DexProgramClass clazz, ProgramDefinition context) {
assert checkIfObsolete();
assert context != null;
syntheticItems.addLegacySyntheticClass(clazz, context, FeatureSplit.BASE);
}
public void addSynthesizedClassToBase(DexProgramClass clazz, Iterable<DexProgramClass> contexts) {
assert checkIfObsolete();
assert !IterableUtils.isEmpty(contexts);
SyntheticItems syntheticItems = getSyntheticItems();
contexts.forEach(
context -> syntheticItems.addLegacySyntheticClass(clazz, context, FeatureSplit.BASE));
}
public List<DexProgramClass> classes() {
assert checkIfObsolete();
return app.classes();
}
public List<DexProgramClass> classesWithDeterministicOrder() {
assert checkIfObsolete();
return app.classesWithDeterministicOrder();
}
public void forEachMethod(Consumer<ProgramMethod> consumer) {
for (DexProgramClass clazz : classes()) {
clazz.forEachProgramMethod(consumer);
}
}
@Override
public DexClass definitionFor(DexType type) {
return definitionForWithoutExistenceAssert(type);
}
public final DexClass definitionForWithoutExistenceAssert(DexType type) {
assert checkIfObsolete();
return syntheticItems.definitionFor(type, app::definitionFor);
}
public DexClass definitionForDesugarDependency(DexClass dependent, DexType type) {
if (dependent.type == type) {
return dependent;
}
DexClass definition = definitionFor(type);
if (definition != null && !definition.isLibraryClass() && !dependent.isLibraryClass()) {
InterfaceMethodRewriter.reportDependencyEdge(dependent, definition, this);
}
return definition;
}
public DexProgramClass unsafeDirectProgramTypeLookup(DexType type) {
return app.programDefinitionFor(type);
}
public Origin originFor(DexType type) {
assert checkIfObsolete();
DexClass definition = app.definitionFor(type);
return definition == null ? Origin.unknown() : definition.origin;
}
/**
* Lookup static method on the method holder, or answers null.
*
* @param method the method to lookup
* @param context the method the invoke is contained in, i.e., the caller.
* @return The actual target for {@code method} if on the holder, or {@code null}.
*/
public final DexEncodedMethod lookupStaticTargetOnItself(
DexMethod method, ProgramMethod context) {
if (method.holder != context.getHolderType()) {
return null;
}
DexEncodedMethod singleTarget = context.getHolder().lookupDirectMethod(method);
if (singleTarget != null && singleTarget.isStatic()) {
return singleTarget;
}
return null;
}
/**
* Lookup direct method on the method holder, or answers null.
*
* @param method the method to lookup
* @param context the method the invoke is contained in, i.e., the caller.
* @return The actual target for {@code method} if on the holder, or {@code null}.
*/
public final DexEncodedMethod lookupDirectTargetOnItself(
DexMethod method, ProgramMethod context) {
if (method.holder != context.getHolderType()) {
return null;
}
DexEncodedMethod singleTarget = context.getHolder().lookupDirectMethod(method);
if (singleTarget != null && !singleTarget.isStatic()) {
return singleTarget;
}
return null;
}
public boolean hasClassHierarchy() {
assert checkIfObsolete();
return false;
}
public AppInfoWithClassHierarchy withClassHierarchy() {
assert checkIfObsolete();
return null;
}
public boolean hasLiveness() {
assert checkIfObsolete();
return false;
}
public AppInfoWithLiveness withLiveness() {
assert checkIfObsolete();
return null;
}
public final FieldResolutionResult resolveField(DexField field, ProgramMethod context) {
return resolveFieldOn(field.holder, field, context);
}
public FieldResolutionResult resolveFieldOn(DexType type, DexField field, ProgramMethod context) {
// Only allow resolution if the field is declared in the context.
if (type != context.getHolderType()) {
return FieldResolutionResult.failure();
}
DexProgramClass clazz = context.getHolder();
DexEncodedField definition = clazz.lookupField(field);
return definition != null
? new SuccessfulFieldResolutionResult(clazz, clazz, definition)
: FieldResolutionResult.unknown();
}
}