Merge commit '70ebc812a8092a8b760c05682c8eb7d16b2cfab2' into dev-release
diff --git a/src/library_desugar/desugar_jdk_libs.json b/src/library_desugar/desugar_jdk_libs.json
index 795458a..67139d3 100644
--- a/src/library_desugar/desugar_jdk_libs.json
+++ b/src/library_desugar/desugar_jdk_libs.json
@@ -2,7 +2,7 @@
"configuration_format_version": 3,
"group_id" : "com.tools.android",
"artifact_id" : "desugar_jdk_libs",
- "version": "1.1.8",
+ "version": "1.1.9",
"required_compilation_api_level": 26,
"synthesized_library_classes_package_prefix": "j$.",
"support_all_callbacks_from_library": true,
@@ -258,4 +258,4 @@
"-keepattributes InnerClasses",
"-dontwarn sun.misc.Unsafe"
]
-}
\ No newline at end of file
+}
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs.json b/src/library_desugar/jdk11/desugar_jdk_libs.json
index 0180c03..05b48f0 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs.json
@@ -1,5 +1,5 @@
{
- "identifier": "com.tools.android:desugar_jdk_libs_configuration:2.0.2",
+ "identifier": "com.tools.android:desugar_jdk_libs_configuration:2.0.3",
"configuration_format_version": 100,
"required_compilation_api_level": 30,
"synthesized_library_classes_package_prefix": "j$.",
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_minimal.json b/src/library_desugar/jdk11/desugar_jdk_libs_minimal.json
index fb728c1..03edf18 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_minimal.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_minimal.json
@@ -1,5 +1,5 @@
{
- "identifier": "com.tools.android:desugar_jdk_libs_configuration_minimal:2.0.2",
+ "identifier": "com.tools.android:desugar_jdk_libs_configuration_minimal:2.0.3",
"configuration_format_version": 100,
"required_compilation_api_level": 24,
"synthesized_library_classes_package_prefix": "j$.",
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_nio.json b/src/library_desugar/jdk11/desugar_jdk_libs_nio.json
index 787243a..667ecc9 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_nio.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_nio.json
@@ -1,5 +1,5 @@
{
- "identifier": "com.tools.android:desugar_jdk_libs_configuration_nio:2.0.2",
+ "identifier": "com.tools.android:desugar_jdk_libs_configuration_nio:2.0.3",
"configuration_format_version": 100,
"required_compilation_api_level": 30,
"synthesized_library_classes_package_prefix": "j$.",
diff --git a/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java b/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java
index 7599bb6..03ae2fd 100644
--- a/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java
+++ b/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java
@@ -22,6 +22,7 @@
protected static final String ART_PROFILE_FLAG = "--art-profile";
protected static final String MIN_API_FLAG = "--min-api";
+ protected static final String STARTUP_PROFILE_FLAG = "--startup-profile";
protected static final String THREAD_COUNT_FLAG = "--thread-count";
protected static final String MAP_DIAGNOSTICS = "--map-diagnostics";
protected static final String DUMP_INPUT_TO_FILE = "--dumpinputtofile";
diff --git a/src/main/java/com/android/tools/r8/D8CommandParser.java b/src/main/java/com/android/tools/r8/D8CommandParser.java
index 4cf6711..7485cc8 100644
--- a/src/main/java/com/android/tools/r8/D8CommandParser.java
+++ b/src/main/java/com/android/tools/r8/D8CommandParser.java
@@ -27,8 +27,6 @@
public class D8CommandParser extends BaseCompilerCommandParser<D8Command, D8Command.Builder> {
- static final String STARTUP_PROFILE_FLAG = "--startup-profile";
-
private static final Set<String> OPTIONS_WITH_ONE_PARAMETER =
ImmutableSet.of(
"--output",
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 7a28ef3..1edde59 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -122,8 +122,8 @@
mapIdProvider,
null,
false,
- null,
- null,
+ Collections.emptyList(),
+ Collections.emptyList(),
classConflictResolver,
cancelCompilationChecker);
this.d8Command = d8Command;
diff --git a/src/main/java/com/android/tools/r8/R8CommandParser.java b/src/main/java/com/android/tools/r8/R8CommandParser.java
index f7db94e..f3fd1b8 100644
--- a/src/main/java/com/android/tools/r8/R8CommandParser.java
+++ b/src/main/java/com/android/tools/r8/R8CommandParser.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.profile.art.ArtProfileConsumerUtils;
import com.android.tools.r8.profile.art.ArtProfileProviderUtils;
+import com.android.tools.r8.profile.startup.StartupProfileProviderUtils;
import com.android.tools.r8.utils.FlagFile;
import com.android.tools.r8.utils.MapIdTemplateProvider;
import com.android.tools.r8.utils.SourceFileTemplateProvider;
@@ -47,6 +48,7 @@
"--map-id-template",
"--source-file-template",
ART_PROFILE_FLAG,
+ STARTUP_PROFILE_FLAG,
THREAD_COUNT_FLAG);
// Note: this must be a subset of OPTIONS_WITH_ONE_PARAMETER.
@@ -312,6 +314,10 @@
builder.addArtProfileForRewriting(
ArtProfileProviderUtils.createFromHumanReadableArtProfile(artProfilePath),
ArtProfileConsumerUtils.create(rewrittenArtProfilePath));
+ } else if (arg.equals(STARTUP_PROFILE_FLAG)) {
+ Path startupProfilePath = Paths.get(nextArg);
+ builder.addStartupProfileProviders(
+ StartupProfileProviderUtils.createFromHumanReadableArtProfile(startupProfilePath));
} else if (arg.startsWith("--")) {
if (tryParseAssertionArgument(builder, arg, argsOrigin)) {
continue;
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index 919de23..5ebfb20 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -85,6 +85,7 @@
private GraphLens codeLens = GraphLens.getIdentityLens();
private GraphLens graphLens = GraphLens.getIdentityLens();
private InitClassLens initClassLens;
+ private GraphLens kotlinMetadataLens = GraphLens.getIdentityLens();
private NamingLens namingLens = NamingLens.getIdentityLens();
private ProguardCompatibilityActions proguardCompatibilityActions;
private RootSet rootSet;
@@ -594,6 +595,14 @@
this.initClassLens = initClassLens;
}
+ public GraphLens getKotlinMetadataLens() {
+ return kotlinMetadataLens;
+ }
+
+ public void setKotlinMetadataLens(GraphLens kotlinMetadataLens) {
+ this.kotlinMetadataLens = kotlinMetadataLens;
+ }
+
public void setInitializedClassesInInstanceMethods(
InitializedClassesInInstanceMethods initializedClassesInInstanceMethods) {
this.initializedClassesInInstanceMethods = initializedClassesInInstanceMethods;
@@ -939,6 +948,7 @@
firstUnappliedLens.withAlternativeParentLens(
newMemberRebindingLens,
() -> {
+ GraphLens appliedLensInModifiedLens = GraphLens.getIdentityLens();
if (appView.hasLiveness()) {
appView
.withLiveness()
@@ -957,7 +967,9 @@
appView.setArtProfileCollection(
appView.getArtProfileCollection().rewrittenWithLens(appView, lens));
appView.setAssumeInfoCollection(
- appView.getAssumeInfoCollection().rewrittenWithLens(appView, lens));
+ appView
+ .getAssumeInfoCollection()
+ .rewrittenWithLens(appView, lens, appliedLensInModifiedLens));
if (appView.hasInitClassLens()) {
appView.setInitClassLens(appView.initClassLens().rewrittenWithLens(lens));
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
index 9807531..2b7a222 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.androidapi.ComputedApiLevel;
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
+import com.android.tools.r8.ir.analysis.type.DynamicType;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.analysis.value.SingleValue;
@@ -449,6 +450,13 @@
.recordFieldHasAbstractValue(fixedUpField, appView, abstractValue));
}
+ public Builder clearDynamicType() {
+ return addBuildConsumer(
+ fixedUpField ->
+ OptimizationFeedbackSimple.getInstance()
+ .markFieldHasDynamicType(fixedUpField, DynamicType.unknown()));
+ }
+
public Builder clearAnnotations() {
return setAnnotations(DexAnnotationSet.empty());
}
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 579b21f..2dfb637 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -85,6 +85,16 @@
"Ljava/lang/invoke/MethodHandles$Lookup;";
public static final String dalvikAnnotationOptimizationPrefixString =
"Ldalvik/annotation/optimization/";
+ public static final String androidUtilSparseArrayDescriptorString = "Landroid/util/SparseArray;";
+ public static final String androidContentResTypedArrayDescriptorString =
+ "Landroid/content/res/TypedArray;";
+ public static final String androidContentContentProviderClientDescriptorString =
+ "Landroid/content/ContentProviderClient;";
+ public static final String androidDrmDrmManagerClientDescriptorString =
+ "Landroid/drm/DrmManagerClient;";
+ public static final String androidMediaMediaDrmDescriptorString = "Landroid/media/MediaDrm;";
+ public static final String androidMediaMediaMetadataRetrieverDescriptorString =
+ "Landroid/media/MediaMetadataRetriever;";
/** Set of types that may be synthesized during compilation. */
private final Set<DexType> possibleCompilerSynthesizedTypes = Sets.newIdentityHashSet();
@@ -608,7 +618,17 @@
createStaticallyKnownType("Landroid/util/Property;");
public final DexType androidViewViewType = createStaticallyKnownType("Landroid/view/View;");
public final DexType androidUtilSparseArrayType =
- createStaticallyKnownType("Landroid/util/SparseArray;");
+ createStaticallyKnownType(androidUtilSparseArrayDescriptorString);
+ public final DexType androidContentResTypedArrayType =
+ createStaticallyKnownType(androidContentResTypedArrayDescriptorString);
+ public final DexType androidContentContentProviderClientType =
+ createStaticallyKnownType(androidContentContentProviderClientDescriptorString);
+ public final DexType androidDrmDrmManagerClientType =
+ createStaticallyKnownType(androidDrmDrmManagerClientDescriptorString);
+ public final DexType androidMediaMediaDrmType =
+ createStaticallyKnownType(androidMediaMediaDrmDescriptorString);
+ public final DexType androidMediaMediaMetadataRetrieverType =
+ createStaticallyKnownType(androidMediaMediaMetadataRetrieverDescriptorString);
public final StringBuildingMethods stringBuilderMethods =
new StringBuildingMethods(stringBuilderType);
@@ -662,6 +682,16 @@
public final AndroidViewViewMembers androidViewViewMembers = new AndroidViewViewMembers();
public final AndroidUtilSparseArrayMembers androidUtilSparseArrayMembers =
new AndroidUtilSparseArrayMembers();
+ public final AndroidContentResTypedArrayMembers androidContentResTypedArrayMembers =
+ new AndroidContentResTypedArrayMembers();
+ public final AndroidContentContentProviderClientMembers
+ androidContentContentProviderClientMembers = new AndroidContentContentProviderClientMembers();
+ public final AndroidDrmDrmManagerClientMembers androidDrmDrmManagerClientMembers =
+ new AndroidDrmDrmManagerClientMembers();
+ public final AndroidMediaMediaDrmMembers androidMediaMediaDrmMembers =
+ new AndroidMediaMediaDrmMembers();
+ public final AndroidMediaMetadataRetrieverMembers androidMediaMetadataRetrieverMembers =
+ new AndroidMediaMetadataRetrieverMembers();
// java.**
public final JavaIoFileMembers javaIoFileMembers = new JavaIoFileMembers();
@@ -1135,6 +1165,7 @@
}
}
+ // android.util.SparseArray
public class AndroidUtilSparseArrayMembers extends LibraryMembers {
public final DexMethod put =
createMethod(androidUtilSparseArrayType, createProto(voidType, intType, objectType), "put");
@@ -1143,6 +1174,46 @@
androidUtilSparseArrayType, createProto(voidType, intType, objectType), setString);
}
+ // android.content.res.TypedArray
+ public class AndroidContentResTypedArrayMembers extends LibraryMembers {
+ public final DexMethod recycle =
+ createMethod(androidContentResTypedArrayType, createProto(voidType), "recycle");
+ public final DexMethod close =
+ createMethod(androidContentResTypedArrayType, createProto(voidType), "close");
+ }
+
+ // android.content.ContentProviderClient
+ public class AndroidContentContentProviderClientMembers extends LibraryMembers {
+ public final DexMethod release =
+ createMethod(androidContentContentProviderClientType, createProto(voidType), "release");
+ public final DexMethod close =
+ createMethod(androidContentContentProviderClientType, createProto(voidType), "close");
+ }
+
+ // android.drm.DrmManagerClient
+ public class AndroidDrmDrmManagerClientMembers extends LibraryMembers {
+ public final DexMethod release =
+ createMethod(androidDrmDrmManagerClientType, createProto(voidType), "release");
+ public final DexMethod close =
+ createMethod(androidDrmDrmManagerClientType, createProto(voidType), "close");
+ }
+
+ // android.media.MediaDrm
+ public class AndroidMediaMediaDrmMembers extends LibraryMembers {
+ public final DexMethod release =
+ createMethod(androidMediaMediaDrmType, createProto(voidType), "release");
+ public final DexMethod close =
+ createMethod(androidMediaMediaDrmType, createProto(voidType), "close");
+ }
+
+ // android.media.MediaMetadataRetriever
+ public class AndroidMediaMetadataRetrieverMembers extends LibraryMembers {
+ public final DexMethod release =
+ createMethod(androidMediaMediaMetadataRetrieverType, createProto(voidType), "release");
+ public final DexMethod close =
+ createMethod(androidMediaMediaMetadataRetrieverType, createProto(voidType), "close");
+ }
+
public class BooleanMembers extends BoxedPrimitiveMembers {
public final DexField FALSE = createField(boxedBooleanType, boxedBooleanType, "FALSE");
diff --git a/src/main/java/com/android/tools/r8/graph/lens/GraphLens.java b/src/main/java/com/android/tools/r8/graph/lens/GraphLens.java
index bd71700..6f292cb 100644
--- a/src/main/java/com/android/tools/r8/graph/lens/GraphLens.java
+++ b/src/main/java/com/android/tools/r8/graph/lens/GraphLens.java
@@ -152,10 +152,11 @@
public abstract DexField getRenamedFieldSignature(DexField originalField, GraphLens codeLens);
- public final DexMember<?, ?> getRenamedMemberSignature(DexMember<?, ?> originalMember) {
+ public final DexMember<?, ?> getRenamedMemberSignature(
+ DexMember<?, ?> originalMember, GraphLens codeLens) {
return originalMember.isDexField()
- ? getRenamedFieldSignature(originalMember.asDexField())
- : getRenamedMethodSignature(originalMember.asDexMethod());
+ ? getRenamedFieldSignature(originalMember.asDexField(), codeLens)
+ : getRenamedMethodSignature(originalMember.asDexMethod(), codeLens);
}
public final DexMethod getRenamedMethodSignature(DexMethod originalMethod) {
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java
index 55aad86d..a12baa2 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java
@@ -139,7 +139,7 @@
for (DexProgramClass root : subtypingForrest.getProgramRoots()) {
subtypingForrest.traverseNodeDepthFirst(root, HashBiMap.create(), this::fixupProgramClass);
}
- new AnnotationFixer(lens).run(appView.appInfo().classes());
+ new AnnotationFixer(lens, appView.graphLens()).run(appView.appInfo().classes());
}
return lens;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
index 2a543a8..4df6b75 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
@@ -37,6 +37,7 @@
import com.android.tools.r8.ir.optimize.ClassInitializerDefaultsOptimization.ClassInitializerDefaultsResult;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.ArrayUtils;
import com.android.tools.r8.utils.Timing;
import java.util.IdentityHashMap;
import java.util.List;
@@ -262,13 +263,14 @@
return null;
}
+ DexType[] valuesTypes = new DexType[valuesSize];
ObjectState[] valuesState = new ObjectState[valuesSize];
if (invokeNewArray != null) {
// Populate array values from filled-new-array values.
List<Value> inValues = invokeNewArray.inValues();
for (int i = 0; i < valuesSize; ++i) {
- if (!updateEnumValueState(valuesState, i, inValues.get(i))) {
+ if (!updateEnumValueState(valuesState, valuesTypes, i, inValues.get(i))) {
return null;
}
}
@@ -291,7 +293,7 @@
if (index < 0 || index >= valuesSize) {
return null;
}
- if (!updateEnumValueState(valuesState, index, arrayPut.value())) {
+ if (!updateEnumValueState(valuesState, valuesTypes, index, arrayPut.value())) {
return null;
}
break;
@@ -323,18 +325,20 @@
return null;
}
- for (ObjectState objectState : valuesState) {
- if (objectState == null) {
- return null;
- }
+ if (ArrayUtils.contains(valuesState, null)) {
+ return null;
}
+ // This should be guaranteed since valuesState and valuesTypes are updated at the same time.
+ assert !ArrayUtils.contains(valuesTypes, null);
return appView
.abstractValueFactory()
- .createSingleFieldValue(valuesField.getReference(), new EnumValuesObjectState(valuesState));
+ .createSingleFieldValue(
+ valuesField.getReference(), new EnumValuesObjectState(valuesState, valuesTypes));
}
- private boolean updateEnumValueState(ObjectState[] valuesState, int index, Value value) {
+ private boolean updateEnumValueState(
+ ObjectState[] valuesState, DexType[] valuesTypes, int index, Value value) {
Value root = value.getAliasedValue();
if (root.isPhi()) {
return false;
@@ -360,6 +364,8 @@
if (valuesState[index] != null) {
return false;
}
+ assert definition.isNewInstance();
+ valuesTypes[index] = definition.asNewInstance().getType();
valuesState[index] = objectState;
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/EnumValuesObjectState.java b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/EnumValuesObjectState.java
index 3a50ca7..722dccc 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/EnumValuesObjectState.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/EnumValuesObjectState.java
@@ -7,10 +7,12 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.analysis.value.UnknownValue;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.ArrayUtils;
import java.util.Arrays;
import java.util.Objects;
import java.util.function.BiConsumer;
@@ -18,11 +20,20 @@
public class EnumValuesObjectState extends ObjectState {
private final ObjectState[] state;
+ // Contains information about the class of each enum instance.
+ private final ObjectClassForOrdinal objectClassForOrdinal;
- public EnumValuesObjectState(ObjectState[] state) {
+ public EnumValuesObjectState(ObjectState[] state, DexType[] valuesTypes) {
assert state.length > 0;
+ assert valuesTypes.length == state.length;
assert Arrays.stream(state).noneMatch(Objects::isNull);
this.state = state;
+ this.objectClassForOrdinal = ObjectClassForOrdinal.create(valuesTypes);
+ }
+
+ EnumValuesObjectState(ObjectState[] state, ObjectClassForOrdinal objectClassForOrdinal) {
+ this.state = state;
+ this.objectClassForOrdinal = objectClassForOrdinal;
}
@Override
@@ -40,6 +51,13 @@
return state[ordinal];
}
+ public DexType getObjectClassForOrdinal(int ordinal) {
+ if (ordinal < 0 || ordinal >= state.length) {
+ return null;
+ }
+ return objectClassForOrdinal.getObjectClassForOrdinal(ordinal);
+ }
+
public int getEnumValuesSize() {
return state.length;
}
@@ -77,7 +95,8 @@
for (int i = 0; i < state.length; i++) {
newState[i] = state[i].rewrittenWithLens(appView, lens, codeLens);
}
- return new EnumValuesObjectState(newState);
+ return new EnumValuesObjectState(
+ newState, objectClassForOrdinal.rewrittenWithLens(appView, lens, codeLens));
}
@Override
@@ -89,16 +108,124 @@
if (state.length != other.state.length) {
return false;
}
- for (int i = 0; i < state.length; i++) {
- if (!state[i].equals(other.state[i])) {
- return false;
- }
+ if (!Arrays.equals(state, other.state)) {
+ return false;
}
- return true;
+ return objectClassForOrdinal.equals(other.objectClassForOrdinal);
}
@Override
public int hashCode() {
return Arrays.hashCode(state);
}
+
+ abstract static class ObjectClassForOrdinal {
+
+ static ObjectClassForOrdinal create(DexType[] valuesClass) {
+ return sameType(valuesClass)
+ ? new UniformObjectClassForOrdinal(valuesClass[0])
+ : new VariableObjectClassForOrdinal(valuesClass);
+ }
+
+ static boolean sameType(DexType[] valuesClass) {
+ DexType defaultType = valuesClass[0];
+ for (DexType type : valuesClass) {
+ if (type != defaultType) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ abstract DexType getObjectClassForOrdinal(int ordinal);
+
+ abstract ObjectClassForOrdinal rewrittenWithLens(
+ AppView<AppInfoWithLiveness> appView, GraphLens lens, GraphLens codeLens);
+
+ @Override
+ public abstract int hashCode();
+
+ @Override
+ public abstract boolean equals(Object obj);
+ }
+
+ static class UniformObjectClassForOrdinal extends ObjectClassForOrdinal {
+ private final DexType type;
+
+ UniformObjectClassForOrdinal(DexType type) {
+ assert type != null;
+ this.type = type;
+ }
+
+ @Override
+ DexType getObjectClassForOrdinal(int ordinal) {
+ return type;
+ }
+
+ @Override
+ ObjectClassForOrdinal rewrittenWithLens(
+ AppView<AppInfoWithLiveness> appView, GraphLens lens, GraphLens codeLens) {
+ DexType rewrittenType = lens.lookupType(type, codeLens);
+ assert rewrittenType.isClassType();
+ return new UniformObjectClassForOrdinal(rewrittenType);
+ }
+
+ @Override
+ public int hashCode() {
+ return type.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof UniformObjectClassForOrdinal)) {
+ return false;
+ }
+ UniformObjectClassForOrdinal other = (UniformObjectClassForOrdinal) obj;
+ return type == other.type;
+ }
+ }
+
+ static class VariableObjectClassForOrdinal extends ObjectClassForOrdinal {
+ private final DexType[] types;
+
+ VariableObjectClassForOrdinal(DexType[] types) {
+ assert Arrays.stream(types).noneMatch(Objects::isNull);
+ this.types = types;
+ }
+
+ @Override
+ DexType getObjectClassForOrdinal(int ordinal) {
+ assert ordinal >= 0 && ordinal < types.length;
+ return types[ordinal];
+ }
+
+ @Override
+ ObjectClassForOrdinal rewrittenWithLens(
+ AppView<AppInfoWithLiveness> appView, GraphLens lens, GraphLens codeLens) {
+ DexType[] newTypes =
+ ArrayUtils.map(
+ types,
+ type -> {
+ DexType rewrittenType = lens.lookupType(type, codeLens);
+ assert rewrittenType.isClassType();
+ return rewrittenType;
+ },
+ DexType.EMPTY_ARRAY);
+ return create(newTypes);
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(types);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof VariableObjectClassForOrdinal)) {
+ return false;
+ }
+ VariableObjectClassForOrdinal other = (VariableObjectClassForOrdinal) obj;
+ return Arrays.equals(types, other.types);
+ }
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/NonEmptyObjectState.java b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/NonEmptyObjectState.java
index b9a9933..2b6f00d 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/NonEmptyObjectState.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/NonEmptyObjectState.java
@@ -55,7 +55,7 @@
@Override
public boolean equals(Object o) {
- if (getClass() != o.getClass()) {
+ if (o == null || getClass() != o.getClass()) {
return false;
}
NonEmptyObjectState other = (NonEmptyObjectState) o;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
index 47d762c..4643e0a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -45,12 +45,17 @@
import com.android.tools.r8.ir.desugar.backports.BooleanMethodRewrites;
import com.android.tools.r8.ir.desugar.backports.CollectionMethodGenerators;
import com.android.tools.r8.ir.desugar.backports.CollectionMethodRewrites;
+import com.android.tools.r8.ir.desugar.backports.ContentProviderClientMethodRewrites;
+import com.android.tools.r8.ir.desugar.backports.DrmManagerClientMethodRewrites;
import com.android.tools.r8.ir.desugar.backports.FloatMethodRewrites;
import com.android.tools.r8.ir.desugar.backports.LongMethodRewrites;
+import com.android.tools.r8.ir.desugar.backports.MediaDrmMethodRewrites;
+import com.android.tools.r8.ir.desugar.backports.MediaMetadataRetrieverMethodRewrites;
import com.android.tools.r8.ir.desugar.backports.NumericMethodRewrites;
import com.android.tools.r8.ir.desugar.backports.ObjectsMethodRewrites;
import com.android.tools.r8.ir.desugar.backports.OptionalMethodRewrites;
import com.android.tools.r8.ir.desugar.backports.SparseArrayMethodRewrites;
+import com.android.tools.r8.ir.desugar.backports.TypedArrayMethodRewrites;
import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeter;
import com.android.tools.r8.position.MethodPosition;
import com.android.tools.r8.synthesis.SyntheticItems.GlobalSyntheticsStrategy;
@@ -235,6 +240,12 @@
initializeAndroidOThreadLocalMethodProviderWithSupplier(factory);
}
}
+ if (options.getMinApiLevel().isLessThan(AndroidApiLevel.P)) {
+ initializeAndroidPMethodProviders(factory);
+ }
+ if (options.getMinApiLevel().isLessThan(AndroidApiLevel.Q)) {
+ initializeAndroidQMethodProviders(factory);
+ }
if (options.getMinApiLevel().isLessThan(AndroidApiLevel.R)) {
if (options.testing.alwaysBackportListSetMapMethods
|| typeIsPresentWithoutBackportsFrom(factory.setType, AndroidApiLevel.R)) {
@@ -813,6 +824,22 @@
}
initializeMathExactApis(factory, factory.mathType);
+
+ // android.content.res.ContentProviderClient
+
+ // void android.content.ContentProviderClient.close()
+ addProvider(
+ new InvokeRewriter(
+ factory.androidContentContentProviderClientMembers.close,
+ ContentProviderClientMethodRewrites.rewriteClose()));
+
+ // android.drm.DrmManagerClient
+
+ // void android.drm.DrmManagerClient.close()
+ addProvider(
+ new InvokeRewriter(
+ factory.androidDrmDrmManagerClientMembers.close,
+ DrmManagerClientMethodRewrites.rewriteClose()));
}
/**
@@ -1051,6 +1078,21 @@
method, BackportedMethods::StringMethods_joinIterable, "joinIterable"));
}
+ private void initializeAndroidPMethodProviders(DexItemFactory factory) {
+ // void android.drm.DrmManagerClient.close()
+ addProvider(
+ new InvokeRewriter(
+ factory.androidMediaMediaDrmMembers.close, MediaDrmMethodRewrites.rewriteClose()));
+ }
+
+ private void initializeAndroidQMethodProviders(DexItemFactory factory) {
+ // void android.drm.DrmManagerClient.close()
+ addProvider(
+ new InvokeRewriter(
+ factory.androidMediaMetadataRetrieverMembers.close,
+ MediaMetadataRetrieverMethodRewrites.rewriteClose()));
+ }
+
private void initializeAndroidRObjectsMethodProviderWithSupplier(DexItemFactory factory) {
// Objects
DexType type = factory.objectsType;
@@ -1286,10 +1328,18 @@
// android.util.SparseArray
- // void android.util.SparseArray.set(int, Object))
+ // void android.util.SparseArray.set(int, Object)
addProvider(
new InvokeRewriter(
factory.androidUtilSparseArrayMembers.set, SparseArrayMethodRewrites.rewriteSet()));
+
+ // android.content.res.TypedArray
+
+ // void android.content.res.TypedArray.close()
+ addProvider(
+ new InvokeRewriter(
+ factory.androidContentResTypedArrayMembers.close,
+ TypedArrayMethodRewrites.rewriteClose()));
}
private void initializeAndroidSv2MethodProviders(DexItemFactory factory) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/ContentProviderClientMethodRewrites.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/ContentProviderClientMethodRewrites.java
new file mode 100644
index 0000000..8881483
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/ContentProviderClientMethodRewrites.java
@@ -0,0 +1,24 @@
+// Copyright (c) 2023, 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.ir.desugar.backports;
+
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.ir.desugar.BackportedMethodRewriter.MethodInvokeRewriter;
+import org.objectweb.asm.Opcodes;
+
+public final class ContentProviderClientMethodRewrites {
+
+ private ContentProviderClientMethodRewrites() {}
+
+ public static MethodInvokeRewriter rewriteClose() {
+ // Rewrite android/content/ContentProviderClient#close to
+ // android/content/ContentProviderClient#recycle
+ return (invoke, factory) ->
+ new CfInvoke(
+ Opcodes.INVOKEVIRTUAL,
+ factory.androidContentContentProviderClientMembers.release,
+ false);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/DrmManagerClientMethodRewrites.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/DrmManagerClientMethodRewrites.java
new file mode 100644
index 0000000..408f560
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/DrmManagerClientMethodRewrites.java
@@ -0,0 +1,21 @@
+// Copyright (c) 2023, 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.ir.desugar.backports;
+
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.ir.desugar.BackportedMethodRewriter.MethodInvokeRewriter;
+import org.objectweb.asm.Opcodes;
+
+public final class DrmManagerClientMethodRewrites {
+
+ private DrmManagerClientMethodRewrites() {}
+
+ public static MethodInvokeRewriter rewriteClose() {
+ // Rewrite android/drm/DrmManagerClient#close to android/drm/DrmManagerClient#release
+ return (invoke, factory) ->
+ new CfInvoke(
+ Opcodes.INVOKEVIRTUAL, factory.androidDrmDrmManagerClientMembers.release, false);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/MediaDrmMethodRewrites.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/MediaDrmMethodRewrites.java
new file mode 100644
index 0000000..57b0fe2
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/MediaDrmMethodRewrites.java
@@ -0,0 +1,20 @@
+// Copyright (c) 2023, 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.ir.desugar.backports;
+
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.ir.desugar.BackportedMethodRewriter.MethodInvokeRewriter;
+import org.objectweb.asm.Opcodes;
+
+public final class MediaDrmMethodRewrites {
+
+ private MediaDrmMethodRewrites() {}
+
+ public static MethodInvokeRewriter rewriteClose() {
+ // Rewrite android/media/MediaDrm#close to android/media/MediaDrm#release
+ return (invoke, factory) ->
+ new CfInvoke(Opcodes.INVOKEVIRTUAL, factory.androidMediaMediaDrmMembers.release, false);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/MediaMetadataRetrieverMethodRewrites.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/MediaMetadataRetrieverMethodRewrites.java
new file mode 100644
index 0000000..07aec55
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/MediaMetadataRetrieverMethodRewrites.java
@@ -0,0 +1,22 @@
+// Copyright (c) 2023, 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.ir.desugar.backports;
+
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.ir.desugar.BackportedMethodRewriter.MethodInvokeRewriter;
+import org.objectweb.asm.Opcodes;
+
+public final class MediaMetadataRetrieverMethodRewrites {
+
+ private MediaMetadataRetrieverMethodRewrites() {}
+
+ public static MethodInvokeRewriter rewriteClose() {
+ // Rewrite android/media/MediaMetadataRetriever#close to
+ // android/media/MediaMetadataRetriever#release
+ return (invoke, factory) ->
+ new CfInvoke(
+ Opcodes.INVOKEVIRTUAL, factory.androidMediaMetadataRetrieverMembers.release, false);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/TypedArrayMethodRewrites.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/TypedArrayMethodRewrites.java
new file mode 100644
index 0000000..941f0ba
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/TypedArrayMethodRewrites.java
@@ -0,0 +1,21 @@
+// Copyright (c) 2023, 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.ir.desugar.backports;
+
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.ir.desugar.BackportedMethodRewriter.MethodInvokeRewriter;
+import org.objectweb.asm.Opcodes;
+
+public final class TypedArrayMethodRewrites {
+
+ private TypedArrayMethodRewrites() {}
+
+ public static MethodInvokeRewriter rewriteClose() {
+ // Rewrite android/content/res/TypedArray#close to android/content/res/TypedArray#recycle
+ return (invoke, factory) ->
+ new CfInvoke(
+ Opcodes.INVOKEVIRTUAL, factory.androidContentResTypedArrayMembers.recycle, false);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumDataMap.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumDataMap.java
index 00c4f50..4a91dc0 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumDataMap.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumDataMap.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -109,6 +110,8 @@
// Map each enum instance field to the list of field known data.
final ImmutableMap<DexField, EnumInstanceFieldKnownData> instanceFieldMap;
+ // Map each ordinal to their original type. This is recorded *only* if the enum has subtypes.
+ final Int2ReferenceMap<DexType> valuesTypes;
// Map each enum instance (static field) to the unboxed integer value.
final ImmutableMap<DexField, Integer> unboxedValues;
// Fields matching the $VALUES content and type, usually one.
@@ -118,10 +121,12 @@
public EnumData(
ImmutableMap<DexField, EnumInstanceFieldKnownData> instanceFieldMap,
+ Int2ReferenceMap<DexType> valuesTypes,
ImmutableMap<DexField, Integer> unboxedValues,
ImmutableSet<DexField> valuesFields,
int valuesSize) {
this.instanceFieldMap = instanceFieldMap;
+ this.valuesTypes = valuesTypes;
this.unboxedValues = unboxedValues;
this.valuesFields = valuesFields;
this.valuesSize = valuesSize;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
index 4666036..5f9e4f2 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
@@ -50,6 +50,7 @@
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.StaticFieldValues.EnumStaticFieldValues;
import com.android.tools.r8.ir.analysis.type.ArrayTypeElement;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
+import com.android.tools.r8.ir.analysis.type.DynamicType;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.analysis.value.objectstate.EnumValuesObjectState;
@@ -92,6 +93,7 @@
import com.android.tools.r8.ir.optimize.enums.eligibility.Reason.IllegalInvokeWithImpreciseParameterTypeReason;
import com.android.tools.r8.ir.optimize.enums.eligibility.Reason.MissingContentsForEnumValuesArrayReason;
import com.android.tools.r8.ir.optimize.enums.eligibility.Reason.MissingEnumStaticFieldValuesReason;
+import com.android.tools.r8.ir.optimize.enums.eligibility.Reason.MissingExactDynamicEnumTypeForEnumWithSubtypesReason;
import com.android.tools.r8.ir.optimize.enums.eligibility.Reason.MissingInstanceFieldValueForEnumInstanceReason;
import com.android.tools.r8.ir.optimize.enums.eligibility.Reason.MissingObjectStateForEnumInstanceReason;
import com.android.tools.r8.ir.optimize.enums.eligibility.Reason.UnsupportedInstanceFieldValueForEnumInstanceReason;
@@ -762,8 +764,8 @@
@Override
public void fixup(DexEncodedField field, MutableFieldOptimizationInfo optimizationInfo) {
optimizationInfo
- .fixupClassTypeReferences(appView, graphLens)
- .fixupAbstractValue(appView, graphLens, codeLens);
+ .fixupAbstractValue(appView, graphLens, codeLens)
+ .fixupClassTypeReferences(appView, graphLens);
}
@Override
@@ -827,12 +829,16 @@
private EnumData buildData(DexProgramClass enumClass, Set<DexField> instanceFields) {
if (!enumClass.hasStaticFields()) {
- return new EnumData(ImmutableMap.of(), ImmutableMap.of(), ImmutableSet.of(), -1);
+ return new EnumData(ImmutableMap.of(), null, ImmutableMap.of(), ImmutableSet.of(), -1);
}
// This map holds all the accessible fields to their unboxed value, so we can remap the field
// read to the unboxed value.
ImmutableMap.Builder<DexField, Integer> unboxedValues = ImmutableMap.builder();
+ // This maps the ordinal to their original type so that enum with subtypes can be correctly
+ // handled.
+ Int2ReferenceMap<DexType> valueTypes = new Int2ReferenceArrayMap<>();
+ boolean isEnumWithSubtypes = enumUnboxingCandidatesInfo.hasSubtypes(enumClass.getType());
// This maps the ordinal to the object state, note that some fields may have been removed,
// hence the entry is in this map but not the enumToOrdinalMap.
Int2ReferenceMap<ObjectState> ordinalToObjectState = new Int2ReferenceArrayMap<>();
@@ -874,6 +880,18 @@
int ordinal = optionalOrdinal.getAsInt();
unboxedValues.put(staticField.getReference(), ordinalToUnboxedInt(ordinal));
ordinalToObjectState.put(ordinal, enumState);
+ if (isEnumWithSubtypes) {
+ DynamicType dynamicType = staticField.getOptimizationInfo().getDynamicType();
+ if (dynamicType.isExactClassType()) {
+ valueTypes.put(ordinal, dynamicType.getExactClassType().getClassType());
+ } else {
+ reportFailure(
+ enumClass,
+ new MissingExactDynamicEnumTypeForEnumWithSubtypesReason(
+ staticField.getReference()));
+ return null;
+ }
+ }
} else if (factory.enumMembers.isValuesFieldCandidate(staticField, enumClass.type)) {
ObjectState valuesState =
enumStaticFieldValues.getObjectStateForPossiblyPinnedField(staticField.getReference());
@@ -905,11 +923,24 @@
ObjectState enumState = valuesContents.getObjectStateForOrdinal(ordinal);
if (enumState.isEmpty()) {
// If $VALUES is used, we need data for all enums, at least the ordinal.
+ reportFailure(
+ enumClass,
+ new MissingInstanceFieldValueForEnumInstanceReason(
+ factory.enumMembers.ordinalField, ordinal));
return null;
}
assert getOrdinal(enumState).isPresent();
assert getOrdinal(enumState).getAsInt() == ordinal;
ordinalToObjectState.put(ordinal, enumState);
+ if (isEnumWithSubtypes) {
+ DexType type = valuesContents.getObjectClassForOrdinal(ordinal);
+ if (type == null) {
+ reportFailure(
+ enumClass, new MissingExactDynamicEnumTypeForEnumWithSubtypesReason(ordinal));
+ return null;
+ }
+ valueTypes.put(ordinal, type);
+ }
}
}
}
@@ -925,6 +956,7 @@
return new EnumData(
instanceFieldsData,
+ isEnumWithSubtypes ? valueTypes : null,
unboxedValues.build(),
valuesField.build(),
valuesContents == null ? EnumData.INVALID_VALUES_SIZE : valuesContents.getEnumValuesSize());
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateInfoCollection.java
index 9feeed2..bfeb83b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateInfoCollection.java
@@ -38,6 +38,10 @@
new EnumUnboxingCandidateInfo(appView, enumClass, graphLensForPrimaryOptimizationPass));
}
+ public boolean hasSubtypes(DexType enumType) {
+ return !enumTypeToInfo.get(enumType).getSubclasses().isEmpty();
+ }
+
public void setEnumSubclasses(DexType superEnum, Set<DexProgramClass> subclasses) {
enumTypeToInfo.get(superEnum).setSubclasses(subclasses);
}
@@ -159,6 +163,10 @@
graphLensForPrimaryOptimizationPass);
}
+ public Set<DexProgramClass> getSubclasses() {
+ return subclasses;
+ }
+
public void setSubclasses(Set<DexProgramClass> subclasses) {
this.subclasses = subclasses;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
index 67efedd..738ed1e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
+import com.android.tools.r8.graph.DexEncodedField.Builder;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
@@ -623,12 +624,7 @@
DexField newField = field.withType(newType, factory);
lensBuilder.move(field, newField);
DexEncodedField newEncodedField =
- encodedField.toTypeSubstitutedField(
- appView,
- newField,
- builder ->
- builder.setAbstractValue(
- encodedField.getOptimizationInfo().getAbstractValue(), appView));
+ encodedField.toTypeSubstitutedField(appView, newField, Builder::clearDynamicType);
if (encodedField.isStatic() && encodedField.hasExplicitStaticValue()) {
assert encodedField.getStaticValue() == DexValue.DexValueNull.NULL;
newEncodedField.setStaticValue(DexValue.DexValueInt.DEFAULT);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/eligibility/Reason.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/eligibility/Reason.java
index 5f31298..26c35b2 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/eligibility/Reason.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/eligibility/Reason.java
@@ -124,6 +124,34 @@
}
}
+ public static class MissingExactDynamicEnumTypeForEnumWithSubtypesReason extends Reason {
+
+ private final DexField enumField;
+ private final int ordinal;
+
+ public MissingExactDynamicEnumTypeForEnumWithSubtypesReason(DexField enumField) {
+ this.enumField = enumField;
+ this.ordinal = -1;
+ }
+
+ public MissingExactDynamicEnumTypeForEnumWithSubtypesReason(int ordinal) {
+ this.ordinal = ordinal;
+ this.enumField = null;
+ }
+
+ @Override
+ public Object getKind() {
+ return getClass();
+ }
+
+ @Override
+ public String toString() {
+ return "MissingDynamicType("
+ + (enumField != null ? enumField.toSourceString() : "ordinal=" + ordinal)
+ + ")";
+ }
+ }
+
public static class MissingInstanceFieldValueForEnumInstanceReason extends Reason {
private final DexField enumField;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java
index 89b97ad..406aa24 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java
@@ -64,9 +64,10 @@
this.abstractValue = abstractValue;
}
- public void fixupAbstractValue(
+ public MutableFieldOptimizationInfo fixupAbstractValue(
AppView<AppInfoWithLiveness> appView, GraphLens lens, GraphLens codeLens) {
setAbstractValue(abstractValue.rewrittenWithLens(appView, lens, codeLens));
+ return this;
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
index c766497..3fdb8b4 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
@@ -53,7 +53,7 @@
@Override
public void markFieldHasDynamicType(DexEncodedField field, DynamicType dynamicType) {
- // Ignored.
+ field.getMutableOptimizationInfo().setDynamicType(dynamicType);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataMembersTracker.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataMembersTracker.java
index 88691a9..98dc167 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataMembersTracker.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataMembersTracker.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexMember;
-import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.utils.IterableUtils;
import com.google.common.collect.Sets;
@@ -48,7 +47,10 @@
// underlying types are changed.
diffComparedToRewritten.forEach(
diff -> {
- DexReference rewrittenReference = appView.graphLens().lookupReference(diff);
+ DexMember<?, ?> rewrittenReference =
+ appView
+ .graphLens()
+ .getRenamedMemberSignature(diff, appView.getKotlinMetadataLens());
assert diffComparedToOriginal.contains(rewrittenReference);
assert IterableUtils.findOrDefault(
diff.getReferencedTypes(), type -> isKotlinJvmType(appView, type), null)
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
index 858a57c..04392f3 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
@@ -20,6 +20,7 @@
import com.android.tools.r8.graph.DexValue.DexValueArray;
import com.android.tools.r8.graph.DexValue.DexValueInt;
import com.android.tools.r8.graph.DexValue.DexValueString;
+import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.utils.BooleanBox;
import com.android.tools.r8.utils.ConsumerUtils;
import com.android.tools.r8.utils.Pair;
@@ -84,7 +85,10 @@
}
public void runForR8(ExecutorService executorService) throws ExecutionException {
- DexType rewrittenMetadataType = appView.graphLens().lookupClassType(factory.kotlinMetadataType);
+ GraphLens graphLens = appView.graphLens();
+ GraphLens kotlinMetadataLens = appView.getKotlinMetadataLens();
+ DexType rewrittenMetadataType =
+ graphLens.lookupClassType(factory.kotlinMetadataType, kotlinMetadataLens);
DexClass kotlinMetadata = appView.definitionFor(rewrittenMetadataType);
WriteMetadataFieldInfo writeMetadataFieldInfo =
new WriteMetadataFieldInfo(
@@ -124,6 +128,7 @@
writeKotlinInfoToAnnotation(clazz, kotlinInfo, oldMeta, writeMetadataFieldInfo);
},
executorService);
+ appView.setKotlinMetadataLens(appView.graphLens());
}
public void runForD8(ExecutorService executorService) throws ExecutionException {
diff --git a/src/main/java/com/android/tools/r8/profile/art/ArtProfile.java b/src/main/java/com/android/tools/r8/profile/art/ArtProfile.java
index 1455800..cc12b86 100644
--- a/src/main/java/com/android/tools/r8/profile/art/ArtProfile.java
+++ b/src/main/java/com/android/tools/r8/profile/art/ArtProfile.java
@@ -297,15 +297,25 @@
@Override
public Builder addClassRule(ArtProfileClassRule classRule) {
- assert !rules.containsKey(classRule.getReference());
rules.put(classRule.getType(), classRule);
return this;
}
@Override
public Builder addMethodRule(ArtProfileMethodRule methodRule) {
- assert !rules.containsKey(methodRule.getReference());
- rules.put(methodRule.getMethod(), methodRule);
+ rules.compute(
+ methodRule.getReference(),
+ (reference, existingRule) -> {
+ if (existingRule == null) {
+ return methodRule;
+ }
+ ArtProfileMethodRule existingMethodRule = (ArtProfileMethodRule) existingRule;
+ return ArtProfileMethodRule.builder()
+ .setMethod(methodRule.getMethod())
+ .join(methodRule)
+ .join(existingMethodRule)
+ .build();
+ });
return this;
}
diff --git a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
index 00e55a7..cffb1cf 100644
--- a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
+++ b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
@@ -151,7 +151,7 @@
repackagingTreeFixer.fixupClasses(appView.appInfo().classesWithDeterministicOrder()));
appBuilder.replaceProgramClasses(newProgramClasses);
RepackagingLens lens = lensBuilder.build(appView, packageMappings);
- new AnnotationFixer(lens).run(appBuilder.getProgramClasses());
+ new AnnotationFixer(lens, appView.graphLens()).run(appBuilder.getProgramClasses());
return lens;
}
diff --git a/src/main/java/com/android/tools/r8/shaking/AnnotationFixer.java b/src/main/java/com/android/tools/r8/shaking/AnnotationFixer.java
index c1a8677..dc9c163 100644
--- a/src/main/java/com/android/tools/r8/shaking/AnnotationFixer.java
+++ b/src/main/java/com/android/tools/r8/shaking/AnnotationFixer.java
@@ -26,9 +26,15 @@
public class AnnotationFixer {
private final GraphLens lens;
+ private final GraphLens annotationLens;
- public AnnotationFixer(GraphLens lens) {
+ public AnnotationFixer(GraphLens lens, GraphLens annotationLens) {
this.lens = lens;
+ this.annotationLens = annotationLens;
+ }
+
+ private DexType lookupType(DexType type) {
+ return lens.lookupType(type, annotationLens);
}
public void run(Iterable<DexProgramClass> classes) {
@@ -54,7 +60,7 @@
private DexEncodedAnnotation rewriteEncodedAnnotation(DexEncodedAnnotation original) {
DexEncodedAnnotation rewritten =
- original.rewrite(lens::lookupType, this::rewriteAnnotationElement);
+ original.rewrite(this::lookupType, this::rewriteAnnotationElement);
assert rewritten != null;
return rewritten;
}
@@ -96,7 +102,7 @@
}
} else if (value.isDexValueEnum()) {
DexField original = value.asDexValueEnum().value;
- DexField rewritten = lens.lookupField(original);
+ DexField rewritten = lens.lookupField(original, annotationLens);
if (original != rewritten) {
return new DexValueEnum(rewritten);
}
@@ -112,7 +118,7 @@
// If we identified references in the string it would be a DexItemBasedValueString.
} else if (value.isDexValueType()) {
DexType originalType = value.asDexValueType().value;
- DexType rewrittenType = lens.lookupType(originalType);
+ DexType rewrittenType = lookupType(originalType);
if (rewrittenType != originalType) {
return new DexValueType(rewrittenType);
}
diff --git a/src/main/java/com/android/tools/r8/shaking/AssumeInfoCollection.java b/src/main/java/com/android/tools/r8/shaking/AssumeInfoCollection.java
index bc3f728..75d7671 100644
--- a/src/main/java/com/android/tools/r8/shaking/AssumeInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/shaking/AssumeInfoCollection.java
@@ -60,11 +60,13 @@
return isSideEffectFree(member.getReference());
}
- public AssumeInfoCollection rewrittenWithLens(AppView<?> appView, GraphLens graphLens) {
+ public AssumeInfoCollection rewrittenWithLens(
+ AppView<?> appView, GraphLens graphLens, GraphLens appliedLens) {
Map<DexMember<?, ?>, AssumeInfo> rewrittenCollection = new IdentityHashMap<>();
backing.forEach(
(reference, info) -> {
- DexMember<?, ?> rewrittenReference = graphLens.getRenamedMemberSignature(reference);
+ DexMember<?, ?> rewrittenReference =
+ graphLens.getRenamedMemberSignature(reference, appliedLens);
AssumeInfo rewrittenInfo = info.rewrittenWithLens(appView, graphLens);
assert !rewrittenInfo.isEmpty();
rewrittenCollection.put(rewrittenReference, rewrittenInfo);
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index 91c86e3..2397d02 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -1690,7 +1690,7 @@
}
VerticalClassMergerGraphLens lens = lensBuilder.build(appView, mergedClasses);
if (lens != null) {
- new AnnotationFixer(lens).run(appView.appInfo().classes());
+ new AnnotationFixer(lens, appView.graphLens()).run(appView.appInfo().classes());
}
return lens;
}
diff --git a/src/main/java/com/android/tools/r8/utils/ArrayUtils.java b/src/main/java/com/android/tools/r8/utils/ArrayUtils.java
index b8d37cb..3e5104a 100644
--- a/src/main/java/com/android/tools/r8/utils/ArrayUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ArrayUtils.java
@@ -7,6 +7,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
+import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.IntPredicate;
@@ -75,20 +76,21 @@
* @param emptyArray an empty array
* @return an array with written elements
*/
- public static <T> T[] map(T[] original, Function<T, T> mapper, T[] emptyArray) {
+ @SuppressWarnings("unchecked")
+ public static <S, T> T[] map(S[] original, Function<S, T> mapper, T[] emptyArray) {
ArrayList<T> results = null;
for (int i = 0; i < original.length; i++) {
- T oldOne = original[i];
+ S oldOne = original[i];
T newOne = mapper.apply(oldOne);
if (newOne == oldOne) {
if (results != null) {
- results.add(oldOne);
+ results.add((T) oldOne);
}
} else {
if (results == null) {
results = new ArrayList<>(original.length);
for (int j = 0; j < i; j++) {
- results.add(original[j]);
+ results.add((T) original[j]);
}
}
if (newOne != null) {
@@ -96,7 +98,7 @@
}
}
}
- return results != null ? results.toArray(emptyArray) : original;
+ return results != null ? results.toArray(emptyArray) : (T[]) original;
}
/** Rewrites the input array to the output array unconditionally. */
@@ -137,7 +139,7 @@
public static <T> boolean contains(T[] elements, T elementToLookFor) {
for (Object element : elements) {
- if (element.equals(elementToLookFor)) {
+ if (Objects.equals(element, elementToLookFor)) {
return true;
}
}
diff --git a/src/test/java/com/android/tools/r8/CommandTestBase.java b/src/test/java/com/android/tools/r8/CommandTestBase.java
index 1ea2212..886aeba 100644
--- a/src/test/java/com/android/tools/r8/CommandTestBase.java
+++ b/src/test/java/com/android/tools/r8/CommandTestBase.java
@@ -13,17 +13,29 @@
import com.android.tools.r8.profile.art.ArtProfileConsumer;
import com.android.tools.r8.profile.art.ArtProfileForRewriting;
import com.android.tools.r8.profile.art.ArtProfileProvider;
+import com.android.tools.r8.profile.startup.profile.StartupProfile;
+import com.android.tools.r8.profile.startup.profile.StartupProfileRule;
+import com.android.tools.r8.startup.StartupProfileProvider;
+import com.android.tools.r8.startup.diagnostic.MissingStartupProfileItemsDiagnostic;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.IntBox;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.Timing;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.nio.file.Path;
+import java.util.Collection;
import java.util.List;
import org.junit.Test;
public abstract class CommandTestBase<C extends BaseCompilerCommand> extends TestBase {
+
+ public boolean isL8() {
+ return false;
+ }
+
private void mapDiagnosticsMissingArguments(String... args) {
try {
DiagnosticsChecker.checkErrorsContains(
@@ -375,6 +387,69 @@
}
}
+ @Test
+ public void startupProfileFlagAbsentTest() throws Exception {
+ assertTrue(parseWithRequiredArgs().getStartupProfileProviders().isEmpty());
+ }
+
+ @Test
+ public void startupProfileFlagPresentTest() throws Exception {
+ // Create a simple profile.
+ Path profile = temp.newFile("profile.txt").toPath();
+ String profileRule = "Lfoo/bar/Baz;->qux()V";
+ FileUtils.writeTextFile(profile, profileRule);
+
+ // Pass the profile on the command line.
+ List<StartupProfileProvider> startupProfileProviders;
+ try {
+ startupProfileProviders =
+ parseWithRequiredArgs(
+ "--min-api",
+ Integer.toString(AndroidApiLevel.L.getLevel()),
+ "--startup-profile",
+ profile.toString())
+ .getStartupProfileProviders();
+ } catch (CompilationFailedException e) {
+ assertTrue(isL8());
+ return;
+ }
+
+ assertEquals(1, startupProfileProviders.size());
+
+ // Construct the internal profile representation using the provider.
+ InternalOptions options = new InternalOptions();
+ MissingStartupProfileItemsDiagnostic.Builder missingStartupProfileItemsDiagnosticBuilder =
+ MissingStartupProfileItemsDiagnostic.Builder.nop();
+ StartupProfileProvider startupProfileProvider = startupProfileProviders.get(0);
+ StartupProfile.Builder startupProfileBuilder =
+ StartupProfile.builder(
+ options, missingStartupProfileItemsDiagnosticBuilder, startupProfileProvider);
+ startupProfileProvider.getStartupProfile(startupProfileBuilder);
+
+ // Verify we found the same rule.
+ StartupProfile startupProfile = startupProfileBuilder.build();
+ Collection<StartupProfileRule> startupItems =
+ ListUtils.newArrayList(consumer -> startupProfile.forEachRule(consumer::accept));
+ assertEquals(1, startupItems.size());
+ StartupProfileRule startupItem = startupItems.iterator().next();
+ startupItem.accept(
+ startupClass -> fail(),
+ startupMethod -> assertEquals(profileRule, startupMethod.getReference().toSmaliString()));
+ }
+
+ @Test
+ public void startupProfileFlagMissingParameterTest() {
+ String expectedErrorContains =
+ isL8() ? "Unknown option: --startup-profile" : "Missing parameter for --startup-profile.";
+ try {
+ DiagnosticsChecker.checkErrorsContains(
+ expectedErrorContains, handler -> parseWithRequiredArgs(handler, "--startup-profile"));
+ fail("Expected failure");
+ } catch (CompilationFailedException e) {
+ // Expected.
+ }
+ }
+
private String[] prepareArgs(String[] args) {
String[] actualTestArgs;
String[] additionalTestArgs = requiredArgsForTest();
diff --git a/src/test/java/com/android/tools/r8/D8CommandTest.java b/src/test/java/com/android/tools/r8/D8CommandTest.java
index f4cbb5d..a81451f 100644
--- a/src/test/java/com/android/tools/r8/D8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/D8CommandTest.java
@@ -779,61 +779,6 @@
assertTrue(parse("--android-platform-build").getAndroidPlatformBuild());
}
- @Test
- public void startupProfileFlagAbsentTest() throws Exception {
- assertTrue(parse().getStartupProfileProviders().isEmpty());
- }
-
- @Test
- public void startupProfileFlagPresentTest() throws Exception {
- // Create a simple profile.
- Path profile = temp.newFile("profile.txt").toPath();
- String profileRule = "Lfoo/bar/Baz;->qux()V";
- FileUtils.writeTextFile(profile, profileRule);
-
- // Pass the profile on the command line.
- List<StartupProfileProvider> startupProfileProviders =
- parse(
- "--min-api",
- Integer.toString(AndroidApiLevel.L.getLevel()),
- "--startup-profile",
- profile.toString())
- .getStartupProfileProviders();
- assertEquals(1, startupProfileProviders.size());
-
- // Construct the internal profile representation using the provider.
- InternalOptions options = new InternalOptions();
- MissingStartupProfileItemsDiagnostic.Builder missingStartupProfileItemsDiagnosticBuilder =
- MissingStartupProfileItemsDiagnostic.Builder.nop();
- StartupProfileProvider startupProfileProvider = startupProfileProviders.get(0);
- StartupProfile.Builder startupProfileBuilder =
- StartupProfile.builder(
- options, missingStartupProfileItemsDiagnosticBuilder, startupProfileProvider);
- startupProfileProvider.getStartupProfile(startupProfileBuilder);
-
- // Verify we found the same rule.
- StartupProfile startupProfile = startupProfileBuilder.build();
- Collection<StartupProfileRule> startupItems =
- ListUtils.newArrayList(consumer -> startupProfile.forEachRule(consumer::accept));
- assertEquals(1, startupItems.size());
- StartupProfileRule startupItem = startupItems.iterator().next();
- startupItem.accept(
- startupClass -> fail(),
- startupMethod -> assertEquals(profileRule, startupMethod.getReference().toSmaliString()));
- }
-
- @Test
- public void startupProfileFlagMissingParameterTest() {
- String expectedErrorContains = "Missing parameter for --startup-profile.";
- try {
- DiagnosticsChecker.checkErrorsContains(
- expectedErrorContains, handler -> parse(handler, "--startup-profile"));
- fail("Expected failure");
- } catch (CompilationFailedException e) {
- // Expected.
- }
- }
-
@Override
String[] requiredArgsForTest() {
return new String[0];
diff --git a/src/test/java/com/android/tools/r8/L8CommandTest.java b/src/test/java/com/android/tools/r8/L8CommandTest.java
index 4b42d31..6f5f226 100644
--- a/src/test/java/com/android/tools/r8/L8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/L8CommandTest.java
@@ -65,6 +65,11 @@
return StringResource.fromFile(libraryDesugaringSpecification.getSpecification());
}
+ @Override
+ public boolean isL8() {
+ return true;
+ }
+
@Test(expected = CompilationFailedException.class)
public void emptyBuilder() throws Throwable {
verifyEmptyCommand(L8Command.builder().build());
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ContentProviderClientBackportTest.java b/src/test/java/com/android/tools/r8/desugar/backports/ContentProviderClientBackportTest.java
new file mode 100644
index 0000000..e15b419
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ContentProviderClientBackportTest.java
@@ -0,0 +1,104 @@
+// Copyright (c) 2023, 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.desugar.backports;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper.DexVm;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ContentProviderClientBackportTest extends AbstractBackportTest {
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withDexRuntimesAndAllApiLevels().build();
+ }
+
+ public ContentProviderClientBackportTest(TestParameters parameters) throws IOException {
+ super(
+ parameters,
+ ContentProviderClientBackportTest.getContentProviderClient(parameters),
+ ImmutableList.of(
+ ContentProviderClientBackportTest.getTestRunner(),
+ ContentProviderClientBackportTest.getContentProviderClient(parameters)));
+
+ // The constructor is used by the test and release has been available since API 5 and is the
+ // method close is rewritten to.
+ ignoreInvokes("<init>");
+ ignoreInvokes("release");
+
+ // android.content.ContentProviderClient.close added in API 24.
+ registerTarget(AndroidApiLevel.N, 1);
+ }
+
+ private static byte[] getContentProviderClient(TestParameters parameters) throws IOException {
+ if (parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N)) {
+ assertTrue(parameters.getRuntime().asDex().getVm().isNewerThanOrEqual(DexVm.ART_7_0_0_HOST));
+ return transformer(ContentProviderClientApiLevel24.class)
+ .setClassDescriptor(DexItemFactory.androidContentContentProviderClientDescriptorString)
+ .transform();
+ } else {
+ return transformer(ContentProviderClient.class)
+ .setClassDescriptor(DexItemFactory.androidContentContentProviderClientDescriptorString)
+ .transform();
+ }
+ }
+
+ private static byte[] getTestRunner() throws IOException {
+ return transformer(TestRunner.class)
+ .replaceClassDescriptorInMethodInstructions(
+ descriptor(ContentProviderClient.class),
+ DexItemFactory.androidContentContentProviderClientDescriptorString)
+ .transform();
+ }
+
+ public static class ContentProviderClient {
+ public boolean wasClosed = false;
+
+ public void close() {
+ TestRunner.doFail("close should not be called");
+ }
+
+ public void release() {
+ wasClosed = true;
+ }
+ }
+
+ public static class ContentProviderClientApiLevel24 {
+ public boolean wasClosed = false;
+
+ public void close() {
+ wasClosed = true;
+ }
+
+ public void release() {
+ TestRunner.doFail("release should not be called");
+ }
+ }
+
+ public static class TestRunner extends MiniAssert {
+
+ public static void main(String[] args) {
+ ContentProviderClient contentProviderClient = new ContentProviderClient();
+ MiniAssert.assertFalse(contentProviderClient.wasClosed);
+ contentProviderClient.close();
+ MiniAssert.assertTrue(contentProviderClient.wasClosed);
+ }
+
+ // Forwards to MiniAssert to avoid having to make it public.
+ public static void doFail(String message) {
+ MiniAssert.fail(message);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/DrmManagerClientBackportTest.java b/src/test/java/com/android/tools/r8/desugar/backports/DrmManagerClientBackportTest.java
new file mode 100644
index 0000000..6b16c6c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/DrmManagerClientBackportTest.java
@@ -0,0 +1,104 @@
+// Copyright (c) 2023, 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.desugar.backports;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper.DexVm;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class DrmManagerClientBackportTest extends AbstractBackportTest {
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withDexRuntimesAndAllApiLevels().build();
+ }
+
+ public DrmManagerClientBackportTest(TestParameters parameters) throws IOException {
+ super(
+ parameters,
+ DrmManagerClientBackportTest.getDrmManagerClient(parameters),
+ ImmutableList.of(
+ DrmManagerClientBackportTest.getTestRunner(),
+ DrmManagerClientBackportTest.getDrmManagerClient(parameters)));
+
+ // The constructor is used by the test and release has been available since API 5 and is the
+ // method close is rewritten to.
+ ignoreInvokes("<init>");
+ ignoreInvokes("release");
+
+ // android.drm.DrmManagerClient.close added in API 24.
+ registerTarget(AndroidApiLevel.N, 1);
+ }
+
+ private static byte[] getDrmManagerClient(TestParameters parameters) throws IOException {
+ if (parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N)) {
+ assertTrue(parameters.getRuntime().asDex().getVm().isNewerThanOrEqual(DexVm.ART_7_0_0_HOST));
+ return transformer(DrmManagerClientApiLevel24.class)
+ .setClassDescriptor(DexItemFactory.androidDrmDrmManagerClientDescriptorString)
+ .transform();
+ } else {
+ return transformer(DrmManagerClient.class)
+ .setClassDescriptor(DexItemFactory.androidDrmDrmManagerClientDescriptorString)
+ .transform();
+ }
+ }
+
+ private static byte[] getTestRunner() throws IOException {
+ return transformer(TestRunner.class)
+ .replaceClassDescriptorInMethodInstructions(
+ descriptor(DrmManagerClient.class),
+ DexItemFactory.androidDrmDrmManagerClientDescriptorString)
+ .transform();
+ }
+
+ public static class DrmManagerClient {
+ public boolean wasClosed = false;
+
+ public void close() {
+ TestRunner.doFail("close should not be called");
+ }
+
+ public void release() {
+ wasClosed = true;
+ }
+ }
+
+ public static class DrmManagerClientApiLevel24 {
+ public boolean wasClosed = false;
+
+ public void close() {
+ wasClosed = true;
+ }
+
+ public void release() {
+ TestRunner.doFail("release should not be called");
+ }
+ }
+
+ public static class TestRunner extends MiniAssert {
+
+ public static void main(String[] args) {
+ DrmManagerClient drmManagerClient = new DrmManagerClient();
+ MiniAssert.assertFalse(drmManagerClient.wasClosed);
+ drmManagerClient.close();
+ MiniAssert.assertTrue(drmManagerClient.wasClosed);
+ }
+
+ // Forwards to MiniAssert to avoid having to make it public.
+ public static void doFail(String message) {
+ MiniAssert.fail(message);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/MediaDrmBackportTest.java b/src/test/java/com/android/tools/r8/desugar/backports/MediaDrmBackportTest.java
new file mode 100644
index 0000000..500308b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/MediaDrmBackportTest.java
@@ -0,0 +1,102 @@
+// Copyright (c) 2023, 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.desugar.backports;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper.DexVm;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class MediaDrmBackportTest extends AbstractBackportTest {
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withDexRuntimesAndAllApiLevels().build();
+ }
+
+ public MediaDrmBackportTest(TestParameters parameters) throws IOException {
+ super(
+ parameters,
+ MediaDrmBackportTest.getMediaDrm(parameters),
+ ImmutableList.of(
+ MediaDrmBackportTest.getTestRunner(), MediaDrmBackportTest.getMediaDrm(parameters)));
+
+ // The constructor is used by the test and release has been available since API 18 and is the
+ // method close is rewritten to.
+ ignoreInvokes("<init>");
+ ignoreInvokes("release");
+
+ // android.media.MediaDrm.close added in API 28.
+ registerTarget(AndroidApiLevel.P, 1);
+ }
+
+ private static byte[] getMediaDrm(TestParameters parameters) throws IOException {
+ if (parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.P)) {
+ assertTrue(parameters.getRuntime().asDex().getVm().isNewerThanOrEqual(DexVm.ART_8_1_0_HOST));
+ return transformer(MediaDrmApiLevel28.class)
+ .setClassDescriptor(DexItemFactory.androidMediaMediaDrmDescriptorString)
+ .transform();
+ } else {
+ return transformer(MediaDrm.class)
+ .setClassDescriptor(DexItemFactory.androidMediaMediaDrmDescriptorString)
+ .transform();
+ }
+ }
+
+ private static byte[] getTestRunner() throws IOException {
+ return transformer(TestRunner.class)
+ .replaceClassDescriptorInMethodInstructions(
+ descriptor(MediaDrm.class), DexItemFactory.androidMediaMediaDrmDescriptorString)
+ .transform();
+ }
+
+ public static class MediaDrm {
+ public boolean wasClosed = false;
+
+ public void close() {
+ TestRunner.doFail("close should not be called");
+ }
+
+ public void release() {
+ wasClosed = true;
+ }
+ }
+
+ public static class MediaDrmApiLevel28 {
+ public boolean wasClosed = false;
+
+ public void close() {
+ wasClosed = true;
+ }
+
+ public void release() {
+ TestRunner.doFail("release should not be called");
+ }
+ }
+
+ public static class TestRunner extends MiniAssert {
+
+ public static void main(String[] args) {
+ MediaDrm mediaDrm = new MediaDrm();
+ MiniAssert.assertFalse(mediaDrm.wasClosed);
+ mediaDrm.close();
+ MiniAssert.assertTrue(mediaDrm.wasClosed);
+ }
+
+ // Forwards to MiniAssert to avoid having to make it public.
+ public static void doFail(String message) {
+ MiniAssert.fail(message);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/MediaMetadataRetrieverBackportTest.java b/src/test/java/com/android/tools/r8/desugar/backports/MediaMetadataRetrieverBackportTest.java
new file mode 100644
index 0000000..b3cbfe2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/MediaMetadataRetrieverBackportTest.java
@@ -0,0 +1,104 @@
+// Copyright (c) 2023, 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.desugar.backports;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper.DexVm;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class MediaMetadataRetrieverBackportTest extends AbstractBackportTest {
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withDexRuntimesAndAllApiLevels().build();
+ }
+
+ public MediaMetadataRetrieverBackportTest(TestParameters parameters) throws IOException {
+ super(
+ parameters,
+ MediaMetadataRetrieverBackportTest.getMediaMetadataRetriever(parameters),
+ ImmutableList.of(
+ MediaMetadataRetrieverBackportTest.getTestRunner(),
+ MediaMetadataRetrieverBackportTest.getMediaMetadataRetriever(parameters)));
+
+ // The constructor is used by the test and release has been available since API 10 and is the
+ // method close is rewritten to.
+ ignoreInvokes("<init>");
+ ignoreInvokes("release");
+
+ // android.media.MediaMetadataRetriever.close added in API 29.
+ registerTarget(AndroidApiLevel.Q, 1);
+ }
+
+ private static byte[] getMediaMetadataRetriever(TestParameters parameters) throws IOException {
+ if (parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.Q)) {
+ assertTrue(parameters.getRuntime().asDex().getVm().isNewerThanOrEqual(DexVm.ART_10_0_0_HOST));
+ return transformer(MediaMetadataRetrieverApiLevel29.class)
+ .setClassDescriptor(DexItemFactory.androidMediaMediaMetadataRetrieverDescriptorString)
+ .transform();
+ } else {
+ return transformer(MediaMetadataRetriever.class)
+ .setClassDescriptor(DexItemFactory.androidMediaMediaMetadataRetrieverDescriptorString)
+ .transform();
+ }
+ }
+
+ private static byte[] getTestRunner() throws IOException {
+ return transformer(TestRunner.class)
+ .replaceClassDescriptorInMethodInstructions(
+ descriptor(MediaMetadataRetriever.class),
+ DexItemFactory.androidMediaMediaMetadataRetrieverDescriptorString)
+ .transform();
+ }
+
+ public static class MediaMetadataRetriever {
+ public boolean wasClosed = false;
+
+ public void close() {
+ TestRunner.doFail("close should not be called");
+ }
+
+ public void release() {
+ wasClosed = true;
+ }
+ }
+
+ public static class MediaMetadataRetrieverApiLevel29 {
+ public boolean wasClosed = false;
+
+ public void close() {
+ wasClosed = true;
+ }
+
+ public void release() {
+ TestRunner.doFail("release should not be called");
+ }
+ }
+
+ public static class TestRunner extends MiniAssert {
+
+ public static void main(String[] args) {
+ MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
+ MiniAssert.assertFalse(mediaMetadataRetriever.wasClosed);
+ mediaMetadataRetriever.close();
+ MiniAssert.assertTrue(mediaMetadataRetriever.wasClosed);
+ }
+
+ // Forwards to MiniAssert to avoid having to make it public.
+ public static void doFail(String message) {
+ MiniAssert.fail(message);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/TypedArrayBackportTest.java b/src/test/java/com/android/tools/r8/desugar/backports/TypedArrayBackportTest.java
new file mode 100644
index 0000000..06e759d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/TypedArrayBackportTest.java
@@ -0,0 +1,104 @@
+// Copyright (c) 2023, 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.desugar.backports;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper.DexVm;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class TypedArrayBackportTest extends AbstractBackportTest {
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withDexRuntimesAndAllApiLevels().build();
+ }
+
+ public TypedArrayBackportTest(TestParameters parameters) throws IOException {
+ super(
+ parameters,
+ TypedArrayBackportTest.getTypedArray(parameters),
+ ImmutableList.of(
+ TypedArrayBackportTest.getTestRunner(),
+ TypedArrayBackportTest.getTypedArray(parameters)));
+
+ // The constructor is used by the test and recycle has been available since API 1 and is the
+ // method close is rewritten to.
+ ignoreInvokes("<init>");
+ ignoreInvokes("recycle");
+
+ // android.content.res.TypedArray.close added in API 31.
+ registerTarget(AndroidApiLevel.S, 1);
+ }
+
+ private static byte[] getTypedArray(TestParameters parameters) throws IOException {
+ if (parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.S)) {
+ assertTrue(parameters.getRuntime().asDex().getVm().isNewerThanOrEqual(DexVm.ART_12_0_0_HOST));
+ return transformer(TypedArrayAndroidApiLevel31.class)
+ .setClassDescriptor(DexItemFactory.androidContentResTypedArrayDescriptorString)
+ .transform();
+ } else {
+ return transformer(TypedArray.class)
+ .setClassDescriptor(DexItemFactory.androidContentResTypedArrayDescriptorString)
+ .transform();
+ }
+ }
+
+ private static byte[] getTestRunner() throws IOException {
+ return transformer(TestRunner.class)
+ .replaceClassDescriptorInMethodInstructions(
+ descriptor(TypedArray.class),
+ DexItemFactory.androidContentResTypedArrayDescriptorString)
+ .transform();
+ }
+
+ public static class TypedArray {
+ public boolean wasClosed = false;
+
+ public void close() {
+ TestRunner.doFail("close should not be called");
+ }
+
+ public void recycle() {
+ wasClosed = true;
+ }
+ }
+
+ public static class TypedArrayAndroidApiLevel31 {
+ public boolean wasClosed = false;
+
+ public void close() {
+ wasClosed = true;
+ }
+
+ public void recycle() {
+ TestRunner.doFail("recycle should not be called");
+ }
+ }
+
+ public static class TestRunner extends MiniAssert {
+
+ public static void main(String[] args) {
+ TypedArray typedArray = new TypedArray();
+ MiniAssert.assertFalse(typedArray.wasClosed);
+ typedArray.close();
+ MiniAssert.assertTrue(typedArray.wasClosed);
+ }
+
+ // Forwards to MiniAssert to avoid having to make it public.
+ public static void doFail(String message) {
+ MiniAssert.fail(message);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/profile/art/DuplicateDescriptorsInArtProfileTest.java b/src/test/java/com/android/tools/r8/profile/art/DuplicateDescriptorsInArtProfileTest.java
new file mode 100644
index 0000000..fac8889
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/profile/art/DuplicateDescriptorsInArtProfileTest.java
@@ -0,0 +1,90 @@
+// Copyright (c) 2023, 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.profile.art;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.MethodReferenceUtils;
+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 DuplicateDescriptorsInArtProfileTest extends TestBase {
+
+ static final ClassReference MAIN_CLASS_REFERENCE = Reference.classFromClass(Main.class);
+ static final MethodReference MAIN_METHOD_REFERENCE = MethodReferenceUtils.mainMethod(Main.class);
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(Backend.DEX)
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addArtProfileForRewriting(
+ new ArtProfileProvider() {
+ @Override
+ public void getArtProfile(ArtProfileBuilder profileBuilder) {
+ profileBuilder.addClassRule(
+ classRuleBuilder -> classRuleBuilder.setClassReference(MAIN_CLASS_REFERENCE));
+ profileBuilder.addClassRule(
+ classRuleBuilder -> classRuleBuilder.setClassReference(MAIN_CLASS_REFERENCE));
+ profileBuilder.addMethodRule(
+ methodRuleBuilder ->
+ methodRuleBuilder
+ .setMethodReference(MAIN_METHOD_REFERENCE)
+ .setMethodRuleInfo(
+ methodRuleInfoBuilder -> methodRuleInfoBuilder.setIsHot(true)));
+ profileBuilder.addMethodRule(
+ methodRuleBuilder ->
+ methodRuleBuilder
+ .setMethodReference(MAIN_METHOD_REFERENCE)
+ .setMethodRuleInfo(
+ methodRuleInfoBuilder -> methodRuleInfoBuilder.setIsStartup(true)));
+ profileBuilder.addMethodRule(
+ methodRuleBuilder ->
+ methodRuleBuilder
+ .setMethodReference(MAIN_METHOD_REFERENCE)
+ .setMethodRuleInfo(
+ methodRuleInfoBuilder ->
+ methodRuleInfoBuilder.setIsPostStartup(true)));
+ }
+
+ @Override
+ public Origin getOrigin() {
+ return Origin.unknown();
+ }
+ })
+ .compile()
+ .inspectResidualArtProfile(
+ profileInspector ->
+ profileInspector
+ .assertContainsClassRule(MAIN_CLASS_REFERENCE)
+ .inspectMethodRule(
+ MAIN_METHOD_REFERENCE,
+ methodInspector ->
+ methodInspector.assertIsHot().assertIsStartup().assertIsPostStartup())
+ .assertContainsNoOtherRules());
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {}
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/startup/DuplicateDescriptorsInStartupProfileTest.java b/src/test/java/com/android/tools/r8/startup/DuplicateDescriptorsInStartupProfileTest.java
new file mode 100644
index 0000000..668c2a3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/startup/DuplicateDescriptorsInStartupProfileTest.java
@@ -0,0 +1,89 @@
+// Copyright (c) 2023, 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.startup;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.startup.profile.ExternalStartupClass;
+import com.android.tools.r8.startup.profile.ExternalStartupMethod;
+import com.android.tools.r8.startup.utils.StartupTestingUtils;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.MethodReferenceUtils;
+import com.google.common.collect.ImmutableList;
+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 DuplicateDescriptorsInStartupProfileTest extends TestBase {
+
+ static final ClassReference MAIN_CLASS_REFERENCE = Reference.classFromClass(Main.class);
+ static final MethodReference MAIN_METHOD_REFERENCE = MethodReferenceUtils.mainMethod(Main.class);
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(Backend.DEX)
+ .addInnerClasses(getClass())
+ .addKeepAllClassesRule()
+ .apply(
+ testBuilder ->
+ StartupTestingUtils.addStartupProfile(
+ testBuilder,
+ ImmutableList.of(
+ ExternalStartupClass.builder()
+ .setClassReference(MAIN_CLASS_REFERENCE)
+ .build(),
+ ExternalStartupMethod.builder()
+ .setMethodReference(MAIN_METHOD_REFERENCE)
+ .build())))
+ .apply(
+ testBuilder ->
+ StartupTestingUtils.addStartupProfile(
+ testBuilder,
+ ImmutableList.of(
+ ExternalStartupClass.builder()
+ .setClassReference(MAIN_CLASS_REFERENCE)
+ .build(),
+ ExternalStartupClass.builder()
+ .setClassReference(MAIN_CLASS_REFERENCE)
+ .build(),
+ ExternalStartupMethod.builder()
+ .setMethodReference(MAIN_METHOD_REFERENCE)
+ .build(),
+ ExternalStartupMethod.builder()
+ .setMethodReference(MAIN_METHOD_REFERENCE)
+ .build())))
+ .setMinApi(AndroidApiLevel.L)
+ .compile()
+ .inspectMultiDex(
+ primaryInspector -> assertThat(primaryInspector.clazz(Main.class), isPresent()),
+ secondaryInspector ->
+ assertThat(secondaryInspector.clazz(PostStartup.class), isPresent()));
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {}
+ }
+
+ static class PostStartup {}
+}
diff --git a/src/test/java/com/android/tools/r8/startup/InliningOutOfStartupPartitionTest.java b/src/test/java/com/android/tools/r8/startup/InliningOutOfStartupPartitionTest.java
index e1a415d..ba065b7 100644
--- a/src/test/java/com/android/tools/r8/startup/InliningOutOfStartupPartitionTest.java
+++ b/src/test/java/com/android/tools/r8/startup/InliningOutOfStartupPartitionTest.java
@@ -50,8 +50,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
- .apply(
- testBuilder -> StartupTestingUtils.setStartupConfiguration(testBuilder, startupItems))
+ .apply(testBuilder -> StartupTestingUtils.addStartupProfile(testBuilder, startupItems))
.setMinApi(parameters)
.compile()
.inspect(
diff --git a/src/test/java/com/android/tools/r8/startup/MinimalStartupDexFromStartupMethodRuleTest.java b/src/test/java/com/android/tools/r8/startup/MinimalStartupDexFromStartupMethodRuleTest.java
index ae0fe36..20e850f 100644
--- a/src/test/java/com/android/tools/r8/startup/MinimalStartupDexFromStartupMethodRuleTest.java
+++ b/src/test/java/com/android/tools/r8/startup/MinimalStartupDexFromStartupMethodRuleTest.java
@@ -69,7 +69,7 @@
}
private void configureStartupConfiguration(TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder) {
- StartupTestingUtils.setStartupConfiguration(
+ StartupTestingUtils.addStartupProfile(
testBuilder,
ImmutableList.of(
ExternalStartupMethod.builder()
diff --git a/src/test/java/com/android/tools/r8/startup/MinimalStartupDexTest.java b/src/test/java/com/android/tools/r8/startup/MinimalStartupDexTest.java
index 53c02be..91f9d7d 100644
--- a/src/test/java/com/android/tools/r8/startup/MinimalStartupDexTest.java
+++ b/src/test/java/com/android/tools/r8/startup/MinimalStartupDexTest.java
@@ -67,7 +67,7 @@
.setEnableMinimalStartupDex(true)
.setEnableStartupCompletenessCheckForTesting())
.enableInliningAnnotations()
- .apply(testBuilder -> StartupTestingUtils.setStartupConfiguration(testBuilder, startupList))
+ .apply(testBuilder -> StartupTestingUtils.addStartupProfile(testBuilder, startupList))
.setMinApi(parameters)
.compile()
.inspectMultiDex(
diff --git a/src/test/java/com/android/tools/r8/startup/StartupSyntheticPlacementTest.java b/src/test/java/com/android/tools/r8/startup/StartupSyntheticPlacementTest.java
index 92d3129..697aa2d 100644
--- a/src/test/java/com/android/tools/r8/startup/StartupSyntheticPlacementTest.java
+++ b/src/test/java/com/android/tools/r8/startup/StartupSyntheticPlacementTest.java
@@ -196,7 +196,7 @@
.setMixedSectionLayoutStrategyInspector(
getMixedSectionLayoutInspector(inspector, testBuilder.isD8TestBuilder()));
})
- .apply(ignore -> StartupTestingUtils.setStartupConfiguration(testBuilder, startupList));
+ .apply(ignore -> StartupTestingUtils.addStartupProfile(testBuilder, startupList));
}
private List<String> getExpectedOutput() {
diff --git a/src/test/java/com/android/tools/r8/startup/StartupSyntheticWithoutContextTest.java b/src/test/java/com/android/tools/r8/startup/StartupSyntheticWithoutContextTest.java
index 14a1e1b..6b21589 100644
--- a/src/test/java/com/android/tools/r8/startup/StartupSyntheticWithoutContextTest.java
+++ b/src/test/java/com/android/tools/r8/startup/StartupSyntheticWithoutContextTest.java
@@ -92,7 +92,7 @@
.getTestingOptions()
.setMixedSectionLayoutStrategyInspector(getMixedSectionLayoutInspector());
})
- .apply(testBuilder -> StartupTestingUtils.setStartupConfiguration(testBuilder, startupList))
+ .apply(testBuilder -> StartupTestingUtils.addStartupProfile(testBuilder, startupList))
.setMinApi(parameters)
.compile()
.inspectMultiDex(this::inspectPrimaryDex, this::inspectSecondaryDex)
diff --git a/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java b/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java
index 3ee4a45..8805931 100644
--- a/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java
+++ b/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java
@@ -158,7 +158,7 @@
runResult.getResult().setStdout(stdoutBuilder.toString());
}
- public static void setStartupConfiguration(
+ public static void addStartupProfile(
TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder,
Collection<ExternalStartupItem> startupItems) {
StartupProfileProvider startupProfileProvider =
diff --git a/third_party/openjdk/desugar_jdk_libs_11.tar.gz.sha1 b/third_party/openjdk/desugar_jdk_libs_11.tar.gz.sha1
index 8fc0af6..c845f51 100644
--- a/third_party/openjdk/desugar_jdk_libs_11.tar.gz.sha1
+++ b/third_party/openjdk/desugar_jdk_libs_11.tar.gz.sha1
@@ -1 +1 @@
-91bdabe13dd74051654146af7f9b8f87b332f198
\ No newline at end of file
+e01c698069f2b52bd80864b70adfeaf0c27e5f4f
\ No newline at end of file