Rewrite type elements after redundant interface removal
Bug: 183734568
Change-Id: Ic2354d7d15f2794bea112b4ed7ce74379edd4913
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index a6f1b9c..546fad4 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -374,7 +374,7 @@
shrinker -> shrinker.run(Mode.INITIAL_TREE_SHAKING));
TreePruner pruner = new TreePruner(appViewWithLiveness);
- DirectMappedDexApplication prunedApp = pruner.run();
+ DirectMappedDexApplication prunedApp = pruner.run(executorService);
// Recompute the subtyping information.
Set<DexType> removedClasses = pruner.getRemovedClasses();
@@ -609,7 +609,7 @@
DefaultTreePrunerConfiguration.getInstance());
TreePruner pruner = new TreePruner(appViewWithLiveness, treePrunerConfiguration);
- DirectMappedDexApplication application = pruner.run();
+ DirectMappedDexApplication application = pruner.run(executorService);
Set<DexType> removedClasses = pruner.getRemovedClasses();
if (options.usageInformationConsumer != null) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 412a66d..6d57a75 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -2568,12 +2568,15 @@
if (type.isClassType()) {
if (!appView.enableWholeProgramOptimizations()) {
// Don't reason at the level of interfaces in D8.
- return ClassTypeElement.create(type, nullability, InterfaceCollection.empty());
+ return ClassTypeElement.createForD8(type, nullability);
}
assert appView.appInfo().hasClassHierarchy();
if (appView.isInterface(type).isTrue()) {
return ClassTypeElement.create(
- objectType, nullability, InterfaceCollection.singleton(type));
+ objectType,
+ nullability,
+ appView.withClassHierarchy(),
+ InterfaceCollection.singleton(type));
}
// In theory, `interfaces` is the least upper bound of implemented interfaces.
// It is expensive to walk through type hierarchy; collect implemented interfaces;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeElement.java
index caca28e..78332d5 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeElement.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
import java.util.Objects;
+import java.util.Set;
import java.util.function.Function;
public class ArrayTypeElement extends ReferenceTypeElement {
@@ -134,10 +135,12 @@
@Override
public ArrayTypeElement fixupClassTypeReferences(
- AppView<? extends AppInfoWithClassHierarchy> appView, Function<DexType, DexType> mapping) {
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ Function<DexType, DexType> mapping,
+ Set<DexType> prunedTypes) {
if (memberTypeLattice.isReferenceType()) {
TypeElement substitutedMemberType =
- memberTypeLattice.fixupClassTypeReferences(appView, mapping);
+ memberTypeLattice.fixupClassTypeReferences(appView, mapping, prunedTypes);
if (substitutedMemberType != memberTypeLattice) {
return ArrayTypeElement.create(substitutedMemberType, nullability);
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeElement.java
index e1a924c..083c27f 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeElement.java
@@ -23,6 +23,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Queue;
+import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -37,11 +38,16 @@
private final DexType type;
public static ClassTypeElement create(
- DexType classType, Nullability nullability, InterfaceCollection interfaces) {
+ DexType classType,
+ Nullability nullability,
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ InterfaceCollection interfaces) {
+ assert appView != null;
+ assert appView.enableWholeProgramOptimizations();
assert interfaces != null;
return NullabilityVariants.create(
nullability,
- (variants) -> new ClassTypeElement(classType, nullability, interfaces, variants, null));
+ variants -> new ClassTypeElement(classType, nullability, interfaces, variants, appView));
}
public static ClassTypeElement create(
@@ -49,9 +55,18 @@
Nullability nullability,
AppView<? extends AppInfoWithClassHierarchy> appView) {
assert appView != null;
+ assert appView.enableWholeProgramOptimizations();
return NullabilityVariants.create(
nullability,
- (variants) -> new ClassTypeElement(classType, nullability, null, variants, appView));
+ variants -> new ClassTypeElement(classType, nullability, null, variants, appView));
+ }
+
+ public static ClassTypeElement createForD8(DexType classType, Nullability nullability) {
+ return NullabilityVariants.create(
+ nullability,
+ variants ->
+ new ClassTypeElement(
+ classType, nullability, InterfaceCollection.empty(), variants, null));
}
private ClassTypeElement(
@@ -61,11 +76,13 @@
NullabilityVariants<ClassTypeElement> variants,
AppView<? extends AppInfoWithClassHierarchy> appView) {
super(nullability);
+ assert appView != null
+ ? appView.enableWholeProgramOptimizations()
+ : (interfaces != null && interfaces.isEmpty());
assert classType.isClassType();
- assert interfaces != null || appView != null;
- type = classType;
+ this.type = classType;
this.appView = appView;
- lazyInterfaces = interfaces;
+ this.lazyInterfaces = interfaces;
this.variants = variants;
}
@@ -75,12 +92,13 @@
public InterfaceCollection getInterfaces() {
if (lazyInterfaces == null) {
+ // Class type interfaces are cached on DexItemFactory.
assert appView != null;
- lazyInterfaces =
- appView.dexItemFactory()
- .getOrComputeLeastUpperBoundOfImplementedInterfaces(type, appView);
+ assert appView.enableWholeProgramOptimizations();
+ return appView
+ .dexItemFactory()
+ .getOrComputeLeastUpperBoundOfImplementedInterfaces(type, appView);
}
- assert lazyInterfaces != null;
return lazyInterfaces;
}
@@ -90,11 +108,6 @@
return new ClassTypeElement(type, nullability, lazyInterfaces, variants, appView);
}
- public boolean isRelatedTo(ClassTypeElement other, AppView<?> appView) {
- return lessThanOrEqualUpToNullability(other, appView)
- || other.lessThanOrEqualUpToNullability(this, appView);
- }
-
@Override
public ClassTypeElement getOrCreateVariant(Nullability nullability) {
ClassTypeElement variant = variants.get(nullability);
@@ -156,17 +169,21 @@
@Override
public TypeElement fixupClassTypeReferences(
- AppView<? extends AppInfoWithClassHierarchy> appView, Function<DexType, DexType> mapping) {
+ AppView<? extends AppInfoWithClassHierarchy> ignore,
+ Function<DexType, DexType> mapping,
+ Set<DexType> prunedTypes) {
+ assert appView != null;
+ assert appView.enableWholeProgramOptimizations();
+
DexType mappedType = mapping.apply(type);
if (mappedType.isPrimitiveType()) {
return PrimitiveTypeElement.fromDexType(mappedType, false);
}
- if (mappedType != type) {
- return create(mappedType, nullability, appView);
- }
- // If the mapped type is not object and no computation of interfaces, we can return early.
- if (mappedType != appView.dexItemFactory().objectType && lazyInterfaces == null) {
- return this;
+
+ // If there are no interfaces, then just return the mapped type element. Otherwise, the list of
+ // interfaces require rewriting.
+ if (lazyInterfaces == null || lazyInterfaces.isEmpty()) {
+ return mappedType == type ? this : create(mappedType, nullability, appView);
}
// For most types there will not have been a change thus we iterate without allocating a new
@@ -176,6 +193,9 @@
getInterfaces()
.forEach(
(iface, isKnown) -> {
+ if (prunedTypes.contains(iface)) {
+ return;
+ }
DexType substitutedType = mapping.apply(iface);
if (iface != substitutedType) {
hasChangedInterfaces.set();
@@ -196,7 +216,7 @@
if (hasChangedInterfaces.get()) {
if (interfaceToClassChange.isSet()) {
assert !interfaceToClassChange.get().isInterface();
- assert type == appView.dexItemFactory().objectType;
+ assert mappedType == appView.dexItemFactory().objectType;
return create(interfaceToClassChange.get().type, nullability, appView);
} else {
Builder builder = InterfaceCollection.builder();
@@ -206,38 +226,53 @@
assert iface == rewritten || isKnown : "Rewritten implies program types thus known.";
builder.addInterface(rewritten, isKnown);
});
- return create(mappedType, nullability, builder.build());
+ return create(mappedType, nullability, appView, builder.build());
}
}
- return this;
+ return mappedType == type ? this : create(mappedType, nullability, appView, getInterfaces());
}
ClassTypeElement join(ClassTypeElement other, AppView<?> appView) {
- Nullability nullability = nullability().join(other.nullability());
if (!appView.enableWholeProgramOptimizations()) {
- assert lazyInterfaces != null && lazyInterfaces.isEmpty();
- assert other.lazyInterfaces != null && other.lazyInterfaces.isEmpty();
- return ClassTypeElement.create(
+ assert lazyInterfaces != null;
+ assert lazyInterfaces.isEmpty();
+ assert other.lazyInterfaces != null;
+ assert other.lazyInterfaces.isEmpty();
+ return ClassTypeElement.createForD8(
getClassType() == other.getClassType()
? getClassType()
: appView.dexItemFactory().objectType,
- nullability,
- InterfaceCollection.empty());
+ nullability().join(other.nullability()));
}
+ return joinWithClassHierarchy(other);
+ }
+
+ private ClassTypeElement joinWithClassHierarchy(ClassTypeElement other) {
+ assert appView != null;
+ assert appView.enableWholeProgramOptimizations();
DexType lubType =
- computeLeastUpperBoundOfClasses(
- appView.appInfo().withClassHierarchy(), getClassType(), other.getClassType());
+ computeLeastUpperBoundOfClasses(appView.appInfo(), getClassType(), other.getClassType());
InterfaceCollection c1lubItfs = getInterfaces();
InterfaceCollection c2lubItfs = other.getInterfaces();
- InterfaceCollection lubItfs = null;
- if (c1lubItfs.equals(c2lubItfs)) {
- lubItfs = c1lubItfs;
- }
- if (lubItfs == null) {
- lubItfs =
- computeLeastUpperBoundOfInterfaces(appView.withClassHierarchy(), c1lubItfs, c2lubItfs);
- }
- return ClassTypeElement.create(lubType, nullability, lubItfs);
+ InterfaceCollection lubItfs =
+ c1lubItfs.equals(c2lubItfs)
+ ? c1lubItfs
+ : computeLeastUpperBoundOfInterfaces(appView, c1lubItfs, c2lubItfs);
+ InterfaceCollection lubItfsDefault =
+ appView
+ .dexItemFactory()
+ .getOrComputeLeastUpperBoundOfImplementedInterfaces(lubType, appView);
+ Nullability lubNullability = nullability().join(other.nullability());
+
+ // If the computed interfaces are identical to the interfaces of `lubType`, then do not include
+ // the interfaces in the ClassTypeElement. This canonicalization of interfaces reduces memory,
+ // but also reduces the amount of work involved in lens rewriting class type elements (the null
+ // element does not require any rewriting).
+ //
+ // From a correctness point of view, both solutions should work.
+ return lubItfs.equals(lubItfsDefault)
+ ? create(lubType, lubNullability, appView)
+ : create(lubType, lubNullability, appView, lubItfs);
}
/**
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeElement.java
index ecc466a..25cb05d 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeElement.java
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.analysis.type;
+import static java.util.Collections.emptySet;
+
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
@@ -11,6 +13,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.ir.code.Value;
+import java.util.Set;
import java.util.function.Function;
/** The base abstraction of lattice elements for local type analysis. */
@@ -68,14 +71,28 @@
return ReferenceTypeElement.getNullType();
}
- public TypeElement fixupClassTypeReferences(
+ public final TypeElement fixupClassTypeReferences(
AppView<? extends AppInfoWithClassHierarchy> appView, Function<DexType, DexType> mapping) {
+ return fixupClassTypeReferences(appView, mapping, emptySet());
+ }
+
+ public TypeElement fixupClassTypeReferences(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ Function<DexType, DexType> mapping,
+ Set<DexType> prunedTypes) {
return this;
}
public final TypeElement rewrittenWithLens(
AppView<? extends AppInfoWithClassHierarchy> appView, GraphLens graphLens) {
- return fixupClassTypeReferences(appView, graphLens::lookupType);
+ return rewrittenWithLens(appView, graphLens, emptySet());
+ }
+
+ public final TypeElement rewrittenWithLens(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ GraphLens graphLens,
+ Set<DexType> prunedTypes) {
+ return fixupClassTypeReferences(appView, graphLens::lookupType, prunedTypes);
}
public boolean isNullable() {
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java b/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java
index 1ef9cf5..508b115 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java
@@ -93,7 +93,8 @@
assert verifyLambdaInterfaces(returnType, lambdaInterfaceSet, objectType);
- return ClassTypeElement.create(objectType, Nullability.maybeNull(), lambdaInterfaceSet);
+ return ClassTypeElement.create(
+ objectType, Nullability.maybeNull(), appView.withClassHierarchy(), lambdaInterfaceSet);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java
index b2f291a..b4141c6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java
@@ -4,14 +4,18 @@
package com.android.tools.r8.ir.optimize.info;
+import static java.util.Collections.emptySet;
+
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.analysis.value.UnknownValue;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import java.util.Set;
/**
* Optimization info for fields.
@@ -34,8 +38,15 @@
public MutableFieldOptimizationInfo fixupClassTypeReferences(
AppView<? extends AppInfoWithClassHierarchy> appView, GraphLens lens) {
+ return fixupClassTypeReferences(appView, lens, emptySet());
+ }
+
+ public MutableFieldOptimizationInfo fixupClassTypeReferences(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ GraphLens lens,
+ Set<DexType> prunedTypes) {
if (dynamicUpperBoundType != null) {
- dynamicUpperBoundType = dynamicUpperBoundType.rewrittenWithLens(appView, lens);
+ dynamicUpperBoundType = dynamicUpperBoundType.rewrittenWithLens(appView, lens, prunedTypes);
}
if (dynamicLowerBoundType != null) {
TypeElement dynamicLowerBoundType =
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedback.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedback.java
index 256f80a..b384693 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedback.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedback.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.ir.conversion.FieldOptimizationFeedback;
import com.android.tools.r8.ir.conversion.MethodOptimizationFeedback;
import com.android.tools.r8.shaking.AppInfoWithLivenessModifier;
@@ -28,8 +29,16 @@
public void fixupOptimizationInfos(
AppView<?> appView, ExecutorService executorService, OptimizationInfoFixer fixer)
throws ExecutionException {
+ fixupOptimizationInfos(appView.appInfo().classes(), executorService, fixer);
+ }
+
+ public void fixupOptimizationInfos(
+ Iterable<DexProgramClass> classes,
+ ExecutorService executorService,
+ OptimizationInfoFixer fixer)
+ throws ExecutionException {
ThreadUtils.processItems(
- appView.appInfo().classes(),
+ classes,
clazz -> {
for (DexEncodedField field : clazz.fields()) {
FieldOptimizationInfo optimizationInfo = field.getOptimizationInfo();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java
index e33f49c..03eee35 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.ir.optimize.info;
+import static java.util.Collections.emptySet;
+
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexType;
@@ -147,13 +149,20 @@
public UpdatableMethodOptimizationInfo fixupClassTypeReferences(
AppView<? extends AppInfoWithClassHierarchy> appView, GraphLens lens) {
+ return fixupClassTypeReferences(appView, lens, emptySet());
+ }
+
+ public UpdatableMethodOptimizationInfo fixupClassTypeReferences(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ GraphLens lens,
+ Set<DexType> prunedTypes) {
if (returnsObjectWithUpperBoundType != null) {
returnsObjectWithUpperBoundType =
- returnsObjectWithUpperBoundType.rewrittenWithLens(appView, lens);
+ returnsObjectWithUpperBoundType.rewrittenWithLens(appView, lens, prunedTypes);
}
if (returnsObjectWithLowerBoundType != null) {
TypeElement returnsObjectWithLowerBoundType =
- this.returnsObjectWithLowerBoundType.rewrittenWithLens(appView, lens);
+ this.returnsObjectWithLowerBoundType.rewrittenWithLens(appView, lens, prunedTypes);
if (returnsObjectWithLowerBoundType.isClassType()) {
this.returnsObjectWithLowerBoundType = returnsObjectWithLowerBoundType.asClassType();
} else {
diff --git a/src/main/java/com/android/tools/r8/shaking/TreePruner.java b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
index 8f606c1..577ecc2 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -18,6 +18,11 @@
import com.android.tools.r8.graph.GenericSignatureTypeVariableRemover;
import com.android.tools.r8.graph.InnerClassAttribute;
import com.android.tools.r8.graph.NestMemberClassAttribute;
+import com.android.tools.r8.ir.optimize.info.MutableFieldOptimizationInfo;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedback.OptimizationInfoFixer;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
+import com.android.tools.r8.ir.optimize.info.UpdatableMethodOptimizationInfo;
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.InternalOptions;
@@ -30,6 +35,8 @@
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
import java.util.function.Predicate;
public class TreePruner {
@@ -63,15 +70,18 @@
this::isAttributeReferencingPrunedItem);
}
- public DirectMappedDexApplication run() {
+ public DirectMappedDexApplication run(ExecutorService executorService) throws ExecutionException {
DirectMappedDexApplication application = appView.appInfo().app().asDirect();
Timing timing = application.timing;
timing.begin("Pruning application...");
try {
DirectMappedDexApplication.Builder builder = removeUnused(application);
- return prunedTypes.isEmpty() && !appView.options().configurationDebugging
- ? application
- : builder.build();
+ DirectMappedDexApplication newApplication =
+ prunedTypes.isEmpty() && !appView.options().configurationDebugging
+ ? application
+ : builder.build();
+ fixupOptimizationInfo(newApplication, executorService);
+ return newApplication;
} finally {
timing.end();
}
@@ -99,7 +109,7 @@
&& !options.forceProguardCompatibility) {
// The class is only needed as a type but never instantiated. Make it abstract to reflect
// this.
- if (clazz.accessFlags.isFinal()) {
+ if (clazz.isFinal()) {
// We cannot mark this class abstract, as it is final (not supported on Android).
// However, this might extend an abstract class and we might have removed the
// corresponding methods in this class. This might happen if we only keep this
@@ -127,7 +137,7 @@
private void pruneUnusedInterfaces(DexProgramClass clazz) {
Set<DexType> reachableInterfaces = new LinkedHashSet<>();
- for (DexType type : clazz.interfaces.values) {
+ for (DexType type : clazz.getInterfaces()) {
retainReachableInterfacesFrom(type, reachableInterfaces);
}
if (!reachableInterfaces.isEmpty()) {
@@ -382,6 +392,33 @@
return Collections.unmodifiableCollection(methodsToKeepForConfigurationDebugging);
}
+ private void fixupOptimizationInfo(
+ DirectMappedDexApplication application, ExecutorService executorService)
+ throws ExecutionException {
+ // Clear the type elements cache due to redundant interface removal.
+ appView.dexItemFactory().clearTypeElementsCache();
+
+ OptimizationFeedback feedback = OptimizationFeedbackSimple.getInstance();
+ feedback.fixupOptimizationInfos(
+ application.classes(),
+ executorService,
+ new OptimizationInfoFixer() {
+ @Override
+ public void fixup(DexEncodedField field, MutableFieldOptimizationInfo optimizationInfo) {
+ optimizationInfo.fixupClassTypeReferences(appView, appView.graphLens(), prunedTypes);
+ }
+
+ @Override
+ public void fixup(
+ DexEncodedMethod method, UpdatableMethodOptimizationInfo optimizationInfo) {
+ optimizationInfo.fixupClassTypeReferences(appView, appView.graphLens(), prunedTypes);
+ }
+ });
+
+ // Verify that the fixup did not lead to the caching of any elements.
+ assert appView.dexItemFactory().verifyNoCachedTypeElements();
+ }
+
private boolean verifyNoDeadFields(DexProgramClass clazz) {
for (DexEncodedField field : clazz.fields()) {
// Pinned field which type is never instantiated are always null, they are marked as dead
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeElementWidthTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeElementWidthTest.java
index c07c431..609c892 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeElementWidthTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeElementWidthTest.java
@@ -76,8 +76,7 @@
public void testReferenceWidth() {
DexItemFactory dexItemFactory = new DexItemFactory();
ClassTypeElement referenceType =
- ClassTypeElement.create(
- dexItemFactory.objectType, Nullability.maybeNull(), InterfaceCollection.empty());
+ ClassTypeElement.createForD8(dexItemFactory.objectType, Nullability.maybeNull());
assertFalse(referenceType.isSinglePrimitive());
assertFalse(referenceType.isWidePrimitive());
assertEquals(1, referenceType.requiredRegisters());