Full horizontal class merging before writing
Bug: b/324527514
Fixes: b/296852026
Change-Id: I63ce734ee2da1258364764f88ed44b9a5bbeeba4
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 2717f8a..eb4825c 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -78,6 +78,7 @@
import com.android.tools.r8.optimize.interfaces.analysis.CfOpenClosedInterfacesAnalysis;
import com.android.tools.r8.optimize.proto.ProtoNormalizer;
import com.android.tools.r8.optimize.redundantbridgeremoval.RedundantBridgeRemover;
+import com.android.tools.r8.optimize.singlecaller.SingleCallerInliner;
import com.android.tools.r8.origin.CommandLineOrigin;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.profile.art.ArtProfileCompletenessChecker;
@@ -769,6 +770,7 @@
.runIfNecessary(executorService, timing);
assert appView.dexItemFactory().verifyNoCachedTypeElements();
+ new SingleCallerInliner(appViewWithLiveness).runIfNecessary(executorService, timing);
new ProtoNormalizer(appViewWithLiveness).run(executorService, timing);
}
}
diff --git a/src/main/java/com/android/tools/r8/classmerging/ClassMergerGraphLens.java b/src/main/java/com/android/tools/r8/classmerging/ClassMergerGraphLens.java
index 300d399..7408427 100644
--- a/src/main/java/com/android/tools/r8/classmerging/ClassMergerGraphLens.java
+++ b/src/main/java/com/android/tools/r8/classmerging/ClassMergerGraphLens.java
@@ -9,10 +9,8 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.classmerging.MergedClasses;
import com.android.tools.r8.graph.lens.NestedGraphLens;
-import com.android.tools.r8.ir.conversion.ExtraParameter;
import com.android.tools.r8.utils.collections.BidirectionalManyToManyRepresentativeMap;
import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeMap;
-import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -30,9 +28,6 @@
public abstract static class BuilderBase<
GL extends ClassMergerGraphLens, MC extends MergedClasses> {
- public abstract void addExtraParameters(
- DexMethod from, DexMethod to, List<? extends ExtraParameter> extraParameters);
-
public abstract void commitPendingUpdates();
public abstract void fixupField(DexField from, DexField to);
diff --git a/src/main/java/com/android/tools/r8/classmerging/ClassMergerMode.java b/src/main/java/com/android/tools/r8/classmerging/ClassMergerMode.java
index 9c459af..bb9a37b 100644
--- a/src/main/java/com/android/tools/r8/classmerging/ClassMergerMode.java
+++ b/src/main/java/com/android/tools/r8/classmerging/ClassMergerMode.java
@@ -14,17 +14,4 @@
public boolean isFinal() {
return this == FINAL;
}
-
- public boolean isRestrictedToAlphaRenaming() {
- return isFinal();
- }
-
- // Similar to isRestrictedToAlphaRenaming(), but used on paths that are R8 specific. All usages of
- // this method should be removed as a result of running a full final round of horizontal class
- // merging.
- @Deprecated
- @SuppressWarnings("InlineMeSuggester")
- public boolean isRestrictedToAlphaRenamingInR8() {
- return isRestrictedToAlphaRenaming();
- }
}
diff --git a/src/main/java/com/android/tools/r8/classmerging/ClassMergerTreeFixer.java b/src/main/java/com/android/tools/r8/classmerging/ClassMergerTreeFixer.java
index 6f58680..c1e27ad 100644
--- a/src/main/java/com/android/tools/r8/classmerging/ClassMergerTreeFixer.java
+++ b/src/main/java/com/android/tools/r8/classmerging/ClassMergerTreeFixer.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.classmerging;
-import static com.android.tools.r8.ir.conversion.ExtraUnusedParameter.computeExtraUnusedParameters;
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
@@ -18,9 +18,9 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.EnclosingMethodAttribute;
+import com.android.tools.r8.graph.ImmediateProgramSubtypingInfo;
import com.android.tools.r8.graph.classmerging.MergedClasses;
import com.android.tools.r8.graph.fixup.TreeFixerBase;
-import com.android.tools.r8.horizontalclassmerging.SubtypingForrestForClasses;
import com.android.tools.r8.shaking.AnnotationFixer;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.ArrayUtils;
@@ -32,8 +32,10 @@
import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.IdentityHashMap;
+import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
@@ -46,9 +48,10 @@
MC extends MergedClasses>
extends TreeFixerBase {
+ private final ClassMergerSharedData classMergerSharedData;
+ private final ImmediateProgramSubtypingInfo immediateSubtypingInfo;
protected final LB lensBuilder;
protected final MC mergedClasses;
- private final ClassMergerSharedData classMergerSharedData;
private final Map<DexProgramClass, DexType> originalSuperTypes = new IdentityHashMap<>();
@@ -59,10 +62,12 @@
public ClassMergerTreeFixer(
AppView<?> appView,
ClassMergerSharedData classMergerSharedData,
+ ImmediateProgramSubtypingInfo immediateSubtypingInfo,
LB lensBuilder,
MC mergedClasses) {
super(appView);
this.classMergerSharedData = classMergerSharedData;
+ this.immediateSubtypingInfo = immediateSubtypingInfo;
this.lensBuilder = lensBuilder;
this.mergedClasses = mergedClasses;
}
@@ -78,12 +83,10 @@
Iterables.filter(classes, DexProgramClass::isInterface).forEach(this::fixupInterfaceClass);
classes.forEach(this::fixupAttributes);
classes.forEach(this::fixupProgramClassSuperTypes);
- SubtypingForrestForClasses subtypingForrest =
- new SubtypingForrestForClasses(appView.withClassHierarchy());
+
// TODO(b/170078037): parallelize this code segment.
- for (DexProgramClass root : subtypingForrest.getProgramRoots()) {
- subtypingForrest.traverseNodeDepthFirst(
- root, new DexMethodSignatureBiMap<>(), this::fixupProgramClass);
+ for (DexProgramClass root : getRoots()) {
+ traverseProgramClassesDepthFirst(root, new DexMethodSignatureBiMap<>());
}
postprocess();
GL lens = lensBuilder.build(appViewWithLiveness, mergedClasses);
@@ -92,6 +95,38 @@
return lens;
}
+ private List<DexProgramClass> getRoots() {
+ List<DexProgramClass> roots = new ArrayList<>();
+ for (DexProgramClass clazz : appView.appInfo().classes()) {
+ if (!clazz.isInterface() && !mergedClasses.isMergeSource(clazz.getType())) {
+ DexProgramClass superClass =
+ asProgramClassOrNull(appView.definitionFor(clazz.getSuperType(), clazz));
+ if (superClass == null) {
+ roots.add(clazz);
+ }
+ }
+ }
+ return roots;
+ }
+
+ private void traverseProgramClassesDepthFirst(
+ DexProgramClass clazz, DexMethodSignatureBiMap<DexMethodSignature> state) {
+ DexMethodSignatureBiMap<DexMethodSignature> newState = fixupProgramClass(clazz, state);
+ for (DexProgramClass subclass : immediateSubtypingInfo.getSubclasses(clazz)) {
+ traverseProgramClassesDepthFirst(subclass, newState);
+ }
+ if (mergedClasses.isMergeTarget(clazz.getType())) {
+ for (DexType sourceType : mergedClasses.getSourcesFor(clazz.getType())) {
+ DexProgramClass sourceClass = appView.definitionFor(sourceType).asProgramClass();
+ for (DexProgramClass subclass : immediateSubtypingInfo.getSubclasses(sourceClass)) {
+ if (subclass != clazz) {
+ traverseProgramClassesDepthFirst(subclass, newState);
+ }
+ }
+ }
+ }
+ }
+
public void preprocess() {
// Intentionally empty.
}
@@ -289,10 +324,6 @@
newMethodReference,
classMergerSharedData.getExtraUnusedArgumentTypes(),
tryMethod -> !newMethodSignatures.containsValue(tryMethod.getSignature()));
- lensBuilder.addExtraParameters(
- originalMethodReference,
- newMethodReference,
- computeExtraUnusedParameters(originalMethodReference, newMethodReference));
} else {
newMethodReference =
dexItemFactory.createFreshMethodNameWithoutHolder(
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
index 5d0b33c..9618cd6 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
@@ -242,7 +242,6 @@
void appendClassIdField() {
assert appView.hasLiveness();
- assert !mode.isRestrictedToAlphaRenamingInR8();
DexEncodedField classIdField =
DexEncodedField.syntheticBuilder()
@@ -373,11 +372,14 @@
}
public static class Builder {
+
private final AppView<?> appView;
private final IRCodeProvider codeProvider;
private final ClassMergerMode mode;
private final HorizontalMergeGroup group;
+ private List<VirtualMethodMerger> virtualMethodMergers;
+
public Builder(
AppView<?> appView,
IRCodeProvider codeProvider,
@@ -389,19 +391,19 @@
this.mode = mode;
}
- @SuppressWarnings("MixedMutabilityReturnType")
- private List<VirtualMethodMerger> createVirtualMethodMergers() {
+ public Builder initializeVirtualMethodMergers() {
if (!appView.hasClassHierarchy()) {
assert getVirtualMethodMergerBuilders().isEmpty();
- return Collections.emptyList();
+ virtualMethodMergers = Collections.emptyList();
+ return this;
}
Map<DexMethodSignature, VirtualMethodMerger.Builder> virtualMethodMergerBuilders =
getVirtualMethodMergerBuilders();
if (virtualMethodMergerBuilders.isEmpty()) {
- return Collections.emptyList();
+ virtualMethodMergers = Collections.emptyList();
+ return this;
}
- List<VirtualMethodMerger> virtualMethodMergers =
- new ArrayList<>(virtualMethodMergerBuilders.size());
+ virtualMethodMergers = new ArrayList<>(virtualMethodMergerBuilders.size());
List<VirtualMethodMerger> nonNopOrTrivialVirtualMethodMergers =
new ArrayList<>(virtualMethodMergerBuilders.size());
for (VirtualMethodMerger.Builder builder : virtualMethodMergerBuilders.values()) {
@@ -418,7 +420,7 @@
// first, then the non trivial mergers are processed and correctly deal with conflicting
// signatures.
assert verifyNopOrTrivialAreFirst(virtualMethodMergers);
- return virtualMethodMergers;
+ return this;
}
private boolean verifyNopOrTrivialAreFirst(List<VirtualMethodMerger> virtualMethodMergers) {
@@ -450,6 +452,16 @@
return virtualMethodMergerBuilders;
}
+ public void initializeClassIdField() {
+ boolean requiresClassIdField =
+ virtualMethodMergers.stream()
+ .anyMatch(virtualMethodMerger -> !virtualMethodMerger.isNopOrTrivial());
+ if (requiresClassIdField) {
+ assert appView.enableWholeProgramOptimizations();
+ createClassIdField();
+ }
+ }
+
private void createClassIdField() {
DexField field =
appView
@@ -467,16 +479,6 @@
public ClassMerger build(
HorizontalClassMergerGraphLens.Builder lensBuilder) {
- List<VirtualMethodMerger> virtualMethodMergers = createVirtualMethodMergers();
-
- boolean requiresClassIdField =
- virtualMethodMergers.stream()
- .anyMatch(virtualMethodMerger -> !virtualMethodMerger.isNopOrTrivial());
- if (requiresClassIdField) {
- assert !mode.isRestrictedToAlphaRenaming();
- createClassIdField();
- }
-
return new ClassMerger(appView, codeProvider, mode, lensBuilder, group, virtualMethodMergers);
}
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
index 18f1d1a..849e67a 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ImmediateProgramSubtypingInfo;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.PrunedItems;
import com.android.tools.r8.horizontalclassmerging.code.SyntheticInitializerConverter;
@@ -116,8 +117,7 @@
Timing timing)
throws ExecutionException {
// Run the policies on all program classes to produce a final grouping.
- List<Policy> policies =
- PolicyScheduler.getPolicies(appView, codeProvider, mode, runtimeTypeCheckInfo);
+ List<Policy> policies = PolicyScheduler.getPolicies(appView, mode, runtimeTypeCheckInfo);
Collection<HorizontalMergeGroup> groups =
new HorizontalClassMergerPolicyExecutor()
.run(getInitialGroups(), policies, executorService, timing);
@@ -128,12 +128,26 @@
return;
}
+ ClassMergerSharedData classMergerSharedData = new ClassMergerSharedData(appView);
HorizontalClassMergerGraphLens.Builder lensBuilder =
new HorizontalClassMergerGraphLens.Builder();
- // Merge the classes.
- List<ClassMerger> classMergers = initializeClassMergers(codeProvider, lensBuilder, groups);
- ClassMergerSharedData classMergerSharedData = new ClassMergerSharedData(appView);
+ // Determine which classes need a class id field.
+ List<ClassMerger.Builder> classMergerBuilders = createClassMergerBuilders(codeProvider, groups);
+ initializeClassIdFields(classMergerBuilders);
+
+ // Ensure that all allocations of classes that end up needing a class id use a constructor on
+ // the class itself.
+ ImmediateProgramSubtypingInfo immediateSubtypingInfo =
+ appView.enableWholeProgramOptimizations()
+ ? ImmediateProgramSubtypingInfo.createWithDeterministicOrder(
+ appView.withClassHierarchy())
+ : null;
+ new UndoConstructorInlining(appView, classMergerSharedData, immediateSubtypingInfo)
+ .runIfNecessary(groups, mode, executorService, timing);
+
+ // Merge classes.
+ List<ClassMerger> classMergers = createClassMergers(classMergerBuilders, lensBuilder);
ProfileCollectionAdditions profileCollectionAdditions =
ProfileCollectionAdditions.create(appView);
SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder =
@@ -158,7 +172,13 @@
appView.setHorizontallyMergedClasses(mergedClasses, mode);
HorizontalClassMergerGraphLens horizontalClassMergerGraphLens =
- createLens(classMergerSharedData, mergedClasses, lensBuilder, executorService, timing);
+ createLens(
+ classMergerSharedData,
+ immediateSubtypingInfo,
+ mergedClasses,
+ lensBuilder,
+ executorService,
+ timing);
profileCollectionAdditions =
profileCollectionAdditions.rewriteMethodReferences(
horizontalClassMergerGraphLens::getNextMethodToInvoke);
@@ -166,10 +186,10 @@
assert verifyNoCyclesInInterfaceHierarchies(appView, groups);
FieldAccessInfoCollectionModifier fieldAccessInfoCollectionModifier = null;
- if (mode.isRestrictedToAlphaRenaming()) {
- assert groups.stream().noneMatch(HorizontalMergeGroup::hasClassIdField);
- } else {
+ if (appView.enableWholeProgramOptimizations()) {
fieldAccessInfoCollectionModifier = createFieldAccessInfoCollectionModifier(groups);
+ } else {
+ assert groups.stream().noneMatch(HorizontalMergeGroup::hasClassIdField);
}
// Set the new graph lens before finalizing any synthetic code.
@@ -381,21 +401,34 @@
return initialGroups;
}
- /**
- * Prepare horizontal class merging by determining which virtual methods and constructors need to
- * be merged and how the merging should be performed.
- */
- private List<ClassMerger> initializeClassMergers(
- IRCodeProvider codeProvider,
- HorizontalClassMergerGraphLens.Builder lensBuilder,
- Collection<HorizontalMergeGroup> groups) {
- List<ClassMerger> classMergers = new ArrayList<>(groups.size());
+ private List<ClassMerger.Builder> createClassMergerBuilders(
+ IRCodeProvider codeProvider, Collection<HorizontalMergeGroup> groups) {
+ List<ClassMerger.Builder> classMergerBuilders = new ArrayList<>(groups.size());
for (HorizontalMergeGroup group : groups) {
assert group.isNonTrivial();
assert group.hasInstanceFieldMap();
assert group.hasTarget();
- classMergers.add(
- new ClassMerger.Builder(appView, codeProvider, group, mode).build(lensBuilder));
+ classMergerBuilders.add(new ClassMerger.Builder(appView, codeProvider, group, mode));
+ }
+ return classMergerBuilders;
+ }
+
+ private void initializeClassIdFields(List<ClassMerger.Builder> classMergerBuilders) {
+ for (ClassMerger.Builder classMergerBuilder : classMergerBuilders) {
+ classMergerBuilder.initializeVirtualMethodMergers().initializeClassIdField();
+ }
+ }
+
+ /**
+ * Prepare horizontal class merging by determining which virtual methods and constructors need to
+ * be merged and how the merging should be performed.
+ */
+ private List<ClassMerger> createClassMergers(
+ List<ClassMerger.Builder> classMergerBuilders,
+ HorizontalClassMergerGraphLens.Builder lensBuilder) {
+ List<ClassMerger> classMergers = new ArrayList<>(classMergerBuilders.size());
+ for (ClassMerger.Builder classMergerBuilder : classMergerBuilders) {
+ classMergers.add(classMergerBuilder.build(lensBuilder));
}
appView.dexItemFactory().clearTypeElementsCache();
return classMergers;
@@ -427,13 +460,14 @@
*/
private HorizontalClassMergerGraphLens createLens(
ClassMergerSharedData classMergerSharedData,
+ ImmediateProgramSubtypingInfo immediateSubtypingInfo,
HorizontallyMergedClasses mergedClasses,
HorizontalClassMergerGraphLens.Builder lensBuilder,
ExecutorService executorService,
Timing timing)
throws ExecutionException {
return new HorizontalClassMergerTreeFixer(
- appView, classMergerSharedData, mergedClasses, lensBuilder)
+ appView, classMergerSharedData, immediateSubtypingInfo, mergedClasses, lensBuilder)
.run(executorService, timing);
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
index 81d95ee..17bfc2b 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.horizontalclassmerging;
+import static com.android.tools.r8.ir.conversion.ExtraUnusedParameter.computeExtraUnusedParameters;
+
import com.android.tools.r8.classmerging.ClassMergerGraphLens;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedMember;
@@ -15,7 +17,9 @@
import com.android.tools.r8.graph.lens.FieldLookupResult;
import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.graph.lens.MethodLookupResult;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.code.InvokeType;
+import com.android.tools.r8.ir.conversion.ExtraConstantIntParameter;
import com.android.tools.r8.ir.conversion.ExtraParameter;
import com.android.tools.r8.utils.IterableUtils;
import com.android.tools.r8.utils.collections.BidirectionalManyToOneHashMap;
@@ -26,7 +30,6 @@
import com.android.tools.r8.utils.collections.MutableBidirectionalManyToOneRepresentativeMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Streams;
-import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
@@ -34,13 +37,13 @@
public class HorizontalClassMergerGraphLens extends ClassMergerGraphLens {
- private final Map<DexMethod, List<ExtraParameter>> methodExtraParameters;
+ private final Map<DexMethod, ExtraConstantIntParameter> methodExtraParameters;
private final HorizontallyMergedClasses mergedClasses;
private HorizontalClassMergerGraphLens(
AppView<?> appView,
HorizontallyMergedClasses mergedClasses,
- Map<DexMethod, List<ExtraParameter>> methodExtraParameters,
+ Map<DexMethod, ExtraConstantIntParameter> methodExtraParameters,
BidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap,
BidirectionalManyToOneMap<DexMethod, DexMethod> methodMap,
BidirectionalManyToOneRepresentativeMap<DexMethod, DexMethod> newMethodSignatures) {
@@ -116,18 +119,7 @@
return super.internalDescribeLookupMethod(previous, context, codeLens);
}
assert previous.hasReboundReference();
- List<ExtraParameter> extraParameters =
- methodExtraParameters.get(previous.getReboundReference());
- MethodLookupResult lookup = super.internalDescribeLookupMethod(previous, context, codeLens);
- if (extraParameters == null) {
- return lookup;
- }
- return MethodLookupResult.builder(this, codeLens)
- .setReboundReference(lookup.getReboundReference())
- .setReference(lookup.getReference())
- .setPrototypeChanges(lookup.getPrototypeChanges().withExtraParameters(extraParameters))
- .setType(lookup.getType())
- .build();
+ return super.internalDescribeLookupMethod(previous, context, codeLens);
}
@Override
@@ -147,6 +139,47 @@
.build();
}
+ @Override
+ protected RewrittenPrototypeDescription internalDescribePrototypeChanges(
+ RewrittenPrototypeDescription prototypeChanges,
+ DexMethod previousMethod,
+ DexMethod newMethod) {
+ if (newMethod.getArity() > previousMethod.getArity()) {
+ assert dexItemFactory().isConstructor(previousMethod);
+ RewrittenPrototypeDescription collisionResolution =
+ RewrittenPrototypeDescription.createForExtraParameters(
+ computeExtraUnusedParameters(previousMethod, newMethod));
+ ExtraConstantIntParameter extraParameter = methodExtraParameters.get(previousMethod);
+ if (extraParameter != null) {
+ List<ExtraParameter> extraParameters =
+ (List<ExtraParameter>) collisionResolution.getExtraParameters();
+ extraParameters.set(0, extraParameter);
+ }
+ return prototypeChanges.combine(collisionResolution);
+ }
+ assert newMethod.getArity() == previousMethod.getArity();
+ return prototypeChanges;
+ }
+
+ @Override
+ public RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(
+ DexMethod newMethod, GraphLens codeLens) {
+ if (this == codeLens) {
+ return getIdentityLens().lookupPrototypeChangesForMethodDefinition(newMethod, codeLens);
+ }
+ DexMethod previousMethod = getPreviousMethodSignature(newMethod);
+ RewrittenPrototypeDescription lookup =
+ getPrevious().lookupPrototypeChangesForMethodDefinition(previousMethod, codeLens);
+ if (newMethod.getArity() > previousMethod.getArity()) {
+ assert dexItemFactory().isConstructor(previousMethod);
+ RewrittenPrototypeDescription collisionResolution =
+ RewrittenPrototypeDescription.createForExtraParameters(
+ computeExtraUnusedParameters(previousMethod, newMethod));
+ return lookup.combine(collisionResolution);
+ }
+ return lookup;
+ }
+
public static class Builder
extends BuilderBase<HorizontalClassMergerGraphLens, HorizontallyMergedClasses> {
@@ -156,7 +189,7 @@
BidirectionalManyToOneHashMap.newIdentityHashMap();
private final MutableBidirectionalManyToOneRepresentativeMap<DexMethod, DexMethod>
newMethodSignatures = BidirectionalManyToOneRepresentativeHashMap.newIdentityHashMap();
- private final Map<DexMethod, List<ExtraParameter>> methodExtraParameters =
+ private final Map<DexMethod, ExtraConstantIntParameter> methodExtraParameters =
new IdentityHashMap<>();
private final MutableBidirectionalManyToOneMap<DexMethod, DexMethod> pendingMethodMapUpdates =
@@ -329,28 +362,11 @@
* where many constructors are merged into a single constructor. The synthesized constructor
* therefore does not have a unique reverse constructor.
*/
- void mapMergedConstructor(DexMethod from, DexMethod to, List<ExtraParameter> extraParameters) {
+ void mapMergedConstructor(
+ DexMethod from, DexMethod to, ExtraConstantIntParameter extraParameter) {
mapMethod(from, to);
- if (!extraParameters.isEmpty()) {
- methodExtraParameters.put(from, extraParameters);
- }
- }
-
- @Override
- public void addExtraParameters(
- DexMethod from, DexMethod to, List<? extends ExtraParameter> extraParameters) {
- Set<DexMethod> originalMethodSignatures = methodMap.getKeys(from);
- if (originalMethodSignatures.isEmpty()) {
- methodExtraParameters
- .computeIfAbsent(from, ignore -> new ArrayList<>(extraParameters.size()))
- .addAll(extraParameters);
- } else {
- for (DexMethod originalMethodSignature : originalMethodSignatures) {
- methodExtraParameters
- .computeIfAbsent(
- originalMethodSignature, ignore -> new ArrayList<>(extraParameters.size()))
- .addAll(extraParameters);
- }
+ if (extraParameter != null) {
+ methodExtraParameters.put(from, extraParameter);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerTreeFixer.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerTreeFixer.java
index b1859ae..794ca05 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerTreeFixer.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerTreeFixer.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.classmerging.ClassMergerSharedData;
import com.android.tools.r8.classmerging.ClassMergerTreeFixer;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ImmediateProgramSubtypingInfo;
import com.android.tools.r8.utils.Timing;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@@ -25,9 +26,10 @@
public HorizontalClassMergerTreeFixer(
AppView<?> appView,
ClassMergerSharedData classMergerSharedData,
+ ImmediateProgramSubtypingInfo immediateSubtypingInfo,
HorizontallyMergedClasses mergedClasses,
HorizontalClassMergerGraphLens.Builder lensBuilder) {
- super(appView, classMergerSharedData, lensBuilder, mergedClasses);
+ super(appView, classMergerSharedData, immediateSubtypingInfo, lensBuilder, mergedClasses);
}
/**
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java
index 05088a9..75deda3 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.horizontalclassmerging;
+import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
+
import com.android.tools.r8.cf.code.CfFrame;
import com.android.tools.r8.cf.code.CfInstanceFieldRead;
import com.android.tools.r8.cf.code.CfInstruction;
@@ -15,7 +17,6 @@
import com.android.tools.r8.cf.code.CfSwitch;
import com.android.tools.r8.cf.code.CfSwitch.Kind;
import com.android.tools.r8.cf.code.frame.FrameType;
-import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -24,9 +25,16 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.horizontalclassmerging.VirtualMethodMerger.SuperMethodReference;
+import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.code.IRMetadata;
+import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.code.ValueType;
+import com.android.tools.r8.lightir.LirBuilder;
import com.android.tools.r8.lightir.LirCode;
+import com.android.tools.r8.lightir.LirEncodingStrategy;
+import com.android.tools.r8.lightir.LirStrategy;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.IterableUtils;
import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
@@ -164,7 +172,117 @@
AppView<? extends AppInfoWithClassHierarchy> appView,
ProgramMethod method,
HorizontalClassMergerGraphLens lens) {
- throw new Unreachable();
+ LirEncodingStrategy<Value, Integer> strategy =
+ LirStrategy.getDefaultStrategy().getEncodingStrategy();
+ LirBuilder<Value, Integer> lirBuilder =
+ LirCode.builder(
+ method.getReference(),
+ method.getDefinition().isD8R8Synthesized(),
+ strategy,
+ appView.options())
+ .setMetadata(IRMetadata.unknown());
+
+ int instructionIndex = 0;
+ List<Value> argumentValues = new ArrayList<>();
+ TypeElement returnType =
+ method.getReturnType().isVoidType() ? null : method.getReturnType().toTypeElement(appView);
+
+ // Add receiver argument.
+ DexType receiverType = method.getHolderType();
+ TypeElement receiverTypeElement = receiverType.toTypeElement(appView, definitelyNotNull());
+ Value receiverValue = Value.createNoDebugLocal(instructionIndex, receiverTypeElement);
+ argumentValues.add(receiverValue);
+ strategy.defineValue(receiverValue, receiverValue.getNumber());
+ lirBuilder.addArgument(receiverValue.getNumber(), false);
+ instructionIndex++;
+
+ // Add non-receiver arguments.
+ for (; instructionIndex < method.getDefinition().getNumberOfArguments(); instructionIndex++) {
+ DexType argumentType = method.getArgumentType(instructionIndex);
+ TypeElement argumentTypeElement = argumentType.toTypeElement(appView);
+ Value argumentValue = Value.createNoDebugLocal(instructionIndex, argumentTypeElement);
+ argumentValues.add(argumentValue);
+ strategy.defineValue(argumentValue, argumentValue.getNumber());
+ lirBuilder.addArgument(argumentValue.getNumber(), argumentType.isBooleanType());
+ }
+
+ // Read class id field from receiver.
+ TypeElement classIdValueType = TypeElement.getInt();
+ Value classIdValue = Value.createNoDebugLocal(instructionIndex, classIdValueType);
+ strategy.defineValue(classIdValue, classIdValue.getNumber());
+ lirBuilder.addInstanceGet(classIdField, receiverValue);
+ instructionIndex++;
+
+ // Emit switch.
+ IntBidirectionalIterator classIdIterator = mappedMethods.keySet().iterator();
+ int[] keys = new int[mappedMethods.size() - BooleanUtils.intValue(superMethod == null)];
+ int[] targets = new int[keys.length];
+ int nextTarget = instructionIndex - argumentValues.size() + 3;
+ for (int i = 0; i < keys.length; i++) {
+ keys[i] = classIdIterator.nextInt();
+ targets[i] = nextTarget;
+ nextTarget += 2;
+ }
+ lirBuilder.addIntSwitch(classIdValue, keys, targets);
+ instructionIndex++;
+
+ // Emit switch fallthrough.
+ if (superMethod == null) {
+ DexMethod fallthroughTarget =
+ lens.getNextMethodSignature(mappedMethods.get(mappedMethods.lastIntKey()));
+ if (method.getHolder().isInterface()) {
+ lirBuilder.addInvokeInterface(fallthroughTarget, argumentValues);
+ } else {
+ lirBuilder.addInvokeVirtual(fallthroughTarget, argumentValues);
+ }
+ } else {
+ DexMethod reboundFallthroughTarget =
+ lens.lookupInvokeSuper(superMethod.getReboundReference(), method).getReference();
+ DexMethod fallthroughTarget =
+ reboundFallthroughTarget.withHolder(
+ lens.getNextClassType(superMethod.getReference().getHolderType()),
+ appView.dexItemFactory());
+ lirBuilder.addInvokeSuper(fallthroughTarget, argumentValues, false);
+ }
+ if (method.getReturnType().isVoidType()) {
+ lirBuilder.addReturnVoid();
+ } else {
+ Value returnValue = Value.createNoDebugLocal(instructionIndex, returnType);
+ strategy.defineValue(returnValue, returnValue.getNumber());
+ lirBuilder.addReturn(returnValue);
+ }
+ instructionIndex += 2;
+
+ // Emit switch cases.
+ for (int classId : keys) {
+ DexMethod target = lens.getNextMethodSignature(mappedMethods.get(classId));
+ if (method.getHolder().isInterface()) {
+ lirBuilder.addInvokeInterface(target, argumentValues);
+ } else {
+ lirBuilder.addInvokeVirtual(target, argumentValues);
+ }
+ if (method.getReturnType().isVoidType()) {
+ lirBuilder.addReturnVoid();
+ } else {
+ Value returnValue = Value.createNoDebugLocal(instructionIndex, returnType);
+ strategy.defineValue(returnValue, returnValue.getNumber());
+ lirBuilder.addReturn(returnValue);
+ }
+ instructionIndex += 2;
+ }
+
+ return new LirCode<>(lirBuilder.build()) {
+
+ @Override
+ public boolean hasExplicitCodeLens() {
+ return true;
+ }
+
+ @Override
+ public GraphLens getCodeLens(AppView<?> appView) {
+ return lens;
+ }
+ };
}
private static CfFrame createCfFrameForSwitchCase(ProgramMethod representative, int localsSize) {
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerAnalysis.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerAnalysis.java
index f49af82..96aeb10 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerAnalysis.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerAnalysis.java
@@ -150,7 +150,10 @@
// TODO(b/189296638): Consider allowing constructor forwarding.
if (!lensRewrittenInvokedMethod.isInstanceInitializer(appView.dexItemFactory())
- || lensRewrittenInvokedMethod.getHolderType() != group.getSuperType()) {
+ || !appView
+ .appInfo()
+ .isSubtype(
+ group.getSuperType(), lensRewrittenInvokedMethod.getHolderType())) {
return invalid();
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerDescription.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerDescription.java
index dc5f15e..a543580 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerDescription.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerDescription.java
@@ -72,7 +72,7 @@
*
* @param originalMethodReference the original reference of the representative method
*/
- public IncompleteMergedInstanceInitializerCode createCfCode(
+ public IncompleteMergedInstanceInitializerCode createCode(
DexMethod originalMethodReference,
HorizontalMergeGroup group,
boolean hasClassId,
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
index 2a87bb4..7f25de0 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
@@ -22,7 +22,6 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.horizontalclassmerging.code.ConstructorEntryPointSynthesizedCode;
import com.android.tools.r8.ir.conversion.ExtraConstantIntParameter;
-import com.android.tools.r8.ir.conversion.ExtraParameter;
import com.android.tools.r8.ir.conversion.ExtraUnusedParameter;
import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
import com.android.tools.r8.utils.ArrayUtils;
@@ -30,7 +29,6 @@
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.SetUtils;
import com.android.tools.r8.utils.structural.Ordered;
-import com.google.common.collect.ImmutableList;
import it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
@@ -275,11 +273,8 @@
boolean needsClassId,
int extraNulls) {
if (hasInstanceInitializerDescription()) {
- return instanceInitializerDescription.createCfCode(
- getOriginalMethodReference(),
- group,
- needsClassId,
- extraNulls);
+ return instanceInitializerDescription.createCode(
+ getOriginalMethodReference(), group, needsClassId, extraNulls);
}
assert useSyntheticMethod();
return new ConstructorEntryPointSynthesizedCode(
@@ -305,28 +300,19 @@
boolean needsClassId =
instanceInitializers.size() > 1
&& (!hasInstanceInitializerDescription() || group.hasClassIdField());
- assert !mode.isRestrictedToAlphaRenamingInR8() || !needsClassId;
DexMethod newMethodReferenceTemplate = getNewMethodReference(representative, needsClassId);
- assert !mode.isRestrictedToAlphaRenamingInR8()
- || classMethodsBuilder.isFresh(newMethodReferenceTemplate);
DexMethod newMethodReference =
dexItemFactory.createInstanceInitializerWithFreshProto(
newMethodReferenceTemplate,
- mode.isRestrictedToAlphaRenamingInR8()
- ? ImmutableList.of()
- : classMergerSharedData.getExtraUnusedArgumentTypes(),
+ classMergerSharedData.getExtraUnusedArgumentTypes(),
classMethodsBuilder::isFresh);
// Compute the extra unused null parameters.
List<ExtraUnusedParameter> extraUnusedParameters =
computeExtraUnusedParameters(newMethodReferenceTemplate, newMethodReference);
- // Verify that the merge is a simple renaming in the final round of merging.
- assert !mode.isRestrictedToAlphaRenamingInR8()
- || newMethodReference == newMethodReferenceTemplate;
-
// Move instance initializers to target class.
if (hasInstanceInitializerDescription()) {
lensBuilder.moveMethods(instanceInitializers, newMethodReference);
@@ -360,14 +346,13 @@
// Map each of the instance initializers to the new instance initializer in the graph lens.
for (ProgramMethod instanceInitializer : instanceInitializers) {
- List<ExtraParameter> extraParameters = new ArrayList<>();
- if (needsClassId) {
- int classIdentifier = classIdentifiers.getInt(instanceInitializer.getHolderType());
- extraParameters.add(new ExtraConstantIntParameter(classIdentifier));
- }
- extraParameters.addAll(extraUnusedParameters);
+ ExtraConstantIntParameter extraParameter =
+ needsClassId
+ ? new ExtraConstantIntParameter(
+ classIdentifiers.getInt(instanceInitializer.getHolderType()))
+ : null;
lensBuilder.mapMergedConstructor(
- instanceInitializer.getReference(), newMethodReference, extraParameters);
+ instanceInitializer.getReference(), newMethodReference, extraParameter);
}
DexEncodedMethod representativeMethod = representative.getDefinition();
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
index 5ea7df7..75cc55c 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
@@ -23,7 +23,6 @@
import com.android.tools.r8.horizontalclassmerging.policies.NoClassAnnotationCollisions;
import com.android.tools.r8.horizontalclassmerging.policies.NoClassInitializerCycles;
import com.android.tools.r8.horizontalclassmerging.policies.NoClassInitializerWithObservableSideEffects;
-import com.android.tools.r8.horizontalclassmerging.policies.NoConstructorCollisions;
import com.android.tools.r8.horizontalclassmerging.policies.NoDeadEnumLiteMaps;
import com.android.tools.r8.horizontalclassmerging.policies.NoDeadLocks;
import com.android.tools.r8.horizontalclassmerging.policies.NoDefaultInterfaceMethodCollisions;
@@ -35,7 +34,6 @@
import com.android.tools.r8.horizontalclassmerging.policies.NoIndirectRuntimeTypeChecks;
import com.android.tools.r8.horizontalclassmerging.policies.NoInnerClasses;
import com.android.tools.r8.horizontalclassmerging.policies.NoInstanceFieldAnnotations;
-import com.android.tools.r8.horizontalclassmerging.policies.NoInstanceInitializerMerging;
import com.android.tools.r8.horizontalclassmerging.policies.NoInterfaces;
import com.android.tools.r8.horizontalclassmerging.policies.NoKeepRules;
import com.android.tools.r8.horizontalclassmerging.policies.NoKotlinMetadata;
@@ -44,7 +42,6 @@
import com.android.tools.r8.horizontalclassmerging.policies.NoResourceClasses;
import com.android.tools.r8.horizontalclassmerging.policies.NoServiceLoaders;
import com.android.tools.r8.horizontalclassmerging.policies.NoVerticallyMergedClasses;
-import com.android.tools.r8.horizontalclassmerging.policies.NoVirtualMethodMerging;
import com.android.tools.r8.horizontalclassmerging.policies.NoWeakerAccessPrivileges;
import com.android.tools.r8.horizontalclassmerging.policies.NotMatchedByNoHorizontalClassMerging;
import com.android.tools.r8.horizontalclassmerging.policies.NotTwoInitsWithMonitors;
@@ -74,12 +71,10 @@
public static List<Policy> getPolicies(
AppView<?> appView,
- IRCodeProvider codeProvider,
ClassMergerMode mode,
RuntimeTypeCheckInfo runtimeTypeCheckInfo) {
if (appView.hasClassHierarchy()) {
- return getPoliciesForR8(
- appView.withClassHierarchy(), codeProvider, mode, runtimeTypeCheckInfo);
+ return getPoliciesForR8(appView.withClassHierarchy(), mode, runtimeTypeCheckInfo);
} else {
return getPoliciesForD8(appView.withoutClassHierarchy(), mode);
}
@@ -99,13 +94,12 @@
private static List<Policy> getPoliciesForR8(
AppView<? extends AppInfoWithClassHierarchy> appView,
- IRCodeProvider codeProvider,
ClassMergerMode mode,
RuntimeTypeCheckInfo runtimeTypeCheckInfo) {
List<Policy> policies =
ImmutableList.<Policy>builder()
.addAll(getSingleClassPolicies(appView, mode, runtimeTypeCheckInfo))
- .addAll(getMultiClassPolicies(appView, codeProvider, mode, runtimeTypeCheckInfo))
+ .addAll(getMultiClassPolicies(appView, mode, runtimeTypeCheckInfo))
.build();
policies = appView.options().testing.horizontalClassMergingPolicyRewriter.apply(policies);
assert verifyPolicyOrderingConstraints(policies);
@@ -221,44 +215,24 @@
private static List<Policy> getMultiClassPolicies(
AppView<? extends AppInfoWithClassHierarchy> appView,
- IRCodeProvider codeProvider,
ClassMergerMode mode,
RuntimeTypeCheckInfo runtimeTypeCheckInfo) {
ImmutableList.Builder<Policy> builder = ImmutableList.builder();
-
addRequiredMultiClassPolicies(appView, mode, runtimeTypeCheckInfo, builder);
-
if (!appView.options().horizontalClassMergerOptions().isRestrictedToSynthetics()) {
AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
addMultiClassPoliciesForMergingNonSyntheticClasses(appViewWithLiveness, builder);
}
-
- if (mode.isRestrictedToAlphaRenamingInR8()) {
- builder.add(
- new NoVirtualMethodMerging(appView, mode), new NoConstructorCollisions(appView, mode));
- } else {
- AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
- if (mode.isInitial()) {
- builder.add(new AllInstantiatedOrUninstantiated(appViewWithLiveness, mode));
- }
- builder.add(
- new PreserveMethodCharacteristics(appViewWithLiveness, mode),
- new MinimizeInstanceFieldCasts());
+ if (mode.isInitial()) {
+ assert appView.hasLiveness();
+ builder.add(new AllInstantiatedOrUninstantiated(appView.withLiveness()));
}
-
+ if (appView.hasLiveness()) {
+ builder.add(new PreserveMethodCharacteristics(appView.withLiveness(), mode));
+ }
+ builder.add(new MinimizeInstanceFieldCasts());
addMultiClassPoliciesForInterfaceMerging(appView, mode, builder);
-
- builder.add(new LimitClassGroups(appView));
-
- if (mode.isRestrictedToAlphaRenamingInR8()) {
- // This needs to reason about equivalence of instance initializers, which relies on the
- // mapping from instance fields on source classes to the instance fields on target classes.
- // This policy therefore selects a target for each merge group and creates the mapping for
- // instance fields. For this reason we run this policy in the very end.
- builder.add(new NoInstanceInitializerMerging(appView, codeProvider, mode));
- }
-
- return builder.add(new FinalizeMergeGroup(appView, mode)).build();
+ return builder.add(new LimitClassGroups(appView), new FinalizeMergeGroup(appView)).build();
}
private static List<? extends Policy> getMultiClassPoliciesForD8(
@@ -275,7 +249,7 @@
new NoDifferentApiReferenceLevel(appView),
new LimitClassGroups(appView));
assert verifyMultiClassPoliciesIrrelevantForMergingSyntheticsInD8(appView, mode, builder);
- builder.add(new FinalizeMergeGroup(appView, mode));
+ builder.add(new FinalizeMergeGroup(appView));
return builder.build();
}
@@ -292,12 +266,12 @@
new NoClassAnnotationCollisions(),
new SameFeatureSplit(appView),
new SameStartupPartition(appView),
- new SameInstanceFields(appView, mode),
+ new SameInstanceFields(appView),
new SameMainDexGroup(appView),
new SameNestHost(appView),
new SameParentClass(),
new SyntheticItemsPolicy(appView, mode),
- new RespectPackageBoundaries(appView, mode),
+ new RespectPackageBoundaries(appView),
new NoDifferentApiReferenceLevel(appView),
new NoIndirectRuntimeTypeChecks(appView, runtimeTypeCheckInfo),
new NoWeakerAccessPrivileges(appView, immediateSubtypingInfo),
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/SubtypingForrestForClasses.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/SubtypingForrestForClasses.java
deleted file mode 100644
index afb02cd..0000000
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/SubtypingForrestForClasses.java
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright (c) 2020, 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.horizontalclassmerging;
-
-import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexProgramClass;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.IdentityHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.function.BiFunction;
-
-/**
- * Calculates the subtyping forrest for all classes. Unlike {@link
- * com.android.tools.r8.graph.SubtypingInfo}, interfaces are not included in this subtyping
- * information and only the immediate parents are stored (i.e. the transitive parents are not
- * calculated). In the following example graph, the roots are A, E and G, and each edge indicates an
- * entry in {@link SubtypingForrestForClasses#subtypeMap} going from the parent to an entry in the
- * collection of children. <code>
- * A E G
- * / \ |
- * B C F
- * |
- * D
- * </code>
- */
-public class SubtypingForrestForClasses {
-
- private final AppView<? extends AppInfoWithClassHierarchy> appView;
- private final Collection<DexProgramClass> roots = new ArrayList<>();
- private final Map<DexProgramClass, List<DexProgramClass>> subtypeMap = new IdentityHashMap<>();
-
- public SubtypingForrestForClasses(AppView<? extends AppInfoWithClassHierarchy> appView) {
- this.appView = appView;
- calculateSubtyping(appView.appInfo().classes());
- }
-
- private DexProgramClass superClass(DexProgramClass clazz) {
- return appView.programDefinitionFor(clazz.superType, clazz);
- }
-
- private void calculateSubtyping(Iterable<DexProgramClass> classes) {
- classes.forEach(this::calculateSubtyping);
- }
-
- private void calculateSubtyping(DexProgramClass clazz) {
- if (clazz.isInterface()) {
- return;
- }
- DexProgramClass superClass = superClass(clazz);
- if (superClass == null) {
- roots.add(clazz);
- } else {
- subtypeMap.computeIfAbsent(superClass, ignore -> new ArrayList<>()).add(clazz);
- }
- }
-
- public Collection<DexProgramClass> getProgramRoots() {
- return roots;
- }
-
- public Collection<DexProgramClass> getSubtypesFor(DexProgramClass clazz) {
- return subtypeMap.getOrDefault(clazz, Collections.emptyList());
- }
-
- public <T> T traverseNodeDepthFirst(
- DexProgramClass clazz, T state, BiFunction<DexProgramClass, T, T> consumer) {
- T newState = consumer.apply(clazz, state);
- getSubtypesFor(clazz).forEach(subClazz -> traverseNodeDepthFirst(subClazz, newState, consumer));
- return newState;
- }
-}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java
index 6b87383..d872901 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadataProvider;
import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.horizontalclassmerging.ConstructorEntryPoint;
@@ -24,11 +25,13 @@
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Position.SyntheticPosition;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.IRToLirFinalizer;
import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.conversion.SourceCode;
import com.android.tools.r8.lightir.LirCode;
import com.android.tools.r8.utils.RetracerForCodePrinting;
+import com.android.tools.r8.utils.Timing;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
@@ -94,7 +97,25 @@
AppView<? extends AppInfoWithClassHierarchy> appView,
ProgramMethod method,
HorizontalClassMergerGraphLens lens) {
- throw new Unreachable();
+ for (Int2ReferenceMap.Entry<DexMethod> entry : typeConstructors.int2ReferenceEntrySet()) {
+ entry.setValue(lens.getNextMethodSignature(entry.getValue()));
+ }
+ IRCode irCode = buildIR(method, appView);
+ LirCode<Integer> lirCode =
+ new IRToLirFinalizer(appView)
+ .finalizeCode(irCode, BytecodeMetadataProvider.empty(), Timing.empty());
+ return new LirCode<>(lirCode) {
+
+ @Override
+ public boolean hasExplicitCodeLens() {
+ return true;
+ }
+
+ @Override
+ public GraphLens getCodeLens(AppView<?> appView) {
+ return lens;
+ }
+ };
}
@Override
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/AllInstantiatedOrUninstantiated.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/AllInstantiatedOrUninstantiated.java
index e5839b6..d118b1d 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/AllInstantiatedOrUninstantiated.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/AllInstantiatedOrUninstantiated.java
@@ -4,22 +4,18 @@
package com.android.tools.r8.horizontalclassmerging.policies;
-import com.android.tools.r8.classmerging.ClassMergerMode;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.horizontalclassmerging.MultiClassSameReferencePolicy;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+// This policy is only used to prevent that horizontal class merging regresses the
+// uninstantiated type optimization.
public class AllInstantiatedOrUninstantiated extends MultiClassSameReferencePolicy<Boolean> {
private final AppView<AppInfoWithLiveness> appView;
- public AllInstantiatedOrUninstantiated(
- AppView<AppInfoWithLiveness> appView, ClassMergerMode mode) {
- // This policy is only used to prevent that horizontal class merging regresses the
- // uninstantiated type optimization. Since there won't be any IR processing after the final
- // round of horizontal class merging, there is no need to use the policy.
- assert mode.isInitial();
+ public AllInstantiatedOrUninstantiated(AppView<AppInfoWithLiveness> appView) {
this.appView = appView;
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/FinalizeMergeGroup.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/FinalizeMergeGroup.java
index c70a156..0d32b98 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/FinalizeMergeGroup.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/FinalizeMergeGroup.java
@@ -4,16 +4,12 @@
package com.android.tools.r8.horizontalclassmerging.policies;
-import com.android.tools.r8.classmerging.ClassMergerMode;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.horizontalclassmerging.HorizontalMergeGroup;
import com.android.tools.r8.horizontalclassmerging.MultiClassPolicy;
import com.android.tools.r8.utils.ListUtils;
-import com.android.tools.r8.utils.SetUtils;
import com.android.tools.r8.utils.collections.EmptyBidirectionalOneToOneMap;
import java.util.Collection;
-import java.util.Set;
/**
* Identifies when instance initializer merging is required and bails out. This is needed to ensure
@@ -26,24 +22,16 @@
public class FinalizeMergeGroup extends MultiClassPolicy {
private final AppView<?> appView;
- private final ClassMergerMode mode;
- public FinalizeMergeGroup(AppView<?> appView, ClassMergerMode mode) {
+ public FinalizeMergeGroup(AppView<?> appView) {
this.appView = appView;
- this.mode = mode;
}
@Override
public Collection<HorizontalMergeGroup> apply(HorizontalMergeGroup group) {
if (appView.enableWholeProgramOptimizations()) {
- if (group.isInterfaceGroup() || !mode.isRestrictedToAlphaRenamingInR8()) {
- group.selectTarget(appView);
- group.selectInstanceFieldMap(appView.withClassHierarchy());
- } else {
- // In the final round of merging each group should be finalized by the
- // NoInstanceInitializerMerging policy.
- assert verifyAlreadyFinalized(group);
- }
+ group.selectTarget(appView);
+ group.selectInstanceFieldMap(appView.withClassHierarchy());
} else {
assert !group.hasTarget();
assert !group.hasInstanceFieldMap();
@@ -62,21 +50,4 @@
public boolean isIdentityForInterfaceGroups() {
return true;
}
-
- private boolean verifyAlreadyFinalized(HorizontalMergeGroup group) {
- assert group.hasTarget();
- assert group.getClasses().contains(group.getTarget());
- assert group.hasInstanceFieldMap();
- Set<DexType> types =
- SetUtils.newIdentityHashSet(
- builder -> group.forEach(clazz -> builder.accept(clazz.getType())));
- group
- .getInstanceFieldMap()
- .forEach(
- (sourceField, targetField) -> {
- assert types.contains(sourceField.getHolderType());
- assert types.contains(targetField.getHolderType());
- });
- return true;
- }
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoConstructorCollisions.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoConstructorCollisions.java
deleted file mode 100644
index c1d9320..0000000
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoConstructorCollisions.java
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright (c) 2020, 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.horizontalclassmerging.policies;
-
-import com.android.tools.r8.classmerging.ClassMergerMode;
-import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.horizontalclassmerging.HorizontalMergeGroup;
-import com.android.tools.r8.horizontalclassmerging.MultiClassPolicyWithPreprocessing;
-import com.android.tools.r8.utils.ArrayUtils;
-import com.android.tools.r8.utils.IterableUtils;
-import com.android.tools.r8.utils.ListUtils;
-import com.android.tools.r8.utils.WorkList;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.IdentityHashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ExecutorService;
-
-/**
- * In the final round, we're not allowed to resolve constructor collisions by appending null
- * arguments to constructor calls.
- *
- * <p>As an example, if a class in the program declares the constructors {@code <init>(A)} and
- * {@code <init>(B)}, the classes A and B must not be merged.
- *
- * <p>To avoid collisions of this kind, we run over all the classes in the program, and apply the
- * current set of merge groups to the constructor signatures of each class. Then, in case of a
- * collision, we extract all the mapped types from the constructor signatures, and prevent merging
- * of these types.
- */
-public class NoConstructorCollisions extends MultiClassPolicyWithPreprocessing<Set<DexType>> {
-
- private final AppView<? extends AppInfoWithClassHierarchy> appView;
- private final DexItemFactory dexItemFactory;
-
- public NoConstructorCollisions(
- AppView<? extends AppInfoWithClassHierarchy> appView, ClassMergerMode mode) {
- assert mode.isRestrictedToAlphaRenamingInR8();
- this.appView = appView;
- this.dexItemFactory = appView.dexItemFactory();
- }
-
- /**
- * Removes the classes in {@param collisionResolution} from {@param group}, and returns the new
- * filtered group.
- */
- @Override
- public Collection<HorizontalMergeGroup> apply(
- HorizontalMergeGroup group, Set<DexType> collisionResolution) {
- HorizontalMergeGroup newGroup =
- new HorizontalMergeGroup(
- Iterables.filter(group, clazz -> !collisionResolution.contains(clazz.getType())));
- return newGroup.isTrivial() ? Collections.emptyList() : ListUtils.newLinkedList(newGroup);
- }
-
- /**
- * Computes the set of classes that must not be merged, because the merging of these classes could
- * lead to constructor collisions.
- */
- @Override
- public Set<DexType> preprocess(
- Collection<HorizontalMergeGroup> groups, ExecutorService executorService) {
- // Build a mapping from types to groups.
- Map<DexType, HorizontalMergeGroup> groupsByType = new IdentityHashMap<>();
- for (HorizontalMergeGroup group : groups) {
- for (DexProgramClass clazz : group) {
- groupsByType.put(clazz.getType(), group);
- }
- }
-
- // Find the set of types that must not be merged, because they could lead to a constructor
- // collision.
- Set<DexType> collisionResolution = Sets.newIdentityHashSet();
- // Iterate over all the instance initializers of the current class. If the current class is in
- // a merge group, we must include all constructors of the entire merge group.
- WorkList.newIdentityWorkList(appView.appInfo().classes())
- .process(
- (current, workList) -> {
- Iterable<DexProgramClass> group =
- groupsByType.containsKey(current.getType())
- ? groupsByType.get(current.getType())
- : IterableUtils.singleton(current);
- Set<DexMethod> seen = Sets.newIdentityHashSet();
- for (DexProgramClass clazz : group) {
- for (DexEncodedMethod method :
- clazz.directMethods(DexEncodedMethod::isInstanceInitializer)) {
- // Rewrite the constructor reference using the current merge groups.
- DexMethod newReference = rewriteReference(method.getReference(), groupsByType);
- if (!seen.add(newReference)) {
- // Found a collision. Block all referenced types from being merged.
- for (DexType type : method.getProto().getBaseTypes(dexItemFactory)) {
- if (type.isClassType() && groupsByType.containsKey(type)) {
- collisionResolution.add(type);
- }
- }
- }
- }
- }
- workList.markAsSeen(group);
- });
- return collisionResolution;
- }
-
- private DexProto rewriteProto(DexProto proto, Map<DexType, HorizontalMergeGroup> groups) {
- DexType[] parameters =
- ArrayUtils.map(
- proto.getParameters().values,
- parameter -> rewriteType(parameter, groups),
- DexType.EMPTY_ARRAY);
- return dexItemFactory.createProto(rewriteType(proto.getReturnType(), groups), parameters);
- }
-
- private DexMethod rewriteReference(DexMethod method, Map<DexType, HorizontalMergeGroup> groups) {
- return dexItemFactory.createMethod(
- rewriteType(method.getHolderType(), groups),
- rewriteProto(method.getProto(), groups),
- method.getName());
- }
-
- @SuppressWarnings("ReferenceEquality")
- private DexType rewriteType(DexType type, Map<DexType, HorizontalMergeGroup> groups) {
- if (type.isArrayType()) {
- DexType baseType = type.toBaseType(dexItemFactory);
- DexType rewrittenBaseType = rewriteType(baseType, groups);
- if (rewrittenBaseType == baseType) {
- return type;
- }
- return type.replaceBaseType(rewrittenBaseType, dexItemFactory);
- }
- if (type.isClassType()) {
- if (!groups.containsKey(type)) {
- return type;
- }
- return groups.get(type).getClasses().getFirst().getType();
- }
- assert type.isPrimitiveType() || type.isVoidType();
- return type;
- }
-
- @Override
- public String getName() {
- return "NoConstructorCollisions";
- }
-}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInstanceInitializerMerging.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInstanceInitializerMerging.java
deleted file mode 100644
index dffdc02..0000000
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInstanceInitializerMerging.java
+++ /dev/null
@@ -1,346 +0,0 @@
-// Copyright (c) 2020, 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.horizontalclassmerging.policies;
-
-import static com.android.tools.r8.utils.MapUtils.ignoreKey;
-
-import com.android.tools.r8.classmerging.ClassMergerMode;
-import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexMethodSignature;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.DexTypeList;
-import com.android.tools.r8.graph.MethodAccessInfoCollection;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.horizontalclassmerging.ClassInstanceFieldsMerger;
-import com.android.tools.r8.horizontalclassmerging.HorizontalMergeGroup;
-import com.android.tools.r8.horizontalclassmerging.IRCodeProvider;
-import com.android.tools.r8.horizontalclassmerging.InstanceInitializerAnalysis;
-import com.android.tools.r8.horizontalclassmerging.InstanceInitializerAnalysis.AbsentInstanceInitializer;
-import com.android.tools.r8.horizontalclassmerging.InstanceInitializerAnalysis.InstanceInitializer;
-import com.android.tools.r8.horizontalclassmerging.InstanceInitializerAnalysis.PresentInstanceInitializer;
-import com.android.tools.r8.horizontalclassmerging.InstanceInitializerDescription;
-import com.android.tools.r8.horizontalclassmerging.MultiClassPolicyWithPreprocessing;
-import com.android.tools.r8.utils.IterableUtils;
-import com.android.tools.r8.utils.ListUtils;
-import com.android.tools.r8.utils.MapUtils;
-import com.android.tools.r8.utils.SetUtils;
-import com.android.tools.r8.utils.collections.BidirectionalManyToOneHashMap;
-import com.android.tools.r8.utils.collections.MutableBidirectionalManyToOneMap;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.IdentityHashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.ExecutorService;
-import java.util.function.Function;
-
-/**
- * Identifies when instance initializer merging is required and bails out. This is needed to ensure
- * that we don't need to append extra null arguments at constructor call sites, such that the result
- * of the final round of class merging can be described as a renaming only.
- *
- * <p>This policy requires that all instance initializers with the same signature (relaxed, by
- * converting references types to java.lang.Object) have the same behavior.
- */
-public class NoInstanceInitializerMerging
- extends MultiClassPolicyWithPreprocessing<Map<DexProgramClass, Set<DexMethod>>> {
-
- private final AppView<? extends AppInfoWithClassHierarchy> appView;
- private final IRCodeProvider codeProvider;
-
- public NoInstanceInitializerMerging(
- AppView<? extends AppInfoWithClassHierarchy> appView,
- IRCodeProvider codeProvider,
- ClassMergerMode mode) {
- assert mode.isRestrictedToAlphaRenamingInR8();
- this.appView = appView;
- this.codeProvider = codeProvider;
- }
-
- @Override
- @SuppressWarnings("MixedMutabilityReturnType")
- public Map<DexProgramClass, Set<DexMethod>> preprocess(
- Collection<HorizontalMergeGroup> groups, ExecutorService executorService) {
- if (!appView.options().canHaveNonReboundConstructorInvoke()) {
- return Collections.emptyMap();
- }
-
- if (appView.hasLiveness()) {
- DexItemFactory dexItemFactory = appView.dexItemFactory();
- MethodAccessInfoCollection methodAccessInfoCollection =
- appView.appInfoWithLiveness().getMethodAccessInfoCollection();
-
- // Compute a mapping for the merge candidates to efficiently determine if a given type is a
- // merge candidate.
- Map<DexType, DexProgramClass> mergeCandidates =
- MapUtils.newImmutableMap(
- builder ->
- IterableUtils.flatten(groups)
- .forEach(
- mergeCandidate -> builder.put(mergeCandidate.getType(), mergeCandidate)));
-
- // Compute a mapping from merge candidates to the constructors that have been removed by
- // constructor shrinking.
- return MapUtils.newIdentityHashMap(
- builder ->
- methodAccessInfoCollection.forEachDirectInvoke(
- (method, contexts) -> {
- DexProgramClass mergeCandidateHolder =
- mergeCandidates.get(method.getHolderType());
- if (mergeCandidateHolder != null
- && method.isInstanceInitializer(dexItemFactory)
- && mergeCandidateHolder.getMethodCollection().getMethod(method) == null) {
- builder
- .computeIfAbsent(
- mergeCandidateHolder, ignoreKey(Sets::newIdentityHashSet))
- .add(method);
- }
- }));
- }
-
- // Constructor shrinking is disabled when shrinking is disabled.
- assert !appView.options().isShrinking();
- return Collections.emptyMap();
- }
-
- @Override
- @SuppressWarnings("MixedMutabilityReturnType")
- public Collection<HorizontalMergeGroup> apply(
- HorizontalMergeGroup group, Map<DexProgramClass, Set<DexMethod>> absentInstanceInitializers) {
- assert !group.hasTarget();
- assert !group.hasInstanceFieldMap();
-
- if (group.isInterfaceGroup()) {
- return ListUtils.newLinkedList(group);
- }
-
- // When we merge equivalent instance initializers with different protos, we find the least upper
- // bound of each parameter type. As a result of this, the final instance initializer signatures
- // are not known until all instance initializers in the group are known. Therefore, we disallow
- // merging of classes that have multiple methods with the same relaxed method signature (where
- // reference parameters are converted to java.lang.Object), to ensure that merging will result
- // in a simple renaming (specifically, we must not need to append null arguments to constructor
- // calls due to constructor collisions).
- group.removeIf(
- clazz ->
- hasMultipleInstanceInitializersWithSameRelaxedSignature(
- clazz, absentInstanceInitializers));
-
- if (group.isEmpty()) {
- return Collections.emptyList();
- }
-
- // We want to allow merging of equivalent instance initializers. Equivalence depends on the
- // mapping of instance fields, so we must compute this mapping now.
- group.selectTarget(appView);
- group.selectInstanceFieldMap(appView);
-
- Map<HorizontalMergeGroup, Map<DexMethodSignature, InstanceInitializer>> newGroups =
- new LinkedHashMap<>();
-
- // Caching of instance initializer descriptions, which are used to determine equivalence.
- // TODO(b/181846319): Make this cache available to the instance initializer merger so that we
- // don't reanalyze instance initializers.
- Map<DexMethod, Optional<InstanceInitializerDescription>> instanceInitializerDescriptions =
- new IdentityHashMap<>();
- Function<InstanceInitializer, Optional<InstanceInitializerDescription>>
- instanceInitializerDescriptionProvider =
- instanceInitializer ->
- getOrComputeInstanceInitializerDescription(
- group, instanceInitializer, instanceInitializerDescriptions);
-
- // Partition group into smaller groups where there are no (non-equivalent) instance initializer
- // collisions.
- for (DexProgramClass clazz : group) {
- HorizontalMergeGroup newGroup = null;
- Map<DexMethodSignature, InstanceInitializer> classInstanceInitializers =
- getInstanceInitializersByRelaxedSignature(clazz, absentInstanceInitializers);
- for (Entry<HorizontalMergeGroup, Map<DexMethodSignature, InstanceInitializer>> entry :
- newGroups.entrySet()) {
- HorizontalMergeGroup candidateGroup = entry.getKey();
- Map<DexMethodSignature, InstanceInitializer> groupInstanceInitializers = entry.getValue();
- if (canAddClassToGroup(
- classInstanceInitializers,
- groupInstanceInitializers,
- instanceInitializerDescriptionProvider)) {
- newGroup = candidateGroup;
- classInstanceInitializers.forEach(groupInstanceInitializers::put);
- break;
- }
- }
- if (newGroup != null) {
- newGroup.add(clazz);
- } else {
- newGroups.put(new HorizontalMergeGroup(clazz), classInstanceInitializers);
- }
- }
-
- // Remove trivial groups and finalize the newly created groups.
- Collection<HorizontalMergeGroup> newNonTrivialGroups = removeTrivialGroups(newGroups.keySet());
- setInstanceFieldMaps(newNonTrivialGroups, group);
- return newNonTrivialGroups;
- }
-
- private boolean canAddClassToGroup(
- Map<DexMethodSignature, InstanceInitializer> classInstanceInitializers,
- Map<DexMethodSignature, InstanceInitializer> groupInstanceInitializers,
- Function<InstanceInitializer, Optional<InstanceInitializerDescription>>
- instanceInitializerDescriptionProvider) {
- for (Entry<DexMethodSignature, InstanceInitializer> entry :
- classInstanceInitializers.entrySet()) {
- DexMethodSignature relaxedSignature = entry.getKey();
- InstanceInitializer classInstanceInitializer = entry.getValue();
- InstanceInitializer groupInstanceInitializer =
- groupInstanceInitializers.get(relaxedSignature);
- if (groupInstanceInitializer == null) {
- continue;
- }
-
- Optional<InstanceInitializerDescription> classInstanceInitializerDescription =
- instanceInitializerDescriptionProvider.apply(classInstanceInitializer);
- if (!classInstanceInitializerDescription.isPresent()) {
- return false;
- }
-
- Optional<InstanceInitializerDescription> groupInstanceInitializerDescription =
- instanceInitializerDescriptionProvider.apply(groupInstanceInitializer);
- if (!groupInstanceInitializerDescription.isPresent()
- || !classInstanceInitializerDescription.equals(groupInstanceInitializerDescription)) {
- return false;
- }
- }
- return true;
- }
-
- private boolean hasMultipleInstanceInitializersWithSameRelaxedSignature(
- DexProgramClass clazz, Map<DexProgramClass, Set<DexMethod>> absentInstanceInitializers) {
- Set<DexMethod> instanceInitializerReferences =
- SetUtils.unionIdentityHashSet(
- SetUtils.newIdentityHashSet(
- IterableUtils.transform(
- clazz.programInstanceInitializers(), ProgramMethod::getReference)),
- absentInstanceInitializers.getOrDefault(clazz, Collections.emptySet()));
- if (instanceInitializerReferences.size() <= 1) {
- return false;
- }
-
- Set<DexMethod> seen = SetUtils.newIdentityHashSet();
- return Iterables.any(
- instanceInitializerReferences,
- instanceInitializerReference ->
- !seen.add(getRelaxedSignature(instanceInitializerReference)));
- }
-
- private Map<DexMethodSignature, InstanceInitializer> getInstanceInitializersByRelaxedSignature(
- DexProgramClass clazz, Map<DexProgramClass, Set<DexMethod>> absentInstanceInitializers) {
- Map<DexMethodSignature, InstanceInitializer> result = new HashMap<>();
- for (ProgramMethod presentInstanceInitializer : clazz.programInstanceInitializers()) {
- DexMethodSignature relaxedSignature =
- getRelaxedSignature(presentInstanceInitializer).getSignature();
- InstanceInitializer previous =
- result.put(relaxedSignature, new PresentInstanceInitializer(presentInstanceInitializer));
- assert previous == null;
- }
- for (DexMethod absentInstanceInitializer :
- absentInstanceInitializers.getOrDefault(clazz, Collections.emptySet())) {
- DexMethodSignature relaxedSignature =
- getRelaxedSignature(absentInstanceInitializer).getSignature();
- InstanceInitializer previous =
- result.put(relaxedSignature, new AbsentInstanceInitializer(absentInstanceInitializer));
- assert previous == null;
- }
- return result;
- }
-
- private Optional<InstanceInitializerDescription> getOrComputeInstanceInitializerDescription(
- HorizontalMergeGroup group,
- InstanceInitializer instanceInitializer,
- Map<DexMethod, Optional<InstanceInitializerDescription>> instanceInitializerDescriptions) {
- return instanceInitializerDescriptions.computeIfAbsent(
- instanceInitializer.getReference(),
- key -> {
- InstanceInitializerDescription instanceInitializerDescription =
- InstanceInitializerAnalysis.analyze(
- appView, codeProvider, group, instanceInitializer);
- return Optional.ofNullable(instanceInitializerDescription);
- });
- }
-
- private DexMethod getRelaxedSignature(ProgramMethod instanceInitializer) {
- return getRelaxedSignature(instanceInitializer.getReference());
- }
-
- @SuppressWarnings("ReferenceEquality")
- private DexMethod getRelaxedSignature(DexMethod instanceInitializerReference) {
- DexType objectType = appView.dexItemFactory().objectType;
- DexTypeList parameters = instanceInitializerReference.getParameters();
- DexTypeList relaxedParameters =
- parameters.map(parameter -> parameter.isPrimitiveType() ? parameter : objectType);
- return parameters != relaxedParameters
- ? appView
- .dexItemFactory()
- .createInstanceInitializer(
- instanceInitializerReference.getHolderType(), relaxedParameters)
- : instanceInitializerReference;
- }
-
- private void setInstanceFieldMaps(
- Iterable<HorizontalMergeGroup> newGroups, HorizontalMergeGroup group) {
- for (HorizontalMergeGroup newGroup : newGroups) {
- // Set target.
- newGroup.selectTarget(appView);
-
- // Construct mapping from instance fields on old target to instance fields on new target.
- // Note the importance of this: If we create a fresh mapping from the instance fields of each
- // source class to the new target class, we could invalidate the constructor equivalence.
- Map<DexEncodedField, DexEncodedField> oldTargetToNewTargetInstanceFieldMap =
- new IdentityHashMap<>();
- if (newGroup.getTarget() != group.getTarget()) {
- ClassInstanceFieldsMerger.mapFields(
- appView,
- group.getTarget(),
- newGroup.getTarget(),
- oldTargetToNewTargetInstanceFieldMap::put);
- }
-
- // Construct mapping from source to target fields.
- MutableBidirectionalManyToOneMap<DexEncodedField, DexEncodedField> instanceFieldMap =
- BidirectionalManyToOneHashMap.newLinkedHashMap();
- newGroup.forEachSource(
- source ->
- source.forEachProgramInstanceField(
- sourceField -> {
- DexEncodedField oldTargetInstanceField =
- group.getTargetInstanceField(sourceField).getDefinition();
- DexEncodedField newTargetInstanceField =
- oldTargetToNewTargetInstanceFieldMap.getOrDefault(
- oldTargetInstanceField, oldTargetInstanceField);
- instanceFieldMap.put(sourceField.getDefinition(), newTargetInstanceField);
- }));
- newGroup.setInstanceFieldMap(instanceFieldMap);
- }
- }
-
- @Override
- public String getName() {
- return "NoInstanceInitializerMerging";
- }
-
- @Override
- public boolean isIdentityForInterfaceGroups() {
- return true;
- }
-}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoVirtualMethodMerging.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoVirtualMethodMerging.java
deleted file mode 100644
index 3320310..0000000
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoVirtualMethodMerging.java
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright (c) 2020, 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.horizontalclassmerging.policies;
-
-import com.android.tools.r8.classmerging.ClassMergerMode;
-import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
-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.DexMethodSignature;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.horizontalclassmerging.HorizontalMergeGroup;
-import com.android.tools.r8.horizontalclassmerging.MultiClassPolicy;
-import com.android.tools.r8.utils.IterableUtils;
-import com.android.tools.r8.utils.SetUtils;
-import com.google.common.collect.Iterables;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-
-/**
- * Identifies when virtual method merging is required and bails out. This is needed to ensure that
- * we don't need to synthesize any $r8$classId fields, such that the result of the final round of
- * class merging can be described as a renaming only.
- */
-public class NoVirtualMethodMerging extends MultiClassPolicy {
-
- private final AppView<? extends AppInfoWithClassHierarchy> appView;
-
- public NoVirtualMethodMerging(
- AppView<? extends AppInfoWithClassHierarchy> appView, ClassMergerMode mode) {
- assert mode.isRestrictedToAlphaRenamingInR8();
- this.appView = appView;
- }
-
- @Override
- public Collection<HorizontalMergeGroup> apply(HorizontalMergeGroup group) {
- Map<HorizontalMergeGroup, Map<DexMethodSignature, ProgramMethod>> newGroups =
- new LinkedHashMap<>();
- for (DexProgramClass clazz : group) {
- Map<DexMethodSignature, ProgramMethod> classMethods = new HashMap<>();
- clazz.forEachProgramVirtualMethodMatching(
- DexEncodedMethod::isNonAbstractVirtualMethod,
- method -> classMethods.put(method.getMethodSignature(), method));
-
- HorizontalMergeGroup newGroup = null;
- for (Entry<HorizontalMergeGroup, Map<DexMethodSignature, ProgramMethod>> entry :
- newGroups.entrySet()) {
- HorizontalMergeGroup candidateGroup = entry.getKey();
- Map<DexMethodSignature, ProgramMethod> groupMethods = entry.getValue();
- if (canAddNonAbstractVirtualMethodsToGroup(
- clazz, classMethods.values(), candidateGroup, groupMethods)) {
- newGroup = candidateGroup;
- groupMethods.putAll(classMethods);
- break;
- }
- }
-
- if (newGroup != null) {
- newGroup.add(clazz);
- } else {
- newGroups.put(new HorizontalMergeGroup(clazz), classMethods);
- }
- }
- return removeTrivialGroups(newGroups.keySet());
- }
-
- private boolean canAddNonAbstractVirtualMethodsToGroup(
- DexProgramClass clazz,
- Collection<ProgramMethod> methods,
- HorizontalMergeGroup group,
- Map<DexMethodSignature, ProgramMethod> groupMethods) {
- // For each of clazz' virtual methods, check that adding these methods to the group does not
- // require method merging.
- for (ProgramMethod method : methods) {
- ProgramMethod groupMethod = groupMethods.get(method.getMethodSignature());
- if (groupMethod != null || hasNonAbstractDefinitionInHierarchy(group, method)) {
- return false;
- }
- }
- // For each of the group's virtual methods, check that adding these methods clazz does not
- // require method merging.
- for (ProgramMethod method : groupMethods.values()) {
- if (hasNonAbstractDefinitionInHierarchy(clazz, method)) {
- return false;
- }
- }
- return true;
- }
-
- private boolean hasNonAbstractDefinitionInHierarchy(
- HorizontalMergeGroup group, ProgramMethod method) {
- return hasNonAbstractDefinitionInSuperClass(group.getSuperType(), method)
- || hasNonAbstractDefinitionInSuperInterface(
- SetUtils.newIdentityHashSet(IterableUtils.flatMap(group, DexClass::getInterfaces)),
- method);
- }
-
- private boolean hasNonAbstractDefinitionInHierarchy(DexProgramClass clazz, ProgramMethod method) {
- return hasNonAbstractDefinitionInSuperClass(clazz.getSuperType(), method)
- || hasNonAbstractDefinitionInSuperInterface(clazz.getInterfaces(), method);
- }
-
- private boolean hasNonAbstractDefinitionInSuperClass(DexType superType, ProgramMethod method) {
- SingleResolutionResult<?> resolutionResult =
- appView
- .appInfo()
- .resolveMethodOnClassLegacy(superType, method.getReference())
- .asSingleResolution();
- return resolutionResult != null && !resolutionResult.getResolvedMethod().isAbstract();
- }
-
- private boolean hasNonAbstractDefinitionInSuperInterface(
- Iterable<DexType> interfaceTypes, ProgramMethod method) {
- return Iterables.any(
- interfaceTypes,
- interfaceType -> {
- SingleResolutionResult<?> resolutionResult =
- appView
- .appInfo()
- .resolveMethodOnInterfaceLegacy(interfaceType, method.getReference())
- .asSingleResolution();
- return resolutionResult != null && !resolutionResult.getResolvedMethod().isAbstract();
- });
- }
-
- @Override
- public String getName() {
- return "NoVirtualMethodMerging";
- }
-}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreserveMethodCharacteristics.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreserveMethodCharacteristics.java
index caf75a0..1486c2f 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreserveMethodCharacteristics.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreserveMethodCharacteristics.java
@@ -39,10 +39,10 @@
private final MethodAccessFlags accessFlags;
private final boolean isAssumeNoSideEffectsMethod;
private final OptionalBool isLibraryMethodOverride;
- private final boolean isMainDexRoot;
+ private final OptionalBool isMainDexRoot;
private MethodCharacteristics(
- DexEncodedMethod method, boolean isAssumeNoSideEffectsMethod, boolean isMainDexRoot) {
+ DexEncodedMethod method, boolean isAssumeNoSideEffectsMethod, OptionalBool isMainDexRoot) {
this.accessFlags =
MethodAccessFlags.builder()
.setPrivate(method.getAccessFlags().isPrivate())
@@ -57,11 +57,14 @@
}
static MethodCharacteristics create(
- AppView<AppInfoWithLiveness> appView, DexEncodedMethod method) {
+ AppView<AppInfoWithLiveness> appView, ClassMergerMode mode, DexEncodedMethod method) {
return new MethodCharacteristics(
method,
appView.getAssumeInfoCollection().isSideEffectFree(method.getReference()),
- appView.appInfo().getMainDexInfo().isTracedMethodRoot(method.getReference()));
+ mode.isInitial()
+ ? OptionalBool.of(
+ appView.appInfo().getMainDexInfo().isTracedMethodRoot(method.getReference()))
+ : OptionalBool.unknown());
}
@Override
@@ -91,12 +94,12 @@
}
private final AppView<AppInfoWithLiveness> appView;
+ private final ClassMergerMode mode;
public PreserveMethodCharacteristics(AppView<AppInfoWithLiveness> appView, ClassMergerMode mode) {
- // This policy checks that method merging does invalidate various properties. Thus there is no
- // reason to run this policy if method merging is not allowed.
- assert !mode.isRestrictedToAlphaRenamingInR8();
+ // This policy checks that method merging does invalidate various properties.
this.appView = appView;
+ this.mode = mode;
}
public static class TargetGroup {
@@ -108,12 +111,14 @@
return group;
}
- public boolean tryAdd(AppView<AppInfoWithLiveness> appView, DexProgramClass clazz) {
+ public boolean tryAdd(
+ AppView<AppInfoWithLiveness> appView, ClassMergerMode mode, DexProgramClass clazz) {
Map<DexMethodSignature, MethodCharacteristics> newMethods = new HashMap<>();
for (DexEncodedMethod method : clazz.methods(this::isSubjectToMethodMerging)) {
DexMethodSignature signature = method.getSignature();
MethodCharacteristics existingCharacteristics = methodMap.get(signature);
- MethodCharacteristics methodCharacteristics = MethodCharacteristics.create(appView, method);
+ MethodCharacteristics methodCharacteristics =
+ MethodCharacteristics.create(appView, mode, method);
if (existingCharacteristics == null) {
newMethods.put(signature, methodCharacteristics);
continue;
@@ -143,10 +148,11 @@
List<TargetGroup> groups = new ArrayList<>();
for (DexProgramClass clazz : group) {
- boolean added = Iterables.any(groups, targetGroup -> targetGroup.tryAdd(appView, clazz));
+ boolean added =
+ Iterables.any(groups, targetGroup -> targetGroup.tryAdd(appView, mode, clazz));
if (!added) {
TargetGroup newGroup = new TargetGroup();
- added = newGroup.tryAdd(appView, clazz);
+ added = newGroup.tryAdd(appView, mode, clazz);
assert added;
groups.add(newGroup);
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/RespectPackageBoundaries.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/RespectPackageBoundaries.java
index 9b8306d..892c40c 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/RespectPackageBoundaries.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/RespectPackageBoundaries.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.horizontalclassmerging.policies;
-import com.android.tools.r8.classmerging.ClassMergerMode;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
@@ -28,12 +27,9 @@
public class RespectPackageBoundaries extends MultiClassPolicy {
private final AppView<? extends AppInfoWithClassHierarchy> appView;
- private final ClassMergerMode mode;
- public RespectPackageBoundaries(
- AppView<? extends AppInfoWithClassHierarchy> appView, ClassMergerMode mode) {
+ public RespectPackageBoundaries(AppView<? extends AppInfoWithClassHierarchy> appView) {
this.appView = appView;
- this.mode = mode;
}
boolean shouldRestrictMergingAcrossPackageBoundary(DexProgramClass clazz) {
@@ -93,20 +89,15 @@
@Override
protected boolean checkRewrittenFieldType(DexClassAndField field) {
- if (mode.isRestrictedToAlphaRenamingInR8()) {
- // No relaxing of field types, hence no insertion of casts where we need
- // to guarantee visibility.
- } else {
- // If the type of the field is package private, we need to keep the
- // current class in its package in case we end up synthesizing a
- // check-cast for the field type after relaxing the type of the field
- // after instance field merging.
- DexType fieldBaseType = field.getType().toBaseType(dexItemFactory());
- if (fieldBaseType.isClassType()) {
- DexClass fieldBaseClass = appView.definitionFor(fieldBaseType);
- if (fieldBaseClass == null || !fieldBaseClass.isPublic()) {
- return setFoundPackagePrivateAccess();
- }
+ // If the type of the field is package private, we need to keep the
+ // current class in its package in case we end up synthesizing a
+ // check-cast for the field type after relaxing the type of the field
+ // after instance field merging.
+ DexType fieldBaseType = field.getType().toBaseType(dexItemFactory());
+ if (fieldBaseType.isClassType()) {
+ DexClass fieldBaseClass = appView.definitionFor(fieldBaseType);
+ if (fieldBaseClass == null || !fieldBaseClass.isPublic()) {
+ return setFoundPackagePrivateAccess();
}
}
return continueSearchForPackagePrivateAccess();
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameInstanceFields.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameInstanceFields.java
index 73ff6fc..d3cb879 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameInstanceFields.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameInstanceFields.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.horizontalclassmerging.policies;
-import com.android.tools.r8.classmerging.ClassMergerMode;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedField;
@@ -21,25 +20,16 @@
public class SameInstanceFields extends MultiClassSameReferencePolicy<Multiset<InstanceFieldInfo>> {
private final DexItemFactory dexItemFactory;
- private final ClassMergerMode mode;
- public SameInstanceFields(
- AppView<? extends AppInfoWithClassHierarchy> appView, ClassMergerMode mode) {
+ public SameInstanceFields(AppView<? extends AppInfoWithClassHierarchy> appView) {
this.dexItemFactory = appView.dexItemFactory();
- this.mode = mode;
}
@Override
public Multiset<InstanceFieldInfo> getMergeKey(DexProgramClass clazz) {
Multiset<InstanceFieldInfo> fields = HashMultiset.create();
for (DexEncodedField field : clazz.instanceFields()) {
- // We do not allow merging fields with different types in the final round of horizontal class
- // merging, since that requires inserting check-cast instructions at reads.
- InstanceFieldInfo instanceFieldInfo =
- mode.isRestrictedToAlphaRenamingInR8()
- ? InstanceFieldInfo.createExact(field)
- : InstanceFieldInfo.createRelaxed(field, dexItemFactory);
- fields.add(instanceFieldInfo);
+ fields.add(InstanceFieldInfo.createRelaxed(field, dexItemFactory));
}
return fields;
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 048460e..31577fc 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -709,7 +709,7 @@
}
if (!isDebugMode) {
- new StringOptimizer(appView).run(code, timing);
+ new StringOptimizer(appView).run(code, methodProcessor, methodProcessingContext, timing);
timing.begin("Optimize library methods");
appView
.libraryMethodOptimizer()
@@ -821,7 +821,8 @@
constantCanonicalizer.canonicalize();
timing.end();
previous = printMethod(code, "IR after constant canonicalization (SSA)", previous);
- new DexConstantOptimizer(appView, constantCanonicalizer).run(code, timing);
+ new DexConstantOptimizer(appView, constantCanonicalizer)
+ .run(code, methodProcessor, methodProcessingContext, timing);
previous = printMethod(code, "IR after dex constant optimization (SSA)", previous);
}
@@ -847,7 +848,8 @@
deadCodeRemover.run(code, timing);
- new ParentConstructorHoistingCodeRewriter(appView).run(code, timing);
+ new ParentConstructorHoistingCodeRewriter(appView)
+ .run(code, methodProcessor, methodProcessingContext, timing);
BytecodeMetadataProvider.Builder bytecodeMetadataProviderBuilder =
BytecodeMetadataProvider.builder();
@@ -877,7 +879,7 @@
assert code.isConsistentSSA(appView);
// TODO(b/214496607): Remove when dynamic types are safe w.r.t. interface assignment rules.
- new MoveResultRewriter(appView).run(code, timing);
+ new MoveResultRewriter(appView).run(code, methodProcessor, methodProcessingContext, timing);
}
// Assert that we do not have unremoved non-sense code in the output, e.g., v <- non-null NULL.
diff --git a/src/main/java/com/android/tools/r8/lightir/LirBuilder.java b/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
index 6f68845..a35a20f 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
@@ -810,6 +810,10 @@
for (int i = 0; i < keys.length; i++) {
targets[i] = getBlockIndex(keyToTargetMap.get(keys[i]));
}
+ return addIntSwitch(value, keys, targets);
+ }
+
+ public LirBuilder<V, EV> addIntSwitch(V value, int[] keys, int[] targets) {
IntSwitchPayload payload = new IntSwitchPayload(keys, targets);
return addInstructionTemplate(
LirOpcodes.TABLESWITCH,
diff --git a/src/main/java/com/android/tools/r8/lightir/LirCode.java b/src/main/java/com/android/tools/r8/lightir/LirCode.java
index 0158379..6f93b21 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirCode.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirCode.java
@@ -534,8 +534,11 @@
ProgramMethod method,
AppView<?> appView,
MutableMethodConversionOptions conversionOptions) {
+ GraphLens codeLens = method.getDefinition().getCode().getCodeLens(appView);
RewrittenPrototypeDescription protoChanges =
- appView.graphLens().lookupPrototypeChangesForMethodDefinition(method.getReference());
+ appView
+ .graphLens()
+ .lookupPrototypeChangesForMethodDefinition(method.getReference(), codeLens);
return internalBuildIR(
method, appView, new NumberGenerator(), null, protoChanges, conversionOptions);
}
diff --git a/src/main/java/com/android/tools/r8/lightir/LirLensCodeRewriter.java b/src/main/java/com/android/tools/r8/lightir/LirLensCodeRewriter.java
index 26a4261..a610af6 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirLensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirLensCodeRewriter.java
@@ -138,6 +138,9 @@
private boolean hasPotentialNonTrivialInvokeRewriting(
DexMethod method, InvokeType type, MethodLookupResult result) {
+ if (graphLens.isHorizontalClassMergerGraphLens()) {
+ return !result.getPrototypeChanges().isEmpty();
+ }
if (graphLens.isProtoNormalizerLens()) {
return result.getPrototypeChanges().getArgumentInfoCollection().hasArgumentPermutation();
}
@@ -315,25 +318,29 @@
}
private boolean hasNonTrivialMethodChanges() {
+ if (graphLens.isClassMergerLens()) {
+ RewrittenPrototypeDescription prototypeChanges =
+ graphLens.lookupPrototypeChangesForMethodDefinition(context.getReference(), codeLens);
+ assert prototypeChanges.getArgumentInfoCollection().isEmpty();
+ assert !prototypeChanges.hasRewrittenReturnInfo();
+ if (prototypeChanges.hasExtraParameters()) {
+ return true;
+ }
+ VerticalClassMergerGraphLens verticalClassMergerLens = graphLens.asVerticalClassMergerLens();
+ if (verticalClassMergerLens != null) {
+ DexMethod previousReference =
+ verticalClassMergerLens.getPreviousMethodSignature(contextReference);
+ return verticalClassMergerLens.hasInterfaceBeenMergedIntoClass(
+ previousReference.getReturnType());
+ }
+ }
if (graphLens.isProtoNormalizerLens()) {
RewrittenPrototypeDescription prototypeChanges =
graphLens.lookupPrototypeChangesForMethodDefinition(context.getReference(), codeLens);
+ assert !prototypeChanges.hasExtraParameters();
+ assert !prototypeChanges.hasRewrittenReturnInfo();
return prototypeChanges.getArgumentInfoCollection().hasArgumentPermutation();
}
- VerticalClassMergerGraphLens verticalClassMergerLens = graphLens.asVerticalClassMergerLens();
- if (verticalClassMergerLens != null) {
- DexMethod previousReference =
- verticalClassMergerLens.getPreviousMethodSignature(contextReference);
- if (verticalClassMergerLens.hasInterfaceBeenMergedIntoClass(
- previousReference.getReturnType())) {
- return true;
- }
- RewrittenPrototypeDescription prototypeChanges =
- graphLens.lookupPrototypeChangesForMethodDefinition(context.getReference(), codeLens);
- if (!prototypeChanges.isEmpty()) {
- return true;
- }
- }
return false;
}
diff --git a/src/main/java/com/android/tools/r8/naming/Minifier.java b/src/main/java/com/android/tools/r8/naming/Minifier.java
index 937d6a3..376c969 100644
--- a/src/main/java/com/android/tools/r8/naming/Minifier.java
+++ b/src/main/java/com/android/tools/r8/naming/Minifier.java
@@ -277,7 +277,6 @@
InternalNamingState internalState,
BiPredicate<DexString, DexMethod> isAvailable) {
if (!method.isProgramMethod()) {
- assert isAvailable.test(method.getName(), method.getReference());
return method.getName();
}
assert allowMemberRenaming(method);
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMerger.java
index b19cfe0..dfdd31b 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMerger.java
@@ -97,7 +97,7 @@
private void run(ExecutorService executorService, Timing timing) throws ExecutionException {
timing.begin("Setup");
ImmediateProgramSubtypingInfo immediateSubtypingInfo =
- ImmediateProgramSubtypingInfo.create(appView);
+ ImmediateProgramSubtypingInfo.createWithDeterministicOrder(appView);
// Compute the disjoint class hierarchies for parallel processing.
List<Set<DexProgramClass>> connectedComponents =
@@ -123,7 +123,12 @@
return;
}
VerticalClassMergerGraphLens lens =
- runFixup(classMergerSharedData, verticalClassMergerResult, executorService, timing);
+ runFixup(
+ classMergerSharedData,
+ immediateSubtypingInfo,
+ verticalClassMergerResult,
+ executorService,
+ timing);
assert verifyGraphLens(lens, verticalClassMergerResult);
// Update keep info and art profiles.
@@ -230,12 +235,13 @@
private VerticalClassMergerGraphLens runFixup(
ClassMergerSharedData classMergerSharedData,
+ ImmediateProgramSubtypingInfo immediateSubtypingInfo,
VerticalClassMergerResult verticalClassMergerResult,
ExecutorService executorService,
Timing timing)
throws ExecutionException {
return new VerticalClassMergerTreeFixer(
- appView, classMergerSharedData, verticalClassMergerResult)
+ appView, classMergerSharedData, immediateSubtypingInfo, verticalClassMergerResult)
.run(executorService, timing);
}
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerGraphLens.java b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerGraphLens.java
index 783b3d2..8d0ad13 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerGraphLens.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerGraphLens.java
@@ -23,7 +23,6 @@
import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.code.InvokeType;
-import com.android.tools.r8.ir.conversion.ExtraParameter;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.KeepInfoCollection;
import com.android.tools.r8.utils.InternalOptions;
@@ -40,7 +39,6 @@
import java.util.Collection;
import java.util.Collections;
import java.util.IdentityHashMap;
-import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@@ -372,12 +370,6 @@
}
@Override
- public void addExtraParameters(
- DexMethod from, DexMethod to, List<? extends ExtraParameter> extraParameters) {
- // Intentionally empty.
- }
-
- @Override
public void commitPendingUpdates() {
// Commit new field signatures.
newFieldSignatures.putAll(pendingNewFieldSignatureUpdates);
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerTreeFixer.java b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerTreeFixer.java
index ff87a99..b601485 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerTreeFixer.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerTreeFixer.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.classmerging.ClassMergerSharedData;
import com.android.tools.r8.classmerging.ClassMergerTreeFixer;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ImmediateProgramSubtypingInfo;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.Timing;
import java.util.List;
@@ -23,10 +24,12 @@
VerticalClassMergerTreeFixer(
AppView<AppInfoWithLiveness> appView,
ClassMergerSharedData classMergerSharedData,
+ ImmediateProgramSubtypingInfo immediateSubtypingInfo,
VerticalClassMergerResult verticalClassMergerResult) {
super(
appView,
classMergerSharedData,
+ immediateSubtypingInfo,
VerticalClassMergerGraphLens.Builder.createBuilderForFixup(verticalClassMergerResult),
verticalClassMergerResult.getVerticallyMergedClasses());
this.synthesizedBridges = verticalClassMergerResult.getSynthesizedBridges();
diff --git a/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java
index e2beb9e..93a9889 100644
--- a/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java
@@ -128,7 +128,7 @@
.withOptionConsumer(opts -> opts.enableClassInlining = false)
.withBuilderTransformation(
b -> b.addProguardConfiguration(PROGUARD_OPTIONS, Origin.unknown()))
- .withDexCheck(inspector -> checkLambdaCount(inspector, 11, "lambdadesugaring"))
+ .withDexCheck(inspector -> checkLambdaCount(inspector, 6, "lambdadesugaring"))
.run(Paths.get(ToolHelper.THIRD_PARTY_DIR, "examplesAndroidOLegacy"));
test("lambdadesugaring", "lambdadesugaring", "LambdaDesugaring")
@@ -167,7 +167,7 @@
.withOptionConsumer(opts -> opts.enableClassInlining = false)
.withBuilderTransformation(
b -> b.addProguardConfiguration(PROGUARD_OPTIONS, Origin.unknown()))
- .withDexCheck(inspector -> checkLambdaCount(inspector, 11, "lambdadesugaring"))
+ .withDexCheck(inspector -> checkLambdaCount(inspector, 6, "lambdadesugaring"))
.run(Paths.get(ToolHelper.THIRD_PARTY_DIR, "examplesAndroidOLegacy"));
test("lambdadesugaring", "lambdadesugaring", "LambdaDesugaring")
@@ -202,7 +202,7 @@
b ->
b.addProguardConfiguration(
getProguardOptionsNPlus(enableProguardCompatibilityMode), Origin.unknown()))
- .withDexCheck(inspector -> checkLambdaCount(inspector, 6, "lambdadesugaringnplus"))
+ .withDexCheck(inspector -> checkLambdaCount(inspector, 3, "lambdadesugaringnplus"))
.run();
test("lambdadesugaringnplus", "lambdadesugaringnplus", "LambdasWithStaticAndDefaultMethods")
@@ -214,7 +214,7 @@
b ->
b.addProguardConfiguration(
getProguardOptionsNPlus(enableProguardCompatibilityMode), Origin.unknown()))
- .withDexCheck(inspector -> checkLambdaCount(inspector, 3, "lambdadesugaringnplus"))
+ .withDexCheck(inspector -> checkLambdaCount(inspector, 2, "lambdadesugaringnplus"))
.run();
}
@@ -244,7 +244,7 @@
b ->
b.addProguardConfiguration(
getProguardOptionsNPlus(enableProguardCompatibilityMode), Origin.unknown()))
- .withDexCheck(inspector -> checkLambdaCount(inspector, 6, "lambdadesugaringnplus"))
+ .withDexCheck(inspector -> checkLambdaCount(inspector, 3, "lambdadesugaringnplus"))
.run();
test("lambdadesugaringnplus", "lambdadesugaringnplus", "LambdasWithStaticAndDefaultMethods")
@@ -256,7 +256,7 @@
b ->
b.addProguardConfiguration(
getProguardOptionsNPlus(enableProguardCompatibilityMode), Origin.unknown()))
- .withDexCheck(inspector -> checkLambdaCount(inspector, 3, "lambdadesugaringnplus"))
+ .withDexCheck(inspector -> checkLambdaCount(inspector, 2, "lambdadesugaringnplus"))
.run();
}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingSubReferenceApiTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingSubReferenceApiTest.java
index dff5d14..4f6282a 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingSubReferenceApiTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingSubReferenceApiTest.java
@@ -6,7 +6,7 @@
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
import static com.android.tools.r8.utils.AndroidApiLevel.L_MR1;
-import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsentIf;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static junit.framework.TestCase.assertEquals;
import static org.hamcrest.CoreMatchers.not;
@@ -14,7 +14,6 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NoInliningOfDefaultInitializer;
import com.android.tools.r8.NoMethodStaticizing;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -26,22 +25,20 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class ApiModelNoVerticalMergingSubReferenceApiTest extends TestBase {
- private final TestParameters parameters;
+ @Parameter(0)
+ public TestParameters parameters;
@Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withAllRuntimesAndApiLevels().build();
}
- public ApiModelNoVerticalMergingSubReferenceApiTest(TestParameters parameters) {
- this.parameters = parameters;
- }
-
@Test()
public void testR8() throws Exception {
Method apiMethod = Api.class.getDeclaredMethod("apiLevel22");
@@ -57,7 +54,6 @@
.apply(ApiModelingTestHelper::disableOutliningAndStubbing)
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
- .enableNoInliningOfDefaultInitializerAnnotations()
.enableNoMethodStaticizingAnnotations()
.addVerticallyMergedClassesInspector(
inspector -> {
@@ -78,9 +74,7 @@
assertThat(base, not(isPresent()));
ClassSubject sub = inspector.clazz(Sub.class);
assertThat(sub, isPresent());
- assertThat(
- sub.uniqueInstanceInitializer(),
- isAbsentIf(parameters.canHaveNonReboundConstructorInvoke()));
+ assertThat(sub.uniqueInstanceInitializer(), isAbsent());
assertEquals(1, sub.virtualMethods().size());
FoundMethodSubject callCallApi = sub.virtualMethods().get(0);
assertEquals("callCallApi", callCallApi.getOriginalName());
@@ -109,7 +103,6 @@
}
@NeverClassInline
- @NoInliningOfDefaultInitializer
public static class Sub extends Base {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingTest.java
index 2e368e9..3f93300 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoVerticalMergingTest.java
@@ -6,7 +6,7 @@
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
import static com.android.tools.r8.utils.AndroidApiLevel.L_MR1;
-import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsentIf;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static junit.framework.TestCase.assertEquals;
import static org.hamcrest.CoreMatchers.not;
@@ -14,7 +14,6 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NoInliningOfDefaultInitializer;
import com.android.tools.r8.NoMethodStaticizing;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -26,22 +25,20 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class ApiModelNoVerticalMergingTest extends TestBase {
- private final TestParameters parameters;
+ @Parameter(0)
+ public TestParameters parameters;
@Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withAllRuntimesAndApiLevels().build();
}
- public ApiModelNoVerticalMergingTest(TestParameters parameters) {
- this.parameters = parameters;
- }
-
@Test()
public void testR8() throws Exception {
Method apiMethod = Api.class.getDeclaredMethod("apiLevel22");
@@ -57,7 +54,6 @@
.apply(ApiModelingTestHelper::disableOutliningAndStubbing)
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
- .enableNoInliningOfDefaultInitializerAnnotations()
.enableNoMethodStaticizingAnnotations()
.addVerticallyMergedClassesInspector(
inspector -> {
@@ -77,9 +73,7 @@
assertThat(base, not(isPresent()));
ClassSubject sub = inspector.clazz(Sub.class);
assertThat(sub, isPresent());
- assertThat(
- sub.uniqueInstanceInitializer(),
- isAbsentIf(parameters.canHaveNonReboundConstructorInvoke()));
+ assertThat(sub.uniqueInstanceInitializer(), isAbsent());
assertEquals(1, sub.virtualMethods().size());
FoundMethodSubject callCallApi = sub.virtualMethods().get(0);
assertEquals("callCallApi", callCallApi.getOriginalName());
@@ -109,7 +103,6 @@
}
@NeverClassInline
- @NoInliningOfDefaultInitializer
public static class Sub extends Base {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/BridgeWithInvokeSuperOnInterfaceTest.java b/src/test/java/com/android/tools/r8/bridgeremoval/BridgeWithInvokeSuperOnInterfaceTest.java
index 4c6af25..e6d8721 100644
--- a/src/test/java/com/android/tools/r8/bridgeremoval/BridgeWithInvokeSuperOnInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/BridgeWithInvokeSuperOnInterfaceTest.java
@@ -4,9 +4,9 @@
package com.android.tools.r8.bridgeremoval;
-import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static org.hamcrest.CoreMatchers.not;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.NoVerticalClassMerging;
@@ -16,7 +16,7 @@
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -60,9 +60,12 @@
// Check that we are removing the bridge if we support default methods.
if (parameters.canUseDefaultAndStaticInterfaceMethods()) {
ClassSubject J = inspector.clazz(J.class);
- assertThat(J, isPresent());
- MethodSubject fooMethod = J.uniqueMethodWithOriginalName("foo");
- assertThat(fooMethod, not(isPresent()));
+ assertThat(J, isAbsent());
+ assertTrue(
+ inspector.allClasses().stream()
+ .allMatch(
+ classSubject ->
+ classSubject.allMethods(FoundMethodSubject::isBridge).isEmpty()));
}
})
.run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingAfterConstructorShrinkingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingAfterConstructorShrinkingTest.java
index 4c390c7..f13a1a1 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingAfterConstructorShrinkingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingAfterConstructorShrinkingTest.java
@@ -54,7 +54,8 @@
options -> options.horizontalClassMergerOptions().disableInitialRoundOfClassMerging())
.addHorizontallyMergedClassesInspector(
i -> {
- if (enableRetargetingOfConstructorBridgeCalls) {
+ if (enableRetargetingOfConstructorBridgeCalls
+ || parameters.canInitNewInstanceUsingSuperclassConstructor()) {
i.assertClassesMerged(A.class, B.class);
} else {
i.assertNoClassesMerged();
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingAfterConstructorShrinkingWithRepackagingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingAfterConstructorShrinkingWithRepackagingTest.java
index 1dab3a8..9ac51d6 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingAfterConstructorShrinkingWithRepackagingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingAfterConstructorShrinkingWithRepackagingTest.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.classmerging.horizontal;
import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsentIf;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
@@ -77,7 +78,8 @@
options -> options.horizontalClassMergerOptions().disableInitialRoundOfClassMerging())
.addHorizontallyMergedClassesInspector(
i -> {
- if (enableRetargetingOfConstructorBridgeCalls) {
+ if (enableRetargetingOfConstructorBridgeCalls
+ || parameters.canInitNewInstanceUsingSuperclassConstructor()) {
// Repackaging will have moved both classes to top-level package, so rename them.
i.assertClassReferencesMerged(
moveToTopLevelPackage(A.class), moveToTopLevelPackage(B.class));
@@ -96,29 +98,45 @@
// Verify Parent and Parent.<init>(Parent) are present and that Parent has been
// repackaged into the default package.
ClassSubject parentClassSubject = inspector.clazz(Parent.class);
- assertThat(parentClassSubject, isPresent());
- assertEquals("", parentClassSubject.getDexProgramClass().getType().getPackageName());
+ assertThat(
+ parentClassSubject,
+ isAbsentIf(parameters.canInitNewInstanceUsingSuperclassConstructor()));
+ if (parentClassSubject.isPresent()) {
+ assertEquals(
+ "", parentClassSubject.getDexProgramClass().getType().getPackageName());
- MethodSubject parentInstanceInitializerSubject =
- parentClassSubject.uniqueInstanceInitializer();
- assertThat(parentInstanceInitializerSubject, isPresent());
- assertEquals(
- parentClassSubject.asTypeSubject(),
- parentInstanceInitializerSubject.getParameter(0));
+ MethodSubject parentInstanceInitializerSubject =
+ parentClassSubject.uniqueInstanceInitializer();
+ assertThat(parentInstanceInitializerSubject, isPresent());
+ assertEquals(
+ parentClassSubject.asTypeSubject(),
+ parentInstanceInitializerSubject.getParameter(0));
+ }
// Verify that A and A.<init>(Parent) are present.
ClassSubject aClassSubject = inspector.clazz(A.class);
assertThat(aClassSubject, isPresent());
assertEquals("", aClassSubject.getDexProgramClass().getType().getPackageName());
- MethodSubject aInstanceInitializerSubject = aClassSubject.uniqueInstanceInitializer();
+ MethodSubject aInstanceInitializerSubject =
+ aClassSubject.uniqueMethodThatMatches(
+ method ->
+ method.isInstanceInitializer()
+ && method
+ .streamInstructions()
+ .anyMatch(instruction -> instruction.isConstString("Ouch!")));
assertThat(aInstanceInitializerSubject, isPresent());
+
assertEquals(
- parentClassSubject.asTypeSubject(), aInstanceInitializerSubject.getParameter(0));
+ parentClassSubject.isPresent()
+ ? parentClassSubject.asTypeSubject()
+ : aClassSubject.asTypeSubject(),
+ aInstanceInitializerSubject.getParameter(0));
// Verify that B or B's initializer was removed.
ClassSubject bClassSubject = inspector.clazz(B.class);
- if (enableRetargetingOfConstructorBridgeCalls) {
+ if (enableRetargetingOfConstructorBridgeCalls
+ || parameters.canInitNewInstanceUsingSuperclassConstructor()) {
assertThat(bClassSubject, isAbsent());
} else {
assertThat(bClassSubject, isPresent());
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerConstructorCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerConstructorCollisionTest.java
index 79b5725..67c2d49 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerConstructorCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerConstructorCollisionTest.java
@@ -12,6 +12,10 @@
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.NoHorizontalClassMerging;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
+import com.android.tools.r8.utils.Box;
import org.junit.Test;
public class TreeFixerConstructorCollisionTest extends HorizontalClassMergingTestBase {
@@ -21,14 +25,28 @@
@Test
public void testR8() throws Exception {
+ Box<ClassReference> aClassReferenceAfterRepackaging = new Box<>();
testForR8(parameters.getBackend())
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addHorizontallyMergedClassesInspector(
- inspector ->
- inspector.assertIsCompleteMergeGroup(A.class, B.class).assertNoOtherClassesMerged())
+ inspector -> {
+ ClassReference aClassReference = aClassReferenceAfterRepackaging.get();
+ inspector
+ .assertIsCompleteMergeGroup(A.class, B.class)
+ .assertIsCompleteMergeGroup(
+ SyntheticItemsTestUtils.syntheticInitializerArgumentType(aClassReference, 0),
+ SyntheticItemsTestUtils.syntheticInitializerArgumentType(aClassReference, 1),
+ SyntheticItemsTestUtils.syntheticInitializerArgumentType(aClassReference, 2),
+ SyntheticItemsTestUtils.syntheticInitializerArgumentType(aClassReference, 3))
+ .assertNoOtherClassesMerged();
+ })
.addOptionsModification(
options -> options.inlinerOptions().setEnableConstructorInlining(false))
+ .addRepackagingInspector(
+ inspector ->
+ aClassReferenceAfterRepackaging.set(
+ inspector.getTarget(Reference.classFromClass(A.class))))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.enableNoHorizontalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideAbstractMethodWithDefaultTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideAbstractMethodWithDefaultTest.java
index abff6e4..c9b170b 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideAbstractMethodWithDefaultTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideAbstractMethodWithDefaultTest.java
@@ -32,10 +32,10 @@
inspector
.applyIf(
parameters.canUseDefaultAndStaticInterfaceMethods(),
- i -> i.assertIsCompleteMergeGroup(I.class, J.class))
- .applyIf(
- !parameters.canUseDefaultAndStaticInterfaceMethods(),
- i -> i.assertIsCompleteMergeGroup(B1.class, B2.class))
+ i -> i.assertIsCompleteMergeGroup(I.class, J.class),
+ i ->
+ i.assertIsCompleteMergeGroup(B1.class, B2.class)
+ .assertIsCompleteMergeGroup(C1.class, C2.class))
.assertNoOtherClassesMerged())
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
@@ -55,7 +55,9 @@
codeInspector.clazz(B2.class),
isPresentIf(parameters.canUseDefaultAndStaticInterfaceMethods()));
assertThat(codeInspector.clazz(C1.class), isPresent());
- assertThat(codeInspector.clazz(C2.class), isPresent());
+ assertThat(
+ codeInspector.clazz(C2.class),
+ isPresentIf(parameters.canUseDefaultAndStaticInterfaceMethods()));
});
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/whyareyounotinlining/WhyAreYouNotInliningInvokeWithUnknownTargetTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/whyareyounotinlining/WhyAreYouNotInliningInvokeWithUnknownTargetTest.java
index 5baa779..06f5aa2 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/whyareyounotinlining/WhyAreYouNotInliningInvokeWithUnknownTargetTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/whyareyounotinlining/WhyAreYouNotInliningInvokeWithUnknownTargetTest.java
@@ -8,6 +8,7 @@
import static org.hamcrest.CoreMatchers.is;
import com.android.tools.r8.DiagnosticsMatcher;
+import com.android.tools.r8.NeverReprocessMethod;
import com.android.tools.r8.NoHorizontalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -39,6 +40,7 @@
.addKeepRules("-whyareyounotinlining class " + A.class.getTypeName() + " { void m(); }")
.enableExperimentalWhyAreYouNotInlining()
.enableNoHorizontalClassMergingAnnotations()
+ .enableNeverReprocessMethodAnnotations()
.setMinApi(parameters)
.allowDiagnosticInfoMessages()
.compile()
@@ -59,6 +61,7 @@
static class TestClass {
+ @NeverReprocessMethod
public static void main(String[] args) {
(System.currentTimeMillis() >= 0 ? new A() : new B()).m();
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java
index c9c9e05..0a52142 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java
@@ -66,8 +66,8 @@
inspector -> {
HorizontalClassMergerOptions defaultHorizontalClassMergerOptions =
new InternalOptions().horizontalClassMergerOptions();
- assertEquals(4833, inspector.getSources().size());
- assertEquals(167, inspector.getTargets().size());
+ assertEquals(4994, inspector.getSources().size());
+ assertEquals(173, inspector.getTargets().size());
assertTrue(
inspector.getMergeGroups().stream()
.allMatch(
diff --git a/src/test/java/com/android/tools/r8/kotlin/sealed/SealedInterfaceSubClassesHorizontalMergeTest.java b/src/test/java/com/android/tools/r8/kotlin/sealed/SealedInterfaceSubClassesHorizontalMergeTest.java
index 238099b..a206c4a 100644
--- a/src/test/java/com/android/tools/r8/kotlin/sealed/SealedInterfaceSubClassesHorizontalMergeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/sealed/SealedInterfaceSubClassesHorizontalMergeTest.java
@@ -13,8 +13,10 @@
import com.android.tools.r8.KotlinTestBase;
import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.Reference;
import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
+import com.android.tools.r8.utils.Box;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collection;
@@ -86,6 +88,8 @@
@Test
public void testR8() throws ExecutionException, CompilationFailedException, IOException {
+ Box<ClassReference> aClassReferenceAfterRepackaging = new Box<>();
+ Box<ClassReference> bClassReferenceAfterRepackaging = new Box<>();
testForR8(parameters.getBackend())
.addProgramFiles(compilationResults.getForConfiguration(kotlinc, targetVersion))
.addProgramFiles(kotlinc.getKotlinStdlibJar())
@@ -103,11 +107,21 @@
inspector
.assertIsCompleteMergeGroup(A, B)
.assertNoOtherClassesMerged()),
- // TODO(b/296852026): Updates to horizintal class merging can cause this to start
- // failing as the classes can actually bne merged without -assumenosideeffects rules.
b ->
b.addHorizontallyMergedClassesInspector(
- HorizontallyMergedClassesInspector::assertNoClassesMerged))
+ inspector ->
+ inspector
+ .assertIsCompleteMergeGroup(
+ aClassReferenceAfterRepackaging.get(),
+ bClassReferenceAfterRepackaging.get())
+ .assertNoOtherClassesMerged())
+ .addRepackagingInspector(
+ inspector -> {
+ aClassReferenceAfterRepackaging.set(
+ inspector.getTarget(Reference.classFromTypeName(A)));
+ bClassReferenceAfterRepackaging.set(
+ inspector.getTarget(Reference.classFromTypeName(B)));
+ }))
.compile()
.assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
.run(parameters.getRuntime(), MAIN)
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingRemoveVirtualBridgeTest.java b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingRemoveVirtualBridgeTest.java
index 4013b58..7e99f86 100644
--- a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingRemoveVirtualBridgeTest.java
+++ b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingRemoveVirtualBridgeTest.java
@@ -62,12 +62,10 @@
inspector -> {
ClassSubject clazz = inspector.clazz(B.class);
assertThat(clazz, isPresent());
- if (parameters.canHaveNonReboundConstructorInvoke()) {
- assertEquals(0, clazz.allMethods().size());
- } else {
- assertEquals(1, clazz.allMethods().size());
- assertThat(clazz.allMethods().get(0), isInstanceInitializer());
- }
+ // TODO(b/324527514): Initializer should be removed when
+ // canHaveNonReboundConstructorInvoke().
+ assertEquals(1, clazz.allMethods().size());
+ assertThat(clazz.allMethods().get(0), isInstanceInitializer());
});
}
diff --git a/src/test/java/com/android/tools/r8/profile/art/completeness/LambdaStaticLibraryMethodImplementationProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/completeness/LambdaStaticLibraryMethodImplementationProfileRewritingTest.java
index c83d81d..6eac7c2 100644
--- a/src/test/java/com/android/tools/r8/profile/art/completeness/LambdaStaticLibraryMethodImplementationProfileRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/profile/art/completeness/LambdaStaticLibraryMethodImplementationProfileRewritingTest.java
@@ -103,9 +103,7 @@
assertThat(lambdaClassSubject, notIf(isPresent(), canUseLambdas));
MethodSubject lambdaInitializerSubject = lambdaClassSubject.uniqueInstanceInitializer();
- assertThat(
- lambdaInitializerSubject,
- notIf(isPresent(), canHaveNonReboundConstructorInvoke || canUseLambdas));
+ assertThat(lambdaInitializerSubject, notIf(isPresent(), canUseLambdas));
MethodSubject lambdaMainMethodSubject =
lambdaClassSubject.uniqueMethodThatMatches(FoundMethodSubject::isVirtual);
@@ -116,10 +114,8 @@
} else {
profileInspector
.assertContainsClassRules(lambdaClassSubject)
- .assertContainsMethodRules(mainMethodSubject, lambdaMainMethodSubject)
- .applyIf(
- !canHaveNonReboundConstructorInvoke,
- i -> i.assertContainsMethodRule(lambdaInitializerSubject));
+ .assertContainsMethodRules(
+ mainMethodSubject, lambdaInitializerSubject, lambdaMainMethodSubject);
}
profileInspector.assertContainsNoOtherRules();
diff --git a/src/test/java/com/android/tools/r8/profile/art/completeness/NestBasedAccessBridgesProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/completeness/NestBasedAccessBridgesProfileRewritingTest.java
index 577518d..f296a71 100644
--- a/src/test/java/com/android/tools/r8/profile/art/completeness/NestBasedAccessBridgesProfileRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/profile/art/completeness/NestBasedAccessBridgesProfileRewritingTest.java
@@ -133,7 +133,8 @@
syntheticConstructorArgumentClassSubject, notIf(isPresent(), canUseNestBasedAccesses));
MethodSubject instanceInitializer = nestMemberClassSubject.init();
- assertThat(instanceInitializer, notIf(isPresent(), canHaveNonReboundConstructorInvoke));
+ // TODO(b/324527514): Should be absent when canHaveNonReboundConstructorInvoke is true.
+ assertThat(instanceInitializer, isPresent());
MethodSubject instanceInitializerWithSyntheticArgumentSubject =
syntheticConstructorArgumentClassSubject.isPresent()
diff --git a/src/test/java/com/android/tools/r8/profile/art/completeness/RecordProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/completeness/RecordProfileRewritingTest.java
index cd72b73..cbab790 100644
--- a/src/test/java/com/android/tools/r8/profile/art/completeness/RecordProfileRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/profile/art/completeness/RecordProfileRewritingTest.java
@@ -199,8 +199,7 @@
ClassSubject recordTagClassSubject = inspector.clazz(recordClassReference);
assertThat(recordTagClassSubject, isAbsentIf(canMergeRecordTag || canUseRecords));
if (recordTagClassSubject.isPresent()) {
- assertEquals(
- canHaveNonReboundConstructorInvoke ? 0 : 1, recordTagClassSubject.allMethods().size());
+ assertEquals(1, recordTagClassSubject.allMethods().size());
}
MethodSubject recordTagInstanceInitializerSubject = recordTagClassSubject.init();
@@ -216,13 +215,12 @@
: recordTagClassSubject.asTypeSubject(),
personRecordClassSubject.getSuperType());
assertEquals(
- canUseRecords ? 6 : canHaveNonReboundConstructorInvoke || !canMergeRecordTag ? 10 : 11,
+ canUseRecords ? 6 : canMergeRecordTag ? 11 : 10,
personRecordClassSubject.allMethods().size());
MethodSubject personDefaultInstanceInitializerSubject = personRecordClassSubject.init();
assertThat(
- personDefaultInstanceInitializerSubject,
- isPresentIf(!canHaveNonReboundConstructorInvoke && canMergeRecordTag && !canUseRecords));
+ personDefaultInstanceInitializerSubject, isPresentIf(canMergeRecordTag && !canUseRecords));
MethodSubject personInstanceInitializerSubject =
canMergeRecordTag
@@ -317,7 +315,7 @@
i.assertContainsMethodRules(
nameNestAccessorMethodSubject, ageNestAccessorMethodSubject))
.applyIf(
- !canHaveNonReboundConstructorInvoke && canMergeRecordTag && !canUseRecords,
+ canMergeRecordTag && !canUseRecords,
i -> i.assertContainsMethodRule(personDefaultInstanceInitializerSubject))
.applyIf(
!canUseRecords,
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithOverridesOfPackagePrivateMethodsTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithOverridesOfPackagePrivateMethodsTest.java
index 2f7657a..d3b2371 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageWithOverridesOfPackagePrivateMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithOverridesOfPackagePrivateMethodsTest.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.repackage;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverClassInline;
@@ -30,6 +31,12 @@
testForR8(parameters.getBackend())
.addInnerClasses(getClass())
.addKeepMainRule(TestClass.class)
+ .addHorizontallyMergedClassesInspector(
+ inspector ->
+ inspector
+ .assertIsCompleteMergeGroup(HelloGreeterBase.class, WorldGreeterBase.class)
+ .assertIsCompleteMergeGroup(HelloGreeter.class, WorldGreeter.class)
+ .assertNoOtherClassesMerged())
.apply(this::configureRepackaging)
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
@@ -45,7 +52,7 @@
private void inspect(CodeInspector inspector) {
assertThat(HelloGreeter.class, isNotRepackaged(inspector));
- assertThat(WorldGreeter.class, isNotRepackaged(inspector));
+ assertThat(inspector.clazz(WorldGreeter.class), isAbsent());
}
public static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithOverridesOfProtectedMethodsTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithOverridesOfProtectedMethodsTest.java
index 356bf73..bebcdba 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageWithOverridesOfProtectedMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithOverridesOfProtectedMethodsTest.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.repackage;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverClassInline;
@@ -11,6 +12,9 @@
import com.android.tools.r8.NoParameterTypeStrengthening;
import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -26,9 +30,25 @@
@Test
public void test() throws Exception {
+ Box<ClassReference> helloGreeterAfterRepackaging = new Box<>();
+ Box<ClassReference> worldGreeterAfterRepackaging = new Box<>();
testForR8(parameters.getBackend())
.addInnerClasses(getClass())
.addKeepMainRule(TestClass.class)
+ .addHorizontallyMergedClassesInspector(
+ inspector ->
+ inspector
+ .assertIsCompleteMergeGroup(HelloGreeterBase.class, WorldGreeterBase.class)
+ .assertIsCompleteMergeGroup(
+ helloGreeterAfterRepackaging.get(), worldGreeterAfterRepackaging.get())
+ .assertNoOtherClassesMerged())
+ .addRepackagingInspector(
+ inspector -> {
+ helloGreeterAfterRepackaging.set(
+ inspector.getTarget(Reference.classFromClass(HelloGreeter.class)));
+ worldGreeterAfterRepackaging.set(
+ inspector.getTarget(Reference.classFromClass(WorldGreeter.class)));
+ })
.apply(this::configureRepackaging)
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
@@ -43,7 +63,7 @@
private void inspect(CodeInspector inspector) {
assertThat(HelloGreeter.class, isRepackaged(inspector));
- assertThat(WorldGreeter.class, isRepackaged(inspector));
+ assertThat(inspector.clazz(WorldGreeter.class), isAbsent());
}
public static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/shaking/RetainIndirectlyReferencedConstructorShakingOnDexTest.java b/src/test/java/com/android/tools/r8/shaking/RetainIndirectlyReferencedConstructorShakingOnDexTest.java
index a3d1fef..102603a 100644
--- a/src/test/java/com/android/tools/r8/shaking/RetainIndirectlyReferencedConstructorShakingOnDexTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/RetainIndirectlyReferencedConstructorShakingOnDexTest.java
@@ -76,19 +76,17 @@
ClassSubject bClassSubject = inspector.clazz(B.class);
assertThat(bClassSubject, isPresent());
- assertEquals(
- parameters.canHaveNonReboundConstructorInvoke() ? 0 : 1,
- bClassSubject.allMethods(FoundMethodSubject::isInstanceInitializer).size());
+ // TODO(b/324527514): Should be `1 - intValue(parameters.canHaveNonReboundConstructorInvoke())`.
+ assertEquals(1, bClassSubject.allMethods(FoundMethodSubject::isInstanceInitializer).size());
MethodSubject mainMethodSubject = mainClassSubject.mainMethod();
+ // TODO(b/324527514): Should invoke A.<init> when canHaveNonReboundConstructorInvoke()
+ // && enableRetargetingOfConstructorBridgeCalls.
assertThat(
mainMethodSubject,
invokesMethod(
MethodReferenceUtils.instanceConstructor(
- parameters.canHaveNonReboundConstructorInvoke()
- && enableRetargetingOfConstructorBridgeCalls
- ? Reference.classFromDescriptor(aClassSubject.getFinalDescriptor())
- : Reference.classFromDescriptor(bClassSubject.getFinalDescriptor()))));
+ Reference.classFromDescriptor(bClassSubject.getFinalDescriptor()))));
}
static class Main {
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/AllowHorizontalClassMergingWithIfRuleTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/AllowHorizontalClassMergingWithIfRuleTest.java
index af28109..f8ca87c 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/AllowHorizontalClassMergingWithIfRuleTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/AllowHorizontalClassMergingWithIfRuleTest.java
@@ -31,7 +31,9 @@
.addKeepRules("-if class * { void foo(); } -keep class " + Main.class.getTypeName())
.addHorizontallyMergedClassesInspector(
inspector ->
- inspector.assertIsCompleteMergeGroup(B.class, C.class).assertNoOtherClassesMerged())
+ inspector
+ .assertIsCompleteMergeGroup(A.class, B.class, C.class)
+ .assertNoOtherClassesMerged())
.setMinApi(parameters)
.compile()
.run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java b/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
index 47d969c..a5e5f19 100644
--- a/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
+++ b/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
@@ -152,6 +152,11 @@
originalMethod.getMethodDescriptor());
}
+ public static ClassReference syntheticInitializerArgumentType(
+ ClassReference classReference, int id) {
+ return syntheticClass(classReference, naming.NON_FIXED_INIT_TYPE_ARGUMENT, id);
+ }
+
public static ClassReference syntheticNestConstructorArgumentClass(
ClassReference classReference) {
return Reference.classFromDescriptor(