Prepare generation of constructor reference for overlapping constructors
Bug: 163311975
Change-Id: If968ecfa80c612ae76c9a1d59a81d07b22e01b04
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index b192017..dc680a8 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -2019,6 +2019,11 @@
return createProto(initialProto.returnType, parameterTypes);
}
+ public DexMethod appendTypeToMethod(DexMethod initialMethod, DexType extraLastType) {
+ DexProto newProto = appendTypeToProto(initialMethod.proto, extraLastType);
+ return createMethod(initialMethod.holder, newProto, initialMethod.name);
+ }
+
public DexProto applyClassMappingToProto(
DexProto proto, Function<DexType, DexType> mapping, Map<DexProto, DexProto> cache) {
assert cache != null;
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorMerger.java
index a6bc003..4740da3 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorMerger.java
@@ -13,7 +13,6 @@
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.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.MethodAccessFlags;
@@ -55,6 +54,18 @@
this.dexItemFactory = appView.dexItemFactory();
}
+ /**
+ * The method reference template describes which arguments the constructor must have, and is used
+ * to generate the final reference by appending null arguments until it is fresh.
+ */
+ private DexMethod generateReferenceMethodTemplate() {
+ DexMethod methodTemplate = constructors.iterator().next().getReference();
+ if (!isTrivialMerge()) {
+ methodTemplate = dexItemFactory.appendTypeToMethod(methodTemplate, dexItemFactory.intType);
+ }
+ return methodTemplate;
+ }
+
public int getArity() {
return constructors.iterator().next().getReference().getArity();
}
@@ -104,31 +115,6 @@
return method;
}
- private DexProto getNewConstructorProto(SyntheticArgumentClass syntheticArgumentClass) {
- DexEncodedMethod firstConstructor = constructors.iterator().next();
- DexProto oldProto = firstConstructor.getProto();
-
- if (isTrivialMerge() && syntheticArgumentClass == null) {
- return oldProto;
- }
-
- List<DexType> parameters = new ArrayList<>();
- Collections.addAll(parameters, oldProto.parameters.values);
- if (!isTrivialMerge()) {
- parameters.add(dexItemFactory.intType);
- }
- if (syntheticArgumentClass != null) {
- parameters.add(syntheticArgumentClass.getArgumentClass());
- }
- // TODO(b/165783587): add synthesised class to prevent constructor merge conflict
- return dexItemFactory.createProto(oldProto.returnType, parameters);
- }
-
- private DexMethod getNewConstructorReference(SyntheticArgumentClass syntheticArgumentClass) {
- DexProto proto = getNewConstructorProto(syntheticArgumentClass);
- return appView.dexItemFactory().createMethod(target.type, proto, dexItemFactory.initMethodName);
- }
-
private MethodAccessFlags getAccessFlags() {
// TODO(b/164998929): ensure this behaviour is correct, should probably calculate upper bound
return MethodAccessFlags.fromSharedAccessFlags(
@@ -157,12 +143,13 @@
classIdentifiers.getInt(constructor.getHolderType()), movedConstructor);
}
- DexMethod newConstructorReference = getNewConstructorReference(null);
- boolean addExtraNull = target.lookupMethod(newConstructorReference) != null;
- if (addExtraNull) {
- newConstructorReference = getNewConstructorReference(syntheticArgumentClass);
- assert target.lookupMethod(newConstructorReference) == null;
- }
+ DexMethod methodReferenceTemplate = generateReferenceMethodTemplate();
+ DexMethod newConstructorReference =
+ dexItemFactory.createInstanceInitializerWithFreshProto(
+ methodReferenceTemplate,
+ syntheticArgumentClass.getArgumentClass(),
+ tryMethod -> target.lookupMethod(tryMethod) == null);
+ int extraNulls = newConstructorReference.getArity() - methodReferenceTemplate.getArity();
DexMethod representativeConstructorReference = constructors.iterator().next().method;
ConstructorEntryPointSynthesizedCode synthesizedCode =
@@ -186,9 +173,9 @@
// The constructor does not require the additional argument, just map it like a regular
// method.
DexEncodedMethod oldConstructor = constructors.iterator().next();
- if (addExtraNull) {
+ if (extraNulls > 0) {
List<ExtraParameter> extraParameters = new LinkedList<>();
- extraParameters.add(new ExtraUnusedNullParameter());
+ extraParameters.addAll(Collections.nCopies(extraNulls, new ExtraUnusedNullParameter()));
lensBuilder.moveMergedConstructor(
oldConstructor.method, newConstructorReference, extraParameters);
} else {
@@ -201,9 +188,7 @@
List<ExtraParameter> extraParameters = new LinkedList<>();
extraParameters.add(new ExtraConstantIntParameter(classIdentifier));
- if (addExtraNull) {
- extraParameters.add(new ExtraUnusedNullParameter());
- }
+ extraParameters.addAll(Collections.nCopies(extraNulls, new ExtraUnusedNullParameter()));
lensBuilder.moveMergedConstructor(
oldConstructor.method, newConstructorReference, extraParameters);