Merge commit '68afbc60e854be93182435d71cd56d1710bff0d3' into dev-release
diff --git a/build.gradle b/build.gradle
index eac0f5c..919c260 100644
--- a/build.gradle
+++ b/build.gradle
@@ -333,7 +333,6 @@
"android_jar/lib-v30",
"android_jar/lib-v31",
"android_jar/lib-v32",
- "android_jar/api-versions",
"api-outlining/simple-app-dump",
"binary_compatibility_tests/compiler_api_tests",
"core-lambda-stubs",
diff --git a/scripts/add-android-jar.sh b/scripts/add-android-jar.sh
index 4a0f57c..c83aa2e 100755
--- a/scripts/add-android-jar.sh
+++ b/scripts/add-android-jar.sh
@@ -23,46 +23,23 @@
THIRD_PARTY_ANDROID_JAR=third_party/android_jar
THIRD_PARTY_ANDROID_JAR_LIB=$THIRD_PARTY_ANDROID_JAR/lib-v$SDK_VERSION
-UPDATE_ANDROID_JAR="no"
-if [[ "$UPDATE_ANDROID_JAR" == "yes" ]]; then
- rm -rf $THIRD_PARTY_ANDROID_JAR_LIB
- rm -f ${THIRD_PARTY_ANDROID_JAR_LIB}.tar.gz
- rm -f ${THIRD_PARTY_ANDROID_JAR_LIB}.tar.sha1
+rm -rf $THIRD_PARTY_ANDROID_JAR_LIB
+rm -f ${THIRD_PARTY_ANDROID_JAR_LIB}.tar.gz
+rm -f ${THIRD_PARTY_ANDROID_JAR_LIB}.tar.sha1
- mkdir -p $THIRD_PARTY_ANDROID_JAR_LIB/optional
- cp $SDK_DIR/android.jar $THIRD_PARTY_ANDROID_JAR_LIB/android.jar
- cp $SDK_DIR/optional/*.jar $THIRD_PARTY_ANDROID_JAR_LIB/optional
- cp $SDK_DIR/optional/optional.json $THIRD_PARTY_ANDROID_JAR_LIB/optional
- cp $THIRD_PARTY_ANDROID_JAR/lib-v31/README.google $THIRD_PARTY_ANDROID_JAR_LIB
- vi $THIRD_PARTY_ANDROID_JAR_LIB/README.google
+mkdir -p $THIRD_PARTY_ANDROID_JAR_LIB/optional
+cp $SDK_DIR/android.jar $THIRD_PARTY_ANDROID_JAR_LIB/android.jar
+cp $SDK_DIR/data/api-versions.xml $THIRD_PARTY_ANDROID_JAR_LIB/api-versions.xml
+cp $SDK_DIR/optional/*.jar $THIRD_PARTY_ANDROID_JAR_LIB/optional
+cp $SDK_DIR/optional/optional.json $THIRD_PARTY_ANDROID_JAR_LIB/optional
+cp $THIRD_PARTY_ANDROID_JAR/lib-v31/README.google $THIRD_PARTY_ANDROID_JAR_LIB
+vi $THIRD_PARTY_ANDROID_JAR_LIB/README.google
- (cd $THIRD_PARTY_ANDROID_JAR \
- && upload_to_google_storage.py -a --bucket r8-deps lib-v$SDK_VERSION)
- rm -rf $THIRD_PARTY_ANDROID_JAR_LIB
- rm ${THIRD_PARTY_ANDROID_JAR_LIB}.tar.gz
- git add ${THIRD_PARTY_ANDROID_JAR_LIB}.tar.gz.sha1
-fi
-
-UPDATE_API_DATABASE="no"
-if [[ "$UPDATE_API_DATABASE" == "yes" ]]; then
- rm -rf $THIRD_PARTY_ANDROID_JAR/api-versions
- rm -f $THIRD_PARTY_ANDROID_JAR/api-versions.tar.gz
- rm -f $THIRD_PARTY_ANDROID_JAR/api-versions.tar.gz.sha1
- mkdir -p $THIRD_PARTY_ANDROID_JAR/api-versions
- cp $SDK_DIR/data/api-versions.xml $THIRD_PARTY_ANDROID_JAR/api-versions
- (cd $THIRD_PARTY_ANDROID_JAR \
- && upload_to_google_storage.py -a --bucket r8-deps api-versions)
- tools/gradle.py r8NoManifestWithoutDeps testJar repackageTestDeps
- java -cp build/libs/r8_no_manifest_without_deps.jar:build/libs/deps_all.jar:build/libs/r8tests.jar:build/libs/test_deps_all.jar \
- com.android.tools.r8.apimodel.AndroidApiHashingDatabaseBuilderGeneratorTest
-
- rm -rf $THIRD_PARTY_ANDROID_JAR/api-versions
- rm -f $THIRD_PARTY_ANDROID_JAR/api-versions.tar.gz
- git add $THIRD_PARTY_ANDROID_JAR/api-versions.tar.gz.sha1
- git add src/main/resources/api_database/api_database_ambiguous.txt
- git add src/main/resources/api_database/api_database_api_level.ser
- git add src/main/resources/api_database/api_database_hash_lookup.ser
-fi
+(cd $THIRD_PARTY_ANDROID_JAR \
+ && upload_to_google_storage.py -a --bucket r8-deps lib-v$SDK_VERSION)
+rm -rf $THIRD_PARTY_ANDROID_JAR_LIB
+rm ${THIRD_PARTY_ANDROID_JAR_LIB}.tar.gz
+git add ${THIRD_PARTY_ANDROID_JAR_LIB}.tar.gz.sha1
echo "Update build.gradle with this new cloud dependency, " \
"and verify with tools/gradle.py downloadDeps"
diff --git a/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json b/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json
index 565ffd9..f3a4daa 100644
--- a/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json
+++ b/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json
@@ -3,7 +3,7 @@
"group_id" : "com.tools.android",
"artifact_id" : "chm_only_desugar_jdk_libs",
"version": "1.0.12",
- "required_compilation_api_level": 31,
+ "required_compilation_api_level": 30,
"synthesized_library_classes_package_prefix": "j$.",
"support_all_callbacks_from_library": false,
"common_flags": [
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs.json b/src/library_desugar/jdk11/desugar_jdk_libs.json
index fb03dbb..b075745 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs.json
@@ -3,7 +3,7 @@
"group_id" : "com.tools.android",
"artifact_id" : "desugar_jdk_libs",
"version": "2.0.0",
- "required_compilation_api_level": 31,
+ "required_compilation_api_level": 30,
"synthesized_library_classes_package_prefix": "j$.",
"support_all_callbacks_from_library": true,
"common_flags": [
@@ -205,7 +205,7 @@
"java.nio.charset.StandardCharsets": "j$.nio.charset.StandardCharsets"
},
"retarget_lib_member": {
- "java.lang.Character#isBmpCodePoint": "j$.lang.DesugarCharacter"
+ "java.lang.Character#isBmpCodePoint": "java.lang.DesugarCharacter"
}
}
],
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json b/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json
index fac2ec0..1482909 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json
@@ -3,7 +3,7 @@
"group_id" : "com.tools.android",
"artifact_id" : "desugar_jdk_libs_alternative_3",
"version": "2.0.0",
- "required_compilation_api_level": 31,
+ "required_compilation_api_level": 30,
"synthesized_library_classes_package_prefix": "j$.",
"support_all_callbacks_from_library": false,
"common_flags": [
@@ -209,7 +209,7 @@
"java.nio.charset.StandardCharsets": "j$.nio.charset.StandardCharsets"
},
"retarget_lib_member": {
- "java.lang.Character#isBmpCodePoint": "j$.lang.DesugarCharacter"
+ "java.lang.Character#isBmpCodePoint": "java.lang.DesugarCharacter"
}
}
],
diff --git a/src/main/java/com/android/tools/r8/AssertionsConfiguration.java b/src/main/java/com/android/tools/r8/AssertionsConfiguration.java
index 12e7b48..2f119ca 100644
--- a/src/main/java/com/android/tools/r8/AssertionsConfiguration.java
+++ b/src/main/java/com/android/tools/r8/AssertionsConfiguration.java
@@ -170,8 +170,11 @@
/**
* Rewrite the throwing of <code>java.lang.AssertionError</code> to call the supplied method
* <code>assertionHandler</code>. The method must be a reference to a static method taking one
- * argument of type <code>java.lang.AssertionError</code>. After the assertion handler as been
- * called, the code continues as if assertions where disabled.
+ * argument. The type of the argument should be <code>java.lang.Throwable</code> as kotlinc will
+ * generate code where the assertion error is thrown as <code>java.lang.Throwable</code>. If all
+ * code is generated by javac then the type of the argument can be <code>
+ * java.lang.AssertionError</code>. After the assertion handler as been called, the code
+ * continues as if assertions where disabled.
*/
public AssertionsConfiguration.Builder setAssertionHandler(MethodReference assertionHandler) {
this.transformation = null;
diff --git a/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java b/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java
index bce73f0..7ef1569 100644
--- a/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java
+++ b/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java
@@ -105,7 +105,7 @@
InternalOptions getInternalOptions() {
InternalOptions options = new InternalOptions(factory, getReporter());
options.setMinApiLevel(AndroidApiLevel.getAndroidApiLevel(minApiLevel));
- options.desugaredLibrarySpecification = desugaredLibrarySpecification;
+ options.setDesugaredLibrarySpecification(desugaredLibrarySpecification, getInputApp());
return options;
}
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index cd0bc2f..9232563 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -204,7 +204,7 @@
// enabling code.
ClassInitializerAssertionEnablingAnalysis analysis =
new ClassInitializerAssertionEnablingAnalysis(
- appView.dexItemFactory(), OptimizationFeedbackSimple.getInstance());
+ appView, OptimizationFeedbackSimple.getInstance());
ThreadUtils.processItems(
appView.appInfo().classes(),
clazz -> {
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 8dd34a8..0967f55 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -498,8 +498,7 @@
internal.encodeChecksums = getIncludeClassesChecksum();
internal.dexClassChecksumFilter = getDexClassChecksumFilter();
internal.enableInheritanceClassInDexDistributor = isOptimizeMultidexForLinearAlloc();
-
- internal.desugaredLibrarySpecification = desugaredLibrarySpecification;
+ internal.setDesugaredLibrarySpecification(desugaredLibrarySpecification, getInputApp());
internal.synthesizedClassPrefix = synthesizedClassPrefix;
internal.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 26c99ce..6da92e2 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -194,7 +194,7 @@
internal.enableInheritanceClassInDexDistributor = false;
assert desugaredLibrarySpecification != null;
- internal.desugaredLibrarySpecification = desugaredLibrarySpecification;
+ internal.setDesugaredLibrarySpecification(desugaredLibrarySpecification, getInputApp());
internal.synthesizedClassPrefix =
desugaredLibrarySpecification.getSynthesizedLibraryClassesPackagePrefix();
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index b96eaef..85c05f6 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -75,6 +75,7 @@
import com.android.tools.r8.optimize.MemberRebindingIdentityLensFactory;
import com.android.tools.r8.optimize.VisibilityBridgeRemover;
import com.android.tools.r8.optimize.bridgehoisting.BridgeHoisting;
+import com.android.tools.r8.optimize.proto.ProtoNormalizer;
import com.android.tools.r8.origin.CommandLineOrigin;
import com.android.tools.r8.repackaging.Repackaging;
import com.android.tools.r8.repackaging.RepackagingLens;
@@ -310,7 +311,7 @@
if (!options.mainDexKeepRules.isEmpty()) {
MainDexListBuilder.checkForAssumedLibraryTypes(appView.appInfo());
}
- if (!options.desugaredLibrarySpecification.getRetargetCoreLibMember().isEmpty()) {
+ if (options.machineDesugaredLibrarySpecification.hasRetargeting()) {
DesugaredLibraryRetargeterLibraryTypeSynthesizer.checkForAssumedLibraryTypes(appView);
DesugaredLibraryRetargeterLibraryTypeSynthesizer.amendLibraryWithRetargetedMembers(appView);
}
@@ -517,6 +518,8 @@
.runIfNecessary(runtimeTypeCheckInfo, executorService, timing);
}
+ new ProtoNormalizer(appViewWithLiveness).run(executorService, timing);
+
// Clear traced methods roots to not hold on to the main dex live method set.
appView.appInfo().getMainDexInfo().clearTracedMethodRoots();
@@ -1005,9 +1008,11 @@
enqueuer.registerAnalysis(new InitializedClassesInInstanceMethodsAnalysis(appView));
}
if (AssertionsRewriter.isEnabled(appView.options())) {
- enqueuer.registerAnalysis(
+ ClassInitializerAssertionEnablingAnalysis analysis =
new ClassInitializerAssertionEnablingAnalysis(
- appView.dexItemFactory(), OptimizationFeedbackSimple.getInstance()));
+ appView, OptimizationFeedbackSimple.getInstance());
+ enqueuer.registerAnalysis(analysis);
+ enqueuer.registerFieldAccessAnalysis(analysis);
}
if (options.isClassMergingExtensionRequired(enqueuer.getMode())) {
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index bf04680..5bc9ddd 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -943,7 +943,7 @@
internal.enableInheritanceClassInDexDistributor = isOptimizeMultidexForLinearAlloc();
- internal.desugaredLibrarySpecification = desugaredLibrarySpecification;
+ internal.setDesugaredLibrarySpecification(desugaredLibrarySpecification, getInputApp());
internal.synthesizedClassPrefix = synthesizedClassPrefix;
internal.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
diff --git a/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java b/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
index 2e2aa7a..cce0852 100644
--- a/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
+++ b/src/main/java/com/android/tools/r8/androidapi/AndroidApiReferenceLevelCache.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.ConsumerUtils;
import com.google.common.collect.ImmutableList;
@@ -18,7 +17,6 @@
public class AndroidApiReferenceLevelCache {
- private final LegacyDesugaredLibrarySpecification desugaredLibrarySpecification;
private final AndroidApiLevelCompute apiLevelCompute;
private final AndroidApiLevelDatabase androidApiLevelDatabase;
private final AppView<?> appView;
@@ -33,7 +31,6 @@
factory = appView.dexItemFactory();
androidApiLevelDatabase =
new AndroidApiLevelHashingDatabaseImpl(predefinedApiTypeLookupForHashing);
- desugaredLibrarySpecification = appView.options().desugaredLibrarySpecification;
}
public static AndroidApiReferenceLevelCache create(
@@ -75,7 +72,7 @@
if (reference.getContextType() == factory.objectType) {
return appView.computedMinApiLevel();
}
- if (desugaredLibrarySpecification.isSupported(reference, appView)) {
+ if (appView.options().machineDesugaredLibrarySpecification.isSupported(reference)) {
// If we end up desugaring the reference, the library classes is bridged by j$ which is part
// of the program.
return appView.computedMinApiLevel();
diff --git a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
index f9b13a4..ef86f73 100644
--- a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
+++ b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
@@ -19,7 +19,6 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.ThrowExceptionCode;
import com.android.tools.r8.graph.UseRegistry;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.synthesis.CommittedItems;
import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
@@ -112,12 +111,10 @@
new ConcurrentHashMap<>();
private final Set<DexType> seenTypes = Sets.newConcurrentHashSet();
private final AndroidApiLevelCompute apiLevelCompute;
- private final LegacyDesugaredLibrarySpecification desugaredLibraryConfiguration;
public ApiReferenceStubber(AppView<? extends AppInfoWithClassHierarchy> appView) {
this.appView = appView;
apiLevelCompute = appView.apiLevelCompute();
- desugaredLibraryConfiguration = appView.options().desugaredLibrarySpecification;
}
public void run(ExecutorService executorService) throws ExecutionException {
@@ -220,7 +217,10 @@
|| libraryClass.getType().toDescriptorString().startsWith("Ljava/")) {
return;
}
- if (desugaredLibraryConfiguration.isSupported(libraryClass.getType(), appView)) {
+ if (appView
+ .options()
+ .machineDesugaredLibrarySpecification
+ .isSupported(libraryClass.getType())) {
return;
}
appView
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
index 2585329..783a837 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
@@ -88,6 +88,10 @@
return opcode == Opcodes.GETFIELD || opcode == Opcodes.GETSTATIC;
}
+ public boolean isStaticFieldGet() {
+ return opcode == Opcodes.GETSTATIC;
+ }
+
@Override
public CfFieldInstruction asFieldInstruction() {
return this;
diff --git a/src/main/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryKeepRuleGenerator.java b/src/main/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryKeepRuleGenerator.java
index a720021..eaec5a0 100644
--- a/src/main/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryKeepRuleGenerator.java
+++ b/src/main/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryKeepRuleGenerator.java
@@ -13,7 +13,7 @@
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.references.ArrayReference;
import com.android.tools.r8.references.ClassReference;
@@ -32,13 +32,11 @@
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.NopDiagnosticsHandler;
-import com.android.tools.r8.utils.SetUtils;
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.TypeReferenceUtils;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
@@ -71,7 +69,7 @@
return false;
}
return namingLens.hasPrefixRewritingLogic()
- || options.desugaredLibrarySpecification.hasEmulatedLibraryInterfaces();
+ || options.machineDesugaredLibrarySpecification.hasEmulatedInterfaces();
}
private void run() {
@@ -80,18 +78,15 @@
}
private Predicate<DexType> createTargetPredicate() {
- LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
- options.desugaredLibrarySpecification;
- Set<DexType> potentialTypesToKeep =
- SetUtils.newIdentityHashSet(
- desugaredLibrarySpecification.getCustomConversions().values(),
- desugaredLibrarySpecification.getEmulateLibraryInterface().values());
+ MachineDesugaredLibrarySpecification desugaredLibrarySpecification =
+ options.machineDesugaredLibrarySpecification;
byte[] synthesizedLibraryClassesPackageDescriptorPrefix =
DexString.encodeToMutf8(
"L" + desugaredLibrarySpecification.getSynthesizedLibraryClassesPackagePrefix());
return type ->
namingLens.prefixRewrittenType(type) != null
- || potentialTypesToKeep.contains(type)
+ || desugaredLibrarySpecification.isEmulatedInterfaceRewrittenType(type)
+ || desugaredLibrarySpecification.isCustomConversionRewrittenType(type)
|| type.getDescriptor().startsWith(synthesizedLibraryClassesPackageDescriptorPrefix);
}
diff --git a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
index cc05c31..3e33ca8 100644
--- a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
+++ b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
@@ -25,7 +25,7 @@
static CodeToKeep createCodeToKeep(InternalOptions options, NamingLens namingLens) {
if ((!namingLens.hasPrefixRewritingLogic()
- && !options.desugaredLibrarySpecification.hasEmulatedLibraryInterfaces())
+ && !options.machineDesugaredLibrarySpecification.hasEmulatedInterfaces())
|| options.isDesugaredLibraryCompilation()
|| options.testing.enableExperimentalDesugaredLibraryKeepRuleGenerator) {
return new NopCodeToKeep();
@@ -57,27 +57,23 @@
}
private final NamingLens namingLens;
- private final Set<DexType> potentialTypesToKeep = Sets.newIdentityHashSet();
private final Map<DexType, KeepStruct> toKeep = new ConcurrentHashMap<>();
private final InternalOptions options;
public DesugaredLibraryCodeToKeep(NamingLens namingLens, InternalOptions options) {
this.namingLens = namingLens;
this.options = options;
- potentialTypesToKeep.addAll(
- options.desugaredLibrarySpecification.getEmulateLibraryInterface().values());
- potentialTypesToKeep.addAll(
- options.desugaredLibrarySpecification.getCustomConversions().values());
}
private boolean shouldKeep(DexType type) {
return namingLens.prefixRewrittenType(type) != null
- || potentialTypesToKeep.contains(type)
+ || options.machineDesugaredLibrarySpecification.isCustomConversionRewrittenType(type)
+ || options.machineDesugaredLibrarySpecification.isEmulatedInterfaceRewrittenType(type)
// TODO(b/158632510): This should prefix match on DexString.
|| type.toDescriptorString()
.startsWith(
"L"
- + options.desugaredLibrarySpecification
+ + options.machineDesugaredLibrarySpecification
.getSynthesizedLibraryClassesPackagePrefix());
}
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
index c928847..f32be7e 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
@@ -8,7 +8,6 @@
import static com.android.tools.r8.utils.TraversalContinuation.CONTINUE;
import com.android.tools.r8.features.ClassToFeatureSplitMap;
-import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
import com.android.tools.r8.graph.MethodResolutionResult.ArrayCloneMethodResult;
import com.android.tools.r8.graph.MethodResolutionResult.ClassNotFoundResult;
import com.android.tools.r8.graph.MethodResolutionResult.IllegalAccessOrNoSuchMethodResult;
@@ -25,7 +24,6 @@
import com.android.tools.r8.utils.BooleanBox;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.Pair;
-import com.android.tools.r8.utils.SetUtils;
import com.android.tools.r8.utils.TraversalContinuation;
import com.android.tools.r8.utils.TriConsumer;
import com.android.tools.r8.utils.TriFunction;
@@ -1013,81 +1011,20 @@
/** Intentionally drops {@param context} since this is only needed in D8. */
@Override
public FieldResolutionResult resolveFieldOn(DexType type, DexField field, ProgramMethod context) {
+ assert checkIfObsolete();
return resolveFieldOn(type, field);
}
- /**
- * Implements resolution of a field descriptor against a type.
- *
- * <p>See <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.2">
- * Section 5.4.3.2 of the JVM Spec</a>.
- */
+ // Keep as instance methods to ensure that one needs AppInfoWithClassHierarchy to do resolution.
public FieldResolutionResult resolveFieldOn(DexType type, DexField field) {
assert checkIfObsolete();
- DexClass holder = definitionFor(type);
- return holder != null ? resolveFieldOn(holder, field) : FieldResolutionResult.failure();
+ return new FieldResolution(this).resolveFieldOn(type, field);
}
- public FieldResolutionResult resolveFieldOn(DexClass holder, DexField field) {
+ // Keep as instance methods to ensure that one needs AppInfoWithClassHierarchy to do resolution.
+ public FieldResolutionResult resolveFieldOn(DexClass clazz, DexField field) {
assert checkIfObsolete();
- assert holder != null;
- return resolveFieldOn(holder, field, holder, SetUtils.newIdentityHashSet(8));
- }
-
- private FieldResolutionResult resolveFieldOn(
- DexClass holder,
- DexField field,
- DexClass initialResolutionHolder,
- Set<DexType> visitedInterfaces) {
- assert checkIfObsolete();
- assert holder != null;
- // Step 1: Class declares the field.
- DexEncodedField definition = holder.lookupField(field);
- if (definition != null) {
- return new SuccessfulFieldResolutionResult(initialResolutionHolder, holder, definition);
- }
- // Step 2: Apply recursively to direct superinterfaces. First match succeeds.
- DexClassAndField result = resolveFieldOnDirectInterfaces(holder, field, visitedInterfaces);
- if (result != null) {
- return new SuccessfulFieldResolutionResult(
- initialResolutionHolder, result.getHolder(), result.getDefinition());
- }
- // Step 3: Apply recursively to superclass.
- if (holder.superType != null) {
- DexClass superClass = definitionFor(holder.superType);
- if (superClass != null) {
- return resolveFieldOn(superClass, field, initialResolutionHolder, visitedInterfaces);
- }
- }
- return FieldResolutionResult.failure();
- }
-
- private DexClassAndField resolveFieldOnDirectInterfaces(
- DexClass clazz, DexField field, Set<DexType> visitedInterfaces) {
- for (DexType interfaceType : clazz.interfaces.values) {
- if (visitedInterfaces.add(interfaceType)) {
- DexClass interfaceClass = definitionFor(interfaceType);
- if (interfaceClass != null) {
- DexClassAndField result =
- resolveFieldOnInterface(interfaceClass, field, visitedInterfaces);
- if (result != null) {
- return result;
- }
- }
- }
- }
- return null;
- }
-
- private DexClassAndField resolveFieldOnInterface(
- DexClass interfaceClass, DexField field, Set<DexType> visitedInterfaces) {
- // Step 1: Class declares the field.
- DexEncodedField definition = interfaceClass.lookupField(field);
- if (definition != null) {
- return DexClassAndField.create(interfaceClass, definition);
- }
- // Step 2: Apply recursively to direct superinterfaces. First match succeeds.
- return resolveFieldOnDirectInterfaces(interfaceClass, field, visitedInterfaces);
+ return new FieldResolution(this).resolveFieldOn(clazz, field);
}
private static class MaximallySpecificMethodsBuilder {
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 14b0ded..24c47b4 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -515,7 +515,6 @@
}
public void setRootSet(RootSet rootSet) {
- assert this.rootSet == null : "Root set should never be recomputed";
this.rootSet = rootSet;
}
@@ -806,9 +805,12 @@
appView.setProguardCompatibilityActions(
appView.getProguardCompatibilityActions().rewrittenWithLens(lens));
}
- if (appView.getMainDexRootSet() != null) {
+ if (appView.hasMainDexRootSet()) {
appView.setMainDexRootSet(appView.getMainDexRootSet().rewrittenWithLens(lens));
}
+ if (appView.hasRootSet()) {
+ appView.setRootSet(appView.rootSet().rewrittenWithLens(lens));
+ }
});
}
diff --git a/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java b/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java
index d0324ee..fd28cde 100644
--- a/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java
+++ b/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.graph;
import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.utils.MapUtils;
import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeHashMap;
import com.android.tools.r8.utils.collections.MutableBidirectionalManyToOneRepresentativeMap;
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java
index f35751b..9ab5faa 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -23,10 +23,11 @@
import com.android.tools.r8.errors.InvalidDebugInfoException;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfo;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
import com.android.tools.r8.graph.bytecodemetadata.BytecodeInstructionMetadata;
import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadata;
+import com.android.tools.r8.graph.proto.ArgumentInfo;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.MemberType;
import com.android.tools.r8.ir.code.NumberGenerator;
diff --git a/src/main/java/com/android/tools/r8/graph/Code.java b/src/main/java/com/android/tools/r8/graph/Code.java
index f8d5917..7a06b3d 100644
--- a/src/main/java/com/android/tools/r8/graph/Code.java
+++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.bytecodemetadata.BytecodeInstructionMetadata;
import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadata;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.Position;
diff --git a/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java b/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java
index 8803346..a544337 100644
--- a/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.graph.DexCode.Try;
import com.android.tools.r8.graph.DexCode.TryHandler;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.Position;
diff --git a/src/main/java/com/android/tools/r8/graph/DexCode.java b/src/main/java/com/android/tools/r8/graph/DexCode.java
index a44fc1d..3c3ce77 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -18,6 +18,7 @@
import com.android.tools.r8.graph.DexDebugInfo.EventBasedDebugInfo;
import com.android.tools.r8.graph.bytecodemetadata.BytecodeInstructionMetadata;
import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadata;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.Position;
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 1f58402..c326dc0 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -43,8 +43,6 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexAnnotation.AnnotatedKind;
import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadataProvider;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.NumericType;
@@ -411,6 +409,11 @@
}
public static ProgramMethod asProgramMethodOrNull(
+ DexEncodedMethod method, DexProgramClass holder) {
+ return method != null ? method.asProgramMethod(holder) : null;
+ }
+
+ public static ProgramMethod asProgramMethodOrNull(
DexEncodedMethod method, DexDefinitionSupplier definitions) {
return method != null ? method.asProgramMethod(definitions) : null;
}
@@ -1208,26 +1211,6 @@
.build();
}
- public DexEncodedMethod toStaticMethodWithoutThis(AppView<AppInfoWithLiveness> appView) {
- checkIfObsolete();
- assert !accessFlags.isStatic();
-
- ArgumentInfoCollection prototypeChanges =
- ArgumentInfoCollection.builder()
- .addArgumentInfo(0, RemovedArgumentInfo.builder().setType(getHolderType()).build())
- .build();
- Builder builder =
- builder(this)
- .promoteToStatic()
- .withoutThisParameter(appView.dexItemFactory())
- .fixupOptimizationInfo(appView, prototypeChanges.createMethodOptimizationInfoFixer())
- .setGenericSignature(MethodTypeSignature.noSignature());
- DexEncodedMethod method = builder.build();
- method.copyMetadata(appView, this);
- setObsolete();
- return method;
- }
-
public String codeToString() {
checkIfObsolete();
return code == null ? "<no code>" : code.toString(this, null);
@@ -1516,21 +1499,6 @@
newNumberOfMissingParameterAnnotations));
}
- public Builder promoteToStatic() {
- this.accessFlags.promoteToStatic();
- return this;
- }
-
- public Builder withoutThisParameter(DexItemFactory factory) {
- assert code != null;
- if (code.isDexCode()) {
- code = code.asDexCode().withoutThisParameter(factory);
- } else {
- throw new Unreachable("Code " + code.getClass().getSimpleName() + " is not supported.");
- }
- return this;
- }
-
public Builder setOptimizationInfo(MethodOptimizationInfo optimizationInfo) {
this.optimizationInfo = optimizationInfo;
return this;
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 5421ba6..686f124 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -32,6 +32,7 @@
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.desugar.LambdaClass;
import com.android.tools.r8.kotlin.Kotlin;
+import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.FieldReference;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.utils.ArrayUtils;
@@ -469,6 +470,7 @@
public final DexType retentionType =
createStaticallyKnownType("Ljava/lang/annotation/Retention;");
public final DexType runtimeExceptionType = createStaticallyKnownType(runtimeExceptionDescriptor);
+ public final DexType assertionErrorType = createStaticallyKnownType(assertionErrorDescriptor);
public final DexType throwableType = createStaticallyKnownType(throwableDescriptor);
public final DexType illegalAccessErrorType =
createStaticallyKnownType(illegalAccessErrorDescriptor);
@@ -2530,6 +2532,10 @@
return createType(createString(descriptor));
}
+ public DexType createType(ClassReference clazz) {
+ return createType(clazz.getDescriptor());
+ }
+
public DexType lookupType(DexString descriptor) {
return types.get(descriptor);
}
@@ -2556,6 +2562,10 @@
fieldReference.getFieldName());
}
+ public DexProto createProto(DexType returnType, DexTypeList parameters) {
+ return createProto(returnType, parameters, createShorty(returnType, parameters.getBacking()));
+ }
+
public DexProto createProto(DexType returnType, DexTypeList parameters, DexString shorty) {
assert !sorted;
DexProto proto = new DexProto(shorty, returnType, parameters);
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethodSignature.java b/src/main/java/com/android/tools/r8/graph/DexMethodSignature.java
index 8cc4fa7..e756d78 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethodSignature.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethodSignature.java
@@ -33,6 +33,10 @@
return getProto().getParameter(index);
}
+ public DexTypeList getParameters() {
+ return getProto().getParameters();
+ }
+
public DexType getReturnType() {
return getProto().getReturnType();
}
diff --git a/src/main/java/com/android/tools/r8/graph/FieldResolution.java b/src/main/java/com/android/tools/r8/graph/FieldResolution.java
new file mode 100644
index 0000000..120bee0
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/FieldResolution.java
@@ -0,0 +1,89 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph;
+
+import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
+import com.android.tools.r8.utils.SetUtils;
+import java.util.Set;
+
+/**
+ * Implements resolution of a field descriptor against a type.
+ *
+ * <p>See <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.2">
+ * Section 5.4.3.2 of the JVM Spec</a>.
+ */
+public class FieldResolution {
+
+ private final DexDefinitionSupplier definitionFor;
+
+ public FieldResolution(DexDefinitionSupplier definitionFor) {
+ this.definitionFor = definitionFor;
+ }
+
+ public FieldResolutionResult resolveFieldOn(DexType type, DexField field) {
+ DexClass holder = definitionFor.contextIndependentDefinitionFor(type);
+ return holder != null ? resolveFieldOn(holder, field) : FieldResolutionResult.failure();
+ }
+
+ public FieldResolutionResult resolveFieldOn(DexClass holder, DexField field) {
+ assert holder != null;
+ return resolveFieldOn(holder, field, holder, SetUtils.newIdentityHashSet(8));
+ }
+
+ private FieldResolutionResult resolveFieldOn(
+ DexClass holder,
+ DexField field,
+ DexClass initialResolutionHolder,
+ Set<DexType> visitedInterfaces) {
+ assert holder != null;
+ // Step 1: Class declares the field.
+ DexEncodedField definition = holder.lookupField(field);
+ if (definition != null) {
+ return new SuccessfulFieldResolutionResult(initialResolutionHolder, holder, definition);
+ }
+ // Step 2: Apply recursively to direct superinterfaces. First match succeeds.
+ DexClassAndField result = resolveFieldOnDirectInterfaces(holder, field, visitedInterfaces);
+ if (result != null) {
+ return new SuccessfulFieldResolutionResult(
+ initialResolutionHolder, result.getHolder(), result.getDefinition());
+ }
+ // Step 3: Apply recursively to superclass.
+ if (holder.superType != null) {
+ DexClass superClass = definitionFor.contextIndependentDefinitionFor(holder.superType);
+ if (superClass != null) {
+ return resolveFieldOn(superClass, field, initialResolutionHolder, visitedInterfaces);
+ }
+ }
+ return FieldResolutionResult.failure();
+ }
+
+ private DexClassAndField resolveFieldOnDirectInterfaces(
+ DexClass clazz, DexField field, Set<DexType> visitedInterfaces) {
+ for (DexType interfaceType : clazz.interfaces.values) {
+ if (visitedInterfaces.add(interfaceType)) {
+ DexClass interfaceClass = definitionFor.contextIndependentDefinitionFor(interfaceType);
+ if (interfaceClass != null) {
+ DexClassAndField result =
+ resolveFieldOnInterface(interfaceClass, field, visitedInterfaces);
+ if (result != null) {
+ return result;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private DexClassAndField resolveFieldOnInterface(
+ DexClass interfaceClass, DexField field, Set<DexType> visitedInterfaces) {
+ // Step 1: Class declares the field.
+ DexEncodedField definition = interfaceClass.lookupField(field);
+ if (definition != null) {
+ return DexClassAndField.create(interfaceClass, definition);
+ }
+ // Step 2: Apply recursively to direct superinterfaces. First match succeeds.
+ return resolveFieldOnDirectInterfaces(interfaceClass, field, visitedInterfaces);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLens.java b/src/main/java/com/android/tools/r8/graph/GraphLens.java
index 3e235b4..3041ccf 100644
--- a/src/main/java/com/android/tools/r8/graph/GraphLens.java
+++ b/src/main/java/com/android/tools/r8/graph/GraphLens.java
@@ -6,6 +6,7 @@
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.optimize.MemberRebindingIdentityLens;
diff --git a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
index 457a6f7..b2efb1b 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -51,6 +51,7 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.CfCode.LocalVariableInfo;
import com.android.tools.r8.graph.JarClassFileReader.ReparseContext;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.If;
import com.android.tools.r8.ir.code.MemberType;
diff --git a/src/main/java/com/android/tools/r8/graph/MethodCollection.java b/src/main/java/com/android/tools/r8/graph/MethodCollection.java
index 3dc2b58..4a403c4 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodCollection.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodCollection.java
@@ -167,6 +167,10 @@
return backing.getMethod(methodProto, methodName);
}
+ public final DexEncodedMethod getMethod(DexMethodSignature method) {
+ return getMethod(method.getProto(), method.getName());
+ }
+
public DexEncodedMethod getMethod(Predicate<DexEncodedMethod> predicate) {
DexEncodedMethod result = backing.getDirectMethod(predicate);
return result != null ? result : backing.getVirtualMethod(predicate);
diff --git a/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java b/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java
index 1f845ed..113c31c 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java
@@ -361,6 +361,10 @@
return null;
}
+ if (getResolvedHolder().isInterface() && getResolvedMethod().isPrivate()) {
+ return getResolutionPair();
+ }
+
// The symbolic reference is the holder type that resolution was initiated at.
DexClass symbolicReference = initialResolutionHolder;
diff --git a/src/main/java/com/android/tools/r8/graph/NestedGraphLens.java b/src/main/java/com/android/tools/r8/graph/NestedGraphLens.java
index 6ab93ed..87e55e9 100644
--- a/src/main/java/com/android/tools/r8/graph/NestedGraphLens.java
+++ b/src/main/java/com/android/tools/r8/graph/NestedGraphLens.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.graph;
import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.utils.IterableUtils;
import com.android.tools.r8.utils.collections.BidirectionalManyToManyRepresentativeMap;
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
index 9bd0c4a..37acbad 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
@@ -6,6 +6,7 @@
import static com.android.tools.r8.ir.optimize.info.OptimizationFeedback.getSimpleFeedback;
import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.Position;
diff --git a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
deleted file mode 100644
index e6a6cba..0000000
--- a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
+++ /dev/null
@@ -1,882 +0,0 @@
-// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.graph;
-
-import com.android.tools.r8.ir.analysis.value.SingleValue;
-import com.android.tools.r8.ir.code.ConstInstruction;
-import com.android.tools.r8.ir.code.IRCode;
-import com.android.tools.r8.ir.code.Instruction;
-import com.android.tools.r8.ir.code.Position;
-import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
-import com.android.tools.r8.ir.conversion.ExtraParameter;
-import com.android.tools.r8.ir.conversion.ExtraUnusedNullParameter;
-import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfoFixer;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.ConsumerUtils;
-import com.android.tools.r8.utils.IntObjConsumer;
-import com.android.tools.r8.utils.IteratorUtils;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Ordering;
-import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
-import it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry;
-import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap;
-import it.unimi.dsi.fastutil.ints.Int2ObjectSortedMap;
-import it.unimi.dsi.fastutil.ints.IntArrayList;
-import it.unimi.dsi.fastutil.ints.IntBidirectionalIterator;
-import it.unimi.dsi.fastutil.ints.IntCollection;
-import it.unimi.dsi.fastutil.ints.IntList;
-import it.unimi.dsi.fastutil.ints.IntLists;
-import it.unimi.dsi.fastutil.ints.IntSortedSet;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Objects;
-import java.util.function.Consumer;
-
-public class RewrittenPrototypeDescription {
-
- public abstract static class ArgumentInfo {
-
- static final ArgumentInfo NO_INFO =
- new ArgumentInfo() {
-
- @Override
- public ArgumentInfo combine(ArgumentInfo info) {
- assert false : "ArgumentInfo NO_INFO should not be combined";
- return info;
- }
-
- @Override
- public boolean isNone() {
- return true;
- }
-
- @Override
- public ArgumentInfo rewrittenWithLens(
- AppView<AppInfoWithLiveness> appView, GraphLens graphLens, GraphLens codeLens) {
- return this;
- }
-
- @Override
- public boolean equals(Object obj) {
- return obj == this;
- }
-
- @Override
- public int hashCode() {
- return System.identityHashCode(this);
- }
- };
-
- @SuppressWarnings("ConstantConditions")
- public static ArgumentInfo combine(ArgumentInfo arg1, ArgumentInfo arg2) {
- if (arg1 == null) {
- assert arg2 != null;
- return arg2;
- }
- if (arg2 == null) {
- assert arg1 != null;
- return arg1;
- }
- return arg1.combine(arg2);
- }
-
- public boolean isNone() {
- return false;
- }
-
- public boolean isRemovedArgumentInfo() {
- return false;
- }
-
- public RemovedArgumentInfo asRemovedArgumentInfo() {
- return null;
- }
-
- public boolean isRewrittenTypeInfo() {
- return false;
- }
-
- public RewrittenTypeInfo asRewrittenTypeInfo() {
- return null;
- }
-
- // ArgumentInfo are combined with `this` first, and the `info` argument second.
- public abstract ArgumentInfo combine(ArgumentInfo info);
-
- public abstract ArgumentInfo rewrittenWithLens(
- AppView<AppInfoWithLiveness> appView, GraphLens graphLens, GraphLens codeLens);
-
- @Override
- public abstract boolean equals(Object obj);
-
- @Override
- public abstract int hashCode();
- }
-
- public static class RemovedArgumentInfo extends ArgumentInfo {
-
- public static class Builder {
-
- private boolean checkNullOrZero;
- private SingleValue singleValue;
- private DexType type;
-
- public Builder setCheckNullOrZero(boolean checkNullOrZero) {
- this.checkNullOrZero = checkNullOrZero;
- return this;
- }
-
- public Builder setSingleValue(SingleValue singleValue) {
- this.singleValue = singleValue;
- return this;
- }
-
- public Builder setType(DexType type) {
- this.type = type;
- return this;
- }
-
- public RemovedArgumentInfo build() {
- assert type != null;
- return new RemovedArgumentInfo(checkNullOrZero, singleValue, type);
- }
- }
-
- private final boolean checkNullOrZero;
- private final SingleValue singleValue;
- private final DexType type;
-
- private RemovedArgumentInfo(boolean checkNullOrZero, SingleValue singleValue, DexType type) {
- this.checkNullOrZero = checkNullOrZero;
- this.singleValue = singleValue;
- this.type = type;
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- public boolean hasSingleValue() {
- return singleValue != null;
- }
-
- public SingleValue getSingleValue() {
- return singleValue;
- }
-
- public DexType getType() {
- return type;
- }
-
- public boolean isCheckNullOrZeroSet() {
- return checkNullOrZero;
- }
-
- @Override
- public boolean isRemovedArgumentInfo() {
- return true;
- }
-
- @Override
- public RemovedArgumentInfo asRemovedArgumentInfo() {
- return this;
- }
-
- @Override
- public ArgumentInfo combine(ArgumentInfo info) {
- assert false : "Once the argument is removed one cannot modify it any further.";
- return this;
- }
-
- @Override
- public RemovedArgumentInfo rewrittenWithLens(
- AppView<AppInfoWithLiveness> appView, GraphLens graphLens, GraphLens codeLens) {
- SingleValue rewrittenSingleValue =
- hasSingleValue() ? singleValue.rewrittenWithLens(appView, graphLens, codeLens) : null;
- DexType rewrittenType = graphLens.lookupType(type, codeLens);
- if (rewrittenSingleValue != singleValue || rewrittenType != type) {
- return new RemovedArgumentInfo(checkNullOrZero, rewrittenSingleValue, rewrittenType);
- }
- return this;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null || getClass() != obj.getClass()) {
- return false;
- }
- RemovedArgumentInfo other = (RemovedArgumentInfo) obj;
- return checkNullOrZero == other.checkNullOrZero
- && type == other.type
- && Objects.equals(singleValue, other.singleValue);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(checkNullOrZero, singleValue, type);
- }
- }
-
- public static class RewrittenTypeInfo extends ArgumentInfo {
-
- private final DexType castType;
- private final DexType oldType;
- private final DexType newType;
- private final SingleValue singleValue;
-
- public static Builder builder() {
- return new Builder();
- }
-
- private RewrittenTypeInfo(
- DexType oldType, DexType newType, DexType castType, SingleValue singleValue) {
- this.castType = castType;
- this.oldType = oldType;
- this.newType = newType;
- this.singleValue = singleValue;
- assert !newType.isVoidType() || singleValue != null;
- }
-
- public RewrittenTypeInfo combine(RewrittenPrototypeDescription other) {
- return other.hasRewrittenReturnInfo() ? combine(other.getRewrittenReturnInfo()) : this;
- }
-
- public DexType getCastType() {
- return castType;
- }
-
- public DexType getNewType() {
- return newType;
- }
-
- public DexType getOldType() {
- return oldType;
- }
-
- public SingleValue getSingleValue() {
- return singleValue;
- }
-
- boolean hasBeenChangedToReturnVoid() {
- return newType.isVoidType();
- }
-
- public boolean hasCastType() {
- return castType != null;
- }
-
- public boolean hasSingleValue() {
- return singleValue != null;
- }
-
- @Override
- public boolean isRewrittenTypeInfo() {
- return true;
- }
-
- @Override
- public RewrittenTypeInfo asRewrittenTypeInfo() {
- return this;
- }
-
- @Override
- public ArgumentInfo combine(ArgumentInfo info) {
- if (info.isRemovedArgumentInfo()) {
- return info;
- }
- assert info.isRewrittenTypeInfo();
- return combine(info.asRewrittenTypeInfo());
- }
-
- public RewrittenTypeInfo combine(RewrittenTypeInfo other) {
- assert !getNewType().isVoidType();
- assert getNewType() == other.getOldType();
- return new RewrittenTypeInfo(
- getOldType(), other.getNewType(), getCastType(), other.getSingleValue());
- }
-
- @Override
- public RewrittenTypeInfo rewrittenWithLens(
- AppView<AppInfoWithLiveness> appView, GraphLens graphLens, GraphLens codeLens) {
- DexType rewrittenCastType =
- castType != null ? graphLens.lookupType(castType, codeLens) : null;
- DexType rewrittenNewType = graphLens.lookupType(newType, codeLens);
- SingleValue rewrittenSingleValue =
- hasSingleValue()
- ? getSingleValue().rewrittenWithLens(appView, graphLens, codeLens)
- : null;
- if (rewrittenCastType != castType
- || rewrittenNewType != newType
- || rewrittenSingleValue != singleValue) {
- // The old type is intentionally not rewritten.
- return new RewrittenTypeInfo(
- oldType, rewrittenNewType, rewrittenCastType, rewrittenSingleValue);
- }
- return this;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null || getClass() != obj.getClass()) {
- return false;
- }
- RewrittenTypeInfo other = (RewrittenTypeInfo) obj;
- return oldType == other.oldType
- && newType == other.newType
- && Objects.equals(singleValue, other.singleValue);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(oldType, newType, singleValue);
- }
-
- public static class Builder {
-
- private DexType castType;
- private DexType oldType;
- private DexType newType;
- private SingleValue singleValue;
-
- public Builder applyIf(boolean condition, Consumer<Builder> consumer) {
- if (condition) {
- consumer.accept(this);
- }
- return this;
- }
-
- public Builder setCastType(DexType castType) {
- this.castType = castType;
- return this;
- }
-
- public Builder setOldType(DexType oldType) {
- this.oldType = oldType;
- return this;
- }
-
- public Builder setNewType(DexType newType) {
- this.newType = newType;
- return this;
- }
-
- public Builder setSingleValue(SingleValue singleValue) {
- this.singleValue = singleValue;
- return this;
- }
-
- public RewrittenTypeInfo build() {
- return new RewrittenTypeInfo(oldType, newType, castType, singleValue);
- }
- }
- }
-
- public static class ArgumentInfoCollection {
-
- private static final ArgumentInfoCollection EMPTY = new ArgumentInfoCollection();
-
- private final Int2ObjectSortedMap<ArgumentInfo> argumentInfos;
-
- // Specific constructor for empty.
- private ArgumentInfoCollection() {
- this.argumentInfos = new Int2ObjectRBTreeMap<>();
- }
-
- private ArgumentInfoCollection(Int2ObjectSortedMap<ArgumentInfo> argumentInfos) {
- assert argumentInfos != null : "should use empty.";
- assert !argumentInfos.isEmpty() : "should use empty.";
- this.argumentInfos = argumentInfos;
- }
-
- public static ArgumentInfoCollection empty() {
- return EMPTY;
- }
-
- public void forEach(IntObjConsumer<ArgumentInfo> consumer) {
- for (Entry<ArgumentInfo> entry : argumentInfos.int2ObjectEntrySet()) {
- consumer.accept(entry.getIntKey(), entry.getValue());
- }
- }
-
- public IntSortedSet getKeys() {
- return argumentInfos.keySet();
- }
-
- public IntCollection getRemovedParameterIndices() {
- int numberOfRemovedArguments = numberOfRemovedArguments();
- if (numberOfRemovedArguments == 0) {
- return IntLists.EMPTY_LIST;
- }
- if (numberOfRemovedArguments == argumentInfos.size()) {
- return getKeys();
- }
- IntList removedParameterIndices = new IntArrayList(numberOfRemovedArguments);
- Iterator<Entry<ArgumentInfo>> iterator = iterator();
- while (iterator.hasNext()) {
- Entry<ArgumentInfo> entry = iterator.next();
- if (entry.getValue().isRemovedArgumentInfo()) {
- removedParameterIndices.add(entry.getIntKey());
- }
- }
- return removedParameterIndices;
- }
-
- public boolean isArgumentRemoved(int argumentIndex) {
- return getArgumentInfo(argumentIndex).isRemovedArgumentInfo();
- }
-
- public boolean isEmpty() {
- return this == EMPTY;
- }
-
- public Iterator<Entry<ArgumentInfo>> iterator() {
- return argumentInfos.int2ObjectEntrySet().iterator();
- }
-
- public boolean hasRemovedArguments() {
- for (ArgumentInfo value : argumentInfos.values()) {
- if (value.isRemovedArgumentInfo()) {
- return true;
- }
- }
- return false;
- }
-
- public int numberOfRemovedArguments() {
- int removed = 0;
- for (ArgumentInfo value : argumentInfos.values()) {
- if (value.isRemovedArgumentInfo()) {
- removed++;
- }
- }
- return removed;
- }
-
- public int numberOfRemovedNonReceiverArguments(ProgramMethod method) {
- return numberOfRemovedArguments()
- - BooleanUtils.intValue(method.getDefinition().isInstance() && isArgumentRemoved(0));
- }
-
- public boolean hasArgumentInfo(int argumentIndex) {
- return argumentInfos.containsKey(argumentIndex);
- }
-
- public ArgumentInfo getArgumentInfo(int argumentIndex) {
- return argumentInfos.getOrDefault(argumentIndex, ArgumentInfo.NO_INFO);
- }
-
- public int size() {
- return argumentInfos.size();
- }
-
- public ArgumentInfoCollection rewrittenWithLens(
- AppView<AppInfoWithLiveness> appView, GraphLens graphLens, GraphLens codeLens) {
- Int2ObjectSortedMap<ArgumentInfo> rewrittenArgumentInfos = new Int2ObjectRBTreeMap<>();
- for (Int2ObjectMap.Entry<ArgumentInfo> entry : argumentInfos.int2ObjectEntrySet()) {
- ArgumentInfo argumentInfo = entry.getValue();
- ArgumentInfo rewrittenArgumentInfo =
- argumentInfo.rewrittenWithLens(appView, graphLens, codeLens);
- if (rewrittenArgumentInfo != argumentInfo) {
- rewrittenArgumentInfos.put(entry.getIntKey(), rewrittenArgumentInfo);
- }
- }
- if (!rewrittenArgumentInfos.isEmpty()) {
- for (Int2ObjectMap.Entry<ArgumentInfo> entry : argumentInfos.int2ObjectEntrySet()) {
- int key = entry.getIntKey();
- if (!rewrittenArgumentInfos.containsKey(key)) {
- rewrittenArgumentInfos.put(key, entry.getValue());
- }
- }
- return new ArgumentInfoCollection(rewrittenArgumentInfos);
- }
- return this;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null || getClass() != obj.getClass()) {
- return false;
- }
- ArgumentInfoCollection other = (ArgumentInfoCollection) obj;
- return argumentInfos.equals(other.argumentInfos);
- }
-
- @Override
- public int hashCode() {
- return argumentInfos.hashCode();
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- public static class Builder {
-
- private Int2ObjectSortedMap<ArgumentInfo> argumentInfos;
-
- public Builder addArgumentInfo(int argIndex, ArgumentInfo argInfo) {
- if (argumentInfos == null) {
- argumentInfos = new Int2ObjectRBTreeMap<>();
- }
- assert !argumentInfos.containsKey(argIndex);
- argumentInfos.put(argIndex, argInfo);
- return this;
- }
-
- public ArgumentInfoCollection build() {
- if (argumentInfos == null || argumentInfos.isEmpty()) {
- return EMPTY;
- }
- return new ArgumentInfoCollection(argumentInfos);
- }
- }
-
- public ArgumentInfoCollection combine(ArgumentInfoCollection info) {
- if (isEmpty()) {
- return info;
- } else {
- if (info.isEmpty()) {
- return this;
- }
- }
-
- Int2ObjectSortedMap<ArgumentInfo> newArgInfos = new Int2ObjectRBTreeMap<>();
- newArgInfos.putAll(argumentInfos);
- IntBidirectionalIterator iterator = argumentInfos.keySet().iterator();
- int offset = 0;
- int nextArgIndex;
- for (int pendingArgIndex : info.argumentInfos.keySet()) {
- nextArgIndex = peekNextOrMax(iterator);
- while (nextArgIndex <= pendingArgIndex + offset) {
- iterator.nextInt();
- ArgumentInfo argumentInfo = argumentInfos.get(nextArgIndex);
- nextArgIndex = peekNextOrMax(iterator);
- if (argumentInfo.isRemovedArgumentInfo()) {
- offset++;
- }
- }
- ArgumentInfo newArgInfo =
- nextArgIndex == pendingArgIndex + offset
- ? ArgumentInfo.combine(
- argumentInfos.get(nextArgIndex), info.argumentInfos.get(pendingArgIndex))
- : info.argumentInfos.get(pendingArgIndex);
- newArgInfos.put(pendingArgIndex + offset, newArgInfo);
- }
- assert Ordering.natural().isOrdered(newArgInfos.keySet());
- return new ArgumentInfoCollection(newArgInfos);
- }
-
- static int peekNextOrMax(IntBidirectionalIterator iterator) {
- if (iterator.hasNext()) {
- int i = iterator.nextInt();
- iterator.previousInt();
- return i;
- }
- return Integer.MAX_VALUE;
- }
-
- public MethodOptimizationInfoFixer createMethodOptimizationInfoFixer() {
- RewrittenPrototypeDescription prototypeChanges =
- RewrittenPrototypeDescription.create(Collections.emptyList(), null, this);
- return prototypeChanges.createMethodOptimizationInfoFixer();
- }
-
- /**
- * Returns a function for rewriting the parameter annotations on a method info after prototype
- * changes were made.
- */
- public Consumer<DexEncodedMethod.Builder> createParameterAnnotationsRemover(
- DexEncodedMethod method) {
- if (numberOfRemovedArguments() > 0 && !method.parameterAnnotationsList.isEmpty()) {
- return builder -> {
- int firstArgumentIndex = method.getFirstNonReceiverArgumentIndex();
- builder.removeParameterAnnotations(
- oldIndex -> getArgumentInfo(oldIndex + firstArgumentIndex).isRemovedArgumentInfo());
- };
- }
- return ConsumerUtils.emptyConsumer();
- }
-
- public int getNewArgumentIndex(int argumentIndex) {
- int numberOfArgumentsRemovedBeforeArgument = 0;
- Iterator<Entry<ArgumentInfo>> iterator = iterator();
- while (iterator.hasNext()) {
- Entry<ArgumentInfo> entry = iterator.next();
- int argumentIndexForInfo = entry.getIntKey();
- if (argumentIndexForInfo >= argumentIndex) {
- break;
- }
- ArgumentInfo argumentInfo = entry.getValue();
- if (argumentInfo.isRemovedArgumentInfo()) {
- numberOfArgumentsRemovedBeforeArgument++;
- }
- }
- assert IteratorUtils.allRemainingMatchDestructive(
- iterator, entry -> entry.getIntKey() >= argumentIndex);
- return argumentIndex - numberOfArgumentsRemovedBeforeArgument;
- }
- }
-
- private static final RewrittenPrototypeDescription NONE = new RewrittenPrototypeDescription();
-
- private final List<ExtraParameter> extraParameters;
- private final ArgumentInfoCollection argumentInfoCollection;
- private final RewrittenTypeInfo rewrittenReturnInfo;
-
- private RewrittenPrototypeDescription() {
- this.extraParameters = Collections.emptyList();
- this.rewrittenReturnInfo = null;
- this.argumentInfoCollection = ArgumentInfoCollection.empty();
- }
-
- private RewrittenPrototypeDescription(
- List<ExtraParameter> extraParameters,
- RewrittenTypeInfo rewrittenReturnInfo,
- ArgumentInfoCollection argumentsInfo) {
- assert argumentsInfo != null;
- this.extraParameters = extraParameters;
- this.rewrittenReturnInfo = rewrittenReturnInfo;
- this.argumentInfoCollection = argumentsInfo;
- assert !isEmpty();
- }
-
- public static RewrittenPrototypeDescription create(
- List<ExtraParameter> extraParameters,
- RewrittenTypeInfo rewrittenReturnInfo,
- ArgumentInfoCollection argumentsInfo) {
- return extraParameters.isEmpty() && rewrittenReturnInfo == null && argumentsInfo.isEmpty()
- ? none()
- : new RewrittenPrototypeDescription(extraParameters, rewrittenReturnInfo, argumentsInfo);
- }
-
- public static RewrittenPrototypeDescription createForRewrittenTypes(
- RewrittenTypeInfo returnInfo, ArgumentInfoCollection rewrittenArgumentsInfo) {
- return create(Collections.emptyList(), returnInfo, rewrittenArgumentsInfo);
- }
-
- public static RewrittenPrototypeDescription none() {
- return NONE;
- }
-
- public Consumer<DexEncodedMethod.Builder> createParameterAnnotationsRemover(
- DexEncodedMethod method) {
- return getArgumentInfoCollection().createParameterAnnotationsRemover(method);
- }
-
- public MethodOptimizationInfoFixer createMethodOptimizationInfoFixer() {
- return new RewrittenPrototypeDescriptionMethodOptimizationInfoFixer(this);
- }
-
- public RewrittenPrototypeDescription combine(RewrittenPrototypeDescription other) {
- if (isEmpty()) {
- return other;
- }
- if (other.isEmpty()) {
- return this;
- }
- // We currently don't have any passes that remove extra parameters inserted by previous passes.
- // If the input prototype changes have removed some of the extra parameters, we would need to
- // adapt the merging of prototype changes below.
- List<ExtraParameter> newExtraParameters =
- ImmutableList.<ExtraParameter>builder()
- .addAll(getExtraParameters())
- .addAll(other.getExtraParameters())
- .build();
- RewrittenTypeInfo newRewrittenTypeInfo =
- hasRewrittenReturnInfo()
- ? getRewrittenReturnInfo().combine(other)
- : other.getRewrittenReturnInfo();
- ArgumentInfoCollection newArgumentInfoCollection =
- getArgumentInfoCollection().combine(other.getArgumentInfoCollection());
- return new RewrittenPrototypeDescription(
- newExtraParameters, newRewrittenTypeInfo, newArgumentInfoCollection);
- }
-
- public boolean isEmpty() {
- return extraParameters.isEmpty()
- && rewrittenReturnInfo == null
- && argumentInfoCollection.isEmpty();
- }
-
- public boolean hasExtraParameters() {
- return !extraParameters.isEmpty();
- }
-
- public List<ExtraParameter> getExtraParameters() {
- return extraParameters;
- }
-
- public int numberOfExtraParameters() {
- return extraParameters.size();
- }
-
- public boolean hasBeenChangedToReturnVoid() {
- return rewrittenReturnInfo != null && rewrittenReturnInfo.hasBeenChangedToReturnVoid();
- }
-
- public ArgumentInfoCollection getArgumentInfoCollection() {
- return argumentInfoCollection;
- }
-
- public boolean hasRewrittenReturnInfo() {
- return rewrittenReturnInfo != null;
- }
-
- public boolean requiresRewritingAtCallSite() {
- return hasRewrittenReturnInfo()
- || numberOfExtraParameters() > 0
- || argumentInfoCollection.numberOfRemovedArguments() > 0;
- }
-
- public RewrittenTypeInfo getRewrittenReturnInfo() {
- return rewrittenReturnInfo;
- }
-
- /**
- * Returns the {@link ConstInstruction} that should be used to materialize the result of
- * invocations to the method represented by this {@link RewrittenPrototypeDescription}.
- *
- * <p>This method should only be used for methods that return a constant value and whose return
- * type has been changed to void.
- *
- * <p>Note that the current implementation always returns null at this point.
- */
- public Instruction getConstantReturn(
- AppView<AppInfoWithLiveness> appView,
- IRCode code,
- Position position,
- TypeAndLocalInfoSupplier info) {
- assert rewrittenReturnInfo != null;
- assert rewrittenReturnInfo.hasSingleValue();
- Instruction instruction =
- rewrittenReturnInfo.getSingleValue().createMaterializingInstruction(appView, code, info);
- instruction.setPosition(position);
- return instruction;
- }
-
- public boolean verifyConstantReturnAccessibleInContext(
- AppView<AppInfoWithLiveness> appView, ProgramMethod method, GraphLens codeLens) {
- SingleValue rewrittenSingleValue =
- rewrittenReturnInfo
- .getSingleValue()
- .rewrittenWithLens(appView, appView.graphLens(), codeLens);
- assert rewrittenSingleValue.isMaterializableInContext(appView, method);
- return true;
- }
-
- public DexMethod rewriteMethod(ProgramMethod method, DexItemFactory dexItemFactory) {
- if (isEmpty()) {
- return method.getReference();
- }
- DexProto rewrittenProto = rewriteProto(method, dexItemFactory);
- return method.getReference().withProto(rewrittenProto, dexItemFactory);
- }
-
- public DexProto rewriteProto(ProgramMethod method, DexItemFactory dexItemFactory) {
- if (isEmpty()) {
- return method.getProto();
- }
- DexType newReturnType =
- rewrittenReturnInfo != null ? rewrittenReturnInfo.getNewType() : method.getReturnType();
- DexType[] newParameters = rewriteParameters(method, dexItemFactory);
- return dexItemFactory.createProto(newReturnType, newParameters);
- }
-
- public DexType[] rewriteParameters(ProgramMethod method, DexItemFactory dexItemFactory) {
- DexType[] params = method.getParameters().values;
- if (isEmpty()) {
- return params;
- }
- DexType[] newParams =
- new DexType
- [params.length
- - argumentInfoCollection.numberOfRemovedNonReceiverArguments(method)
- + extraParameters.size()];
- int offset = method.getDefinition().getFirstNonReceiverArgumentIndex();
- int newParamIndex = 0;
- for (int oldParamIndex = 0; oldParamIndex < params.length; oldParamIndex++) {
- ArgumentInfo argInfo = argumentInfoCollection.getArgumentInfo(oldParamIndex + offset);
- if (argInfo.isNone()) {
- newParams[newParamIndex++] = params[oldParamIndex];
- } else if (argInfo.isRewrittenTypeInfo()) {
- RewrittenTypeInfo rewrittenTypeInfo = argInfo.asRewrittenTypeInfo();
- assert params[oldParamIndex] == rewrittenTypeInfo.oldType;
- newParams[newParamIndex++] = rewrittenTypeInfo.newType;
- }
- }
- for (ExtraParameter extraParameter : extraParameters) {
- newParams[newParamIndex++] = extraParameter.getType(dexItemFactory);
- }
- return newParams;
- }
-
- public RewrittenPrototypeDescription rewrittenWithLens(
- AppView<AppInfoWithLiveness> appView, GraphLens graphLens, GraphLens codeLens) {
- ArgumentInfoCollection newArgumentInfoCollection =
- argumentInfoCollection.rewrittenWithLens(appView, graphLens, codeLens);
- RewrittenTypeInfo newRewrittenReturnInfo =
- hasRewrittenReturnInfo()
- ? rewrittenReturnInfo.rewrittenWithLens(appView, graphLens, codeLens)
- : null;
- if (newArgumentInfoCollection != argumentInfoCollection
- || newRewrittenReturnInfo != rewrittenReturnInfo) {
- return new RewrittenPrototypeDescription(
- extraParameters, newRewrittenReturnInfo, newArgumentInfoCollection);
- }
- return this;
- }
-
- public RewrittenPrototypeDescription withRewrittenReturnInfo(
- RewrittenTypeInfo newRewrittenReturnInfo) {
- if (Objects.equals(rewrittenReturnInfo, newRewrittenReturnInfo)) {
- return this;
- }
- return new RewrittenPrototypeDescription(
- extraParameters, newRewrittenReturnInfo, argumentInfoCollection);
- }
-
- public RewrittenPrototypeDescription withExtraUnusedNullParameters(
- int numberOfExtraUnusedNullParameters) {
- List<ExtraParameter> parameters =
- Collections.nCopies(numberOfExtraUnusedNullParameters, new ExtraUnusedNullParameter());
- return withExtraParameters(parameters);
- }
-
- public RewrittenPrototypeDescription withExtraParameters(ExtraParameter... parameters) {
- return withExtraParameters(Arrays.asList(parameters));
- }
-
- public RewrittenPrototypeDescription withExtraParameters(List<ExtraParameter> parameters) {
- if (parameters.isEmpty()) {
- return this;
- }
- List<ExtraParameter> newExtraParameters =
- new ArrayList<>(extraParameters.size() + parameters.size());
- newExtraParameters.addAll(extraParameters);
- newExtraParameters.addAll(parameters);
- return new RewrittenPrototypeDescription(
- newExtraParameters, rewrittenReturnInfo, argumentInfoCollection);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null || getClass() != obj.getClass()) {
- return false;
- }
- RewrittenPrototypeDescription other = (RewrittenPrototypeDescription) obj;
- return extraParameters.equals(other.extraParameters)
- && Objects.equals(rewrittenReturnInfo, other.rewrittenReturnInfo)
- && argumentInfoCollection.equals(other.argumentInfoCollection);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(extraParameters, rewrittenReturnInfo, argumentInfoCollection);
- }
-}
diff --git a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescriptionMethodOptimizationInfoFixer.java b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescriptionMethodOptimizationInfoFixer.java
index e25d391..f949105 100644
--- a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescriptionMethodOptimizationInfoFixer.java
+++ b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescriptionMethodOptimizationInfoFixer.java
@@ -4,8 +4,9 @@
package com.android.tools.r8.graph;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfo;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfo;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraint;
import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraintFactory;
import com.android.tools.r8.ir.optimize.classinliner.constraint.ClassInlinerMethodConstraint;
diff --git a/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java b/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java
index 8928361..3420b1b 100644
--- a/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java
+++ b/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexCode.Try;
import com.android.tools.r8.graph.DexCode.TryHandler;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.Position;
diff --git a/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java b/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java
index c573130..03b811f 100644
--- a/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java
+++ b/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.graph.DexCode.Try;
import com.android.tools.r8.graph.DexCode.TryHandler;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.Position;
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java
index a6045e4..d110049 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java
@@ -14,42 +14,78 @@
import com.android.tools.r8.cf.code.CfLoad;
import com.android.tools.r8.cf.code.CfLogicalBinop;
import com.android.tools.r8.cf.code.CfStaticFieldWrite;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
-import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.FieldResolutionResult;
import com.android.tools.r8.graph.ProgramDefinition;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.shaking.EnqueuerWorklist;
+import com.android.tools.r8.utils.AssertionConfigurationWithDefault;
import com.google.common.collect.ImmutableList;
import java.util.List;
+import java.util.stream.Collectors;
import org.objectweb.asm.Opcodes;
-public class ClassInitializerAssertionEnablingAnalysis extends EnqueuerAnalysis {
+public class ClassInitializerAssertionEnablingAnalysis extends EnqueuerAnalysis
+ implements EnqueuerFieldAccessAnalysis {
private final DexItemFactory dexItemFactory;
private final OptimizationFeedback feedback;
private final DexString kotlinAssertionsEnabled;
+ private final AssertionConfigurationWithDefault assertionsConfiguration;
+ private final List<DexMethod> assertionHandlers;
public ClassInitializerAssertionEnablingAnalysis(
- DexItemFactory dexItemFactory, OptimizationFeedback feedback) {
- this.dexItemFactory = dexItemFactory;
+ AppView<?> appView, OptimizationFeedback feedback) {
+ this.dexItemFactory = appView.dexItemFactory();
this.feedback = feedback;
this.kotlinAssertionsEnabled = dexItemFactory.createString("ENABLED");
+ this.assertionsConfiguration = appView.options().assertionsConfiguration;
+ this.assertionHandlers =
+ assertionsConfiguration.getAllAssertionHandlers().stream()
+ .map(dexItemFactory::createMethod)
+ .collect(Collectors.toList());
+ }
+
+ private boolean isUsingJavaAssertionsDisabledField(DexField field) {
+ // This does not check the holder, as for inner classes the field is read from the outer class
+ // and not the class itself.
+ return field.getName() == dexItemFactory.assertionsDisabled
+ && field.getType() == dexItemFactory.booleanType;
+ }
+
+ private boolean isUsingKotlinAssertionsEnabledField(DexField field) {
+ return field == dexItemFactory.kotlin.assertions.enabledField;
+ }
+
+ @Override
+ public void traceStaticFieldRead(
+ DexField field,
+ FieldResolutionResult resolutionResult,
+ ProgramMethod context,
+ EnqueuerWorklist worklist) {
+ if (isUsingJavaAssertionsDisabledField(field) || isUsingKotlinAssertionsEnabledField(field)) {
+ assertionHandlers.forEach(
+ assertionHandler -> worklist.enqueueTraceInvokeStaticAction(assertionHandler, context));
+ }
}
@Override
public void processNewlyLiveMethod(
ProgramMethod method, ProgramDefinition context, EnqueuerWorklist worklist) {
DexEncodedMethod definition = method.getDefinition();
- if (definition.isClassInitializer()) {
- Code code = definition.getCode();
- if (code.isCfCode()) {
- if (hasJavacClinitAssertionCode(code.asCfCode()) || hasKotlincClinitAssertionCode(method)) {
- feedback.setInitializerEnablingJavaVmAssertions(definition);
- }
- }
+ if (!definition.hasCode() || !definition.getCode().isCfCode()) {
+ return;
+ }
+ CfCode code = definition.getCode().asCfCode();
+ if (definition.isClassInitializer()
+ && (hasJavacClinitAssertionCode(code) || hasKotlincClinitAssertionCode(method))) {
+ feedback.setInitializerEnablingJavaVmAssertions(definition);
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerFieldAccessAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerFieldAccessAnalysis.java
index eee1f34..d8dadc5 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerFieldAccessAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerFieldAccessAnalysis.java
@@ -7,18 +7,35 @@
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.FieldResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.shaking.EnqueuerWorklist;
public interface EnqueuerFieldAccessAnalysis {
- void traceInstanceFieldRead(
- DexField field, FieldResolutionResult resolutionResult, ProgramMethod context);
+ default void traceInstanceFieldRead(
+ DexField field,
+ FieldResolutionResult resolutionResult,
+ ProgramMethod context,
+ EnqueuerWorklist worklist) {}
+ ;
- void traceInstanceFieldWrite(
- DexField field, FieldResolutionResult resolutionResult, ProgramMethod context);
+ default void traceInstanceFieldWrite(
+ DexField field,
+ FieldResolutionResult resolutionResult,
+ ProgramMethod context,
+ EnqueuerWorklist worklist) {}
+ ;
- void traceStaticFieldRead(
- DexField field, FieldResolutionResult resolutionResult, ProgramMethod context);
+ default void traceStaticFieldRead(
+ DexField field,
+ FieldResolutionResult resolutionResult,
+ ProgramMethod context,
+ EnqueuerWorklist worklist) {}
+ ;
- void traceStaticFieldWrite(
- DexField field, FieldResolutionResult resolutionResult, ProgramMethod context);
+ default void traceStaticFieldWrite(
+ DexField field,
+ FieldResolutionResult resolutionResult,
+ ProgramMethod context,
+ EnqueuerWorklist worklist) {}
+ ;
}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/GetArrayOfMissingTypeVerifyErrorWorkaround.java b/src/main/java/com/android/tools/r8/graph/analysis/GetArrayOfMissingTypeVerifyErrorWorkaround.java
index 74817d0..48ca34d 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/GetArrayOfMissingTypeVerifyErrorWorkaround.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/GetArrayOfMissingTypeVerifyErrorWorkaround.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.graph.FieldResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.shaking.Enqueuer;
+import com.android.tools.r8.shaking.EnqueuerWorklist;
import com.android.tools.r8.shaking.KeepInfo.Joiner;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.InternalOptions;
@@ -61,7 +62,10 @@
@Override
public void traceInstanceFieldRead(
- DexField field, FieldResolutionResult resolutionResult, ProgramMethod context) {
+ DexField field,
+ FieldResolutionResult resolutionResult,
+ ProgramMethod context,
+ EnqueuerWorklist worklist) {
if (isUnsafeToUseFieldOnDalvik(field)) {
enqueuer.getKeepInfo().joinMethod(context, Joiner::disallowOptimization);
}
@@ -69,7 +73,10 @@
@Override
public void traceStaticFieldRead(
- DexField field, FieldResolutionResult resolutionResult, ProgramMethod context) {
+ DexField field,
+ FieldResolutionResult resolutionResult,
+ ProgramMethod context,
+ EnqueuerWorklist worklist) {
if (isUnsafeToUseFieldOnDalvik(field)) {
enqueuer.getKeepInfo().joinMethod(context, Joiner::disallowOptimization);
}
@@ -95,13 +102,19 @@
@Override
public void traceInstanceFieldWrite(
- DexField field, FieldResolutionResult resolutionResult, ProgramMethod context) {
+ DexField field,
+ FieldResolutionResult resolutionResult,
+ ProgramMethod context,
+ EnqueuerWorklist worklist) {
// Intentionally empty.
}
@Override
public void traceStaticFieldWrite(
- DexField field, FieldResolutionResult resolutionResult, ProgramMethod context) {
+ DexField field,
+ FieldResolutionResult resolutionResult,
+ ProgramMethod context,
+ EnqueuerWorklist worklist) {
// Intentionally empty.
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/proto/ArgumentInfo.java b/src/main/java/com/android/tools/r8/graph/proto/ArgumentInfo.java
new file mode 100644
index 0000000..26cf24f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/proto/ArgumentInfo.java
@@ -0,0 +1,74 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph.proto;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+
+public abstract class ArgumentInfo {
+
+ static final ArgumentInfo NO_INFO =
+ new ArgumentInfo() {
+
+ @Override
+ public ArgumentInfo combine(ArgumentInfo info) {
+ return info;
+ }
+
+ @Override
+ public boolean isNone() {
+ return true;
+ }
+
+ @Override
+ public ArgumentInfo rewrittenWithLens(
+ AppView<AppInfoWithLiveness> appView, GraphLens graphLens, GraphLens codeLens) {
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj == this;
+ }
+
+ @Override
+ public int hashCode() {
+ return System.identityHashCode(this);
+ }
+ };
+
+ public boolean isNone() {
+ return false;
+ }
+
+ public boolean isRemovedArgumentInfo() {
+ return false;
+ }
+
+ public RemovedArgumentInfo asRemovedArgumentInfo() {
+ return null;
+ }
+
+ public boolean isRewrittenTypeInfo() {
+ return false;
+ }
+
+ public RewrittenTypeInfo asRewrittenTypeInfo() {
+ return null;
+ }
+
+ // ArgumentInfo are combined with `this` first, and the `info` argument second.
+ public abstract ArgumentInfo combine(ArgumentInfo info);
+
+ public abstract ArgumentInfo rewrittenWithLens(
+ AppView<AppInfoWithLiveness> appView, GraphLens graphLens, GraphLens codeLens);
+
+ @Override
+ public abstract boolean equals(Object obj);
+
+ @Override
+ public abstract int hashCode();
+}
diff --git a/src/main/java/com/android/tools/r8/graph/proto/ArgumentInfoCollection.java b/src/main/java/com/android/tools/r8/graph/proto/ArgumentInfoCollection.java
new file mode 100644
index 0000000..0a9fcbf
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/proto/ArgumentInfoCollection.java
@@ -0,0 +1,356 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph.proto;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfoFixer;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.ConsumerUtils;
+import com.android.tools.r8.utils.IntObjConsumer;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry;
+import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectSortedMap;
+import it.unimi.dsi.fastutil.ints.IntArrayList;
+import it.unimi.dsi.fastutil.ints.IntCollection;
+import it.unimi.dsi.fastutil.ints.IntList;
+import it.unimi.dsi.fastutil.ints.IntLists;
+import it.unimi.dsi.fastutil.ints.IntSortedSet;
+import it.unimi.dsi.fastutil.objects.ObjectBidirectionalIterator;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.function.Consumer;
+
+public class ArgumentInfoCollection {
+
+ private static final Int2ObjectRBTreeMap<ArgumentInfo> EMPTY_MAP = new Int2ObjectRBTreeMap<>();
+ private static final ArgumentInfoCollection EMPTY = new ArgumentInfoCollection();
+
+ private final Int2ObjectSortedMap<ArgumentInfo> argumentInfos;
+ private final int argumentInfosSize;
+ private final ArgumentPermutation argumentPermutation;
+
+ // Specific constructor for empty.
+ private ArgumentInfoCollection() {
+ this.argumentInfos = EMPTY_MAP;
+ this.argumentInfosSize = -1;
+ this.argumentPermutation = ArgumentPermutation.getDefault();
+ }
+
+ private ArgumentInfoCollection(
+ Int2ObjectSortedMap<ArgumentInfo> argumentInfos,
+ int argumentInfosSize,
+ ArgumentPermutation argumentPermutation) {
+ assert argumentInfos != null;
+ assert argumentPermutation != null;
+ assert !argumentInfos.isEmpty() || argumentInfos == EMPTY_MAP;
+ assert !argumentInfos.isEmpty() || !argumentPermutation.isDefault() : "should use empty.";
+ assert argumentInfosSize >= 0;
+ this.argumentInfos = argumentInfos;
+ this.argumentInfosSize = argumentInfosSize;
+ this.argumentPermutation = argumentPermutation;
+ }
+
+ public static ArgumentInfoCollection empty() {
+ return EMPTY;
+ }
+
+ public void forEach(IntObjConsumer<ArgumentInfo> consumer) {
+ for (Entry<ArgumentInfo> entry : argumentInfos.int2ObjectEntrySet()) {
+ consumer.accept(entry.getIntKey(), entry.getValue());
+ }
+ }
+
+ public IntSortedSet getKeys() {
+ return argumentInfos.keySet();
+ }
+
+ public IntCollection getRemovedParameterIndices() {
+ int numberOfRemovedArguments = numberOfRemovedArguments();
+ if (numberOfRemovedArguments == 0) {
+ return IntLists.EMPTY_LIST;
+ }
+ if (numberOfRemovedArguments == argumentInfos.size()) {
+ return getKeys();
+ }
+ IntList removedParameterIndices = new IntArrayList(numberOfRemovedArguments);
+ Iterator<Entry<ArgumentInfo>> iterator = iterator();
+ while (iterator.hasNext()) {
+ Entry<ArgumentInfo> entry = iterator.next();
+ if (entry.getValue().isRemovedArgumentInfo()) {
+ removedParameterIndices.add(entry.getIntKey());
+ }
+ }
+ return removedParameterIndices;
+ }
+
+ public boolean isArgumentRemoved(int argumentIndex) {
+ return getArgumentInfo(argumentIndex).isRemovedArgumentInfo();
+ }
+
+ public boolean isEmpty() {
+ return this == EMPTY;
+ }
+
+ public Iterator<Entry<ArgumentInfo>> iterator() {
+ return argumentInfos.int2ObjectEntrySet().iterator();
+ }
+
+ public boolean hasRemovedArguments() {
+ for (ArgumentInfo value : argumentInfos.values()) {
+ if (value.isRemovedArgumentInfo()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public int numberOfRemovedArguments() {
+ return getNumberOfRemovedArgumentsBefore(Integer.MAX_VALUE, argumentInfos);
+ }
+
+ public int getNumberOfRemovedArgumentsBefore(int index) {
+ return getNumberOfRemovedArgumentsBefore(index, argumentInfos);
+ }
+
+ private static int getNumberOfRemovedArgumentsBefore(
+ int index, Int2ObjectSortedMap<ArgumentInfo> argumentInfos) {
+ int removed = 0;
+ for (Entry<ArgumentInfo> entry : argumentInfos.int2ObjectEntrySet()) {
+ int argumentIndex = entry.getIntKey();
+ ArgumentInfo argumentInfo = entry.getValue();
+ if (argumentIndex >= index) {
+ assert argumentIndex > index || !argumentInfo.isRemovedArgumentInfo();
+ break;
+ }
+ if (argumentInfo.isRemovedArgumentInfo()) {
+ removed++;
+ }
+ }
+ return removed;
+ }
+
+ public int numberOfRemovedNonReceiverArguments(ProgramMethod method) {
+ return numberOfRemovedArguments()
+ - BooleanUtils.intValue(method.getDefinition().isInstance() && isArgumentRemoved(0));
+ }
+
+ public boolean hasArgumentInfo(int argumentIndex) {
+ return argumentInfos.containsKey(argumentIndex);
+ }
+
+ public boolean hasArgumentPermutation() {
+ return !argumentPermutation.isDefault();
+ }
+
+ public ArgumentInfo getArgumentInfo(int argumentIndex) {
+ return argumentInfos.getOrDefault(argumentIndex, ArgumentInfo.NO_INFO);
+ }
+
+ public int getNewArgumentIndex(int argumentIndex) {
+ return getNewArgumentIndex(argumentIndex, getNumberOfRemovedArgumentsBefore(argumentIndex));
+ }
+
+ public int getNewArgumentIndex(int argumentIndex, int numberOfRemovedArgumentsBefore) {
+ int intermediateArgumentIndex = argumentIndex - numberOfRemovedArgumentsBefore;
+ return argumentPermutation.getNewArgumentIndex(intermediateArgumentIndex);
+ }
+
+ public int size() {
+ assert !isEmpty();
+ return argumentInfosSize;
+ }
+
+ public ArgumentInfoCollection rewrittenWithLens(
+ AppView<AppInfoWithLiveness> appView, GraphLens graphLens, GraphLens codeLens) {
+ if (isEmpty()) {
+ return this;
+ }
+ Builder builder = builder();
+ forEach(
+ (argumentIndex, argumentInfo) -> {
+ ArgumentInfo rewrittenArgumentInfo =
+ argumentInfo.rewrittenWithLens(appView, graphLens, codeLens);
+ if (rewrittenArgumentInfo != argumentInfo) {
+ builder.addArgumentInfo(argumentIndex, rewrittenArgumentInfo);
+ }
+ });
+ if (!builder.isEmpty()) {
+ forEach(
+ (argumentIndex, argumentInfo) -> {
+ if (!builder.hasArgumentInfo(argumentIndex)) {
+ builder.addArgumentInfo(argumentIndex, argumentInfo);
+ }
+ });
+ return builder.setArgumentInfosSize(argumentInfosSize).build();
+ }
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ ArgumentInfoCollection other = (ArgumentInfoCollection) obj;
+ return argumentInfos.equals(other.argumentInfos)
+ && argumentPermutation.equals(other.argumentPermutation)
+ && argumentInfosSize == other.argumentInfosSize;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(argumentInfos, argumentPermutation, argumentInfosSize);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+
+ private Int2ObjectSortedMap<ArgumentInfo> argumentInfos = new Int2ObjectRBTreeMap<>();
+ private int argumentInfosSize = -1;
+ private ArgumentPermutation argumentPermutation = ArgumentPermutation.getDefault();
+
+ public Builder addArgumentInfo(int argumentIndex, ArgumentInfo argInfo) {
+ argumentInfos.put(argumentIndex, argInfo);
+ return this;
+ }
+
+ public Builder addArgumentInfos(ArgumentInfoCollection argumentInfoCollection) {
+ argumentInfoCollection.forEach(this::addArgumentInfo);
+ return this;
+ }
+
+ public int getNumberOfRemovedArgumentsBefore(int index) {
+ return ArgumentInfoCollection.getNumberOfRemovedArgumentsBefore(index, argumentInfos);
+ }
+
+ public boolean hasArgumentInfo(int argumentIndex) {
+ return argumentInfos.containsKey(argumentIndex);
+ }
+
+ public boolean isEmpty() {
+ return argumentInfos.isEmpty() && argumentPermutation.isDefault();
+ }
+
+ public Builder setArgumentInfosSize(int argumentInfosSize) {
+ this.argumentInfosSize = argumentInfosSize;
+ return this;
+ }
+
+ public Builder setArgumentPermutation(ArgumentPermutation argumentPermutation) {
+ this.argumentPermutation = argumentPermutation;
+ return this;
+ }
+
+ public ArgumentInfoCollection build() {
+ if (isEmpty()) {
+ return empty();
+ }
+ Int2ObjectSortedMap<ArgumentInfo> argumentInfosOrEmpty =
+ argumentInfos.isEmpty() ? EMPTY_MAP : argumentInfos;
+ return new ArgumentInfoCollection(
+ argumentInfosOrEmpty, argumentInfosSize, argumentPermutation);
+ }
+ }
+
+ public ArgumentInfoCollection combine(ArgumentInfoCollection other) {
+ if (isEmpty()) {
+ return other;
+ }
+ if (other.isEmpty()) {
+ return this;
+ }
+ Builder builder = builder().addArgumentInfos(this);
+ ObjectBidirectionalIterator<Entry<ArgumentInfo>> iterator =
+ argumentInfos.int2ObjectEntrySet().iterator();
+ int offset = 0;
+ for (Entry<ArgumentInfo> entry : other.argumentInfos.int2ObjectEntrySet()) {
+ int pendingArgumentIndex = entry.getIntKey();
+ ArgumentInfo pendingArgumentInfo = entry.getValue();
+ Entry<ArgumentInfo> nextCommittedEntry = peekNext(iterator);
+ while (nextCommittedEntry != null
+ && nextCommittedEntry.getIntKey() <= pendingArgumentIndex + offset) {
+ Entry<ArgumentInfo> committedEntry = iterator.next();
+ ArgumentInfo committedArgumentInfo = committedEntry.getValue();
+ if (committedArgumentInfo.isRemovedArgumentInfo()) {
+ offset++;
+ }
+ nextCommittedEntry = peekNext(iterator);
+ }
+ if (nextCommittedEntry != null
+ && nextCommittedEntry.getIntKey() == pendingArgumentIndex + offset) {
+ ArgumentInfo committedArgumentInfo = nextCommittedEntry.getValue();
+ assert !committedArgumentInfo.isRemovedArgumentInfo();
+ pendingArgumentInfo = committedArgumentInfo.combine(pendingArgumentInfo);
+ }
+ builder.addArgumentInfo(pendingArgumentIndex + offset, pendingArgumentInfo);
+ }
+ // TODO(b/195112263): Double-check the size of the permutation in presence of extra and removed
+ // arguments.
+ ArgumentPermutation.Builder argumentPermutationBuilder =
+ ArgumentPermutation.builder(argumentInfosSize);
+ for (int argumentIndex = 0; argumentIndex < argumentInfosSize; argumentIndex++) {
+ if (isArgumentRemoved(argumentIndex)) {
+ continue;
+ }
+ int intermediateArgumentIndex = getNewArgumentIndex(argumentIndex);
+ if (other.isArgumentRemoved(intermediateArgumentIndex)) {
+ continue;
+ }
+ int newArgumentIndex = other.getNewArgumentIndex(intermediateArgumentIndex);
+ int defaultNewArgumentIndex =
+ argumentIndex - builder.getNumberOfRemovedArgumentsBefore(argumentIndex);
+ if (newArgumentIndex != defaultNewArgumentIndex) {
+ argumentPermutationBuilder.setNewArgumentIndex(argumentIndex, newArgumentIndex);
+ }
+ }
+ return builder
+ .setArgumentInfosSize(argumentInfosSize)
+ .setArgumentPermutation(argumentPermutationBuilder.build())
+ .build();
+ }
+
+ private static Entry<ArgumentInfo> peekNext(
+ ObjectBidirectionalIterator<Entry<ArgumentInfo>> iterator) {
+ if (iterator.hasNext()) {
+ Entry<ArgumentInfo> entry = iterator.next();
+ iterator.previous();
+ return entry;
+ }
+ return null;
+ }
+
+ public MethodOptimizationInfoFixer createMethodOptimizationInfoFixer() {
+ RewrittenPrototypeDescription prototypeChanges =
+ RewrittenPrototypeDescription.create(Collections.emptyList(), null, this);
+ return prototypeChanges.createMethodOptimizationInfoFixer();
+ }
+
+ /**
+ * Returns a function for rewriting the parameter annotations on a method info after prototype
+ * changes were made.
+ */
+ public Consumer<DexEncodedMethod.Builder> createParameterAnnotationsRemover(
+ DexEncodedMethod method) {
+ if (numberOfRemovedArguments() > 0 && !method.parameterAnnotationsList.isEmpty()) {
+ return builder -> {
+ int firstArgumentIndex = method.getFirstNonReceiverArgumentIndex();
+ builder.removeParameterAnnotations(
+ oldIndex -> getArgumentInfo(oldIndex + firstArgumentIndex).isRemovedArgumentInfo());
+ };
+ }
+ return ConsumerUtils.emptyConsumer();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/proto/ArgumentPermutation.java b/src/main/java/com/android/tools/r8/graph/proto/ArgumentPermutation.java
new file mode 100644
index 0000000..6dc9ddc
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/proto/ArgumentPermutation.java
@@ -0,0 +1,57 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph.proto;
+
+import it.unimi.dsi.fastutil.ints.Int2IntArrayMap;
+import it.unimi.dsi.fastutil.ints.Int2IntMap;
+import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
+
+public abstract class ArgumentPermutation {
+
+ public static Builder builder(int size) {
+ return new Builder(size);
+ }
+
+ public static DefaultArgumentPermutation getDefault() {
+ return DefaultArgumentPermutation.get();
+ }
+
+ public abstract int getNewArgumentIndex(int argumentIndex);
+
+ public boolean isDefault() {
+ return false;
+ }
+
+ public static class Builder {
+
+ private final Int2IntMap newArgumentIndices;
+
+ private Builder(int size) {
+ Int2IntMap newArgumentIndices = size <= 30 ? new Int2IntArrayMap() : new Int2IntOpenHashMap();
+ newArgumentIndices.defaultReturnValue(-1);
+ this.newArgumentIndices = newArgumentIndices;
+ }
+
+ public boolean isDefault() {
+ return newArgumentIndices.isEmpty();
+ }
+
+ public Builder setNewArgumentIndex(int argumentIndex, int newArgumentIndex) {
+ if (argumentIndex != newArgumentIndex) {
+ newArgumentIndices.put(argumentIndex, newArgumentIndex);
+ } else {
+ newArgumentIndices.remove(argumentIndex);
+ }
+ return this;
+ }
+
+ public ArgumentPermutation build() {
+ if (isDefault()) {
+ return getDefault();
+ }
+ return new ArgumentPermutationMap(newArgumentIndices);
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/proto/ArgumentPermutationMap.java b/src/main/java/com/android/tools/r8/graph/proto/ArgumentPermutationMap.java
new file mode 100644
index 0000000..15ddfd2
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/proto/ArgumentPermutationMap.java
@@ -0,0 +1,23 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph.proto;
+
+import it.unimi.dsi.fastutil.ints.Int2IntMap;
+
+public class ArgumentPermutationMap extends ArgumentPermutation {
+
+ private final Int2IntMap newArgumentIndices;
+
+ public ArgumentPermutationMap(Int2IntMap newArgumentIndices) {
+ assert newArgumentIndices.defaultReturnValue() == -1;
+ this.newArgumentIndices = newArgumentIndices;
+ }
+
+ @Override
+ public int getNewArgumentIndex(int argumentIndex) {
+ int newArgumentIndex = newArgumentIndices.get(argumentIndex);
+ return newArgumentIndex >= 0 ? newArgumentIndex : argumentIndex;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/proto/DefaultArgumentPermutation.java b/src/main/java/com/android/tools/r8/graph/proto/DefaultArgumentPermutation.java
new file mode 100644
index 0000000..29e3799
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/proto/DefaultArgumentPermutation.java
@@ -0,0 +1,26 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph.proto;
+
+public class DefaultArgumentPermutation extends ArgumentPermutation {
+
+ private static final DefaultArgumentPermutation INSTANCE = new DefaultArgumentPermutation();
+
+ private DefaultArgumentPermutation() {}
+
+ public static DefaultArgumentPermutation get() {
+ return INSTANCE;
+ }
+
+ @Override
+ public int getNewArgumentIndex(int argumentIndex) {
+ return argumentIndex;
+ }
+
+ @Override
+ public boolean isDefault() {
+ return true;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/proto/RemovedArgumentInfo.java b/src/main/java/com/android/tools/r8/graph/proto/RemovedArgumentInfo.java
new file mode 100644
index 0000000..953cedd
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/proto/RemovedArgumentInfo.java
@@ -0,0 +1,116 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph.proto;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.ir.analysis.value.SingleValue;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import java.util.Objects;
+
+public class RemovedArgumentInfo extends ArgumentInfo {
+
+ public static class Builder {
+
+ private boolean checkNullOrZero;
+ private SingleValue singleValue;
+ private DexType type;
+
+ public Builder setCheckNullOrZero(boolean checkNullOrZero) {
+ this.checkNullOrZero = checkNullOrZero;
+ return this;
+ }
+
+ public Builder setSingleValue(SingleValue singleValue) {
+ this.singleValue = singleValue;
+ return this;
+ }
+
+ public Builder setType(DexType type) {
+ this.type = type;
+ return this;
+ }
+
+ public RemovedArgumentInfo build() {
+ assert type != null;
+ return new RemovedArgumentInfo(checkNullOrZero, singleValue, type);
+ }
+ }
+
+ private final boolean checkNullOrZero;
+ private final SingleValue singleValue;
+ private final DexType type;
+
+ private RemovedArgumentInfo(boolean checkNullOrZero, SingleValue singleValue, DexType type) {
+ this.checkNullOrZero = checkNullOrZero;
+ this.singleValue = singleValue;
+ this.type = type;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public boolean hasSingleValue() {
+ return singleValue != null;
+ }
+
+ public SingleValue getSingleValue() {
+ return singleValue;
+ }
+
+ public DexType getType() {
+ return type;
+ }
+
+ public boolean isCheckNullOrZeroSet() {
+ return checkNullOrZero;
+ }
+
+ @Override
+ public boolean isRemovedArgumentInfo() {
+ return true;
+ }
+
+ @Override
+ public RemovedArgumentInfo asRemovedArgumentInfo() {
+ return this;
+ }
+
+ @Override
+ public ArgumentInfo combine(ArgumentInfo info) {
+ assert false : "Once the argument is removed one cannot modify it any further.";
+ return this;
+ }
+
+ @Override
+ public RemovedArgumentInfo rewrittenWithLens(
+ AppView<AppInfoWithLiveness> appView, GraphLens graphLens, GraphLens codeLens) {
+ SingleValue rewrittenSingleValue =
+ hasSingleValue() ? singleValue.rewrittenWithLens(appView, graphLens, codeLens) : null;
+ DexType rewrittenType = graphLens.lookupType(type, codeLens);
+ if (rewrittenSingleValue != singleValue || rewrittenType != type) {
+ return new RemovedArgumentInfo(checkNullOrZero, rewrittenSingleValue, rewrittenType);
+ }
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ RemovedArgumentInfo other = (RemovedArgumentInfo) obj;
+ return checkNullOrZero == other.checkNullOrZero
+ && type == other.type
+ && Objects.equals(singleValue, other.singleValue);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(checkNullOrZero, singleValue, type);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/proto/RewrittenPrototypeDescription.java b/src/main/java/com/android/tools/r8/graph/proto/RewrittenPrototypeDescription.java
new file mode 100644
index 0000000..8459d85
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/proto/RewrittenPrototypeDescription.java
@@ -0,0 +1,293 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph.proto;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.RewrittenPrototypeDescriptionMethodOptimizationInfoFixer;
+import com.android.tools.r8.ir.analysis.value.SingleValue;
+import com.android.tools.r8.ir.code.ConstInstruction;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.Position;
+import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
+import com.android.tools.r8.ir.conversion.ExtraParameter;
+import com.android.tools.r8.ir.conversion.ExtraUnusedNullParameter;
+import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfoFixer;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Consumer;
+
+public class RewrittenPrototypeDescription {
+
+ private static final RewrittenPrototypeDescription NONE = new RewrittenPrototypeDescription();
+
+ private final List<ExtraParameter> extraParameters;
+ private final ArgumentInfoCollection argumentInfoCollection;
+ private final RewrittenTypeInfo rewrittenReturnInfo;
+
+ private RewrittenPrototypeDescription() {
+ this.extraParameters = Collections.emptyList();
+ this.rewrittenReturnInfo = null;
+ this.argumentInfoCollection = ArgumentInfoCollection.empty();
+ }
+
+ private RewrittenPrototypeDescription(
+ List<ExtraParameter> extraParameters,
+ RewrittenTypeInfo rewrittenReturnInfo,
+ ArgumentInfoCollection argumentsInfo) {
+ assert argumentsInfo != null;
+ this.extraParameters = extraParameters;
+ this.rewrittenReturnInfo = rewrittenReturnInfo;
+ this.argumentInfoCollection = argumentsInfo;
+ assert !isEmpty();
+ }
+
+ public static RewrittenPrototypeDescription create(
+ List<ExtraParameter> extraParameters,
+ RewrittenTypeInfo rewrittenReturnInfo,
+ ArgumentInfoCollection argumentsInfo) {
+ return extraParameters.isEmpty() && rewrittenReturnInfo == null && argumentsInfo.isEmpty()
+ ? none()
+ : new RewrittenPrototypeDescription(extraParameters, rewrittenReturnInfo, argumentsInfo);
+ }
+
+ public static RewrittenPrototypeDescription createForRewrittenTypes(
+ RewrittenTypeInfo returnInfo, ArgumentInfoCollection rewrittenArgumentsInfo) {
+ return create(Collections.emptyList(), returnInfo, rewrittenArgumentsInfo);
+ }
+
+ public static RewrittenPrototypeDescription none() {
+ return NONE;
+ }
+
+ public Consumer<DexEncodedMethod.Builder> createParameterAnnotationsRemover(
+ DexEncodedMethod method) {
+ return getArgumentInfoCollection().createParameterAnnotationsRemover(method);
+ }
+
+ public MethodOptimizationInfoFixer createMethodOptimizationInfoFixer() {
+ return new RewrittenPrototypeDescriptionMethodOptimizationInfoFixer(this);
+ }
+
+ public RewrittenPrototypeDescription combine(RewrittenPrototypeDescription other) {
+ if (isEmpty()) {
+ return other;
+ }
+ if (other.isEmpty()) {
+ return this;
+ }
+ // We currently don't have any passes that remove extra parameters inserted by previous passes.
+ // If the input prototype changes have removed some of the extra parameters, we would need to
+ // adapt the merging of prototype changes below.
+ List<ExtraParameter> newExtraParameters =
+ ImmutableList.<ExtraParameter>builder()
+ .addAll(getExtraParameters())
+ .addAll(other.getExtraParameters())
+ .build();
+ RewrittenTypeInfo newRewrittenTypeInfo =
+ hasRewrittenReturnInfo()
+ ? getRewrittenReturnInfo().combine(other)
+ : other.getRewrittenReturnInfo();
+ ArgumentInfoCollection newArgumentInfoCollection =
+ getArgumentInfoCollection().combine(other.getArgumentInfoCollection());
+ return new RewrittenPrototypeDescription(
+ newExtraParameters, newRewrittenTypeInfo, newArgumentInfoCollection);
+ }
+
+ public boolean isEmpty() {
+ return extraParameters.isEmpty()
+ && rewrittenReturnInfo == null
+ && argumentInfoCollection.isEmpty();
+ }
+
+ public boolean hasExtraParameters() {
+ return !extraParameters.isEmpty();
+ }
+
+ public List<ExtraParameter> getExtraParameters() {
+ return extraParameters;
+ }
+
+ public int numberOfExtraParameters() {
+ return extraParameters.size();
+ }
+
+ public boolean hasBeenChangedToReturnVoid() {
+ return rewrittenReturnInfo != null && rewrittenReturnInfo.hasBeenChangedToReturnVoid();
+ }
+
+ public ArgumentInfoCollection getArgumentInfoCollection() {
+ return argumentInfoCollection;
+ }
+
+ public boolean hasRewrittenReturnInfo() {
+ return rewrittenReturnInfo != null;
+ }
+
+ public boolean requiresRewritingAtCallSite() {
+ return hasRewrittenReturnInfo()
+ || numberOfExtraParameters() > 0
+ || argumentInfoCollection.hasArgumentPermutation()
+ || argumentInfoCollection.numberOfRemovedArguments() > 0;
+ }
+
+ public RewrittenTypeInfo getRewrittenReturnInfo() {
+ return rewrittenReturnInfo;
+ }
+
+ /**
+ * Returns the {@link ConstInstruction} that should be used to materialize the result of
+ * invocations to the method represented by this {@link RewrittenPrototypeDescription}.
+ *
+ * <p>This method should only be used for methods that return a constant value and whose return
+ * type has been changed to void.
+ *
+ * <p>Note that the current implementation always returns null at this point.
+ */
+ public Instruction getConstantReturn(
+ AppView<AppInfoWithLiveness> appView,
+ IRCode code,
+ Position position,
+ TypeAndLocalInfoSupplier info) {
+ assert rewrittenReturnInfo != null;
+ assert rewrittenReturnInfo.hasSingleValue();
+ Instruction instruction =
+ rewrittenReturnInfo.getSingleValue().createMaterializingInstruction(appView, code, info);
+ instruction.setPosition(position);
+ return instruction;
+ }
+
+ public boolean verifyConstantReturnAccessibleInContext(
+ AppView<AppInfoWithLiveness> appView, ProgramMethod method, GraphLens codeLens) {
+ SingleValue rewrittenSingleValue =
+ rewrittenReturnInfo
+ .getSingleValue()
+ .rewrittenWithLens(appView, appView.graphLens(), codeLens);
+ assert rewrittenSingleValue.isMaterializableInContext(appView, method);
+ return true;
+ }
+
+ public DexMethod rewriteMethod(ProgramMethod method, DexItemFactory dexItemFactory) {
+ if (isEmpty()) {
+ return method.getReference();
+ }
+ DexProto rewrittenProto = rewriteProto(method, dexItemFactory);
+ return method.getReference().withProto(rewrittenProto, dexItemFactory);
+ }
+
+ public DexProto rewriteProto(ProgramMethod method, DexItemFactory dexItemFactory) {
+ if (isEmpty()) {
+ return method.getProto();
+ }
+ DexType newReturnType =
+ rewrittenReturnInfo != null ? rewrittenReturnInfo.getNewType() : method.getReturnType();
+ DexType[] newParameters = rewriteParameters(method, dexItemFactory);
+ return dexItemFactory.createProto(newReturnType, newParameters);
+ }
+
+ public DexType[] rewriteParameters(ProgramMethod method, DexItemFactory dexItemFactory) {
+ DexType[] params = method.getParameters().values;
+ if (isEmpty()) {
+ return params;
+ }
+ DexType[] newParams =
+ new DexType
+ [params.length
+ - argumentInfoCollection.numberOfRemovedNonReceiverArguments(method)
+ + extraParameters.size()];
+ int offset = method.getDefinition().getFirstNonReceiverArgumentIndex();
+ int newParamIndex = 0;
+ for (int oldParamIndex = 0; oldParamIndex < params.length; oldParamIndex++) {
+ ArgumentInfo argInfo = argumentInfoCollection.getArgumentInfo(oldParamIndex + offset);
+ if (argInfo.isNone()) {
+ newParams[newParamIndex++] = params[oldParamIndex];
+ } else if (argInfo.isRewrittenTypeInfo()) {
+ RewrittenTypeInfo rewrittenTypeInfo = argInfo.asRewrittenTypeInfo();
+ assert params[oldParamIndex] == rewrittenTypeInfo.getOldType();
+ newParams[newParamIndex++] = rewrittenTypeInfo.getNewType();
+ }
+ }
+ for (ExtraParameter extraParameter : extraParameters) {
+ newParams[newParamIndex++] = extraParameter.getType(dexItemFactory);
+ }
+ return newParams;
+ }
+
+ public RewrittenPrototypeDescription rewrittenWithLens(
+ AppView<AppInfoWithLiveness> appView, GraphLens graphLens, GraphLens codeLens) {
+ ArgumentInfoCollection newArgumentInfoCollection =
+ argumentInfoCollection.rewrittenWithLens(appView, graphLens, codeLens);
+ RewrittenTypeInfo newRewrittenReturnInfo =
+ hasRewrittenReturnInfo()
+ ? rewrittenReturnInfo.rewrittenWithLens(appView, graphLens, codeLens)
+ : null;
+ if (newArgumentInfoCollection != argumentInfoCollection
+ || newRewrittenReturnInfo != rewrittenReturnInfo) {
+ return new RewrittenPrototypeDescription(
+ extraParameters, newRewrittenReturnInfo, newArgumentInfoCollection);
+ }
+ return this;
+ }
+
+ public RewrittenPrototypeDescription withRewrittenReturnInfo(
+ RewrittenTypeInfo newRewrittenReturnInfo) {
+ if (Objects.equals(rewrittenReturnInfo, newRewrittenReturnInfo)) {
+ return this;
+ }
+ return new RewrittenPrototypeDescription(
+ extraParameters, newRewrittenReturnInfo, argumentInfoCollection);
+ }
+
+ public RewrittenPrototypeDescription withExtraUnusedNullParameters(
+ int numberOfExtraUnusedNullParameters) {
+ List<ExtraParameter> parameters =
+ Collections.nCopies(numberOfExtraUnusedNullParameters, new ExtraUnusedNullParameter());
+ return withExtraParameters(parameters);
+ }
+
+ public RewrittenPrototypeDescription withExtraParameters(ExtraParameter... parameters) {
+ return withExtraParameters(Arrays.asList(parameters));
+ }
+
+ public RewrittenPrototypeDescription withExtraParameters(List<ExtraParameter> parameters) {
+ if (parameters.isEmpty()) {
+ return this;
+ }
+ List<ExtraParameter> newExtraParameters =
+ new ArrayList<>(extraParameters.size() + parameters.size());
+ newExtraParameters.addAll(extraParameters);
+ newExtraParameters.addAll(parameters);
+ return new RewrittenPrototypeDescription(
+ newExtraParameters, rewrittenReturnInfo, argumentInfoCollection);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ RewrittenPrototypeDescription other = (RewrittenPrototypeDescription) obj;
+ return extraParameters.equals(other.extraParameters)
+ && Objects.equals(rewrittenReturnInfo, other.rewrittenReturnInfo)
+ && argumentInfoCollection.equals(other.argumentInfoCollection);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(extraParameters, rewrittenReturnInfo, argumentInfoCollection);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/proto/RewrittenTypeInfo.java b/src/main/java/com/android/tools/r8/graph/proto/RewrittenTypeInfo.java
new file mode 100644
index 0000000..0f0c49f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/proto/RewrittenTypeInfo.java
@@ -0,0 +1,163 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph.proto;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.ir.analysis.value.SingleValue;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import java.util.Objects;
+import java.util.function.Consumer;
+
+public class RewrittenTypeInfo extends ArgumentInfo {
+
+ private final DexType castType;
+ private final DexType oldType;
+ private final DexType newType;
+ private final SingleValue singleValue;
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ private RewrittenTypeInfo(
+ DexType oldType, DexType newType, DexType castType, SingleValue singleValue) {
+ this.castType = castType;
+ this.oldType = oldType;
+ this.newType = newType;
+ this.singleValue = singleValue;
+ }
+
+ public RewrittenTypeInfo combine(RewrittenPrototypeDescription other) {
+ return other.hasRewrittenReturnInfo() ? combine(other.getRewrittenReturnInfo()) : this;
+ }
+
+ public DexType getCastType() {
+ return castType;
+ }
+
+ public DexType getNewType() {
+ return newType;
+ }
+
+ public DexType getOldType() {
+ return oldType;
+ }
+
+ public SingleValue getSingleValue() {
+ return singleValue;
+ }
+
+ boolean hasBeenChangedToReturnVoid() {
+ return newType.isVoidType();
+ }
+
+ public boolean hasCastType() {
+ return castType != null;
+ }
+
+ public boolean hasSingleValue() {
+ return singleValue != null;
+ }
+
+ @Override
+ public boolean isRewrittenTypeInfo() {
+ return true;
+ }
+
+ @Override
+ public RewrittenTypeInfo asRewrittenTypeInfo() {
+ return this;
+ }
+
+ @Override
+ public ArgumentInfo combine(ArgumentInfo info) {
+ if (info.isRemovedArgumentInfo()) {
+ return info;
+ }
+ assert info.isRewrittenTypeInfo();
+ return combine(info.asRewrittenTypeInfo());
+ }
+
+ public RewrittenTypeInfo combine(RewrittenTypeInfo other) {
+ assert !getNewType().isVoidType();
+ assert getNewType() == other.getOldType();
+ return new RewrittenTypeInfo(
+ getOldType(), other.getNewType(), getCastType(), other.getSingleValue());
+ }
+
+ @Override
+ public RewrittenTypeInfo rewrittenWithLens(
+ AppView<AppInfoWithLiveness> appView, GraphLens graphLens, GraphLens codeLens) {
+ DexType rewrittenCastType = castType != null ? graphLens.lookupType(castType, codeLens) : null;
+ DexType rewrittenNewType = graphLens.lookupType(newType, codeLens);
+ SingleValue rewrittenSingleValue =
+ hasSingleValue() ? getSingleValue().rewrittenWithLens(appView, graphLens, codeLens) : null;
+ if (rewrittenCastType != castType
+ || rewrittenNewType != newType
+ || rewrittenSingleValue != singleValue) {
+ // The old type is intentionally not rewritten.
+ return new RewrittenTypeInfo(
+ oldType, rewrittenNewType, rewrittenCastType, rewrittenSingleValue);
+ }
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ RewrittenTypeInfo other = (RewrittenTypeInfo) obj;
+ return oldType == other.oldType
+ && newType == other.newType
+ && Objects.equals(singleValue, other.singleValue);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(oldType, newType, singleValue);
+ }
+
+ public static class Builder {
+
+ private DexType castType;
+ private DexType oldType;
+ private DexType newType;
+ private SingleValue singleValue;
+
+ public Builder applyIf(boolean condition, Consumer<Builder> consumer) {
+ if (condition) {
+ consumer.accept(this);
+ }
+ return this;
+ }
+
+ public Builder setCastType(DexType castType) {
+ this.castType = castType;
+ return this;
+ }
+
+ public Builder setOldType(DexType oldType) {
+ this.oldType = oldType;
+ return this;
+ }
+
+ public Builder setNewType(DexType newType) {
+ this.newType = newType;
+ return this;
+ }
+
+ public Builder setSingleValue(SingleValue singleValue) {
+ this.singleValue = singleValue;
+ return this;
+ }
+
+ public RewrittenTypeInfo build() {
+ return new RewrittenTypeInfo(oldType, newType, castType, singleValue);
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
index bb8f046..fcae6d5 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
@@ -22,8 +22,8 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.horizontalclassmerging.MergeGroup;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
index f13bd76..ef8d041 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
@@ -178,7 +178,7 @@
executorService);
processFieldsNeverRead(appInfo);
processFieldsNeverWritten(appInfo);
- postMethodProcessorBuilder.put(methodsToReprocess);
+ postMethodProcessorBuilder.rewrittenWithLens(appView.graphLens()).put(methodsToReprocess);
}
private void processClass(DexProgramClass clazz) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/AbstractFieldSet.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/AbstractFieldSet.java
index 58033b1..ab29351 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/AbstractFieldSet.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/AbstractFieldSet.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.PrunedItems;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
/**
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/ConcreteMutableFieldSet.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/ConcreteMutableFieldSet.java
index 84208bb..d62a1d6 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/ConcreteMutableFieldSet.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/ConcreteMutableFieldSet.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.PrunedItems;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.SetUtils;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/EmptyFieldSet.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/EmptyFieldSet.java
index 65e424f..9d2e36a 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/EmptyFieldSet.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/EmptyFieldSet.java
@@ -8,8 +8,8 @@
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.PrunedItems;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.RemovedArgumentInfo;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
public class EmptyFieldSet extends AbstractFieldSet implements KnownFieldSet {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/UnknownFieldSet.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/UnknownFieldSet.java
index c9dcd7a..43823c3 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/UnknownFieldSet.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/UnknownFieldSet.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.PrunedItems;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
public class UnknownFieldSet extends AbstractFieldSet {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/AlwaysSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/AlwaysSimpleInliningConstraint.java
index 9180568..730d980 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/AlwaysSimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/AlwaysSimpleInliningConstraint.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.ir.analysis.inlining;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/EqualToBooleanSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/EqualToBooleanSimpleInliningConstraint.java
index 9a400ae..c83e52e 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/EqualToBooleanSimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/EqualToBooleanSimpleInliningConstraint.java
@@ -5,8 +5,8 @@
package com.android.tools.r8.ir.analysis.inlining;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.RemovedArgumentInfo;
import com.android.tools.r8.ir.analysis.value.SingleValue;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InvokeMethod;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NeverSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NeverSimpleInliningConstraint.java
index d786e67..15f3051 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NeverSimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NeverSimpleInliningConstraint.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.ir.analysis.inlining;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NullSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NullSimpleInliningConstraint.java
index 10af841..2c0448a 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NullSimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NullSimpleInliningConstraint.java
@@ -5,10 +5,10 @@
package com.android.tools.r8.ir.analysis.inlining;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfo;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RewrittenTypeInfo;
+import com.android.tools.r8.graph.proto.ArgumentInfo;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.RemovedArgumentInfo;
+import com.android.tools.r8.graph.proto.RewrittenTypeInfo;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.Instruction;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NumberSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NumberSimpleInliningConstraint.java
index 23b6233..629ed68 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NumberSimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NumberSimpleInliningConstraint.java
@@ -5,8 +5,8 @@
package com.android.tools.r8.ir.analysis.inlining;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.RemovedArgumentInfo;
import com.android.tools.r8.ir.analysis.value.SingleValue;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InvokeMethod;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraint.java
index 64e6f44..a207c8d 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraint.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.ir.analysis.inlining;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.google.common.collect.ImmutableList;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintConjunction.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintConjunction.java
index 55da1c0..6147cd8 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintConjunction.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintConjunction.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.ir.analysis.inlining;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.ListUtils;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintDisjunction.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintDisjunction.java
index 0ac0ced..02c0b01 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintDisjunction.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintDisjunction.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.ir.analysis.inlining;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.ListUtils;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java
index ad8b4d5..d090011 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java
@@ -16,7 +16,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.ConstClass;
import com.android.tools.r8.ir.code.Instruction;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleDexItemBasedStringValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleDexItemBasedStringValue.java
index 4f4f7cd..8a69170 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleDexItemBasedStringValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleDexItemBasedStringValue.java
@@ -13,7 +13,7 @@
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.DexItemBasedConstString;
import com.android.tools.r8.ir.code.Instruction;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
index cbc7e66..ebbfffe 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
@@ -17,7 +17,7 @@
import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
index b3259b0..c9b7f62 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.ConstNumber;
import com.android.tools.r8.ir.code.Instruction;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java
index 57cd2e1..6e69356 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java
@@ -13,7 +13,7 @@
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.ConstString;
import com.android.tools.r8.ir.code.Instruction;
diff --git a/src/main/java/com/android/tools/r8/ir/code/If.java b/src/main/java/com/android/tools/r8/ir/code/If.java
index ce75f73..9269104 100644
--- a/src/main/java/com/android/tools/r8/ir/code/If.java
+++ b/src/main/java/com/android/tools/r8/ir/code/If.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
+import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.CfgPrinter;
import com.android.tools.r8.utils.InternalOutputMode;
import java.util.List;
@@ -205,6 +206,19 @@
&& o.type == type;
}
+ public BasicBlock targetFromTrue() {
+ return targetFromBoolean(true);
+ }
+
+ public BasicBlock targetFromFalse() {
+ return targetFromBoolean(false);
+ }
+
+ public BasicBlock targetFromBoolean(boolean cond) {
+ assert isZeroTest();
+ return targetFromCondition(BooleanUtils.intValue(cond));
+ }
+
public BasicBlock targetFromCondition(ConstNumber value) {
assert isZeroTest();
assert verifyTypeCompatible(value.getOutType(), type);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index 133023f..29bee42 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -36,11 +36,11 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfo;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RewrittenTypeInfo;
+import com.android.tools.r8.graph.proto.ArgumentInfo;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.RemovedArgumentInfo;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
+import com.android.tools.r8.graph.proto.RewrittenTypeInfo;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.PrimitiveTypeElement;
import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
@@ -543,6 +543,7 @@
int argumentIndex = 0;
if (!method.isStatic()) {
+ assert argumentsInfo.getNewArgumentIndex(0) == 0;
writeCallback.accept(register, method.getHolderType());
addThisArgument(register);
argumentIndex++;
@@ -550,12 +551,12 @@
}
int originalNumberOfArguments =
- method.getReference().proto.parameters.values.length
+ method.getParameters().size()
+ argumentsInfo.numberOfRemovedArguments()
+ method.getFirstNonReceiverArgumentIndex()
- prototypeChanges.numberOfExtraParameters();
- int usedArgumentIndex = 0;
+ int numberOfRemovedArguments = 0;
while (argumentIndex < originalNumberOfArguments) {
TypeElement type;
ArgumentInfo argumentInfo = argumentsInfo.getArgumentInfo(argumentIndex);
@@ -566,20 +567,21 @@
TypeElement.fromDexType(
removedArgumentInfo.getType(), Nullability.maybeNull(), appView);
addNonThisArgument(register, type);
+ numberOfRemovedArguments++;
} else {
DexType argType;
+ int newArgumentIndex =
+ argumentsInfo.getNewArgumentIndex(argumentIndex, numberOfRemovedArguments);
if (argumentInfo.isRewrittenTypeInfo()) {
RewrittenTypeInfo argumentRewrittenTypeInfo = argumentInfo.asRewrittenTypeInfo();
- assert method.getReference().proto.getParameter(usedArgumentIndex)
- == argumentRewrittenTypeInfo.getNewType();
+ assert method.getArgumentType(newArgumentIndex) == argumentRewrittenTypeInfo.getNewType();
// The old type is used to prevent that a changed value from reference to primitive
// type breaks IR building. Rewriting from the old to the new type will be done in the
// IRConverter (typically through the lensCodeRewriter).
argType = argumentRewrittenTypeInfo.getOldType();
} else {
- argType = method.getReference().proto.getParameter(usedArgumentIndex);
+ argType = method.getArgumentType(newArgumentIndex);
}
- usedArgumentIndex++;
writeCallback.accept(register, argType);
type = TypeElement.fromDexType(argType, Nullability.maybeNull(), appView);
if (argType.isBooleanType()) {
@@ -588,20 +590,21 @@
addNonThisArgument(register, type);
}
}
- register += type.requiredRegisters();
argumentIndex++;
+ register += type.requiredRegisters();
}
for (ExtraParameter extraParameter : prototypeChanges.getExtraParameters()) {
- DexType argType = method.getReference().proto.getParameter(usedArgumentIndex);
- TypeElement type = extraParameter.getTypeElement(appView, argType);
- register += type.requiredRegisters();
- usedArgumentIndex++;
+ int newArgumentIndex =
+ argumentsInfo.getNewArgumentIndex(argumentIndex, numberOfRemovedArguments);
+ DexType extraArgumentType = method.getArgumentType(newArgumentIndex);
if (extraParameter instanceof ExtraUnusedNullParameter) {
- addExtraUnusedArgument(register, argType);
+ addExtraUnusedArgument(extraArgumentType);
} else {
- addNonThisArgument(register, type);
+ addNonThisArgument(register, extraParameter.getTypeElement(appView, extraArgumentType));
}
+ argumentIndex++;
+ register += extraArgumentType.getRequiredRegisters();
}
}
@@ -988,7 +991,7 @@
value.markAsThis();
}
- private void addExtraUnusedArgument(int register, DexType type) {
+ private void addExtraUnusedArgument(DexType type) {
// Extra unused null arguments should bypass the register check, they may use registers
// beyond the limit of what the method can use. They don't have debug information and are
// always null.
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index efd8593..145ffec 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -690,6 +690,9 @@
// Analyze the data collected by the argument propagator, use the analysis result to update
// the parameter optimization infos, and rewrite the application.
+ // TODO(b/199237357): Automatically rewrite state when lens changes.
+ enumUnboxer.rewriteWithLens();
+ outliner.rewriteWithLens();
appView.withArgumentPropagator(
argumentPropagator ->
argumentPropagator.tearDownCodeScanner(
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
index 8bcdea8..ba22a02 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.ir.conversion;
import static com.android.tools.r8.graph.UseRegistry.MethodHandleUse.NOT_ARGUMENT_TO_LAMBDA_METAFACTORY;
-import static com.android.tools.r8.ir.code.Invoke.Type.STATIC;
import static com.android.tools.r8.ir.code.Invoke.Type.VIRTUAL;
import static com.android.tools.r8.ir.code.Opcodes.ARGUMENT;
import static com.android.tools.r8.ir.code.Opcodes.ASSUME;
@@ -53,12 +52,12 @@
import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfo;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RewrittenTypeInfo;
import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
+import com.android.tools.r8.graph.proto.ArgumentInfo;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.RemovedArgumentInfo;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
+import com.android.tools.r8.graph.proto.RewrittenTypeInfo;
import com.android.tools.r8.ir.analysis.type.DestructivePhiTypeUpdater;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.TypeElement;
@@ -101,7 +100,6 @@
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.optimize.enums.EnumUnboxer;
-import com.android.tools.r8.logging.Log;
import com.android.tools.r8.optimize.MemberRebindingAnalysis;
import com.android.tools.r8.optimize.argumentpropagation.lenscoderewriter.NullCheckInserter;
import com.android.tools.r8.utils.InternalOptions;
@@ -110,10 +108,13 @@
import com.google.common.collect.Sets;
import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Deque;
import java.util.HashSet;
import java.util.IdentityHashMap;
+import java.util.LinkedList;
import java.util.List;
+import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.function.BiFunction;
@@ -337,6 +338,8 @@
invokedMethod, method.getReference(), invoke.getType(), codeLens);
DexMethod actualTarget = lensLookup.getReference();
Invoke.Type actualInvokeType = lensLookup.getType();
+ int numberOfArguments =
+ actualTarget.getNumberOfArguments(actualInvokeType.isStatic());
iterator =
insertCastsForInvokeArgumentsIfNeeded(code, blocks, iterator, invoke, lensLookup);
@@ -350,74 +353,81 @@
prototypeChanges.getArgumentInfoCollection();
if (argumentInfoCollection.isEmpty()) {
if (prototypeChanges.hasExtraParameters()) {
- newInValues = new ArrayList<>(invoke.inValues());
+ newInValues = new ArrayList<>(numberOfArguments);
+ newInValues.addAll(invoke.arguments());
+ prototypeChanges.getExtraParameters().forEach(ignore -> newInValues.add(null));
} else {
- newInValues = invoke.inValues();
+ newInValues = invoke.arguments();
}
} else {
- if (argumentInfoCollection.hasRemovedArguments()) {
- if (Log.ENABLED) {
- Log.info(
- getClass(),
- "Invoked method "
- + invokedMethod.toSourceString()
- + " with "
- + argumentInfoCollection.numberOfRemovedArguments()
- + " arguments removed");
+ newInValues = Arrays.asList(new Value[numberOfArguments]);
+ int numberOfRemovedArguments = 0;
+ for (int argumentIndex = 0;
+ argumentIndex < invoke.arguments().size();
+ argumentIndex++) {
+ ArgumentInfo argumentInfo =
+ argumentInfoCollection.getArgumentInfo(argumentIndex);
+ if (argumentInfo.isRemovedArgumentInfo()) {
+ numberOfRemovedArguments++;
+ continue;
}
- }
- newInValues = new ArrayList<>(actualTarget.proto.parameters.size());
- for (int i = 0; i < invoke.inValues().size(); i++) {
- ArgumentInfo argumentInfo = argumentInfoCollection.getArgumentInfo(i);
+ int newArgumentIndex =
+ argumentInfoCollection.getNewArgumentIndex(
+ argumentIndex, numberOfRemovedArguments);
+ Value newArgument;
if (argumentInfo.isRewrittenTypeInfo()) {
RewrittenTypeInfo argInfo = argumentInfo.asRewrittenTypeInfo();
- Value rewrittenValue =
+ newArgument =
rewriteValueIfDefault(
code,
iterator,
argInfo.getOldType(),
argInfo.getNewType(),
- invoke.inValues().get(i));
- newInValues.add(rewrittenValue);
- } else if (!argumentInfo.isRemovedArgumentInfo()) {
- newInValues.add(invoke.inValues().get(i));
+ invoke.getArgument(argumentIndex));
+ } else {
+ newArgument = invoke.getArgument(argumentIndex);
}
+ newInValues.set(newArgumentIndex, newArgument);
}
}
Instruction constantReturnMaterializingInstruction = null;
- if (prototypeChanges.hasBeenChangedToReturnVoid() && invoke.hasOutValue()) {
- TypeAndLocalInfoSupplier typeAndLocalInfo =
- new TypeAndLocalInfoSupplier() {
- @Override
- public DebugLocalInfo getLocalInfo() {
- return invoke.getLocalInfo();
- }
+ if (invoke.hasOutValue()) {
+ if (invoke.hasUnusedOutValue()) {
+ invoke.clearOutValue();
+ } else if (prototypeChanges.hasBeenChangedToReturnVoid()) {
+ TypeAndLocalInfoSupplier typeAndLocalInfo =
+ new TypeAndLocalInfoSupplier() {
+ @Override
+ public DebugLocalInfo getLocalInfo() {
+ return invoke.getLocalInfo();
+ }
- @Override
- public TypeElement getOutType() {
- return graphLens
- .lookupType(invokedMethod.getReturnType(), codeLens)
- .toTypeElement(appView);
- }
- };
- prototypeChanges.verifyConstantReturnAccessibleInContext(
- appView.withLiveness(), method, graphLens);
- constantReturnMaterializingInstruction =
- prototypeChanges.getConstantReturn(
- appView.withLiveness(),
- code,
- invoke.getPosition(),
- typeAndLocalInfo);
- if (invoke.outValue().hasLocalInfo()) {
- constantReturnMaterializingInstruction
+ @Override
+ public TypeElement getOutType() {
+ return graphLens
+ .lookupType(invokedMethod.getReturnType(), codeLens)
+ .toTypeElement(appView);
+ }
+ };
+ assert prototypeChanges.verifyConstantReturnAccessibleInContext(
+ appView.withLiveness(), method, graphLens);
+ constantReturnMaterializingInstruction =
+ prototypeChanges.getConstantReturn(
+ appView.withLiveness(), code, invoke.getPosition(), typeAndLocalInfo);
+ if (invoke.outValue().hasLocalInfo()) {
+ constantReturnMaterializingInstruction
+ .outValue()
+ .setLocalInfo(invoke.outValue().getLocalInfo());
+ }
+ invoke
.outValue()
- .setLocalInfo(invoke.outValue().getLocalInfo());
- }
- invoke.outValue().replaceUsers(constantReturnMaterializingInstruction.outValue());
- if (invoke.getOutType() != constantReturnMaterializingInstruction.getOutType()) {
- affectedPhis.addAll(
- constantReturnMaterializingInstruction.outValue().uniquePhiUsers());
+ .replaceUsers(constantReturnMaterializingInstruction.outValue());
+ if (invoke.getOutType()
+ != constantReturnMaterializingInstruction.getOutType()) {
+ affectedPhis.addAll(
+ constantReturnMaterializingInstruction.outValue().uniquePhiUsers());
+ }
}
}
@@ -440,9 +450,14 @@
Map<SingleNumberValue, Map<DexType, Value>> parameterMap = new IdentityHashMap<>();
- int parameterIndex = newInValues.size() - (actualInvokeType == STATIC ? 0 : 1);
+ int extraArgumentIndex =
+ numberOfArguments - prototypeChanges.getExtraParameters().size();
for (ExtraParameter parameter : prototypeChanges.getExtraParameters()) {
- DexType type = actualTarget.proto.getParameter(parameterIndex++);
+ int newExtraArgumentIndex =
+ argumentInfoCollection.getNewArgumentIndex(extraArgumentIndex, 0);
+ DexType extraArgumentType =
+ actualTarget.getArgumentType(
+ newExtraArgumentIndex, actualInvokeType.isStatic());
SingleNumberValue numberValue = parameter.getValue(appView);
@@ -452,7 +467,7 @@
parameterMap
.computeIfAbsent(numberValue, ignore -> new IdentityHashMap<>())
.computeIfAbsent(
- type,
+ extraArgumentType,
ignore -> {
finalIterator.previous();
Instruction instruction =
@@ -460,7 +475,8 @@
appView,
code,
TypeAndLocalInfoSupplier.create(
- parameter.getTypeElement(appView, type), null));
+ parameter.getTypeElement(appView, extraArgumentType),
+ null));
assert !instruction.instructionTypeCanThrow();
instruction.setPosition(
options.debug ? invoke.getPosition() : Position.none());
@@ -468,8 +484,7 @@
finalIterator.next();
return instruction.outValue();
});
-
- newInValues.add(value);
+ newInValues.set(newExtraArgumentIndex, value);
// TODO(b/164901008): Fix when the number of arguments overflows.
if (newInValues.size() > 255) {
@@ -478,10 +493,9 @@
+ " the number of arguments of the method "
+ actualTarget);
}
- }
- assert newInValues.size()
- == actualTarget.proto.parameters.size() + (actualInvokeType == STATIC ? 0 : 1);
+ extraArgumentIndex++;
+ }
// TODO(b/157111832): This bit should be part of the graph lens lookup result.
boolean isInterface =
@@ -809,9 +823,11 @@
RewrittenPrototypeDescription prototypeChanges,
Set<Phi> affectedPhis,
Set<UnusedArgument> unusedArguments) {
- List<Instruction> argumentPostlude = new ArrayList<>();
+ ArgumentInfoCollection argumentInfoCollection = prototypeChanges.getArgumentInfoCollection();
+ List<Instruction> argumentPostlude = new LinkedList<>();
int oldArgumentIndex = 0;
- int newArgumentIndex = 0;
+ int nextArgumentIndex = 0;
+ int numberOfRemovedArguments = 0;
InstructionListIterator instructionIterator = code.entryBlock().listIterator(code);
while (instructionIterator.hasNext()) {
Instruction instruction = instructionIterator.next();
@@ -820,8 +836,7 @@
}
Argument argument = instruction.asArgument();
- ArgumentInfo argumentInfo =
- prototypeChanges.getArgumentInfoCollection().getArgumentInfo(oldArgumentIndex);
+ ArgumentInfo argumentInfo = argumentInfoCollection.getArgumentInfo(oldArgumentIndex);
if (argumentInfo.isRemovedArgumentInfo()) {
rewriteRemovedArgument(
code,
@@ -832,24 +847,51 @@
affectedPhis,
argumentPostlude,
unusedArguments);
+ numberOfRemovedArguments++;
} else {
+ int newArgumentIndex =
+ argumentInfoCollection.getNewArgumentIndex(oldArgumentIndex, numberOfRemovedArguments);
+ Argument replacement;
if (argumentInfo.isRewrittenTypeInfo()) {
- rewriteArgumentType(
- code,
- instructionIterator,
- argument,
- argumentInfo.asRewrittenTypeInfo(),
- affectedPhis,
- newArgumentIndex);
+ replacement =
+ rewriteArgumentType(
+ code,
+ argument,
+ argumentInfo.asRewrittenTypeInfo(),
+ affectedPhis,
+ newArgumentIndex);
+ argument.outValue().replaceUsers(replacement.outValue());
} else if (newArgumentIndex != oldArgumentIndex) {
- instructionIterator.replaceCurrentInstruction(
+ replacement =
Argument.builder()
.setIndex(newArgumentIndex)
.setFreshOutValue(code, argument.getOutType(), argument.getLocalInfo())
.setPosition(argument.getPosition())
- .build());
+ .build();
+ argument.outValue().replaceUsers(replacement.outValue());
+ } else {
+ replacement = argument;
}
- newArgumentIndex++;
+ if (newArgumentIndex == nextArgumentIndex) {
+ // This is the right position for the argument. Insert it into the code at this position.
+ if (replacement != argument) {
+ instructionIterator.replaceCurrentInstruction(replacement);
+ }
+ nextArgumentIndex++;
+ } else {
+ // Due the a permutation of the argument order, this argument needs to be inserted at a
+ // later point. Enqueue the argument into the argument postlude.
+ instructionIterator.removeInstructionIgnoreOutValue();
+ ListIterator<Instruction> argumentPostludeIterator = argumentPostlude.listIterator();
+ while (argumentPostludeIterator.hasNext()) {
+ Instruction current = argumentPostludeIterator.next();
+ if (!current.isArgument() || replacement.getIndex() < current.asArgument().getIndex()) {
+ argumentPostludeIterator.previous();
+ break;
+ }
+ }
+ argumentPostludeIterator.add(replacement);
+ }
}
oldArgumentIndex++;
}
@@ -896,9 +938,8 @@
instructionIterator.removeOrReplaceByDebugLocalRead();
}
- private void rewriteArgumentType(
+ private Argument rewriteArgumentType(
IRCode code,
- InstructionListIterator instructionIterator,
Argument argument,
RewrittenTypeInfo rewrittenTypeInfo,
Set<Phi> affectedPhis,
@@ -910,8 +951,8 @@
.setFreshOutValue(code, rewrittenType, argument.getLocalInfo())
.setPosition(argument.getPosition())
.build();
- instructionIterator.replaceCurrentInstruction(replacement);
- affectedPhis.addAll(replacement.outValue().uniquePhiUsers());
+ affectedPhis.addAll(argument.outValue().uniquePhiUsers());
+ return replacement;
}
private void removeUnusedArguments(
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java b/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
index 6e69b3c..ecee91f 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
@@ -73,19 +73,48 @@
methodsToReprocessBuilder.add(method);
}
- public LongLivedProgramMethodSetBuilder<ProgramMethodSet> getMethodsToReprocessBuilder() {
- return methodsToReprocessBuilder;
+ public void add(ProgramMethod method, GraphLens currentGraphLens) {
+ methodsToReprocessBuilder.add(method, currentGraphLens);
+ }
+
+ public void addAll(Collection<ProgramMethod> methods, GraphLens currentGraphLens) {
+ methods.forEach(method -> add(method, currentGraphLens));
+ }
+
+ public boolean contains(ProgramMethod method, GraphLens currentGraphLens) {
+ return methodsToReprocessBuilder.contains(method, currentGraphLens);
+ }
+
+ public PostMethodProcessor.Builder merge(
+ LongLivedProgramMethodSetBuilder<ProgramMethodSet> otherMethodsToReprocessBuilder) {
+ methodsToReprocessBuilder.merge(otherMethodsToReprocessBuilder);
+ return this;
}
public void put(ProgramMethodSet methodsToRevisit) {
methodsToRevisit.forEach(this::add);
}
+ public void remove(ProgramMethod method, GraphLens graphLens) {
+ methodsToReprocessBuilder.remove(method.getReference(), graphLens);
+ }
+
+ public PostMethodProcessor.Builder removeAll(Collection<DexMethod> methods) {
+ methodsToReprocessBuilder.removeAll(methods);
+ return this;
+ }
+
// Some optimizations may change methods, creating new instances of the encoded methods with a
// new signature. The compiler needs to update the set of methods that must be reprocessed
// according to the graph lens.
- public void rewrittenWithLens(AppView<AppInfoWithLiveness> appView) {
+ public PostMethodProcessor.Builder rewrittenWithLens(AppView<AppInfoWithLiveness> appView) {
methodsToReprocessBuilder.rewrittenWithLens(appView);
+ return this;
+ }
+
+ public PostMethodProcessor.Builder rewrittenWithLens(GraphLens graphLens) {
+ methodsToReprocessBuilder.rewrittenWithLens(graphLens);
+ return this;
}
PostMethodProcessor build(
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 49ad698..11d7e80 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
@@ -128,24 +128,16 @@
DexMethod original = appView.graphLens().getOriginalMethodSignature(method);
assert original != null;
MethodProvider provider = rewritableMethods.getProvider(original);
- // TODO(b/150693139): Since the DesugarLibraryRetargeter is run during IR processing while the
- // backported method rewriter is run in cf to cf, we need here to compute if the method is
- // actually going to be retargeted through desugared library backports, and compute the
- // corresponding backported method if so. This can be removed once the DesugarLibraryRetargeter
- // has been moved as a cf to cf transformation.
+ // Old versions of desugared library have in the jar file pre-desugared code. This is used
+ // to undesugar pre-desugared code, then the code is re-desugared with D8/R8. This is
+ // maintained for legacy only, recent desugared library should not be shipped with
+ // pre-desugared code.
+ Map<DexType, DexType> legacyBackport =
+ appView.options().machineDesugaredLibrarySpecification.getLegacyBackport();
if (provider == null
&& appView.options().isDesugaredLibraryCompilation()
- && appView
- .options()
- .desugaredLibrarySpecification
- .getBackportCoreLibraryMember()
- .containsKey(method.holder)) {
- DexType newHolder =
- appView
- .options()
- .desugaredLibrarySpecification
- .getBackportCoreLibraryMember()
- .get(method.holder);
+ && legacyBackport.containsKey(method.holder)) {
+ DexType newHolder = legacyBackport.get(method.holder);
DexMethod backportedMethod =
appView.dexItemFactory().createMethod(newHolder, method.proto, method.name);
provider = rewritableMethods.getProvider(backportedMethod);
@@ -1111,6 +1103,39 @@
type));
}
+ // java.util.concurrent.atomic.AtomicReference
+ {
+ // compareAndSet(Object expect, Object update)
+ DexType type = factory.createType("Ljava/util/concurrent/atomic/AtomicReference;");
+ DexString name = factory.createString("compareAndSet");
+ DexProto proto =
+ factory.createProto(factory.booleanType, factory.objectType, factory.objectType);
+ DexMethod method = factory.createMethod(type, proto, name);
+ addProvider(
+ new StatifyingMethodWithForwardingGenerator(
+ method,
+ BackportedMethods::AtomicReferenceMethods_compareAndSet,
+ "compareAndSet",
+ type));
+ }
+
+ // java.util.concurrent.atomic.AtomicReferenceArray
+ {
+ // compareAndSet(int index, Object expect, Object update)
+ DexType type = factory.createType("Ljava/util/concurrent/atomic/AtomicReferenceArray;");
+ DexString name = factory.createString("compareAndSet");
+ DexProto proto =
+ factory.createProto(
+ factory.booleanType, factory.intType, factory.objectType, factory.objectType);
+ DexMethod method = factory.createMethod(type, proto, name);
+ addProvider(
+ new StatifyingMethodWithForwardingGenerator(
+ method,
+ BackportedMethods::AtomicReferenceArrayMethods_compareAndSet,
+ "compareAndSet",
+ type));
+ }
+
// java.util.concurrent.atomic.AtomicReferenceFieldUpdater
{
// compareAndSet(Object object, Object expect, Object update)
@@ -1412,7 +1437,7 @@
}
private void addProvider(MethodProvider generator) {
- if (appView.options().desugaredLibrarySpecification.isSupported(generator.method, appView)) {
+ if (appView.options().machineDesugaredLibrarySpecification.isSupported(generator.method)) {
// TODO(b/174453232): Remove this after the configuration file format has bee updated
// with the "rewrite_method" section.
if (generator.method.getHolderType() == appView.dexItemFactory().objectsType) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
index 282f4f1..3dbc8a5 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
@@ -32,10 +32,12 @@
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Comparator;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@@ -236,6 +238,9 @@
private void finalizeLambdaDesugaring(
ClassConverterResult.Builder classConverterResultBuilder,
Consumer<ProgramMethod> needsProcessing) {
+ // Sort synthesized lambda classes to ensure deterministic insertion of the synthesized
+ // $r8$lambda$ target methods.
+ synthesizedLambdaClasses.sort(Comparator.comparing(LambdaClass::getType));
for (LambdaClass lambdaClass : synthesizedLambdaClasses) {
lambdaClass.target.ensureAccessibilityIfNeeded(
classConverterResultBuilder, needsProcessing);
@@ -423,9 +428,18 @@
}
private void finalizeLambdaDesugaring() {
+ // Sort synthesized lambda classes to ensure deterministic insertion of the synthesized
+ // $r8$lambda$ target methods.
+ List<Entry<LambdaClass, ProgramMethod>> sortedSynthesizedLambdaClasses =
+ new ArrayList<>(synthesizedLambdaClasses.entrySet());
+ sortedSynthesizedLambdaClasses.sort(Comparator.comparing(entry -> entry.getKey().getType()));
+
Set<DexProgramClass> classesWithSerializableLambdas = Sets.newIdentityHashSet();
- synthesizedLambdaClasses.forEach(
- (lambdaClass, context) -> {
+ sortedSynthesizedLambdaClasses.forEach(
+ entry -> {
+ LambdaClass lambdaClass = entry.getKey();
+ ProgramMethod context = entry.getValue();
+
lambdaClass.target.ensureAccessibilityIfNeeded();
// Populate set of types with serialized lambda method for removal.
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java
index 1fd0ad0..1243435 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java
@@ -57,7 +57,7 @@
InterfaceMethodProcessorFacade interfaceMethodProcessorFacade,
RetargetingInfo retargetingInfo) {
ArrayList<CfPostProcessingDesugaring> desugarings = new ArrayList<>();
- if (!appView.options().desugaredLibrarySpecification.getRetargetCoreLibMember().isEmpty()
+ if (appView.options().machineDesugaredLibrarySpecification.hasRetargeting()
&& !appView.options().isDesugaredLibraryCompilation()) {
desugarings.add(new DesugaredLibraryRetargeterPostProcessor(appView, retargetingInfo));
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
index 33c69ac..e55c246 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
@@ -82,9 +82,9 @@
this.nestBasedAccessDesugaring = NestBasedAccessDesugaring.create(appView);
BackportedMethodRewriter backportedMethodRewriter = null;
desugaredLibraryRetargeter =
- appView.options().desugaredLibrarySpecification.getRetargetCoreLibMember().isEmpty()
- ? null
- : new DesugaredLibraryRetargeter(appView);
+ appView.options().machineDesugaredLibrarySpecification.hasRetargeting()
+ ? new DesugaredLibraryRetargeter(appView)
+ : null;
if (desugaredLibraryRetargeter != null) {
desugarings.add(desugaredLibraryRetargeter);
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/PrefixRewritingMapper.java b/src/main/java/com/android/tools/r8/ir/desugar/PrefixRewritingMapper.java
index bf96b67..90f2505 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/PrefixRewritingMapper.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/PrefixRewritingMapper.java
@@ -4,20 +4,11 @@
package com.android.tools.r8.ir.desugar;
-import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineRewritingFlags;
-import com.android.tools.r8.utils.DescriptorUtils;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Sets;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
import java.util.Map;
-import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
@@ -31,7 +22,7 @@
public abstract DexType rewrittenType(DexType type, AppView<?> appView);
- public abstract DexType rewrittenContextType(DexType type, AppView<?> appView);
+ public abstract DexType rewrittenContextType(DexType type);
public boolean hasRewrittenType(DexType type, AppView<?> appView) {
return rewrittenType(type, appView) != null;
@@ -53,195 +44,34 @@
public abstract void forAllRewrittenTypes(Consumer<DexType> consumer);
- public static class DesugarPrefixRewritingMapper extends PrefixRewritingMapper {
-
- private final Set<DexType> notRewritten = Sets.newConcurrentHashSet();
- private final Map<DexType, DexType> rewritten = new ConcurrentHashMap<>();
- private final Map<DexString, DexString> initialPrefixes;
- private final DexItemFactory factory;
- private final boolean l8Compilation;
-
- public DesugarPrefixRewritingMapper(
- Map<String, String> prefixes, DexItemFactory itemFactory, boolean libraryCompilation) {
- assert itemFactory != null || prefixes.isEmpty();
- this.factory = itemFactory;
- this.l8Compilation = libraryCompilation;
- ImmutableMap.Builder<DexString, DexString> builder = ImmutableMap.builder();
- for (String key : prefixes.keySet()) {
- builder.put(toDescriptorPrefix(key), toDescriptorPrefix(prefixes.get(key)));
- }
- this.initialPrefixes = builder.build();
- validatePrefixes(prefixes);
- }
-
- private DexString toDescriptorPrefix(String prefix) {
- return factory.createString("L" + DescriptorUtils.getBinaryNameFromJavaType(prefix));
- }
-
- @Override
- public void forAllRewrittenTypes(Consumer<DexType> consumer) {
- rewritten.keySet().forEach(consumer);
- }
-
- private void validatePrefixes(Map<String, String> initialPrefixes) {
- String[] prefixes = initialPrefixes.keySet().toArray(new String[0]);
- for (int i = 0; i < prefixes.length; i++) {
- for (int j = i + 1; j < prefixes.length; j++) {
- String small, large;
- if (prefixes[i].length() < prefixes[j].length()) {
- small = prefixes[i];
- large = prefixes[j];
- } else {
- small = prefixes[j];
- large = prefixes[i];
- }
- if (large.startsWith(small)) {
- throw new CompilationError(
- "Inconsistent prefix in desugared library:"
- + " Should a class starting with "
- + small
- + " be rewritten using "
- + small
- + " -> "
- + initialPrefixes.get(small)
- + " or using "
- + large
- + " - > "
- + initialPrefixes.get(large)
- + " ?");
- }
- }
- }
- }
-
- @Override
- public DexType rewrittenType(DexType type, AppView<?> appView) {
- assert appView != null || l8Compilation;
- if (notRewritten.contains(type)) {
- return null;
- }
- if (rewritten.containsKey(type)) {
- return rewritten.get(type);
- }
- return computePrefix(type, appView);
- }
-
- @Override
- public DexType rewrittenContextType(DexType type, AppView<?> appView) {
- DexType rewritten = rewrittenType(type, appView);
- if (rewritten != null) {
- return rewritten;
- }
- LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
- appView.options().desugaredLibrarySpecification;
- if (desugaredLibrarySpecification.getEmulateLibraryInterface().containsKey(type)) {
- return desugaredLibrarySpecification.getEmulateLibraryInterface().get(type);
- }
- for (Map<DexType, DexType> value :
- desugaredLibrarySpecification.getRetargetCoreLibMember().values()) {
- if (value.containsKey(type)) {
- // Hack until machine specification are ready.
- String prefix =
- DescriptorUtils.getJavaTypeFromBinaryName(
- desugaredLibrarySpecification.getSynthesizedLibraryClassesPackagePrefix());
- String interfaceType = type.toString();
- int firstPackage = interfaceType.indexOf('.');
- return appView
- .dexItemFactory()
- .createType(
- DescriptorUtils.javaTypeToDescriptor(
- prefix + interfaceType.substring(firstPackage + 1)));
- }
- }
- return null;
- }
-
- // Besides L8 compilation, program types should not be rewritten.
- private void failIfRewritingProgramType(DexType type, AppView<?> appView) {
- if (l8Compilation) {
- return;
- }
-
- DexType dexType = type.isArrayType() ? type.toBaseType(appView.dexItemFactory()) : type;
- DexClass dexClass = appView.definitionFor(dexType);
- if (dexClass != null && dexClass.isProgramClass()) {
- appView
- .options()
- .reporter
- .error(
- "Cannot compile program class "
- + dexType
- + " since it conflicts with a desugared library rewriting rule.");
- }
- }
-
- @Override
- public void rewriteType(DexType type, DexType rewrittenType) {
- assert !notRewritten.contains(type)
- : "New rewriting rule for "
- + type
- + " but the compiler has already made decisions based on the fact that this type was"
- + " not rewritten";
- assert !rewritten.containsKey(type) || rewritten.get(type) == rewrittenType
- : "New rewriting rule for "
- + type
- + " but the compiler has already made decisions based on a different rewriting rule"
- + " for this type";
- rewritten.put(type, rewrittenType);
- }
-
- private DexType computePrefix(DexType type, AppView<?> appView) {
- DexString prefixToMatch = type.descriptor.withoutArray(factory);
- DexType result = lookup(type, prefixToMatch, initialPrefixes);
- if (result != null) {
- failIfRewritingProgramType(type, appView);
- return result;
- }
- notRewritten.add(type);
- return null;
- }
-
- private DexType lookup(DexType type, DexString prefixToMatch, Map<DexString, DexString> map) {
- // TODO(b/154800164): We could use tries instead of looking-up everywhere.
- for (DexString prefix : map.keySet()) {
- if (prefixToMatch.startsWith(prefix)) {
- DexString rewrittenTypeDescriptor =
- type.descriptor.withNewPrefix(prefix, map.get(prefix), factory);
- DexType rewrittenType = factory.createType(rewrittenTypeDescriptor);
- rewriteType(type, rewrittenType);
- return rewrittenType;
- }
- }
- return null;
- }
-
- @Override
- public boolean isRewriting() {
- return true;
- }
- }
-
public static class MachineDesugarPrefixRewritingMapper extends PrefixRewritingMapper {
- private final PrefixRewritingMapper mapper;
private final Map<DexType, DexType> rewriteType;
private final Map<DexType, DexType> rewriteDerivedTypeOnly;
- public MachineDesugarPrefixRewritingMapper(
- PrefixRewritingMapper mapper, MachineRewritingFlags flags) {
- this.mapper = mapper;
- this.rewriteType = new ConcurrentHashMap<>(flags.getRewriteType());
- rewriteDerivedTypeOnly = flags.getRewriteDerivedTypeOnly();
+ public MachineDesugarPrefixRewritingMapper(MachineDesugaredLibrarySpecification specification) {
+ this.rewriteType = new ConcurrentHashMap<>(specification.getRewriteType());
+ rewriteDerivedTypeOnly = specification.getRewriteDerivedTypeOnly();
}
@Override
public DexType rewrittenType(DexType type, AppView<?> appView) {
- assert mapper.rewrittenType(type, appView) == rewriteType.get(type);
+ if (type.isArrayType()) {
+ DexType rewrittenBaseType =
+ rewrittenType(type.toBaseType(appView.dexItemFactory()), appView);
+ if (rewrittenBaseType == null) {
+ return null;
+ }
+ return appView
+ .dexItemFactory()
+ .createArrayType(type.getNumberOfLeadingSquareBrackets(), rewrittenBaseType);
+ }
return rewriteType.get(type);
}
@Override
- public DexType rewrittenContextType(DexType context, AppView<?> appView) {
+ public DexType rewrittenContextType(DexType context) {
+ assert !context.isArrayType();
if (rewriteType.containsKey(context)) {
return rewriteType.get(context);
}
@@ -250,7 +80,6 @@
@Override
public void rewriteType(DexType type, DexType rewrittenType) {
- mapper.rewriteType(type, rewrittenType);
rewriteType.compute(
type,
(t, val) -> {
@@ -278,7 +107,7 @@
}
@Override
- public DexType rewrittenContextType(DexType type, AppView<?> appView) {
+ public DexType rewrittenContextType(DexType type) {
return null;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
index e6b793f..ccd00a9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
@@ -97,6 +97,8 @@
factory.createSynthesizedType("Ljava/util/OptionalInt;");
factory.createSynthesizedType("Ljava/util/OptionalLong;");
factory.createSynthesizedType("Ljava/util/Set;");
+ factory.createSynthesizedType("Ljava/util/concurrent/atomic/AtomicReference;");
+ factory.createSynthesizedType("Ljava/util/concurrent/atomic/AtomicReferenceArray;");
factory.createSynthesizedType("Ljava/util/concurrent/atomic/AtomicReferenceFieldUpdater;");
factory.createSynthesizedType("Ljava/util/function/Consumer;");
factory.createSynthesizedType("Ljava/util/function/DoubleConsumer;");
@@ -115,6 +117,85 @@
factory.createSynthesizedType("[Ljava/util/Map$Entry;");
}
+ public static CfCode AtomicReferenceArrayMethods_compareAndSet(
+ InternalOptions options, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ CfLabel label4 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 4,
+ 4,
+ ImmutableList.of(
+ label0,
+ new CfFrame(
+ new Int2ReferenceAVLTreeMap<>(
+ new int[] {0, 1, 2, 3},
+ new FrameType[] {
+ FrameType.initialized(
+ options.itemFactory.createType(
+ "Ljava/util/concurrent/atomic/AtomicReferenceArray;")),
+ FrameType.initialized(options.itemFactory.intType),
+ FrameType.initialized(options.itemFactory.objectType),
+ FrameType.initialized(options.itemFactory.objectType)
+ }),
+ new ArrayDeque<>(Arrays.asList())),
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfLoad(ValueType.INT, 1),
+ new CfLoad(ValueType.OBJECT, 2),
+ new CfLoad(ValueType.OBJECT, 3),
+ new CfInvoke(
+ 182,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType(
+ "Ljava/util/concurrent/atomic/AtomicReferenceArray;"),
+ options.itemFactory.createProto(
+ options.itemFactory.booleanType,
+ options.itemFactory.intType,
+ options.itemFactory.objectType,
+ options.itemFactory.objectType),
+ options.itemFactory.createString("compareAndSet")),
+ false),
+ new CfIf(If.Type.EQ, ValueType.INT, label2),
+ label1,
+ new CfConstNumber(1, ValueType.INT),
+ new CfReturn(ValueType.INT),
+ label2,
+ new CfFrame(
+ new Int2ReferenceAVLTreeMap<>(
+ new int[] {0, 1, 2, 3},
+ new FrameType[] {
+ FrameType.initialized(
+ options.itemFactory.createType(
+ "Ljava/util/concurrent/atomic/AtomicReferenceArray;")),
+ FrameType.initialized(options.itemFactory.intType),
+ FrameType.initialized(options.itemFactory.objectType),
+ FrameType.initialized(options.itemFactory.objectType)
+ }),
+ new ArrayDeque<>(Arrays.asList())),
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfLoad(ValueType.INT, 1),
+ new CfInvoke(
+ 182,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType(
+ "Ljava/util/concurrent/atomic/AtomicReferenceArray;"),
+ options.itemFactory.createProto(
+ options.itemFactory.objectType, options.itemFactory.intType),
+ options.itemFactory.createString("get")),
+ false),
+ new CfLoad(ValueType.OBJECT, 2),
+ new CfIfCmp(If.Type.EQ, ValueType.OBJECT, label0),
+ label3,
+ new CfConstNumber(0, ValueType.INT),
+ new CfReturn(ValueType.INT),
+ label4),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
public static CfCode AtomicReferenceFieldUpdaterMethods_compareAndSet(
InternalOptions options, DexMethod method) {
CfLabel label0 = new CfLabel();
@@ -194,6 +275,77 @@
ImmutableList.of());
}
+ public static CfCode AtomicReferenceMethods_compareAndSet(
+ InternalOptions options, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ CfLabel label4 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 3,
+ 3,
+ ImmutableList.of(
+ label0,
+ new CfFrame(
+ new Int2ReferenceAVLTreeMap<>(
+ new int[] {0, 1, 2},
+ new FrameType[] {
+ FrameType.initialized(
+ options.itemFactory.createType(
+ "Ljava/util/concurrent/atomic/AtomicReference;")),
+ FrameType.initialized(options.itemFactory.objectType),
+ FrameType.initialized(options.itemFactory.objectType)
+ }),
+ new ArrayDeque<>(Arrays.asList())),
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfLoad(ValueType.OBJECT, 1),
+ new CfLoad(ValueType.OBJECT, 2),
+ new CfInvoke(
+ 182,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/concurrent/atomic/AtomicReference;"),
+ options.itemFactory.createProto(
+ options.itemFactory.booleanType,
+ options.itemFactory.objectType,
+ options.itemFactory.objectType),
+ options.itemFactory.createString("compareAndSet")),
+ false),
+ new CfIf(If.Type.EQ, ValueType.INT, label2),
+ label1,
+ new CfConstNumber(1, ValueType.INT),
+ new CfReturn(ValueType.INT),
+ label2,
+ new CfFrame(
+ new Int2ReferenceAVLTreeMap<>(
+ new int[] {0, 1, 2},
+ new FrameType[] {
+ FrameType.initialized(
+ options.itemFactory.createType(
+ "Ljava/util/concurrent/atomic/AtomicReference;")),
+ FrameType.initialized(options.itemFactory.objectType),
+ FrameType.initialized(options.itemFactory.objectType)
+ }),
+ new ArrayDeque<>(Arrays.asList())),
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfInvoke(
+ 182,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/util/concurrent/atomic/AtomicReference;"),
+ options.itemFactory.createProto(options.itemFactory.objectType),
+ options.itemFactory.createString("get")),
+ false),
+ new CfLoad(ValueType.OBJECT, 1),
+ new CfIfCmp(If.Type.EQ, ValueType.OBJECT, label0),
+ label3,
+ new CfConstNumber(0, ValueType.INT),
+ new CfReturn(ValueType.INT),
+ label4),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
public static CfCode BooleanMethods_compare(InternalOptions options, DexMethod method) {
CfLabel label0 = new CfLabel();
CfLabel label1 = new CfLabel();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPICallbackSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPICallbackSynthesizer.java
index 150e6c4..b66a96a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPICallbackSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPICallbackSynthesizer.java
@@ -20,13 +20,13 @@
import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaring;
import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryAPICallbackSynthesizorEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APICallbackWrapperCfCodeProvider;
import com.android.tools.r8.utils.OptionalBool;
import com.android.tools.r8.utils.WorkList;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
@@ -109,8 +109,8 @@
if (!appView.rewritePrefix.hasRewrittenTypeInSignature(definition.getProto(), appView)
|| appView
.options()
- .desugaredLibrarySpecification
- .getEmulateLibraryInterface()
+ .machineDesugaredLibrarySpecification
+ .getEmulatedInterfaces()
.containsKey(method.getHolderType())) {
return false;
}
@@ -127,7 +127,7 @@
return false;
}
}
- if (!appView.options().desugaredLibrarySpecification.supportAllCallbacksFromLibrary()
+ if (!appView.options().machineDesugaredLibrarySpecification.supportAllCallbacksFromLibrary()
&& appView.options().isDesugaredLibraryCompilation()) {
return false;
}
@@ -178,13 +178,13 @@
}
private boolean shouldGenerateCallbacksForEmulateInterfaceAPIs(DexClass dexClass) {
- if (appView.options().desugaredLibrarySpecification.supportAllCallbacksFromLibrary()) {
+ if (appView.options().machineDesugaredLibrarySpecification.supportAllCallbacksFromLibrary()) {
return true;
}
- Map<DexType, DexType> emulateLibraryInterfaces =
- appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface();
- return !(emulateLibraryInterfaces.containsKey(dexClass.type)
- || emulateLibraryInterfaces.containsValue(dexClass.type));
+ MachineDesugaredLibrarySpecification specification =
+ appView.options().machineDesugaredLibrarySpecification;
+ return !(specification.getEmulatedInterfaces().containsKey(dexClass.type)
+ || specification.isEmulatedInterfaceRewrittenType(dexClass.type));
}
private ProgramMethod generateCallbackMethod(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
index 987dc8d..f234a1b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
@@ -181,8 +181,8 @@
return interfaceResult != null
&& appView
.options()
- .desugaredLibrarySpecification
- .getEmulateLibraryInterface()
+ .machineDesugaredLibrarySpecification
+ .getEmulatedInterfaces()
.containsKey(interfaceResult.getHolderType());
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
index 4a8cabe..71442ac 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
@@ -13,12 +13,14 @@
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexClasspathClass;
import com.android.tools.r8.graph.DexEncodedField;
+import com.android.tools.r8.graph.DexEncodedMember;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.FieldAccessFlags;
import com.android.tools.r8.graph.MethodAccessFlags;
@@ -38,6 +40,7 @@
import com.android.tools.r8.synthesis.SyntheticClassBuilder;
import com.android.tools.r8.synthesis.SyntheticMethodBuilder;
import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
+import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.StringDiagnostic;
import com.google.common.collect.Iterables;
import java.util.ArrayList;
@@ -174,17 +177,21 @@
private DexMethod getCustomConversion(DexType type, DexType srcType, DexType destType) {
// ConversionType holds the methods "rewrittenType convert(type)" and the other way around.
// But everything is going to be rewritten, so we need to use vivifiedType and type".
- DexType conversionHolder =
- appView.options().desugaredLibrarySpecification.getCustomConversions().get(type);
- if (conversionHolder != null) {
+ Pair<DexType, DexString> pair =
+ appView.options().machineDesugaredLibrarySpecification.getCustomConversions().get(type);
+ if (pair != null) {
return factory.createMethod(
- conversionHolder, factory.createProto(destType, srcType), factory.convertMethodName);
+ pair.getFirst(), factory.createProto(destType, srcType), pair.getSecond());
}
return null;
}
private boolean canConvert(DexType type) {
- return appView.options().desugaredLibrarySpecification.getCustomConversions().containsKey(type)
+ return appView
+ .options()
+ .machineDesugaredLibrarySpecification
+ .getCustomConversions()
+ .containsKey(type)
|| canGenerateWrapper(type);
}
@@ -212,7 +219,7 @@
}
private boolean canGenerateWrapper(DexType type) {
- return appView.options().desugaredLibrarySpecification.getWrapperConversions().contains(type);
+ return appView.options().machineDesugaredLibrarySpecification.getWrappers().containsKey(type);
}
private DexClass getValidClassToWrap(DexType type) {
@@ -458,9 +465,8 @@
if (holderClass == null) {
assert appView
.options()
- .desugaredLibrarySpecification
- .getEmulateLibraryInterface()
- .containsValue(method.getHolderType());
+ .machineDesugaredLibrarySpecification
+ .isEmulatedInterfaceRewrittenType(method.getHolderType());
isInterface = true;
} else {
isInterface = holderClass.isInterface();
@@ -541,19 +547,17 @@
}
private Iterable<DexMethod> allImplementedMethods(DexClass clazz) {
- if (appView.options().testing.machineDesugaredLibrarySpecification != null) {
+ if (appView.options().machineDesugaredLibrarySpecification != null) {
return appView
.options()
- .testing
.machineDesugaredLibrarySpecification
- .getRewritingFlags()
.getWrappers()
.get(clazz.type);
}
List<DexEncodedMethod> dexEncodedMethods =
allImplementedMethodsCache.computeIfAbsent(
clazz.type, type -> internalAllImplementedMethods(clazz));
- return Iterables.transform(dexEncodedMethods, m -> m.getReference());
+ return Iterables.transform(dexEncodedMethods, DexEncodedMember::getReference);
}
private List<DexEncodedMethod> internalAllImplementedMethods(DexClass libraryClass) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecification.java
index 6a6a2d4..1e871b3 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecification.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecification.java
@@ -6,14 +6,9 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.desugar.PrefixRewritingMapper;
-import com.android.tools.r8.ir.desugar.PrefixRewritingMapper.DesugarPrefixRewritingMapper;
import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.InternalOptions;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -23,56 +18,20 @@
private final boolean libraryCompilation;
private final HumanTopLevelFlags topLevelFlags;
private final HumanRewritingFlags rewritingFlags;
- private final PrefixRewritingMapper prefixRewritingMapper;
-
- public static HumanDesugaredLibrarySpecification withOnlyRewritePrefixForTesting(
- Map<String, String> prefix, InternalOptions options) {
- return new HumanDesugaredLibrarySpecification(
- HumanTopLevelFlags.empty(),
- HumanRewritingFlags.withOnlyRewritePrefixForTesting(prefix, options),
- true,
- options.itemFactory);
- }
-
- public static HumanDesugaredLibrarySpecification empty() {
- return new HumanDesugaredLibrarySpecification(
- HumanTopLevelFlags.empty(), HumanRewritingFlags.empty(), false, null) {
-
- @Override
- public boolean isSupported(DexReference reference, AppView<?> appView) {
- return false;
- }
-
- @Override
- public boolean isEmptyConfiguration() {
- return true;
- }
- };
- }
public HumanDesugaredLibrarySpecification(
HumanTopLevelFlags topLevelFlags,
HumanRewritingFlags rewritingFlags,
- boolean libraryCompilation,
- DexItemFactory factory) {
+ boolean libraryCompilation) {
this.libraryCompilation = libraryCompilation;
this.topLevelFlags = topLevelFlags;
this.rewritingFlags = rewritingFlags;
- this.prefixRewritingMapper =
- rewritingFlags.getRewritePrefix().isEmpty()
- ? PrefixRewritingMapper.empty()
- : new DesugarPrefixRewritingMapper(
- rewritingFlags.getRewritePrefix(), factory, libraryCompilation);
}
public boolean supportAllCallbacksFromLibrary() {
return topLevelFlags.supportAllCallbacksFromLibrary();
}
- public PrefixRewritingMapper getPrefixRewritingMapper() {
- return prefixRewritingMapper;
- }
-
public AndroidApiLevel getRequiredCompilationApiLevel() {
return topLevelFlags.getRequiredCompilationAPILevel();
}
@@ -109,10 +68,6 @@
return rewritingFlags.getEmulateLibraryInterface();
}
- public boolean isSupported(DexReference reference, AppView<?> appView) {
- return prefixRewritingMapper.hasRewrittenType(reference.getContextType(), appView);
- }
-
// If the method is retargeted, answers the retargeted method, else null.
public DexMethod retargetMethod(DexEncodedMethod method, AppView<?> appView) {
Map<DexMethod, DexType> retargetCoreLibMember = rewritingFlags.getRetargetCoreLibMember();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
index a612177..e01def6 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
@@ -103,7 +103,7 @@
HumanDesugaredLibrarySpecification config =
new HumanDesugaredLibrarySpecification(
- topLevelFlags, legacyRewritingFlags, libraryCompilation, dexItemFactory);
+ topLevelFlags, legacyRewritingFlags, libraryCompilation);
origin = null;
return config;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java
index 3da0b97..9ab05b9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java
@@ -6,13 +6,9 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.desugar.PrefixRewritingMapper;
-import com.android.tools.r8.ir.desugar.PrefixRewritingMapper.DesugarPrefixRewritingMapper;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions;
@@ -26,25 +22,18 @@
private final boolean libraryCompilation;
private final LegacyTopLevelFlags topLevelFlags;
private final LegacyRewritingFlags rewritingFlags;
- private final PrefixRewritingMapper prefixRewritingMapper;
public static LegacyDesugaredLibrarySpecification withOnlyRewritePrefixForTesting(
Map<String, String> prefix, InternalOptions options) {
return new LegacyDesugaredLibrarySpecification(
LegacyTopLevelFlags.empty(),
LegacyRewritingFlags.withOnlyRewritePrefixForTesting(prefix, options),
- true,
- options.itemFactory);
+ true);
}
public static LegacyDesugaredLibrarySpecification empty() {
return new LegacyDesugaredLibrarySpecification(
- LegacyTopLevelFlags.empty(), LegacyRewritingFlags.empty(), false, null) {
-
- @Override
- public boolean isSupported(DexReference reference, AppView<?> appView) {
- return false;
- }
+ LegacyTopLevelFlags.empty(), LegacyRewritingFlags.empty(), false) {
@Override
public boolean isEmptyConfiguration() {
@@ -56,16 +45,10 @@
public LegacyDesugaredLibrarySpecification(
LegacyTopLevelFlags topLevelFlags,
LegacyRewritingFlags rewritingFlags,
- boolean libraryCompilation,
- DexItemFactory factory) {
+ boolean libraryCompilation) {
this.libraryCompilation = libraryCompilation;
this.topLevelFlags = topLevelFlags;
this.rewritingFlags = rewritingFlags;
- this.prefixRewritingMapper =
- rewritingFlags.getRewritePrefix().isEmpty()
- ? PrefixRewritingMapper.empty()
- : new DesugarPrefixRewritingMapper(
- rewritingFlags.getRewritePrefix(), factory, libraryCompilation);
}
public LegacyTopLevelFlags getTopLevelFlags() {
@@ -80,10 +63,6 @@
return topLevelFlags.supportAllCallbacksFromLibrary();
}
- public PrefixRewritingMapper getPrefixRewritingMapper() {
- return prefixRewritingMapper;
- }
-
public AndroidApiLevel getRequiredCompilationApiLevel() {
return topLevelFlags.getRequiredCompilationAPILevel();
}
@@ -123,10 +102,6 @@
return rewritingFlags.getEmulateLibraryInterface();
}
- public boolean isSupported(DexReference reference, AppView<?> appView) {
- return prefixRewritingMapper.hasRewrittenType(reference.getContextType(), appView);
- }
-
// If the method is retargeted, answers the retargeted method, else null.
public DexMethod retargetMethod(DexEncodedMethod method, AppView<?> appView) {
Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java
index 7cece17..a3afcd9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java
@@ -110,7 +110,7 @@
LegacyDesugaredLibrarySpecification config =
new LegacyDesugaredLibrarySpecification(
- topLevelFlags, legacyRewritingFlags, libraryCompilation, dexItemFactory);
+ topLevelFlags, legacyRewritingFlags, libraryCompilation);
origin = null;
return config;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
index 501482e..e1368e3 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
@@ -4,12 +4,41 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexReference;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.Pair;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Consumer;
+
public class MachineDesugaredLibrarySpecification {
private final boolean libraryCompilation;
private final MachineTopLevelFlags topLevelFlags;
private final MachineRewritingFlags rewritingFlags;
+ public static MachineDesugaredLibrarySpecification empty() {
+ return new MachineDesugaredLibrarySpecification(
+ false, MachineTopLevelFlags.empty(), MachineRewritingFlags.builder().build()) {
+ @Override
+ public boolean isSupported(DexReference reference) {
+ return false;
+ }
+ };
+ }
+
+ public static MachineDesugaredLibrarySpecification withOnlyRewriteTypeForTesting(
+ Map<DexType, DexType> rewriteTypeForTesting) {
+ MachineRewritingFlags.Builder builder = MachineRewritingFlags.builder();
+ rewriteTypeForTesting.forEach(builder::rewriteType);
+ return new MachineDesugaredLibrarySpecification(
+ true, MachineTopLevelFlags.empty(), builder.build());
+ }
+
public MachineDesugaredLibrarySpecification(
boolean libraryCompilation,
MachineTopLevelFlags topLevelFlags,
@@ -23,11 +52,116 @@
return libraryCompilation;
}
- public MachineTopLevelFlags getTopLevelFlags() {
- return topLevelFlags;
+ public AndroidApiLevel getRequiredCompilationAPILevel() {
+ return topLevelFlags.getRequiredCompilationAPILevel();
}
- public MachineRewritingFlags getRewritingFlags() {
- return rewritingFlags;
+ public String getSynthesizedLibraryClassesPackagePrefix() {
+ return topLevelFlags.getSynthesizedLibraryClassesPackagePrefix();
+ }
+
+ public String getIdentifier() {
+ return topLevelFlags.getIdentifier();
+ }
+
+ public String getJsonSource() {
+ return topLevelFlags.getJsonSource();
+ }
+
+ public boolean supportAllCallbacksFromLibrary() {
+ return topLevelFlags.supportAllCallbacksFromLibrary();
+ }
+
+ public List<String> getExtraKeepRules() {
+ return topLevelFlags.getExtraKeepRules();
+ }
+
+ public Map<DexType, DexType> getRewriteType() {
+ return rewritingFlags.getRewriteType();
+ }
+
+ public Map<DexType, DexType> getRewriteDerivedTypeOnly() {
+ return rewritingFlags.getRewriteDerivedTypeOnly();
+ }
+
+ public Map<DexMethod, DexMethod> getStaticRetarget() {
+ return rewritingFlags.getStaticRetarget();
+ }
+
+ public Map<DexMethod, DexMethod> getNonEmulatedVirtualRetarget() {
+ return rewritingFlags.getNonEmulatedVirtualRetarget();
+ }
+
+ public Map<DexMethod, EmulatedDispatchMethodDescriptor> getEmulatedVirtualRetarget() {
+ return rewritingFlags.getEmulatedVirtualRetarget();
+ }
+
+ public void forEachRetargetHolder(Consumer<DexType> consumer) {
+ rewritingFlags.forEachRetargetHolder(consumer);
+ }
+
+ public Map<DexType, EmulatedInterfaceDescriptor> getEmulatedInterfaces() {
+ return rewritingFlags.getEmulatedInterfaces();
+ }
+
+ public EmulatedDispatchMethodDescriptor getEmulatedInterfaceEmulatedDispatchMethodDescriptor(
+ DexMethod method) {
+ return rewritingFlags.getEmulatedInterfaceEmulatedDispatchMethodDescriptor(method);
+ }
+
+ public boolean isCustomConversionRewrittenType(DexType type) {
+ return rewritingFlags.isCustomConversionRewrittenType(type);
+ }
+
+ public boolean isEmulatedInterfaceRewrittenType(DexType type) {
+ return rewritingFlags.isEmulatedInterfaceRewrittenType(type);
+ }
+
+ public Map<DexType, List<DexMethod>> getWrappers() {
+ return rewritingFlags.getWrappers();
+ }
+
+ public Map<DexType, DexType> getLegacyBackport() {
+ return rewritingFlags.getLegacyBackport();
+ }
+
+ public Set<DexType> getDontRetarget() {
+ return rewritingFlags.getDontRetarget();
+ }
+
+ public Map<DexType, Pair<DexType, DexString>> getCustomConversions() {
+ return rewritingFlags.getCustomConversions();
+ }
+
+ public boolean hasRetargeting() {
+ return rewritingFlags.hasRetargeting();
+ }
+
+ public boolean hasEmulatedInterfaces() {
+ return rewritingFlags.hasEmulatedInterfaces();
+ }
+
+ public boolean isSupported(DexReference reference) {
+ // Support through type rewriting.
+ if (rewritingFlags.getRewriteType().containsKey(reference.getContextType())) {
+ return true;
+ }
+ if (!reference.isDexMethod()) {
+ return false;
+ }
+ // Support through retargeting.
+ DexMethod dexMethod = reference.asDexMethod();
+ if (getStaticRetarget().containsKey(dexMethod)
+ || getNonEmulatedVirtualRetarget().containsKey(dexMethod)
+ || getEmulatedVirtualRetarget().containsKey(dexMethod)) {
+ return true;
+ }
+ // Support through emulated interface.
+ for (EmulatedInterfaceDescriptor descriptor : getEmulatedInterfaces().values()) {
+ if (descriptor.getEmulatedMethods().containsKey(dexMethod)) {
+ return true;
+ }
+ }
+ return false;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
index a6c487e..c5c77c6 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
@@ -11,10 +11,12 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.function.Consumer;
public class MachineRewritingFlags {
@@ -94,6 +96,12 @@
return emulatedVirtualRetarget;
}
+ public void forEachRetargetHolder(Consumer<DexType> consumer) {
+ staticRetarget.keySet().forEach(m -> consumer.accept(m.getHolderType()));
+ nonEmulatedVirtualRetarget.keySet().forEach(m -> consumer.accept(m.getHolderType()));
+ emulatedVirtualRetarget.keySet().forEach(m -> consumer.accept(m.getHolderType()));
+ }
+
public Map<DexType, EmulatedInterfaceDescriptor> getEmulatedInterfaces() {
return emulatedInterfaces;
}
@@ -110,10 +118,37 @@
return dontRetarget;
}
+ public boolean isCustomConversionRewrittenType(DexType type) {
+ return Iterables.any(customConversions.values(), pair -> pair.getFirst() == type);
+ }
+
public Map<DexType, Pair<DexType, DexString>> getCustomConversions() {
return customConversions;
}
+ public boolean hasRetargeting() {
+ return !staticRetarget.isEmpty()
+ || !nonEmulatedVirtualRetarget.isEmpty()
+ || !emulatedVirtualRetarget.isEmpty();
+ }
+
+ public boolean isEmulatedInterfaceRewrittenType(DexType type) {
+ return Iterables.any(
+ emulatedInterfaces.values(), descriptor -> descriptor.getRewrittenType() == type);
+ }
+
+ public boolean hasEmulatedInterfaces() {
+ return !emulatedInterfaces.isEmpty();
+ }
+
+ EmulatedDispatchMethodDescriptor getEmulatedInterfaceEmulatedDispatchMethodDescriptor(
+ DexMethod method) {
+ if (!emulatedInterfaces.containsKey(method.getHolderType())) {
+ return null;
+ }
+ return emulatedInterfaces.get(method.getHolderType()).getEmulatedMethods().get(method);
+ }
+
public static class Builder {
Builder() {}
@@ -137,6 +172,7 @@
public void rewriteType(DexType src, DexType target) {
assert src != null;
assert target != null;
+ assert src != target;
rewriteType.put(src, target);
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineTopLevelFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineTopLevelFlags.java
index f426219..0c6a88a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineTopLevelFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineTopLevelFlags.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification;
import com.android.tools.r8.utils.AndroidApiLevel;
+import com.google.common.collect.ImmutableList;
import java.util.List;
public class MachineTopLevelFlags {
@@ -23,6 +24,11 @@
private final boolean supportAllCallbacksFromLibrary;
private final List<String> extraKeepRules;
+ public static MachineTopLevelFlags empty() {
+ return new MachineTopLevelFlags(
+ AndroidApiLevel.B, "unused", null, null, false, ImmutableList.of());
+ }
+
public MachineTopLevelFlags(
AndroidApiLevel requiredCompilationAPILevel,
String synthesizedLibraryClassesPackagePrefix,
@@ -54,7 +60,7 @@
return jsonSource;
}
- public boolean isSupportAllCallbacksFromLibrary() {
+ public boolean supportAllCallbacksFromLibrary() {
return supportAllCallbacksFromLibrary;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
index a54cd8d..5fcf037 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
@@ -129,8 +129,8 @@
}
if (appView
.options()
- .desugaredLibrarySpecification
- .getDontRetargetLibMember()
+ .machineDesugaredLibrarySpecification
+ .getDontRetarget()
.contains(context.getContextType())) {
return NO_REWRITING;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java
index 11fcfb7..eb28d20 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java
@@ -20,7 +20,7 @@
AppView<?> appView, RetargetingInfo retargetingInfo) {
assert appView.options().isDesugaredLibraryCompilation();
if (retargetingInfo == null || retargetingInfo.getEmulatedVirtualRetarget().isEmpty()) {
- assert appView.options().desugaredLibrarySpecification.getRetargetCoreLibMember().isEmpty();
+ assert !appView.options().machineDesugaredLibrarySpecification.hasRetargeting();
return null;
}
return new DesugaredLibraryRetargeterL8Synthesizer(appView, retargetingInfo);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterLibraryTypeSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterLibraryTypeSynthesizer.java
index bbaa4cf..bfb423a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterLibraryTypeSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterLibraryTypeSynthesizer.java
@@ -39,16 +39,16 @@
public class DesugaredLibraryRetargeterLibraryTypeSynthesizer {
public static void checkForAssumedLibraryTypes(AppView<?> appView) {
- Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
- appView.options().desugaredLibrarySpecification.getRetargetCoreLibMember();
- for (DexString methodName : retargetCoreLibMember.keySet()) {
- for (DexType inType : retargetCoreLibMember.get(methodName).keySet()) {
- DexClass typeClass = appView.definitionFor(inType);
- if (typeClass == null) {
- warnMissingRetargetCoreLibraryMember(inType, appView);
- }
- }
- }
+ appView
+ .options()
+ .machineDesugaredLibrarySpecification
+ .forEachRetargetHolder(
+ inType -> {
+ DexClass typeClass = appView.definitionFor(inType);
+ if (typeClass == null) {
+ warnMissingRetargetCoreLibraryMember(inType, appView);
+ }
+ });
}
public static void amendLibraryWithRetargetedMembers(AppView<AppInfoWithClassHierarchy> appView) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
index 414c32d..d1e64ec 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
@@ -127,8 +127,8 @@
}
if (appView
.options()
- .desugaredLibrarySpecification
- .getDontRetargetLibMember()
+ .machineDesugaredLibrarySpecification
+ .getDontRetarget()
.contains(clazz.getType())) {
continue;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/RetargetingInfo.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/RetargetingInfo.java
index 9e1f5e3..b7ac366 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/RetargetingInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/RetargetingInfo.java
@@ -4,24 +4,9 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexClassAndMethod;
-import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.DerivedMethod;
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedDispatchMethodDescriptor;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineRewritingFlags;
-import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
-import com.android.tools.r8.utils.WorkList;
-import com.google.common.collect.ImmutableMap;
-import java.util.ArrayList;
-import java.util.IdentityHashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
import java.util.Map;
public class RetargetingInfo {
@@ -40,15 +25,12 @@
}
public static RetargetingInfo get(AppView<?> appView) {
- if (appView.options().testing.machineDesugaredLibrarySpecification != null) {
- MachineRewritingFlags rewritingFlags =
- appView.options().testing.machineDesugaredLibrarySpecification.getRewritingFlags();
- return new RetargetingInfo(
- rewritingFlags.getStaticRetarget(),
- rewritingFlags.getNonEmulatedVirtualRetarget(),
- rewritingFlags.getEmulatedVirtualRetarget());
- }
- return new RetargetingInfoBuilder(appView).computeRetargetingInfo();
+ MachineDesugaredLibrarySpecification specification =
+ appView.options().machineDesugaredLibrarySpecification;
+ return new RetargetingInfo(
+ specification.getStaticRetarget(),
+ specification.getNonEmulatedVirtualRetarget(),
+ specification.getEmulatedVirtualRetarget());
}
public Map<DexMethod, DexMethod> getStaticRetarget() {
@@ -62,152 +44,4 @@
public Map<DexMethod, EmulatedDispatchMethodDescriptor> getEmulatedVirtualRetarget() {
return emulatedVirtualRetarget;
}
-
- private static class RetargetingInfoBuilder {
-
- private final AppView<?> appView;
- private final Map<DexMethod, DexMethod> staticRetarget = new IdentityHashMap<>();
- private final Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget = new IdentityHashMap<>();
- private final Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedVirtualRetarget =
- new IdentityHashMap<>();
-
- public RetargetingInfoBuilder(AppView<?> appView) {
- this.appView = appView;
- }
-
- private RetargetingInfo computeRetargetingInfo() {
- LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
- appView.options().desugaredLibrarySpecification;
- Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
- desugaredLibrarySpecification.getRetargetCoreLibMember();
- if (retargetCoreLibMember.isEmpty()) {
- return new RetargetingInfo(ImmutableMap.of(), ImmutableMap.of(), ImmutableMap.of());
- }
- for (DexString methodName : retargetCoreLibMember.keySet()) {
- for (DexType inType : retargetCoreLibMember.get(methodName).keySet()) {
- DexClass typeClass = appView.definitionFor(inType);
- if (typeClass != null) {
- DexType newHolder = retargetCoreLibMember.get(methodName).get(inType);
- List<DexClassAndMethod> found = findMethodsWithName(methodName, typeClass);
- for (DexClassAndMethod method : found) {
- DexMethod methodReference = method.getReference();
- if (method.getAccessFlags().isStatic()) {
- staticRetarget.put(
- methodReference,
- computeRetargetMethod(
- methodReference, method.getAccessFlags().isStatic(), newHolder));
- continue;
- }
- if (isEmulatedInterfaceDispatch(method)) {
- continue;
- }
- if (typeClass.isFinal() || method.getAccessFlags().isFinal()) {
- nonEmulatedVirtualRetarget.put(
- methodReference,
- computeRetargetMethod(
- methodReference, method.getAccessFlags().isStatic(), newHolder));
- } else {
- // Virtual rewrites require emulated dispatch for inheritance.
- // The call is rewritten to the dispatch holder class instead.
- DexProto newProto = appView.dexItemFactory().prependHolderToProto(methodReference);
- DexMethod forwardingDexMethod =
- appView.dexItemFactory().createMethod(newHolder, newProto, methodName);
- DerivedMethod forwardingMethod = new DerivedMethod(forwardingDexMethod);
- DerivedMethod interfaceMethod =
- new DerivedMethod(methodReference, SyntheticKind.RETARGET_INTERFACE);
- DerivedMethod dispatchMethod =
- new DerivedMethod(methodReference, SyntheticKind.RETARGET_CLASS);
- emulatedVirtualRetarget.put(
- methodReference,
- new EmulatedDispatchMethodDescriptor(
- interfaceMethod, dispatchMethod, forwardingMethod, new LinkedHashMap<>()));
- }
- }
- }
- }
- }
- if (desugaredLibrarySpecification.isLibraryCompilation()) {
- // TODO(b/177977763): This is only a workaround rewriting invokes of j.u.Arrays.deepEquals0
- // to j.u.DesugarArrays.deepEquals0.
- DexItemFactory itemFactory = appView.options().dexItemFactory();
- DexString name = itemFactory.createString("deepEquals0");
- DexProto proto =
- itemFactory.createProto(
- itemFactory.booleanType, itemFactory.objectType, itemFactory.objectType);
- DexMethod source =
- itemFactory.createMethod(
- itemFactory.createType(itemFactory.arraysDescriptor), proto, name);
- DexMethod target =
- computeRetargetMethod(
- source, true, itemFactory.createType("Ljava/util/DesugarArrays;"));
- staticRetarget.put(source, target);
- // TODO(b/181629049): This is only a workaround rewriting invokes of
- // j.u.TimeZone.getTimeZone taking a java.time.ZoneId.
- name = itemFactory.createString("getTimeZone");
- proto =
- itemFactory.createProto(
- itemFactory.createType("Ljava/util/TimeZone;"),
- itemFactory.createType("Ljava/time/ZoneId;"));
- source =
- itemFactory.createMethod(itemFactory.createType("Ljava/util/TimeZone;"), proto, name);
- target =
- computeRetargetMethod(
- source, true, itemFactory.createType("Ljava/util/DesugarTimeZone;"));
- staticRetarget.put(source, target);
- }
- return new RetargetingInfo(
- ImmutableMap.copyOf(staticRetarget),
- ImmutableMap.copyOf(nonEmulatedVirtualRetarget),
- emulatedVirtualRetarget);
- }
-
- DexMethod computeRetargetMethod(DexMethod method, boolean isStatic, DexType newHolder) {
- DexItemFactory factory = appView.dexItemFactory();
- DexProto newProto = isStatic ? method.getProto() : factory.prependHolderToProto(method);
- return factory.createMethod(newHolder, newProto, method.getName());
- }
-
- private boolean isEmulatedInterfaceDispatch(DexClassAndMethod method) {
- // Answers true if this method is already managed through emulated interface dispatch.
- Map<DexType, DexType> emulateLibraryInterface =
- appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface();
- if (emulateLibraryInterface.isEmpty()) {
- return false;
- }
- DexMethod methodToFind = method.getReference();
- // Look-up all superclass and interfaces, if an emulated interface is found, and it implements
- // the method, answers true.
- WorkList<DexClass> worklist = WorkList.newIdentityWorkList(method.getHolder());
- while (worklist.hasNext()) {
- DexClass clazz = worklist.next();
- if (clazz.isInterface()
- && emulateLibraryInterface.containsKey(clazz.getType())
- && clazz.lookupMethod(methodToFind) != null) {
- return true;
- }
- // All super types are library class, or we are doing L8 compilation.
- clazz.forEachImmediateSupertype(
- superType -> {
- DexClass superClass = appView.definitionFor(superType);
- if (superClass != null) {
- worklist.addIfNotSeen(superClass);
- }
- });
- }
- return false;
- }
-
- private List<DexClassAndMethod> findMethodsWithName(DexString methodName, DexClass clazz) {
- List<DexClassAndMethod> found = new ArrayList<>();
- clazz.forEachClassMethodMatching(
- definition -> definition.getName() == methodName, found::add);
- assert !found.isEmpty()
- : "Should have found a method (library specifications) for "
- + clazz.toSourceString()
- + "."
- + methodName
- + ". Maybe the library used for the compilation should be newer.";
- return found;
- }
- }
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineEmulatedInterfaceConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineEmulatedInterfaceConverter.java
index 2411ba0..04cc12b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineEmulatedInterfaceConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineEmulatedInterfaceConverter.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanRewritingFlags;
@@ -44,10 +43,10 @@
Set<DexMethod> dontRewriteInvocation = rewritingFlags.getDontRewriteInvocation();
emulatedInterfaceHierarchy = processEmulatedInterfaceHierarchy(appInfo, emulateInterfaces);
for (DexType itf : emulateInterfaces.keySet()) {
- DexProgramClass itfClass = appInfo.contextIndependentDefinitionFor(itf).asProgramClass();
+ DexClass itfClass = appInfo.contextIndependentDefinitionFor(itf);
assert itfClass != null;
Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedMethods = new IdentityHashMap<>();
- itfClass.forEachProgramVirtualMethodMatching(
+ itfClass.forEachClassMethodMatching(
m -> m.isDefaultMethod() && !dontRewriteInvocation.contains(m.getReference()),
method ->
emulatedMethods.put(
@@ -104,7 +103,6 @@
for (int i = subInterfaces.size() - 1; i >= 0; i--) {
DexClass subInterfaceClass = appInfo.definitionFor(subInterfaces.get(i));
assert subInterfaceClass != null;
- assert subInterfaceClass.isProgramClass();
// Else computation of subInterface would have failed.
// if the method is implemented, extra dispatch is required.
DexEncodedMethod result = subInterfaceClass.lookupVirtualMethod(method);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
index 6ff7428..92efb24 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
@@ -5,22 +5,31 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanRewritingFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineRewritingFlags;
import com.android.tools.r8.utils.DescriptorUtils;
import com.google.common.collect.ImmutableMap;
+import java.util.IdentityHashMap;
import java.util.Map;
public class HumanToMachinePrefixConverter {
private final AppInfoWithClassHierarchy appInfo;
+ private final MachineRewritingFlags.Builder builder;
+ private final String synthesizedPrefix;
+ private final Map<DexType, DexType> reverse = new IdentityHashMap<>();
- public HumanToMachinePrefixConverter(AppInfoWithClassHierarchy appInfo) {
+ public HumanToMachinePrefixConverter(
+ AppInfoWithClassHierarchy appInfo,
+ MachineRewritingFlags.Builder builder,
+ String synthesizedPrefix) {
this.appInfo = appInfo;
+ this.builder = builder;
+ this.synthesizedPrefix = synthesizedPrefix;
}
private DexString toDescriptorPrefix(String prefix) {
@@ -29,20 +38,30 @@
.createString("L" + DescriptorUtils.getBinaryNameFromJavaType(prefix));
}
- public void convertPrefixFlags(
- HumanRewritingFlags rewritingFlags,
- MachineRewritingFlags.Builder builder,
- String synthesizedPrefix) {
+ public void convertPrefixFlags(HumanRewritingFlags rewritingFlags) {
Map<DexString, DexString> descriptorPrefix = convertRewritePrefix(rewritingFlags);
- rewriteClasses(descriptorPrefix, builder);
- rewriteValues(descriptorPrefix, builder, rewritingFlags.getRetargetCoreLibMember());
- rewriteValues(descriptorPrefix, builder, rewritingFlags.getCustomConversions());
- rewriteEmulatedInterface(builder, rewritingFlags.getEmulateLibraryInterface());
- rewriteRetargetKeys(builder, rewritingFlags.getRetargetCoreLibMember(), synthesizedPrefix);
+ rewriteClasses(descriptorPrefix);
+ rewriteValues(descriptorPrefix, rewritingFlags.getRetargetCoreLibMember());
+ rewriteValues(descriptorPrefix, rewritingFlags.getCustomConversions());
+ rewriteEmulatedInterface(rewritingFlags.getEmulateLibraryInterface());
+ rewriteRetargetKeys(rewritingFlags.getRetargetCoreLibMember());
+ rewriteReverse(descriptorPrefix);
}
- public DexType convertJavaNameToDesugaredLibrary(DexType type, String prefix) {
- String convertedPrefix = DescriptorUtils.getJavaTypeFromBinaryName(prefix);
+ // For custom conversions, this is responsible in rewriting backward.
+ private void rewriteReverse(Map<DexString, DexString> descriptorPrefix) {
+ reverse.forEach(
+ (rewrittenType, type) -> {
+ DexType backwardRewrittenType = rewrittenType(descriptorPrefix, rewrittenType);
+ if (backwardRewrittenType != null) {
+ assert backwardRewrittenType == type;
+ builder.rewriteType(rewrittenType, type);
+ }
+ });
+ }
+
+ public DexType convertJavaNameToDesugaredLibrary(DexType type) {
+ String convertedPrefix = DescriptorUtils.getJavaTypeFromBinaryName(synthesizedPrefix);
String interfaceType = type.toString();
int firstPackage = interfaceType.indexOf('.');
return appInfo
@@ -52,40 +71,49 @@
convertedPrefix + interfaceType.substring(firstPackage + 1)));
}
- private void rewriteRetargetKeys(
- MachineRewritingFlags.Builder builder, Map<DexMethod, DexType> retarget, String prefix) {
+ private void rewriteRetargetKeys(Map<DexMethod, DexType> retarget) {
for (DexMethod dexMethod : retarget.keySet()) {
- DexType type = convertJavaNameToDesugaredLibrary(dexMethod.holder, prefix);
+ DexType type = convertJavaNameToDesugaredLibrary(dexMethod.holder);
builder.rewriteDerivedTypeOnly(dexMethod.holder, type);
}
}
- private void rewriteEmulatedInterface(
- MachineRewritingFlags.Builder builder, Map<DexType, DexType> emulateLibraryInterface) {
+ private void rewriteEmulatedInterface(Map<DexType, DexType> emulateLibraryInterface) {
emulateLibraryInterface.forEach(builder::rewriteDerivedTypeOnly);
}
+ private void rewriteType(DexType type, DexType rewrittenType) {
+ builder.rewriteType(type, rewrittenType);
+ reverse.put(rewrittenType, type);
+ }
+
private void rewriteValues(
Map<DexString, DexString> descriptorPrefix,
- MachineRewritingFlags.Builder builder,
Map<?, DexType> flags) {
for (DexType type : flags.values()) {
DexType rewrittenType = rewrittenType(descriptorPrefix, type);
if (rewrittenType != null) {
- builder.rewriteType(type, rewrittenType);
+ rewriteType(type, rewrittenType);
}
}
}
- private void rewriteClasses(
- Map<DexString, DexString> descriptorPrefix, MachineRewritingFlags.Builder builder) {
- for (DexProgramClass clazz : appInfo.classes()) {
- DexType type = clazz.type;
- DexType rewrittenType = rewrittenType(descriptorPrefix, type);
- if (rewrittenType != null) {
- builder.rewriteType(type, rewrittenType);
- }
+ private void rewriteClasses(Map<DexString, DexString> descriptorPrefix) {
+ for (DexClass clazz : appInfo.app().asDirect().libraryClasses()) {
+ rewriteClass(descriptorPrefix, clazz);
}
+ for (DexClass clazz : appInfo.classes()) {
+ rewriteClass(descriptorPrefix, clazz);
+ }
+ }
+
+ private void rewriteClass(Map<DexString, DexString> descriptorPrefix, DexClass clazz) {
+ DexType type = clazz.type;
+ DexType rewrittenType = rewrittenType(descriptorPrefix, type);
+ if (rewrittenType == null) {
+ return;
+ }
+ rewriteType(type, rewrittenType);
}
private DexType rewrittenType(Map<DexString, DexString> descriptorPrefix, DexType type) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java
index 6dce945..b5c1ac3 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java
@@ -92,10 +92,14 @@
DexClass subclass = appInfo.definitionFor(subtype);
MethodResolutionResult resolutionResult =
appInfo.resolveMethodOn(subclass, src.getReference());
- if (resolutionResult.isSuccessfulMemberResolutionResult()
- && resolutionResult.getResolvedMethod().getReference() != src.getReference()) {
- assert false; // Unsupported.
- }
+ // The resolution is not successful when compiling to dex if the method rewritten is missing
+ // in Android.jar.
+ assert !resolutionResult.isSuccessfulMemberResolutionResult()
+ || resolutionResult.getResolvedMethod().getReference() == src.getReference()
+ // There is a difference in the sql library between Android.jar and the JDK which leads
+ // to this resolution when compiling Cf to Cf while the methods do not exist in Android.
+ || (resolutionResult.getResolvedMethod().getHolderType().toString().contains("java.sql")
+ && resolutionResult.getResolvedMethod().getName().toString().equals("toInstant"));
}
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
index bc3a663..23824c5 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion;
+import com.android.tools.r8.ClassFileResourceProvider;
+import com.android.tools.r8.ProgramResourceProvider;
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
@@ -22,15 +24,51 @@
import com.android.tools.r8.utils.Timing;
import java.io.IOException;
import java.nio.file.Path;
+import java.util.List;
import java.util.concurrent.ExecutorService;
public class HumanToMachineSpecificationConverter {
public MachineDesugaredLibrarySpecification convert(
- HumanDesugaredLibrarySpecification humanSpec, Path androidLib, InternalOptions options)
+ HumanDesugaredLibrarySpecification humanSpec,
+ List<ProgramResourceProvider> desugaredJDKLib,
+ List<ClassFileResourceProvider> library,
+ InternalOptions options)
throws IOException {
- DexApplication app = readApp(androidLib, options);
+ assert !humanSpec.isLibraryCompilation() || desugaredJDKLib != null;
+ AndroidApp.Builder builder = AndroidApp.builder();
+ for (ClassFileResourceProvider classFileResourceProvider : library) {
+ builder.addLibraryResourceProvider(classFileResourceProvider);
+ }
+ if (humanSpec.isLibraryCompilation()) {
+ for (ProgramResourceProvider programResourceProvider : desugaredJDKLib) {
+ builder.addProgramResourceProvider(programResourceProvider);
+ }
+ }
+ return internalConvert(humanSpec, builder.build(), options);
+ }
+
+ public MachineDesugaredLibrarySpecification convert(
+ HumanDesugaredLibrarySpecification humanSpec,
+ Path desugaredJDKLib,
+ Path androidLib,
+ InternalOptions options)
+ throws IOException {
+ assert !humanSpec.isLibraryCompilation() || desugaredJDKLib != null;
+ AndroidApp.Builder builder = AndroidApp.builder();
+ if (humanSpec.isLibraryCompilation()) {
+ builder.addProgramFile(desugaredJDKLib);
+ }
+ AndroidApp inputApp = builder.addLibraryFile(androidLib).build();
+ return internalConvert(humanSpec, inputApp, options);
+ }
+
+ public MachineDesugaredLibrarySpecification internalConvert(
+ HumanDesugaredLibrarySpecification humanSpec, AndroidApp inputApp, InternalOptions options)
+ throws IOException {
+ DexApplication app = readApp(inputApp, options);
AppView<?> appView = AppView.createForD8(AppInfo.createInitialAppInfo(app));
+ LibraryValidator.validate(app, humanSpec.getTopLevelFlags().getRequiredCompilationAPILevel());
MachineRewritingFlags machineRewritingFlags =
convertRewritingFlags(
humanSpec.getSynthesizedLibraryClassesPackagePrefix(),
@@ -59,8 +97,8 @@
new HumanToMachineRetargetConverter(appInfo).convertRetargetFlags(rewritingFlags, builder);
new HumanToMachineEmulatedInterfaceConverter(appInfo)
.convertEmulatedInterfaces(rewritingFlags, appInfo, builder);
- new HumanToMachinePrefixConverter(appInfo)
- .convertPrefixFlags(rewritingFlags, builder, synthesizedPrefix);
+ new HumanToMachinePrefixConverter(appInfo, builder, synthesizedPrefix)
+ .convertPrefixFlags(rewritingFlags);
new HumanToMachineWrapperConverter(appInfo).convertWrappers(rewritingFlags, builder);
rewritingFlags
.getCustomConversions()
@@ -75,10 +113,8 @@
return builder.build();
}
- private DexApplication readApp(Path androidLib, InternalOptions options) throws IOException {
- AndroidApp androidApp = AndroidApp.builder().addProgramFile(androidLib).build();
- ApplicationReader applicationReader =
- new ApplicationReader(androidApp, options, Timing.empty());
+ private DexApplication readApp(AndroidApp inputApp, InternalOptions options) throws IOException {
+ ApplicationReader applicationReader = new ApplicationReader(inputApp, options, Timing.empty());
ExecutorService executorService = ThreadUtils.getExecutorService(options);
return applicationReader.read(executorService).toDirect();
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java
index 34bf5fa..e5c9b42 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion;
+import com.android.tools.r8.ClassFileResourceProvider;
import com.android.tools.r8.StringConsumer;
import com.android.tools.r8.StringResource;
import com.android.tools.r8.dex.ApplicationReader;
@@ -65,7 +66,9 @@
InternalOptions options)
throws IOException {
Origin origin = legacySpec.getOrigin();
- DexApplication app = readApp(androidLib, options);
+ AndroidApp androidApp = AndroidApp.builder().addLibraryFile(androidLib).build();
+ DexApplication app = readApp(androidApp, options);
+ LibraryValidator.validate(app, legacySpec.getTopLevelFlags().getRequiredCompilationAPILevel());
HumanTopLevelFlags humanTopLevelFlags = convertTopLevelFlags(legacySpec.getTopLevelFlags());
Int2ObjectArrayMap<HumanRewritingFlags> commonFlags =
convertRewritingFlagMap(legacySpec.getCommonFlags(), app, origin);
@@ -81,11 +84,30 @@
}
public HumanDesugaredLibrarySpecification convert(
+ LegacyDesugaredLibrarySpecification legacySpec,
+ List<ClassFileResourceProvider> library,
+ InternalOptions options)
+ throws IOException {
+ AndroidApp.Builder builder = AndroidApp.builder();
+ for (ClassFileResourceProvider classFileResourceProvider : library) {
+ builder.addLibraryResourceProvider(classFileResourceProvider);
+ }
+ return internalConvert(legacySpec, builder.build(), options);
+ }
+
+ public HumanDesugaredLibrarySpecification convert(
LegacyDesugaredLibrarySpecification legacySpec, Path androidLib, InternalOptions options)
throws IOException {
- DexApplication app = readApp(androidLib, options);
- HumanTopLevelFlags humanTopLevelFlags = convertTopLevelFlags(legacySpec.getTopLevelFlags());
+ AndroidApp androidApp = AndroidApp.builder().addLibraryFile(androidLib).build();
+ return internalConvert(legacySpec, androidApp, options);
+ }
+ public HumanDesugaredLibrarySpecification internalConvert(
+ LegacyDesugaredLibrarySpecification legacySpec, AndroidApp inputApp, InternalOptions options)
+ throws IOException {
+ DexApplication app = readApp(inputApp, options);
+ LibraryValidator.validate(app, legacySpec.getTopLevelFlags().getRequiredCompilationAPILevel());
+ HumanTopLevelFlags humanTopLevelFlags = convertTopLevelFlags(legacySpec.getTopLevelFlags());
// The origin is not maintained in non multi-level specifications.
// It should not matter since the origin is used to report invalid specifications, and
// converting non multi-level specifications should be performed only with *valid*
@@ -95,10 +117,7 @@
HumanRewritingFlags humanRewritingFlags =
convertRewritingFlags(legacySpec.getRewritingFlags(), app, origin);
return new HumanDesugaredLibrarySpecification(
- humanTopLevelFlags,
- humanRewritingFlags,
- legacySpec.isLibraryCompilation(),
- app.dexItemFactory());
+ humanTopLevelFlags, humanRewritingFlags, legacySpec.isLibraryCompilation());
}
private void legacyLibraryFlagHacks(
@@ -134,10 +153,8 @@
libraryFlags.put(level, builder.build());
}
- private DexApplication readApp(Path androidLib, InternalOptions options) throws IOException {
- AndroidApp androidApp = AndroidApp.builder().addLibraryFile(androidLib).build();
- ApplicationReader applicationReader =
- new ApplicationReader(androidApp, options, Timing.empty());
+ private DexApplication readApp(AndroidApp inputApp, InternalOptions options) throws IOException {
+ ApplicationReader applicationReader = new ApplicationReader(inputApp, options, Timing.empty());
ExecutorService executorService = ThreadUtils.getExecutorService(options);
return applicationReader.read(executorService).toDirect();
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LibraryValidator.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LibraryValidator.java
new file mode 100644
index 0000000..b415c354
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LibraryValidator.java
@@ -0,0 +1,36 @@
+// Copyright (c) 2022, 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.desugaredlibrary.specificationconversion;
+
+import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.utils.AndroidApiLevel;
+
+public class LibraryValidator {
+
+ // Estimates if the library passed is at the expected minimum level, if it is not, raise
+ // a warning.
+ public static void validate(DexApplication app, AndroidApiLevel requiredCompilationAPILevel) {
+ DexType levelType;
+ if (requiredCompilationAPILevel.isEqualTo(AndroidApiLevel.O)) {
+ levelType = app.dexItemFactory.createType("Ljava/time/LocalTime;");
+ } else if (requiredCompilationAPILevel.isEqualTo(AndroidApiLevel.R)) {
+ levelType = app.dexItemFactory.createType("Ljava/util/concurrent/Flow;");
+ } else {
+ app.options.reporter.warning(
+ "Unsupported requiredCompilationAPILevel: " + requiredCompilationAPILevel);
+ return;
+ }
+ DexClass dexClass = app.definitionFor(levelType);
+ if (dexClass == null) {
+ app.options.reporter.warning(
+ "Desugared library requires to be compiled with a library file of API greater or equal to"
+ + " "
+ + requiredCompilationAPILevel
+ + ", but it seems the library file passed is of a lower API.");
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
index 758812e..33f7037 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
@@ -24,10 +24,10 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GenericSignature;
import com.android.tools.r8.graph.GenericSignature.ClassTypeSignature;
-import com.android.tools.r8.graph.LibraryMethod;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.MethodResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.DerivedMethod;
import com.android.tools.r8.position.MethodPosition;
import com.android.tools.r8.utils.BooleanBox;
import com.android.tools.r8.utils.BooleanUtils;
@@ -49,7 +49,6 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
-import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import org.objectweb.asm.Opcodes;
@@ -376,12 +375,7 @@
this.dexItemFactory = appView.dexItemFactory();
this.helper = new InterfaceDesugaringSyntheticHelper(appView);
needsLibraryInfo =
- !appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface().isEmpty()
- || !appView
- .options()
- .desugaredLibrarySpecification
- .getRetargetCoreLibMember()
- .isEmpty();
+ appView.options().machineDesugaredLibrarySpecification.hasEmulatedInterfaces();
this.isLiveMethod = isLiveMethod;
}
@@ -510,7 +504,7 @@
DexClass iface = appView.definitionFor(emulatedInterface);
if (iface != null) {
assert iface.isLibraryClass()
- || appView.options().desugaredLibrarySpecification.isLibraryCompilation();
+ || appView.options().machineDesugaredLibrarySpecification.isLibraryCompilation();
workList.addIfNotSeen(iface.getInterfaces());
}
}
@@ -670,10 +664,10 @@
resolveForwardForSignature(
clazz,
wrapper.get(),
- target -> {
+ (target, forward) -> {
if (isLiveMethod(target) && !superInfo.isTargetedByForwards(target)) {
additionalForwards.add(target);
- addForwardingMethod(target, clazz);
+ addForwardingMethod(target, forward, clazz);
}
});
}
@@ -682,7 +676,7 @@
// Looks up a method signature from the point of 'clazz', if it can dispatch to a default method
// the 'addForward' call-back is called with the target of the forward.
private void resolveForwardForSignature(
- DexClass clazz, DexMethod method, Consumer<DexClassAndMethod> addForward) {
+ DexClass clazz, DexMethod method, BiConsumer<DexClassAndMethod, DexMethod> addForward) {
AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
MethodResolutionResult resolutionResult = appInfo.resolveMethodOn(clazz, method);
if (resolutionResult.isFailedResolution()
@@ -722,50 +716,22 @@
resolutionResult.lookupVirtualDispatchTarget(clazz, appInfo);
assert virtualDispatchTarget != null;
- // Don't forward if the target is explicitly marked as 'dont-rewrite'
- if (dontRewrite(virtualDispatchTarget)) {
- return;
- }
-
// If resolution targets a default interface method, forward it.
if (virtualDispatchTarget.isDefaultMethod()) {
- addForward.accept(virtualDispatchTarget);
+ addForward.accept(
+ virtualDispatchTarget,
+ helper.ensureDefaultAsMethodOfCompanionClassStub(virtualDispatchTarget).getReference());
return;
}
- // Remaining edge cases only pertain to desugaring of library methods.
- if (!virtualDispatchTarget.isLibraryMethod() || ignoreLibraryInfo()) {
- return;
+ DerivedMethod forwardingMethod =
+ helper.computeEmulatedInterfaceForwardingMethod(
+ virtualDispatchTarget.getHolder(), virtualDispatchTarget);
+ if (forwardingMethod != null) {
+ DexMethod concreteForwardingMethod =
+ helper.ensureEmulatedInterfaceForwardingMethod(forwardingMethod);
+ addForward.accept(virtualDispatchTarget, concreteForwardingMethod);
}
-
- LibraryMethod libraryMethod = virtualDispatchTarget.asLibraryMethod();
- if (isRetargetMethod(libraryMethod)) {
- addForward.accept(virtualDispatchTarget);
- return;
- }
-
- // If target is a non-interface library class it may be an emulated interface,
- // except on a rewritten type, where L8 has already dealt with the desugaring.
- if (!libraryMethod.getHolder().isInterface()
- && !appView.rewritePrefix.hasRewrittenType(libraryMethod.getHolderType(), appView)) {
- // Here we use step-3 of resolution to find a maximally specific default interface method.
- DexClassAndMethod result =
- appInfo.lookupMaximallySpecificMethod(libraryMethod.getHolder(), method);
- if (result != null && helper.isEmulatedInterface(result.getHolderType())) {
- addForward.accept(result);
- }
- }
- }
-
- private boolean isRetargetMethod(LibraryMethod method) {
- assert needsLibraryInfo();
- assert method.getDefinition().isNonPrivateVirtualMethod();
- return !method.getAccessFlags().isFinal()
- && appView.options().desugaredLibrarySpecification.retargetMethod(method, appView) != null;
- }
-
- private boolean dontRewrite(DexClassAndMethod method) {
- return needsLibraryInfo() && method.getHolder().isLibraryClass() && helper.dontRewrite(method);
}
// Construction of actual forwarding methods.
@@ -830,7 +796,8 @@
// Note: The parameter 'target' may be a public method on a class in case of desugared
// library retargeting (See below target.isInterface check).
- private void addForwardingMethod(DexClassAndMethod target, DexClass clazz) {
+ private void addForwardingMethod(
+ DexClassAndMethod target, DexMethod forwardMethod, DexClass clazz) {
if (!clazz.isProgramClass()) {
return;
}
@@ -847,10 +814,6 @@
// NOTE: Never add a forwarding method to methods of classes unknown or coming from android.jar
// even if this results in invalid code, these classes are never desugared.
// In desugared library, emulated interface methods can be overridden by retarget lib members.
- DexMethod forwardMethod =
- target.getHolder().isInterface()
- ? helper.ensureDefaultAsMethodOfCompanionClassStub(target).getReference()
- : appView.options().desugaredLibrarySpecification.retargetMethod(target, appView);
DexEncodedMethod desugaringForwardingMethod =
DexEncodedMethod.createDesugaringForwardingMethod(
target.getDefinition(), clazz, forwardMethod, dexItemFactory);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceApplicationRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceApplicationRewriter.java
index 74d94e3..d06fee7 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceApplicationRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceApplicationRewriter.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.utils.IterableUtils;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
@@ -25,8 +26,15 @@
public EmulatedInterfaceApplicationRewriter(AppView<?> appView) {
this.appView = appView;
- this.emulatedInterfaces =
- appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface();
+ emulatedInterfaces = new IdentityHashMap<>();
+ appView
+ .options()
+ .machineDesugaredLibrarySpecification
+ .getEmulatedInterfaces()
+ .forEach(
+ (ei, descriptor) -> {
+ emulatedInterfaces.put(ei, descriptor.getRewrittenType());
+ });
}
public void rewriteApplication(DexApplication.Builder<?> builder) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringForTesting.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringForTesting.java
index a3e0164..6636e1e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringForTesting.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringForTesting.java
@@ -4,10 +4,12 @@
package com.android.tools.r8.ir.desugar.itf;
+import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
+
public class InterfaceDesugaringForTesting {
public static String getEmulateLibraryClassNameSuffix() {
- return InterfaceDesugaringSyntheticHelper.EMULATE_LIBRARY_CLASS_NAME_SUFFIX;
+ return SyntheticKind.EMULATED_INTERFACE_CLASS.descriptor;
}
public static String getCompanionClassNameSuffix() {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
index 77d99e5..cb4a537 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
@@ -24,6 +24,7 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexValue.DexValueInt;
@@ -31,19 +32,20 @@
import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.InvalidCode;
import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.graph.MethodResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.ThrowNullCode;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.DerivedMethod;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedDispatchMethodDescriptor;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedInterfaceDescriptor;
import com.android.tools.r8.ir.desugar.itf.EmulatedInterfaceSynthesizerEventConsumer.ClasspathEmulatedInterfaceSynthesizerEventConsumer;
import com.android.tools.r8.synthesis.SyntheticClassBuilder;
import com.android.tools.r8.synthesis.SyntheticMethodBuilder;
import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.structural.Ordered;
import com.google.common.collect.ImmutableList;
-import java.util.Map;
-import java.util.Set;
import java.util.function.Predicate;
public class InterfaceDesugaringSyntheticHelper {
@@ -57,37 +59,37 @@
}
// Use InterfaceDesugaringForTesting for public accesses in tests.
- static final String EMULATE_LIBRARY_CLASS_NAME_SUFFIX = "$-EL";
static final String COMPANION_CLASS_NAME_SUFFIX = "$-CC";
static final String DEFAULT_METHOD_PREFIX = "$default$";
static final String PRIVATE_METHOD_PREFIX = "$private$";
private final AppView<?> appView;
- private final Map<DexType, DexType> emulatedInterfaces;
private final Predicate<DexType> shouldIgnoreFromReportsPredicate;
public InterfaceDesugaringSyntheticHelper(AppView<?> appView) {
this.appView = appView;
- emulatedInterfaces =
- appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface();
-
this.shouldIgnoreFromReportsPredicate = getShouldIgnoreFromReportsPredicate(appView);
}
boolean isEmulatedInterface(DexType itf) {
- return emulatedInterfaces.containsKey(itf);
+ return appView
+ .options()
+ .machineDesugaredLibrarySpecification
+ .getEmulatedInterfaces()
+ .containsKey(itf);
}
boolean isRewrittenEmulatedInterface(DexType itf) {
- return emulatedInterfaces.containsValue(itf);
- }
-
- Set<DexType> getEmulatedInterfaces() {
- return emulatedInterfaces.keySet();
+ return appView
+ .options()
+ .machineDesugaredLibrarySpecification
+ .isEmulatedInterfaceRewrittenType(itf);
}
DexType getEmulatedInterface(DexType type) {
- return emulatedInterfaces.get(type);
+ EmulatedInterfaceDescriptor interfaceDescriptor =
+ appView.options().machineDesugaredLibrarySpecification.getEmulatedInterfaces().get(type);
+ return interfaceDescriptor == null ? null : interfaceDescriptor.getRewrittenType();
}
boolean isInDesugaredLibrary(DexClass clazz) {
@@ -98,17 +100,6 @@
return appView.rewritePrefix.hasRewrittenType(clazz.type, appView);
}
- boolean dontRewrite(DexClassAndMethod method) {
- for (Pair<DexType, DexString> dontRewrite :
- appView.options().desugaredLibrarySpecification.getDontRewriteInvocation()) {
- if (method.getHolderType() == dontRewrite.getFirst()
- && method.getName() == dontRewrite.getSecond()) {
- return true;
- }
- }
- return false;
- }
-
final boolean isCompatibleDefaultMethod(DexEncodedMethod method) {
assert !method.accessFlags.isConstructor();
assert !method.accessFlags.isStatic();
@@ -129,25 +120,15 @@
return true;
}
- public DexMethod emulateInterfaceLibraryMethod(DexClassAndMethod method) {
- DexItemFactory factory = appView.dexItemFactory();
- return factory.createMethod(
- getEmulateLibraryInterfaceClassType(method.getHolderType(), factory),
- factory.prependTypeToProto(method.getHolderType(), method.getProto()),
- method.getName());
+ DexMethod emulatedInterfaceDispatchMethod(DerivedMethod method, DexType holder) {
+ assert method.getHolderKind() == SyntheticKind.EMULATED_INTERFACE_CLASS;
+ DexProto newProto = appView.dexItemFactory().prependHolderToProto(method.getMethod());
+ return appView.dexItemFactory().createMethod(holder, newProto, method.getName());
}
- private static String getEmulateLibraryInterfaceClassDescriptor(String descriptor) {
- return descriptor.substring(0, descriptor.length() - 1)
- + EMULATE_LIBRARY_CLASS_NAME_SUFFIX
- + ";";
- }
-
- public static DexType getEmulateLibraryInterfaceClassType(DexType type, DexItemFactory factory) {
- assert type.isClassType();
- String descriptor = type.descriptor.toString();
- String elTypeDescriptor = getEmulateLibraryInterfaceClassDescriptor(descriptor);
- return factory.createSynthesizedType(elTypeDescriptor);
+ DexMethod emulatedInterfaceInterfaceMethod(DerivedMethod method) {
+ assert method.getHolderKind() == null;
+ return method.getMethod();
}
public static String getCompanionClassDescriptor(String descriptor) {
@@ -167,10 +148,6 @@
return type.descriptor.toString().endsWith(COMPANION_CLASS_NAME_SUFFIX + ";");
}
- public static boolean isEmulatedLibraryClassType(DexType type) {
- return type.descriptor.toString().endsWith(EMULATE_LIBRARY_CLASS_NAME_SUFFIX + ";");
- }
-
// Gets the interface class for a companion class `type`.
DexType getInterfaceClassType(DexType type) {
return getInterfaceClassType(type, appView.dexItemFactory());
@@ -197,9 +174,91 @@
SyntheticClassBuilder::setInterface);
}
- DexClassAndMethod ensureEmulatedInterfaceMethod(
- DexClassAndMethod method, ClasspathEmulatedInterfaceSynthesizerEventConsumer eventConsumer) {
- DexMethod emulatedInterfaceMethod = emulateInterfaceLibraryMethod(method);
+ DexClassAndMethod lookupMaximallySpecificIncludingSelf(
+ DexClass initialResolutionHolder, DexClassAndMethod method) {
+ assert method.getHolderType().isClassType();
+ if (method.getHolder().isInterface()) {
+ return method;
+ }
+ return appView
+ .appInfoForDesugaring()
+ .lookupMaximallySpecificMethod(initialResolutionHolder, method.getReference());
+ }
+
+ EmulatedDispatchMethodDescriptor getEmulatedDispatchDescriptor(
+ DexClass initialResolutionHolder, DexClassAndMethod method) {
+ if (method == null) {
+ return null;
+ }
+ assert initialResolutionHolder != null;
+ // Outside L8 compilation, only library methods can lead to emulated interface dispatch.
+ if (!method.isLibraryMethod() && !appView.options().isDesugaredLibraryCompilation()) {
+ return null;
+ }
+ DexClassAndMethod maximallySpecificMethod =
+ lookupMaximallySpecificIncludingSelf(initialResolutionHolder, method);
+ if (maximallySpecificMethod == null) {
+ return null;
+ }
+ EmulatedDispatchMethodDescriptor descriptor =
+ appView
+ .options()
+ .machineDesugaredLibrarySpecification
+ .getEmulatedInterfaceEmulatedDispatchMethodDescriptor(
+ maximallySpecificMethod.getReference());
+ if (!appView.options().isDesugaredLibraryCompilation()) {
+ return descriptor;
+ }
+ return requiresEmulatedDispatchInL8(method, descriptor) ? descriptor : null;
+ }
+
+ private boolean requiresEmulatedDispatchInL8(
+ DexClassAndMethod method, EmulatedDispatchMethodDescriptor descriptor) {
+ return method.isLibraryMethod()
+ || isEmulatedInterface(method.getHolderType())
+ || (descriptor != null
+ && descriptor.getDispatchCases().containsKey(method.getHolderType()));
+ }
+
+ DerivedMethod computeEmulatedInterfaceDispatchMethod(MethodResolutionResult resolutionResult) {
+ EmulatedDispatchMethodDescriptor descriptor =
+ getEmulatedDispatchDescriptor(
+ resolutionResult.getInitialResolutionHolder(), resolutionResult.getResolutionPair());
+ return descriptor == null ? null : descriptor.getEmulatedDispatchMethod();
+ }
+
+ DerivedMethod computeEmulatedInterfaceForwardingMethod(
+ DexClass initialResolutionHolder, DexClassAndMethod method) {
+ EmulatedDispatchMethodDescriptor descriptor =
+ getEmulatedDispatchDescriptor(initialResolutionHolder, method);
+ if (descriptor == null) {
+ return null;
+ }
+ return descriptor.getDispatchCases().containsKey(method.getHolderType())
+ ? descriptor.getDispatchCases().get(method.getHolderType())
+ : descriptor.getForwardingMethod();
+ }
+
+ DexMethod ensureEmulatedInterfaceForwardingMethod(DerivedMethod method) {
+ if (method.getHolderKind() == null) {
+ return method.getMethod();
+ }
+ assert method.getHolderKind() == SyntheticKind.COMPANION_CLASS;
+ DexClassAndMethod resolvedMethod =
+ appView.appInfoForDesugaring().resolveMethod(method.getMethod(), true).getResolutionPair();
+ return ensureDefaultAsMethodOfCompanionClassStub(resolvedMethod).getReference();
+ }
+
+ DexClassAndMethod ensureEmulatedInterfaceDispatchMethod(
+ DerivedMethod emulatedDispatchMethod,
+ ClasspathEmulatedInterfaceSynthesizerEventConsumer eventConsumer) {
+ assert emulatedDispatchMethod.getHolderKind() == SyntheticKind.EMULATED_INTERFACE_CLASS;
+ DexClassAndMethod method =
+ appView
+ .appInfoForDesugaring()
+ .resolveMethod(emulatedDispatchMethod.getMethod(), true)
+ .getResolutionPair();
+ assert emulatedDispatchMethod.getHolderKind() == SyntheticKind.EMULATED_INTERFACE_CLASS;
if (method.isProgramMethod()) {
assert appView.options().isDesugaredLibraryCompilation();
DexProgramClass emulatedInterface =
@@ -209,8 +268,15 @@
SyntheticKind.EMULATED_INTERFACE_CLASS,
method.asProgramMethod().getHolder(),
appView);
+ DexMethod emulatedInterfaceMethod =
+ emulatedInterfaceDispatchMethod(emulatedDispatchMethod, emulatedInterface.type);
+ assert emulatedInterface.lookupProgramMethod(emulatedInterfaceMethod) != null;
return emulatedInterface.lookupProgramMethod(emulatedInterfaceMethod);
}
+ // The holder is not used.
+ DexMethod emulatedInterfaceMethod =
+ emulatedInterfaceDispatchMethod(
+ emulatedDispatchMethod, appView.dexItemFactory().objectType);
return appView
.getSyntheticItems()
.ensureFixedClasspathClassMethod(
@@ -511,7 +577,7 @@
return appView.rewritePrefix.hasRewrittenType(type, appView)
|| descriptor.endsWith(companionClassNameDescriptorSuffix)
|| isRewrittenEmulatedInterface(type)
- || options.desugaredLibrarySpecification.getCustomConversions().containsValue(type)
+ || options.machineDesugaredLibrarySpecification.isCustomConversionRewrittenType(type)
|| appView.getDontWarnConfiguration().matches(type);
};
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
index 6740441..0227b1f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
@@ -35,7 +35,8 @@
import com.android.tools.r8.ir.desugar.DesugarDescription;
import com.android.tools.r8.ir.desugar.FreshLocalProvider;
import com.android.tools.r8.ir.desugar.LocalStackAllocator;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.DerivedMethod;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
import com.android.tools.r8.ir.desugar.icce.AlwaysThrowingInstructionDesugaring;
import com.android.tools.r8.ir.desugar.lambda.LambdaInstructionDesugaring;
import com.android.tools.r8.ir.desugar.stringconcat.StringConcatInstructionDesugaring;
@@ -53,7 +54,6 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.BiConsumer;
import java.util.function.Predicate;
//
@@ -119,18 +119,31 @@
}
public static void checkForAssumedLibraryTypes(AppInfo appInfo, InternalOptions options) {
- LegacyDesugaredLibrarySpecification spec = options.desugaredLibrarySpecification;
- BiConsumer<DexType, DexType> registerEntry = registerMapEntry(appInfo);
- spec.getEmulateLibraryInterface().forEach(registerEntry);
- spec.getCustomConversions().forEach(registerEntry);
- spec.getRetargetCoreLibMember().forEach((method, types) -> types.forEach(registerEntry));
- }
-
- private static BiConsumer<DexType, DexType> registerMapEntry(AppInfo appInfo) {
- return (key, value) -> {
- registerType(appInfo, key);
- registerType(appInfo, value);
- };
+ MachineDesugaredLibrarySpecification machineDesugaredLibrarySpecification =
+ options.machineDesugaredLibrarySpecification;
+ machineDesugaredLibrarySpecification
+ .getEmulatedInterfaces()
+ .forEach(
+ (ei, descriptor) -> {
+ registerType(appInfo, ei);
+ registerType(appInfo, descriptor.getRewrittenType());
+ descriptor
+ .getEmulatedMethods()
+ .forEach(
+ (method, methodDescriptor) -> {
+ methodDescriptor
+ .getDispatchCases()
+ .keySet()
+ .forEach(t -> registerType(appInfo, t));
+ });
+ });
+ machineDesugaredLibrarySpecification
+ .getCustomConversions()
+ .forEach(
+ (type, conversionPair) -> {
+ registerType(appInfo, type);
+ registerType(appInfo, conversionPair.getFirst());
+ });
}
private static void registerType(AppInfo appInfo, DexType type) {
@@ -156,9 +169,9 @@
}
private void initializeEmulatedInterfaceVariables() {
- Map<DexType, DexType> emulateLibraryInterface =
- options.desugaredLibrarySpecification.getEmulateLibraryInterface();
- for (DexType interfaceType : emulateLibraryInterface.keySet()) {
+ Set<DexType> emulateLibraryInterface =
+ options.machineDesugaredLibrarySpecification.getEmulatedInterfaces().keySet();
+ for (DexType interfaceType : emulateLibraryInterface) {
DexClass emulatedInterfaceClass = appView.definitionFor(interfaceType);
if (emulatedInterfaceClass != null) {
for (DexEncodedMethod encodedMethod :
@@ -449,24 +462,27 @@
}
private DesugarDescription computeEmulatedInterfaceVirtualDispatchOrNull(CfInvoke invoke) {
- DexClassAndMethod defaultMethod =
- defaultMethodForEmulatedDispatchOrNull(invoke.getMethod(), invoke.isInterface());
- if (defaultMethod != null) {
- return DesugarDescription.builder()
- .setDesugarRewrite(
- (freshLocalProvider,
- localStackAllocator,
- eventConsumer,
- context1,
- methodProcessingContext,
- dexItemFactory) ->
- getInvokeStaticInstructions(
- helper
- .ensureEmulatedInterfaceMethod(defaultMethod, eventConsumer)
- .getReference()))
- .build();
+ MethodResolutionResult resolutionResult =
+ appView.appInfoForDesugaring().resolveMethod(invoke.getMethod(), invoke.isInterface());
+ DerivedMethod emulatedDispatchMethod =
+ helper.computeEmulatedInterfaceDispatchMethod(resolutionResult);
+ if (emulatedDispatchMethod == null) {
+ return null;
}
- return null;
+ return DesugarDescription.builder()
+ .setDesugarRewrite(
+ (freshLocalProvider,
+ localStackAllocator,
+ eventConsumer,
+ context1,
+ methodProcessingContext,
+ dexItemFactory) ->
+ getInvokeStaticInstructions(
+ helper
+ .ensureEmulatedInterfaceDispatchMethod(
+ emulatedDispatchMethod, eventConsumer)
+ .getReference()))
+ .build();
}
private DesugarDescription computeInvokeDirect(
@@ -704,103 +720,49 @@
private DesugarDescription computeEmulatedInterfaceInvokeSpecial(
DexClass clazz, DexMethod invokedMethod, ProgramMethod context) {
- DexType emulatedItf = maximallySpecificEmulatedInterfaceOrNull(invokedMethod);
- if (emulatedItf == null) {
- if (clazz.isInterface() && appView.rewritePrefix.hasRewrittenType(clazz.type, appView)) {
- DexClassAndMethod target =
- appView.appInfoForDesugaring().lookupSuperTarget(invokedMethod, context);
- if (target != null && target.getDefinition().isDefaultMethod()) {
- DexClass holder = target.getHolder();
- if (holder.isLibraryClass() && holder.isInterface()) {
- return DesugarDescription.builder()
- .setDesugarRewrite(
- (freshLocalProvider,
- localStackAllocator,
- eventConsumer,
- context13,
- methodProcessingContext,
- dexItemFactory) -> {
- DexClassAndMethod companionTarget =
- helper.ensureDefaultAsMethodOfCompanionClassStub(target);
- acceptCompanionMethod(target, companionTarget, eventConsumer);
- return getInvokeStaticInstructions(companionTarget.getReference());
- })
- .build();
- }
+ DexClassAndMethod superTarget =
+ appView.appInfoForDesugaring().lookupSuperTarget(invokedMethod, context);
+ if (clazz.isInterface() && appView.rewritePrefix.hasRewrittenType(clazz.type, appView)) {
+ if (superTarget != null && superTarget.getDefinition().isDefaultMethod()) {
+ DexClass holder = superTarget.getHolder();
+ if (holder.isLibraryClass() && holder.isInterface()) {
+ return DesugarDescription.builder()
+ .setDesugarRewrite(
+ (freshLocalProvider,
+ localStackAllocator,
+ eventConsumer,
+ context13,
+ methodProcessingContext,
+ dexItemFactory) -> {
+ DexClassAndMethod companionTarget =
+ helper.ensureDefaultAsMethodOfCompanionClassStub(superTarget);
+ acceptCompanionMethod(superTarget, companionTarget, eventConsumer);
+ return getInvokeStaticInstructions(companionTarget.getReference());
+ })
+ .build();
}
}
- return DesugarDescription.nothing();
}
// That invoke super may not resolve since the super method may not be present
// since it's in the emulated interface. We need to force resolution. If it resolves
// to a library method, then it needs to be rewritten.
// If it resolves to a program overrides, the invoke-super can remain.
- DexClassAndMethod superTarget =
- appView.appInfoForDesugaring().lookupSuperTarget(invokedMethod, context);
- if (superTarget != null && superTarget.isLibraryMethod()) {
- // Rewriting is required because the super invoke resolves into a missing
- // method (method is on desugared library). Find out if it needs to be
- // retargeted or if it just calls a companion class method and rewrite.
- DexMethod retargetMethod =
- options.desugaredLibrarySpecification.retargetMethod(superTarget, appView);
- if (retargetMethod != null) {
- return DesugarDescription.builder()
- .setDesugarRewrite(
- (freshLocalProvider,
- localStackAllocator,
- eventConsumer,
- context14,
- methodProcessingContext,
- dexItemFactory) -> getInvokeStaticInstructions(retargetMethod))
- .build();
- }
- DexClassAndMethod emulatedMethod =
- superTarget.getReference().lookupMemberOnClass(appView.definitionFor(emulatedItf));
- if (emulatedMethod == null) {
- assert false;
- return DesugarDescription.nothing();
- }
- return DesugarDescription.builder()
- .setDesugarRewrite(
- (freshLocalProvider,
- localStackAllocator,
- eventConsumer,
- context15,
- methodProcessingContext,
- dexItemFactory) -> {
- DexClassAndMethod companionMethod =
- helper.ensureDefaultAsMethodOfCompanionClassStub(emulatedMethod);
- return getInvokeStaticInstructions(companionMethod.getReference());
- })
- .build();
+ DerivedMethod forwardingMethod =
+ helper.computeEmulatedInterfaceForwardingMethod(clazz, superTarget);
+ if (forwardingMethod == null) {
+ return DesugarDescription.nothing();
}
- return DesugarDescription.nothing();
- }
-
- private DexClassAndMethod defaultMethodForEmulatedDispatchOrNull(
- DexMethod invokedMethod, boolean interfaceBit) {
- DexType emulatedItf = maximallySpecificEmulatedInterfaceOrNull(invokedMethod);
- if (emulatedItf == null) {
- return null;
- }
- // The call potentially ends up in a library class, in which case we need to rewrite, since the
- // code may be in the desugared library.
- SingleResolutionResult resolution =
- appView
- .appInfoForDesugaring()
- .resolveMethod(invokedMethod, interfaceBit)
- .asSingleResolution();
- if (resolution != null
- && (resolution.getResolvedHolder().isLibraryClass()
- || helper.isEmulatedInterface(resolution.getResolvedHolder().type))) {
- DexClassAndMethod defaultMethod =
- appView.definitionFor(emulatedItf).lookupClassMethod(invokedMethod);
- if (defaultMethod != null && !helper.dontRewrite(defaultMethod)) {
- assert !defaultMethod.getAccessFlags().isAbstract();
- return defaultMethod;
- }
- }
- return null;
+ return DesugarDescription.builder()
+ .setDesugarRewrite(
+ (freshLocalProvider,
+ localStackAllocator,
+ eventConsumer,
+ context14,
+ methodProcessingContext,
+ dexItemFactory) ->
+ getInvokeStaticInstructions(
+ helper.ensureEmulatedInterfaceForwardingMethod(forwardingMethod)))
+ .build();
}
private boolean shouldRewriteToInvokeToThrow(
@@ -809,40 +771,6 @@
|| resolutionResult.getResolvedMethod().isStatic() != isInvokeStatic;
}
- private DexType maximallySpecificEmulatedInterfaceOrNull(DexMethod invokedMethod) {
- // Here we try to avoid doing the expensive look-up on all invokes.
- if (!emulatedMethods.contains(invokedMethod.name)) {
- return null;
- }
- DexClass dexClass = appView.definitionFor(invokedMethod.holder);
- // We cannot rewrite the invoke we do not know what the class is.
- if (dexClass == null) {
- return null;
- }
- DexEncodedMethod singleTarget = null;
- if (dexClass.isInterface()) {
- // Look for exact method on the interface.
- singleTarget = dexClass.lookupMethod(invokedMethod);
- }
- if (singleTarget == null) {
- DexClassAndMethod result =
- appView.appInfoForDesugaring().lookupMaximallySpecificMethod(dexClass, invokedMethod);
- if (result != null) {
- singleTarget = result.getDefinition();
- }
- }
- if (singleTarget == null) {
- // At this point we are in a library class. Failures can happen with NoSuchMethod if a
- // library class implement a method with same signature but not related to emulated
- // interfaces.
- return null;
- }
- if (!singleTarget.isAbstract() && helper.isEmulatedInterface(singleTarget.getHolderType())) {
- return singleTarget.getHolderType();
- }
- return null;
- }
-
private boolean isNonDesugaredLibraryClass(DexClass clazz) {
return clazz.isLibraryClass() && !helper.isInDesugaredLibrary(clazz);
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java
index f712cb4..7e8a2cc 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java
@@ -5,11 +5,9 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ProgramMethod;
@@ -25,27 +23,16 @@
import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
import com.android.tools.r8.synthesis.SyntheticProgramClassBuilder;
import com.android.tools.r8.utils.StringDiagnostic;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
public final class ProgramEmulatedInterfaceSynthesizer implements CfClassSynthesizerDesugaring {
private final AppView<?> appView;
private final InterfaceDesugaringSyntheticHelper helper;
- private final Map<DexType, List<DexType>> emulatedInterfacesHierarchy;
public static ProgramEmulatedInterfaceSynthesizer create(AppView<?> appView) {
if (!appView.options().isDesugaredLibraryCompilation()
- || appView.options().desugaredLibrarySpecification.getEmulateLibraryInterface().isEmpty()) {
+ || !appView.options().machineDesugaredLibrarySpecification.hasEmulatedInterfaces()) {
return null;
}
return new ProgramEmulatedInterfaceSynthesizer(appView);
@@ -54,53 +41,11 @@
public ProgramEmulatedInterfaceSynthesizer(AppView<?> appView) {
this.appView = appView;
helper = new InterfaceDesugaringSyntheticHelper(appView);
- // Avoid the computation outside L8 since it is not needed.
- emulatedInterfacesHierarchy =
- appView.options().isDesugaredLibraryCompilation()
- ? processEmulatedInterfaceHierarchy()
- : Collections.emptyMap();
- }
-
- private Map<DexType, List<DexType>> processEmulatedInterfaceHierarchy() {
- Map<DexType, List<DexType>> emulatedInterfacesHierarchy = new IdentityHashMap<>();
- Set<DexType> processed = Sets.newIdentityHashSet();
- ArrayList<DexType> emulatedInterfacesSorted = new ArrayList<>(helper.getEmulatedInterfaces());
- emulatedInterfacesSorted.sort(DexType::compareTo);
- for (DexType interfaceType : emulatedInterfacesSorted) {
- processEmulatedInterfaceHierarchy(interfaceType, processed, emulatedInterfacesHierarchy);
- }
- return emulatedInterfacesHierarchy;
- }
-
- private void processEmulatedInterfaceHierarchy(
- DexType interfaceType,
- Set<DexType> processed,
- Map<DexType, List<DexType>> emulatedInterfacesHierarchy) {
- if (processed.contains(interfaceType)) {
- return;
- }
- emulatedInterfacesHierarchy.put(interfaceType, new ArrayList<>());
- processed.add(interfaceType);
- DexClass theInterface = appView.definitionFor(interfaceType);
- if (theInterface == null) {
- return;
- }
- LinkedList<DexType> workList = new LinkedList<>(Arrays.asList(theInterface.interfaces.values));
- while (!workList.isEmpty()) {
- DexType next = workList.removeLast();
- if (helper.isEmulatedInterface(next)) {
- processEmulatedInterfaceHierarchy(next, processed, emulatedInterfacesHierarchy);
- emulatedInterfacesHierarchy.get(next).add(interfaceType);
- DexClass nextClass = appView.definitionFor(next);
- if (nextClass != null) {
- workList.addAll(Arrays.asList(nextClass.interfaces.values));
- }
- }
- }
}
DexProgramClass synthesizeProgramEmulatedInterface(
DexProgramClass emulatedInterface,
+ EmulatedInterfaceDescriptor emulatedInterfaceDescriptor,
L8ProgramEmulatedInterfaceSynthesizerEventConsumer eventConsumer) {
return appView
.getSyntheticItems()
@@ -108,20 +53,26 @@
SyntheticNaming.SyntheticKind.EMULATED_INTERFACE_CLASS,
emulatedInterface,
appView,
- builder -> synthesizeEmulateInterfaceMethods(emulatedInterface, builder),
+ builder ->
+ synthesizeEmulateInterfaceMethods(
+ emulatedInterface, emulatedInterfaceDescriptor, builder),
eventConsumer::acceptProgramEmulatedInterface);
}
private void synthesizeEmulateInterfaceMethods(
- DexProgramClass emulatedInterface, SyntheticProgramClassBuilder builder) {
- assert helper.isEmulatedInterface(emulatedInterface.type);
+ DexProgramClass emulatedInterface,
+ EmulatedInterfaceDescriptor emulatedInterfaceDescriptor,
+ SyntheticProgramClassBuilder builder) {
emulatedInterface.forEachProgramVirtualMethodMatching(
- DexEncodedMethod::isDefaultMethod,
+ m -> emulatedInterfaceDescriptor.getEmulatedMethods().containsKey(m.getReference()),
method ->
builder.addMethod(
methodBuilder ->
synthesizeEmulatedInterfaceMethod(
- method, emulatedInterface, builder.getType(), methodBuilder)));
+ method,
+ emulatedInterfaceDescriptor.getEmulatedMethods().get(method.getReference()),
+ builder.getType(),
+ methodBuilder)));
}
private DexMethod emulatedMethod(DerivedMethod method, DexType holder) {
@@ -137,24 +88,17 @@
private void synthesizeEmulatedInterfaceMethod(
ProgramMethod method,
- DexProgramClass theInterface,
+ EmulatedDispatchMethodDescriptor descriptor,
DexType dispatchType,
SyntheticMethodBuilder methodBuilder) {
assert !method.getDefinition().isStatic();
- if (appView.options().testing.machineDesugaredLibrarySpecification != null) {
- synthesizeEmulatedInterfaceMethodFromMachineSpecification(
- method, theInterface, dispatchType, methodBuilder);
- return;
- }
- DexMethod emulatedMethod = helper.emulateInterfaceLibraryMethod(method);
- DexMethod itfMethod =
- method
- .getReference()
- .withHolder(helper.getEmulatedInterface(theInterface.type), appView.dexItemFactory());
+ DexMethod emulatedMethod =
+ helper.emulatedInterfaceDispatchMethod(
+ descriptor.getEmulatedDispatchMethod(), dispatchType);
+ DexMethod itfMethod = helper.emulatedInterfaceInterfaceMethod(descriptor.getInterfaceMethod());
DexMethod companionMethod =
- helper.ensureDefaultAsMethodOfProgramCompanionClassStub(method).getReference();
- LinkedHashMap<DexType, DexMethod> extraDispatchCases =
- getDispatchCases(method, theInterface, companionMethod);
+ helper.ensureEmulatedInterfaceForwardingMethod(descriptor.getForwardingMethod());
+ LinkedHashMap<DexType, DexMethod> extraDispatchCases = resolveDispatchCases(descriptor);
methodBuilder
.setName(emulatedMethod.getName())
.setProto(emulatedMethod.getProto())
@@ -170,162 +114,40 @@
.generateCfCode());
}
- private void synthesizeEmulatedInterfaceMethodFromMachineSpecification(
- ProgramMethod method,
- DexProgramClass theInterface,
- DexType dispatchType,
- SyntheticMethodBuilder methodBuilder) {
- EmulatedInterfaceDescriptor emulatedInterfaceDescriptor =
- appView
- .options()
- .testing
- .machineDesugaredLibrarySpecification
- .getRewritingFlags()
- .getEmulatedInterfaces()
- .get(theInterface.type);
- EmulatedDispatchMethodDescriptor descriptor =
- emulatedInterfaceDescriptor.getEmulatedMethods().get(method.getReference());
- DexMethod emulatedMethod = emulatedMethod(descriptor.getEmulatedDispatchMethod(), dispatchType);
- DexMethod itfMethod = interfaceMethod(descriptor.getInterfaceMethod());
- // TODO(b/184026720): Adapt to use the forwarding method.
- DerivedMethod forwardingMethod = descriptor.getForwardingMethod();
- assert forwardingMethod.getHolderKind() == SyntheticKind.COMPANION_CLASS;
- assert forwardingMethod.getMethod() == method.getReference();
- DexMethod companionMethod =
- helper.ensureDefaultAsMethodOfProgramCompanionClassStub(method).getReference();
- LinkedHashMap<DexType, DexMethod> extraDispatchCases = resolveDispatchCases(descriptor);
- methodBuilder
- .setName(descriptor.getEmulatedDispatchMethod().getName())
- .setProto(descriptor.getEmulatedDispatchMethod().getProto())
- .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
- .setCode(
- emulatedInterfaceMethod ->
- new EmulateDispatchSyntheticCfCodeProvider(
- emulatedMethod.getHolderType(),
- companionMethod,
- itfMethod,
- extraDispatchCases,
- appView)
- .generateCfCode());
- }
-
private LinkedHashMap<DexType, DexMethod> resolveDispatchCases(
EmulatedDispatchMethodDescriptor descriptor) {
LinkedHashMap<DexType, DexMethod> extraDispatchCases = new LinkedHashMap<>();
descriptor
.getDispatchCases()
.forEach(
- (type, derivedMethod) -> {
- DexMethod caseMethod;
- if (derivedMethod.getHolderKind() == null) {
- caseMethod = derivedMethod.getMethod();
- } else {
- assert derivedMethod.getHolderKind() == SyntheticKind.COMPANION_CLASS;
- ProgramMethod resolvedProgramMethod =
- appView
- .appInfoForDesugaring()
- .resolveMethod(derivedMethod.getMethod(), true)
- .getResolvedProgramMethod();
- caseMethod =
- helper
- .ensureDefaultAsMethodOfProgramCompanionClassStub(resolvedProgramMethod)
- .getReference();
- }
- extraDispatchCases.put(type, caseMethod);
- });
+ (type, derivedMethod) ->
+ extraDispatchCases.put(
+ type, helper.ensureEmulatedInterfaceForwardingMethod(derivedMethod)));
return extraDispatchCases;
}
- private LinkedHashMap<DexType, DexMethod> getDispatchCases(
- ProgramMethod method, DexProgramClass theInterface, DexMethod companionMethod) {
- // To properly emulate the library interface call, we need to compute the interfaces
- // inheriting from the interface and manually implement the dispatch with instance of.
- // The list guarantees that an interface is always after interfaces it extends,
- // hence reverse iteration.
- List<DexType> subInterfaces = emulatedInterfacesHierarchy.get(theInterface.type);
- LinkedHashMap<DexType, DexMethod> extraDispatchCases = new LinkedHashMap<>();
- // In practice, there is usually a single case (except for tests),
- // so we do not bother to make the following loop more clever.
- Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
- appView.options().desugaredLibrarySpecification.getRetargetCoreLibMember();
- for (DexString methodName : retargetCoreLibMember.keySet()) {
- if (method.getName() == methodName) {
- for (DexType inType : retargetCoreLibMember.get(methodName).keySet()) {
- DexClass inClass = appView.definitionFor(inType);
- if (inClass != null && implementsInterface(inClass, theInterface.type)) {
- extraDispatchCases.put(
- inType,
- appView
- .dexItemFactory()
- .createMethod(
- retargetCoreLibMember.get(methodName).get(inType),
- appView
- .dexItemFactory()
- .protoWithDifferentFirstParameter(companionMethod.proto, inType),
- method.getName()));
- }
- }
- }
- }
- if (subInterfaces != null) {
- for (int i = subInterfaces.size() - 1; i >= 0; i--) {
- DexClass subInterfaceClass = appView.definitionFor(subInterfaces.get(i));
- assert subInterfaceClass != null;
- assert subInterfaceClass.isProgramClass();
- // Else computation of subInterface would have failed.
- // if the method is implemented, extra dispatch is required.
- DexEncodedMethod result = subInterfaceClass.lookupVirtualMethod(method.getReference());
- if (result != null && !result.isAbstract()) {
- assert result.isDefaultMethod();
- DexMethod forward =
- helper
- .ensureDefaultAsMethodOfProgramCompanionClassStub(
- new ProgramMethod(subInterfaceClass.asProgramClass(), result))
- .getReference();
- extraDispatchCases.put(subInterfaceClass.type, forward);
- }
- }
- } else {
- assert extraDispatchCases.size() <= 1;
- }
- return extraDispatchCases;
- }
-
- private boolean implementsInterface(DexClass clazz, DexType interfaceType) {
- LinkedList<DexType> workList = new LinkedList<>(Arrays.asList(clazz.interfaces.values));
- while (!workList.isEmpty()) {
- DexType next = workList.removeLast();
- if (interfaceType == next) {
- return true;
- }
- DexClass nextClass = appView.definitionFor(next);
- if (nextClass != null) {
- workList.addAll(Arrays.asList(nextClass.interfaces.values));
- }
- }
- return false;
- }
-
@Override
public void synthesizeClasses(CfClassSynthesizerDesugaringEventConsumer eventConsumer) {
assert appView.options().isDesugaredLibraryCompilation();
- for (DexType emulatedInterfaceType : helper.getEmulatedInterfaces()) {
- DexClass emulatedInterfaceClazz = appView.definitionFor(emulatedInterfaceType);
- if (emulatedInterfaceClazz == null || !emulatedInterfaceClazz.isProgramClass()) {
- warnMissingEmulatedInterface(emulatedInterfaceType);
- continue;
- }
- DexProgramClass emulatedInterface = emulatedInterfaceClazz.asProgramClass();
- assert emulatedInterface != null;
- if (!appView.isAlreadyLibraryDesugared(emulatedInterface)
- && needsEmulateInterfaceLibrary(emulatedInterface)) {
- synthesizeProgramEmulatedInterface(emulatedInterface, eventConsumer);
- }
- }
- }
-
- private boolean needsEmulateInterfaceLibrary(DexClass emulatedInterface) {
- return Iterables.any(emulatedInterface.methods(), DexEncodedMethod::isDefaultMethod);
+ appView
+ .options()
+ .machineDesugaredLibrarySpecification
+ .getEmulatedInterfaces()
+ .forEach(
+ (emulatedInterfaceType, emulatedInterfaceDescriptor) -> {
+ DexClass emulatedInterfaceClazz = appView.definitionFor(emulatedInterfaceType);
+ if (emulatedInterfaceClazz == null || !emulatedInterfaceClazz.isProgramClass()) {
+ warnMissingEmulatedInterface(emulatedInterfaceType);
+ return;
+ }
+ DexProgramClass emulatedInterface = emulatedInterfaceClazz.asProgramClass();
+ assert emulatedInterface != null;
+ if (!appView.isAlreadyLibraryDesugared(emulatedInterface)
+ && !emulatedInterfaceDescriptor.getEmulatedMethods().isEmpty()) {
+ synthesizeProgramEmulatedInterface(
+ emulatedInterface, emulatedInterfaceDescriptor, eventConsumer);
+ }
+ });
}
private void warnMissingEmulatedInterface(DexType interfaceType) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/AssertionsRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/AssertionsRewriter.java
index ba2c90f..0da7886 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/AssertionsRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/AssertionsRewriter.java
@@ -12,19 +12,32 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.DominatorTree;
+import com.android.tools.r8.ir.code.FieldInstruction;
+import com.android.tools.r8.ir.code.Goto;
import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.If;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.InvokeStatic;
import com.android.tools.r8.ir.code.StaticGet;
import com.android.tools.r8.ir.code.StaticPut;
+import com.android.tools.r8.ir.code.Throw;
+import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.utils.AssertionConfigurationWithDefault;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.LazyBox;
import com.android.tools.r8.utils.ThrowingCharIterator;
import com.android.tools.r8.utils.Timing;
+import com.android.tools.r8.utils.WorkList;
+import com.google.common.collect.ImmutableList;
import java.io.UTFDataFormatException;
+import java.util.IdentityHashMap;
import java.util.List;
+import java.util.Map;
import java.util.stream.Collectors;
public class AssertionsRewriter {
@@ -72,11 +85,11 @@
}
}
- public boolean isEnabled() {
+ public boolean isCompileTimeEnabled() {
return entry.isCompileTimeEnabled();
}
- public boolean isDisabled() {
+ public boolean isCompileTimeDisabled() {
return entry.isCompileTimeDisabled();
}
@@ -87,6 +100,11 @@
public boolean isAssertionHandler() {
return entry.isAssertionHandler();
}
+
+ public MethodReference getAssertionHandler() {
+ assert isAssertionHandler();
+ return entry.getAssertionHandler();
+ }
}
private final AppView<?> appView;
@@ -322,6 +340,7 @@
if (enabled) {
timing.begin("Rewrite assertions");
runInternal(method, code);
+ assert code.isConsistentSSA();
timing.end();
}
}
@@ -343,6 +362,39 @@
}
clinit = clazz.getClassInitializer();
}
+ // For the transformation to rewrite the throw with a callback collect information on the
+ // blocks covered by the if (!$assertionsDisabled or ENABLED) condition together with weather
+ // the assertion handling is on the true or false branch.
+ Map<If, Boolean> assertionEntryIfs = new IdentityHashMap<>();
+ Map<Throw, BasicBlock> throwSuccessorAfterHandler = new IdentityHashMap<>();
+ if (configuration.isAssertionHandler()) {
+ LazyBox<DominatorTree> dominatorTree = new LazyBox<>(() -> new DominatorTree(code));
+ code.getBlocks()
+ .forEach(
+ basicBlock -> {
+ If theIf = isCheckAssertionsEnabledBlock(basicBlock);
+ if (theIf != null) {
+ // All blocks dominated by the if is the assertion code. For Java it is on the
+ // false branch and for Kotlin on the true branch (for Java it is negated
+ // $assertionsDisabled field and for Kotlin it is the ENABLED field).
+ boolean conditionForAssertionBlock =
+ !isUsingJavaAssertionsDisabledField(
+ theIf.lhs().getDefinition().asStaticGet());
+ BasicBlock assertionBlockEntry =
+ theIf.targetFromBoolean(conditionForAssertionBlock);
+ List<BasicBlock> blocks =
+ dominatorTree.computeIfAbsent().dominatedBlocks(assertionBlockEntry);
+ Throw throwInstruction = isAlwaysThrowingEntry(assertionBlockEntry, blocks);
+ if (throwInstruction != null) {
+ assertionEntryIfs.put(theIf, conditionForAssertionBlock);
+ throwSuccessorAfterHandler.put(
+ throwInstruction, theIf.targetFromBoolean(!conditionForAssertionBlock));
+ }
+ }
+ });
+ }
+ assert assertionEntryIfs.size() == throwSuccessorAfterHandler.size();
+
// For javac generated code it is assumed that the code in <clinit> will tell if the code
// in other methods of the class can have assertion checks.
boolean isInitializerEnablingJavaVmAssertions =
@@ -363,22 +415,57 @@
} else if (current.isStaticPut()) {
StaticPut staticPut = current.asStaticPut();
if (isInitializerEnablingJavaVmAssertions
- && staticPut.getField().name == dexItemFactory.assertionsDisabled) {
+ && isUsingJavaAssertionsDisabledField(staticPut)) {
iterator.remove();
}
} else if (current.isStaticGet()) {
StaticGet staticGet = current.asStaticGet();
// Rewrite $assertionsDisabled getter (only if the initializer enabled assertions).
if (isInitializerEnablingJavaVmAssertions
- && staticGet.getField().name == dexItemFactory.assertionsDisabled) {
- iterator.replaceCurrentInstruction(
- code.createIntConstant(configuration.isDisabled() ? 1 : 0, current.getLocalInfo()));
+ && isUsingJavaAssertionsDisabledField(staticGet)) {
+ // For assertion handler rewrite just leave the static get, as it will become dead code.
+ if (!configuration.isAssertionHandler()) {
+ iterator.replaceCurrentInstruction(
+ code.createIntConstant(
+ configuration.isCompileTimeDisabled() ? 1 : 0, current.getLocalInfo()));
+ }
}
// Rewrite kotlin._Assertions.ENABLED getter.
if (staticGet.getField() == dexItemFactory.kotlin.assertions.enabledField) {
- iterator.replaceCurrentInstruction(
- code.createIntConstant(
- kotlinTransformation.isDisabled() ? 0 : 1, current.getLocalInfo()));
+ // For assertion handler rewrite just leave the static get, as it will become dead code.
+ if (!configuration.isAssertionHandler()) {
+ iterator.replaceCurrentInstruction(
+ code.createIntConstant(
+ kotlinTransformation.isCompileTimeDisabled() ? 0 : 1, current.getLocalInfo()));
+ }
+ }
+ }
+
+ // Rewriting of if and throw to replace throw with invoke of the assertion handler.
+ if (configuration.isAssertionHandler()) {
+ if (current.isIf()) {
+ If ifInstruction = current.asIf();
+ if (assertionEntryIfs.containsKey(ifInstruction)) {
+ ifInstruction
+ .targetFromBoolean(!assertionEntryIfs.get(ifInstruction))
+ .unlinkSinglePredecessorSiblingsAllowed();
+ ifInstruction.lhs().removeUser(ifInstruction);
+ iterator.replaceCurrentInstruction(new Goto());
+ }
+ } else if (current.isThrow()) {
+ Throw throwInstruction = current.asThrow();
+ if (throwSuccessorAfterHandler.containsKey(throwInstruction)) {
+ BasicBlock throwingBlock = throwInstruction.getBlock();
+ iterator.replaceCurrentInstruction(
+ new InvokeStatic(
+ dexItemFactory.createMethod(configuration.getAssertionHandler()),
+ null,
+ ImmutableList.of(throwInstruction.exception())));
+ Goto gotoBlockAfterAssertion = new Goto(throwingBlock);
+ gotoBlockAfterAssertion.setPosition(throwInstruction.getPosition());
+ throwingBlock.link(throwSuccessorAfterHandler.get(throwInstruction));
+ iterator.add(gotoBlockAfterAssertion);
+ }
}
}
}
@@ -389,7 +476,7 @@
ConfigurationEntryWithDexString configuration,
InstructionListIterator iterator,
InvokeMethod invoke) {
- if (iterator.hasNext() && configuration.isDisabled()) {
+ if (iterator.hasNext() && configuration.isCompileTimeDisabled()) {
// Check if the invocation of Class.desiredAssertionStatus() is followed by a static
// put to kotlin._Assertions.ENABLED, and if so remove both instructions.
// See comment in ClassInitializerAssertionEnablingAnalysis for the expected instruction
@@ -416,7 +503,63 @@
iterator.replaceCurrentInstruction(code.createIntConstant(0));
}
} else {
- iterator.replaceCurrentInstruction(code.createIntConstant(configuration.isEnabled() ? 1 : 0));
+ iterator.replaceCurrentInstruction(
+ code.createIntConstant(configuration.isCompileTimeEnabled() ? 1 : 0));
}
}
+
+ private boolean isUsingAssertionsControlField(FieldInstruction instruction) {
+ return isUsingJavaAssertionsDisabledField(instruction)
+ || isUsingKotlinAssertionsEnabledField(instruction);
+ }
+
+ private boolean isUsingJavaAssertionsDisabledField(FieldInstruction instruction) {
+ // This does not check the holder, as for inner classe the field is read from the outer class
+ // and not the class itself.
+ return instruction.getField().getName() == dexItemFactory.assertionsDisabled
+ && instruction.getField().getType() == dexItemFactory.booleanType;
+ }
+
+ private boolean isUsingKotlinAssertionsEnabledField(FieldInstruction instruction) {
+ return instruction.getField() == dexItemFactory.kotlin.assertions.enabledField;
+ }
+
+ private If isCheckAssertionsEnabledBlock(BasicBlock basicBlock) {
+ if (!basicBlock.exit().isIf()) {
+ return null;
+ }
+ If theIf = basicBlock.exit().asIf();
+ if (!theIf.isZeroTest()
+ || !theIf.lhs().isDefinedByInstructionSatisfying(Instruction::isStaticGet)) {
+ return null;
+ }
+ StaticGet staticGet = theIf.lhs().getDefinition().asStaticGet();
+ return isUsingAssertionsControlField(staticGet)
+ && staticGet.value().hasSingleUniqueUser()
+ && !staticGet.value().hasPhiUsers()
+ ? theIf
+ : null;
+ }
+
+ private Throw isAlwaysThrowingEntry(BasicBlock block, List<BasicBlock> blocks) {
+ WorkList<BasicBlock> workList = WorkList.newIdentityWorkList(block);
+ Throw theThrow = null;
+ while (workList.hasNext()) {
+ BasicBlock current = workList.next();
+ workList.addIfNotSeen(current.getNormalSuccessors());
+ if (!blocks.containsAll(current.getNormalSuccessors())) {
+ return null;
+ }
+ if (current.exit().isReturn()) {
+ return null;
+ }
+ if (current.exit().isThrow()) {
+ if (theThrow != null) {
+ return null;
+ }
+ theThrow = current.exit().asThrow();
+ }
+ }
+ return theThrow;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index a658752..fba3991 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -10,7 +10,6 @@
import com.android.tools.r8.androidapi.AvailableApiExceptions;
import com.android.tools.r8.graph.AccessFlags;
-import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexClassAndMethod;
@@ -544,9 +543,8 @@
}
InlineeWithReason buildInliningIR(
- AppView<? extends AppInfoWithClassHierarchy> appView,
+ AppView<AppInfoWithLiveness> appView,
InvokeMethod invoke,
- ProgramMethod context,
InliningIRProvider inliningIRProvider,
LensCodeRewriter lensCodeRewriter) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
@@ -715,12 +713,10 @@
private void synthesizeInitClass(IRCode code) {
List<Value> arguments = code.collectArguments();
- BasicBlock entryBlock = code.entryBlock();
-
+ BasicBlock block = code.entryBlock();
// Insert a new block between the last argument instruction and the first actual instruction
// of the method.
- BasicBlock initClassBlock =
- entryBlock.listIterator(code, arguments.size()).split(code, 0, null);
+ BasicBlock initClassBlock = block.listIterator(code, arguments.size()).split(code, 0, null);
assert !initClassBlock.hasCatchHandlers();
InstructionListIterator iterator = initClassBlock.listIterator(code);
@@ -1018,8 +1014,7 @@
}
InlineeWithReason inlinee =
- action.buildInliningIR(
- appView, invoke, context, inliningIRProvider, lensCodeRewriter);
+ action.buildInliningIR(appView, invoke, inliningIRProvider, lensCodeRewriter);
if (strategy.willExceedBudget(
code, invoke, inlinee, block, whyAreYouNotInliningReporter)) {
assert whyAreYouNotInliningReporter.unsetReasonHasBeenReportedFlag();
@@ -1286,7 +1281,6 @@
Timing timing)
throws ExecutionException {
postMethodProcessorBuilder
- .getMethodsToReprocessBuilder()
.rewrittenWithLens(appView)
.merge(
singleInlineCallers
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MultiCallerInliner.java b/src/main/java/com/android/tools/r8/ir/optimize/MultiCallerInliner.java
index afe3547..8312643 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MultiCallerInliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MultiCallerInliner.java
@@ -199,7 +199,6 @@
LongLivedProgramMethodSetBuilder<ProgramMethodSet> multiInlineCallers =
timing.time("Needs inlining analysis", () -> computeMultiInlineCallerMethods(callGraph));
postMethodProcessorBuilder
- .getMethodsToReprocessBuilder()
.rewrittenWithLens(appView)
.merge(multiInlineCallers);
timing.end();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
index 984b6c1..bcef49c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
@@ -40,6 +40,7 @@
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoCollection;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
+import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.Sets;
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
@@ -91,7 +92,9 @@
}
public static boolean shouldRun(AppView<?> appView, IRCode code) {
- return appView.options().enableRedundantFieldLoadElimination
+ InternalOptions options = appView.options();
+ return options.enableRedundantFieldLoadElimination
+ && !options.debug
&& (code.metadata().mayHaveArrayGet()
|| code.metadata().mayHaveFieldInstruction()
|| code.metadata().mayHaveInitClass());
@@ -553,10 +556,6 @@
}
private void handleArrayGet(InstructionListIterator it, ArrayGet arrayGet) {
- if (arrayGet.outValue().hasLocalInfo()) {
- return;
- }
-
Value array = arrayGet.array().getAliasedValue();
Value index = arrayGet.index().getAliasedValue();
ArraySlot arraySlot = ArraySlot.create(array, index, arrayGet.getMemberType());
@@ -594,11 +593,6 @@
InstanceGet instanceGet,
DexClassAndField field,
AssumeRemover assumeRemover) {
- if (instanceGet.outValue().hasLocalInfo()) {
- clearMostRecentInstanceFieldWrite(instanceGet, field);
- return;
- }
-
Value object = instanceGet.object().getAliasedValue();
FieldAndObject fieldAndObject = new FieldAndObject(field.getReference(), object);
FieldValue replacement = activeState.getInstanceFieldValue(fieldAndObject);
@@ -692,12 +686,6 @@
AssumeRemover assumeRemover) {
markClassAsInitialized(field.getHolderType());
- if (staticGet.outValue().hasLocalInfo()) {
- killNonFinalActiveFields(staticGet);
- clearMostRecentStaticFieldWrite(staticGet, field);
- return;
- }
-
FieldValue replacement = activeState.getStaticFieldValue(field.getReference());
if (replacement != null) {
markAssumeDynamicTypeUsersForRemoval(staticGet, replacement, assumeRemover);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/SimpleDominatingEffectAnalysis.java b/src/main/java/com/android/tools/r8/ir/optimize/SimpleDominatingEffectAnalysis.java
index ae95f9e..0f68783 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/SimpleDominatingEffectAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/SimpleDominatingEffectAnalysis.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.optimize;
+import static com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query.DIRECTLY;
import static com.android.tools.r8.ir.optimize.SimpleDominatingEffectAnalysis.InstructionEffect.NO_EFFECT;
import static com.android.tools.r8.ir.optimize.SimpleDominatingEffectAnalysis.InstructionEffect.OTHER_EFFECT;
import static com.android.tools.r8.utils.TraversalContinuation.BREAK;
@@ -11,10 +12,12 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.DepthFirstSearchWorkListBase.DFSNodeWithState;
import com.android.tools.r8.utils.DepthFirstSearchWorkListBase.StatefulDepthFirstSearchWorkList;
import com.android.tools.r8.utils.IntBox;
@@ -201,6 +204,10 @@
return result.isNotSatisfied();
}
+ public boolean isSatisfied() {
+ return result.isSatisfied();
+ }
+
public boolean isPartial() {
return result.isPartial();
}
@@ -328,4 +335,35 @@
: NO_EFFECT;
});
}
+
+ public static SimpleEffectAnalysisResult triggersClassInitializationBeforeAnyStaticRead(
+ AppView<AppInfoWithLiveness> appView, IRCode code) {
+ assert code.context().getDefinition().isStatic();
+ ProgramMethod context = code.context();
+ return run(
+ code,
+ instruction -> {
+ if (instruction.definitelyTriggersClassInitialization(
+ context.getHolderType(),
+ context,
+ appView,
+ DIRECTLY,
+ AnalysisAssumption.INSTRUCTION_DOES_NOT_THROW)) {
+ // In order to preserve class initialization semantic, the exception must not be caught
+ // by any handler. Therefore, we must ignore this instruction if it is covered by a
+ // catch handler.
+ // Note: this is a conservative approach where we consider that any catch handler could
+ // catch the exception, even if it cannot catch an ExceptionInInitializerError.
+ return InstructionEffect.fromBoolean(!instruction.getBlock().hasCatchHandlers());
+ }
+ // A static field can be updated by a static initializer and then accessed by an instance
+ // method. This is a problem if we later see DESIRED_EFFECT. The check for any instance
+ // method is quite conservative.
+ // TODO(b/217530538): Track if instance methods is accessing static fields.
+ return instruction.isInvokeMethodWithReceiver()
+ || instruction.instructionMayHaveSideEffects(appView, context)
+ ? OTHER_EFFECT
+ : NO_EFFECT;
+ });
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysFalseClassInlinerMethodConstraint.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysFalseClassInlinerMethodConstraint.java
index 645a4bf..1826502 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysFalseClassInlinerMethodConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysFalseClassInlinerMethodConstraint.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
import com.android.tools.r8.ir.optimize.classinliner.analysis.ParameterUsage;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysTrueClassInlinerMethodConstraint.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysTrueClassInlinerMethodConstraint.java
index d629d45..1f33962 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysTrueClassInlinerMethodConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysTrueClassInlinerMethodConstraint.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
import com.android.tools.r8.ir.optimize.classinliner.analysis.ParameterUsage;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraint.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraint.java
index 8b44af5..5bc6317 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraint.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
import com.android.tools.r8.ir.optimize.classinliner.analysis.ParameterUsage;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ConditionalClassInlinerMethodConstraint.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ConditionalClassInlinerMethodConstraint.java
index 4aceb17..eaae1fe 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ConditionalClassInlinerMethodConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ConditionalClassInlinerMethodConstraint.java
@@ -9,8 +9,8 @@
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfo;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfo;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.analysis.value.SingleConstValue;
import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EmptyEnumUnboxer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EmptyEnumUnboxer.java
index 1583873..23ae546 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EmptyEnumUnboxer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EmptyEnumUnboxer.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.StaticFieldValues;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Phi;
@@ -66,6 +66,11 @@
}
@Override
+ public void rewriteWithLens() {
+ // Intentionally empty.
+ }
+
+ @Override
public void unboxEnums(
AppView<AppInfoWithLiveness> appView,
IRConverter converter,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
index 8ff6293..ae119f6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.StaticFieldValues;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Phi;
@@ -46,6 +46,7 @@
public abstract Set<Phi> rewriteCode(
IRCode code, MethodProcessor methodProcessor, RewrittenPrototypeDescription prototypeChanges);
+ public abstract void rewriteWithLens();
public abstract void unboxEnums(
AppView<AppInfoWithLiveness> appView,
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 13fc08e..c8c21eb 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
@@ -43,7 +43,7 @@
import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.PrunedItems;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.StaticFieldValues;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.StaticFieldValues.EnumStaticFieldValues;
import com.android.tools.r8.ir.analysis.type.ArrayTypeElement;
@@ -605,6 +605,12 @@
}
@Override
+ public void rewriteWithLens() {
+ methodsDependingOnLibraryModelisation =
+ methodsDependingOnLibraryModelisation.rewrittenWithLens(appView.graphLens());
+ }
+
+ @Override
public void unboxEnums(
AppView<AppInfoWithLiveness> appView,
IRConverter converter,
@@ -667,7 +673,6 @@
// the builders with the methods removed by the tree fixer (since these methods references are
// already fully lens rewritten).
postMethodProcessorBuilder
- .getMethodsToReprocessBuilder()
.rewrittenWithLens(appView)
.removeAll(treeFixerResult.getPrunedItems().getRemovedMethods())
.merge(
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 39dd787..b79dea1 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
@@ -26,7 +26,7 @@
public class EnumUnboxingCandidateInfoCollection {
private final Map<DexType, EnumUnboxingCandidateInfo> enumTypeToInfo = new ConcurrentHashMap<>();
- private final Set<DexMethod> prunedMethods = Sets.newIdentityHashSet();
+ private final Set<DexMethod> prunedMethods = Sets.newConcurrentHashSet();
public void addCandidate(
AppView<AppInfoWithLiveness> appView,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
index 8a3d24e..e515c08 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
@@ -11,8 +11,9 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.NestedGraphLens;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RewrittenTypeInfo;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
+import com.android.tools.r8.graph.proto.RewrittenTypeInfo;
import com.android.tools.r8.ir.analysis.value.AbstractValueFactory;
import com.android.tools.r8.ir.analysis.value.SingleFieldValue;
import com.android.tools.r8.ir.analysis.value.SingleValue;
@@ -160,8 +161,9 @@
newMethodSignatures.put(from, to);
int offsetDiff = 0;
int toOffset = BooleanUtils.intValue(!toStatic);
- RewrittenPrototypeDescription.ArgumentInfoCollection.Builder builder =
- RewrittenPrototypeDescription.ArgumentInfoCollection.builder();
+ ArgumentInfoCollection.Builder builder =
+ ArgumentInfoCollection.builder()
+ .setArgumentInfosSize(from.getNumberOfArguments(fromStatic));
if (fromStatic != toStatic) {
assert toStatic;
offsetDiff = 1;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
index b0a4ed5..1a62ad5 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
@@ -13,9 +13,9 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfo;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RewrittenTypeInfo;
+import com.android.tools.r8.graph.proto.ArgumentInfo;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
+import com.android.tools.r8.graph.proto.RewrittenTypeInfo;
import com.android.tools.r8.ir.analysis.type.ArrayTypeElement;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.ArrayAccess;
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 773dadf..0214979 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
@@ -24,7 +24,7 @@
import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.PrunedItems;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.BasicBlock;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java
index 95a4b63..293d93f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java
@@ -106,13 +106,24 @@
FieldOptimizationInfo optimizationInfo = definition.getOptimizationInfo();
AbstractValue abstractValue = optimizationInfo.getAbstractValue();
+ if (methodWithReceiver.hasUnusedOutValue()) {
+ // Remove the invoke if it is a call to Enum.name() or Enum.ordinal() as they don't have
+ // any side effects. Enum.toString() can be overridden and calls to it could therefore
+ // have arbitrary side effects.
+ if (methodWithReceiver.getReceiver().getType().isDefinitelyNotNull()
+ && !isToStringInvoke) {
+ assert isNameInvoke || isOrdinalInvoke;
+ iterator.removeOrReplaceByDebugLocalRead();
+ }
+ continue;
+ }
+
Value outValue = methodWithReceiver.outValue();
if (isOrdinalInvoke) {
SingleNumberValue ordinalValue =
getOrdinalValue(code, abstractValue, methodWithReceiver.getReceiver().isNeverNull());
- if (ordinalValue != null) {
- iterator.replaceCurrentInstruction(
- new ConstNumber(outValue, ordinalValue.getValue()));
+ if (ordinalValue != null) {
+ iterator.replaceCurrentInstruction(new ConstNumber(outValue, ordinalValue.getValue()));
}
continue;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/CheckNotNullEnumUnboxerMethodClassification.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/CheckNotNullEnumUnboxerMethodClassification.java
index e9f1bdb..36f2de2 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/CheckNotNullEnumUnboxerMethodClassification.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/CheckNotNullEnumUnboxerMethodClassification.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.ir.optimize.enums.classification;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.code.InvokeStatic;
import com.android.tools.r8.ir.code.Value;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/EnumUnboxerMethodClassification.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/EnumUnboxerMethodClassification.java
index f9192b9..e08270b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/EnumUnboxerMethodClassification.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/EnumUnboxerMethodClassification.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.ir.optimize.enums.classification;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
public abstract class EnumUnboxerMethodClassification {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/UnknownEnumUnboxerMethodClassification.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/UnknownEnumUnboxerMethodClassification.java
index 04529b4..ee10791 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/UnknownEnumUnboxerMethodClassification.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/classification/UnknownEnumUnboxerMethodClassification.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.ir.optimize.enums.classification;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
public final class UnknownEnumUnboxerMethodClassification extends EnumUnboxerMethodClassification {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/ConcreteCallSiteOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/ConcreteCallSiteOptimizationInfo.java
index e855aa1..d8fe949 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/ConcreteCallSiteOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/ConcreteCallSiteOptimizationInfo.java
@@ -9,8 +9,8 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.analysis.type.DynamicType;
import com.android.tools.r8.ir.analysis.type.DynamicTypeWithUpperBound;
import com.android.tools.r8.ir.analysis.type.Nullability;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
index 95483ce..f6aa6ad 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
@@ -18,6 +18,7 @@
import com.android.tools.r8.ir.optimize.info.initializer.DefaultInstanceInitializerInfo;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.OptionalBool;
import com.google.common.collect.ImmutableSet;
import java.util.BitSet;
import java.util.Set;
@@ -161,6 +162,11 @@
}
@Override
+ public OptionalBool isReturnValueUsed() {
+ return OptionalBool.unknown();
+ }
+
+ @Override
public boolean forceInline() {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
index 17cffe5..473f718 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.OptionalBool;
import java.util.BitSet;
import java.util.Set;
@@ -86,6 +87,8 @@
public abstract boolean isMultiCallerMethod();
+ public abstract OptionalBool isReturnValueUsed();
+
public abstract boolean forceInline();
public abstract boolean triggersClassInitBeforeAnySideEffect();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
index acf0da6..594328f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.optimize.info;
-import static com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query.DIRECTLY;
import static com.android.tools.r8.ir.code.DominatorTree.Assumption.MAY_HAVE_UNREACHABLE_BLOCKS;
import static com.android.tools.r8.ir.code.Opcodes.ADD;
import static com.android.tools.r8.ir.code.Opcodes.AND;
@@ -55,7 +54,6 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.MethodResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption;
import com.android.tools.r8.ir.analysis.DeterminismAnalysis;
import com.android.tools.r8.ir.analysis.InitializedClassesOnNormalExitAnalysis;
import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraintAnalysis;
@@ -89,6 +87,8 @@
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.ir.optimize.DynamicTypeOptimization;
+import com.android.tools.r8.ir.optimize.SimpleDominatingEffectAnalysis;
+import com.android.tools.r8.ir.optimize.SimpleDominatingEffectAnalysis.SimpleEffectAnalysisResult;
import com.android.tools.r8.ir.optimize.classinliner.analysis.ClassInlinerMethodConstraintAnalysis;
import com.android.tools.r8.ir.optimize.classinliner.constraint.ClassInlinerMethodConstraint;
import com.android.tools.r8.ir.optimize.enums.classification.EnumUnboxerMethodClassification;
@@ -540,46 +540,15 @@
DexEncodedMethod method, IRCode code, OptimizationFeedback feedback) {
if (method.isStatic()) {
// Identifies if the method preserves class initialization after inlining.
+ SimpleEffectAnalysisResult simpleEffectAnalysisResult =
+ SimpleDominatingEffectAnalysis.triggersClassInitializationBeforeAnyStaticRead(
+ appView, code);
feedback.markTriggerClassInitBeforeAnySideEffect(
- method, triggersClassInitializationBeforeSideEffect(code));
+ method, simpleEffectAnalysisResult.isSatisfied());
}
}
/**
- * Returns true if the given code unconditionally triggers class initialization before any other
- * side effecting instruction.
- *
- * <p>Note: we do not track phis so we may return false negative. This is a conservative approach.
- */
- private boolean triggersClassInitializationBeforeSideEffect(IRCode code) {
- return alwaysTriggerExpectedEffectBeforeAnythingElse(
- code,
- (instruction, it) -> {
- ProgramMethod context = code.context();
- if (instruction.definitelyTriggersClassInitialization(
- context.getHolderType(),
- context,
- appView,
- DIRECTLY,
- AnalysisAssumption.INSTRUCTION_DOES_NOT_THROW)) {
- // In order to preserve class initialization semantic, the exception must not be caught
- // by any handler. Therefore, we must ignore this instruction if it is covered by a
- // catch handler.
- // Note: this is a conservative approach where we consider that any catch handler could
- // catch the exception, even if it cannot catch an ExceptionInInitializerError.
- if (!instruction.getBlock().hasCatchHandlers()) {
- // We found an instruction that preserves initialization of the class.
- return InstructionEffect.DESIRED_EFFECT;
- }
- } else if (instruction.instructionMayHaveSideEffects(appView, context)) {
- // We found a side effect before class initialization.
- return InstructionEffect.OTHER_EFFECT;
- }
- return InstructionEffect.NO_EFFECT;
- });
- }
-
- /**
* Returns true if the given code unconditionally triggers an expected effect before anything
* else, false otherwise.
*
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
index 69f0497..2cffcc0 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
@@ -28,6 +28,7 @@
import com.android.tools.r8.utils.BitSetUtils;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.OptionalBool;
import java.util.BitSet;
import java.util.Collections;
import java.util.Set;
@@ -47,6 +48,7 @@
EnumUnboxerMethodClassification.unknown();
private DynamicType dynamicType = DynamicType.unknown();
private InlinePreference inlining = InlinePreference.Default;
+ private OptionalBool isReturnValueUsed = OptionalBool.unknown();
// Stores information about instance methods and constructors for
// class inliner, null value indicates that the method is not eligible.
private BridgeInfo bridgeInfo = null;
@@ -481,6 +483,15 @@
}
@Override
+ public OptionalBool isReturnValueUsed() {
+ return isReturnValueUsed;
+ }
+
+ void setIsReturnValueUsed(OptionalBool isReturnValueUsed) {
+ this.isReturnValueUsed = isReturnValueUsed;
+ }
+
+ @Override
public boolean forceInline() {
return inlining == InlinePreference.ForceInline;
}
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 5be58f0..1b54d1f 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
@@ -18,6 +18,7 @@
import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfoCollection;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.OptionalBool;
import java.util.BitSet;
import java.util.Set;
import java.util.function.Consumer;
@@ -179,6 +180,10 @@
method.getMutableOptimizationInfo().setInitializerEnablingJavaAssertions();
}
+ public void setIsReturnValueUsed(OptionalBool isReturnValueUsed, ProgramMethod method) {
+ method.getDefinition().getMutableOptimizationInfo().setIsReturnValueUsed(isReturnValueUsed);
+ }
+
@Override
public void setNonNullParamOrThrow(DexEncodedMethod method, BitSet facts) {
method.getMutableOptimizationInfo().setNonNullParamOrThrow(facts);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/EmptyInstanceFieldInitializationInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/EmptyInstanceFieldInitializationInfoCollection.java
index 833f0c6..7694837 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/EmptyInstanceFieldInitializationInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/EmptyInstanceFieldInitializationInfoCollection.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.DexDefinitionSupplier;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import java.util.function.BiConsumer;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldArgumentInitializationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldArgumentInitializationInfo.java
index b689d8a..0d28a5c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldArgumentInitializationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldArgumentInitializationInfo.java
@@ -6,9 +6,9 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfo;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
+import com.android.tools.r8.graph.proto.ArgumentInfo;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.RemovedArgumentInfo;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
/**
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfo.java
index 0a34194..6bf9604 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfo.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.analysis.value.SingleValue;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfoCollection.java
index 2520561..772e2d8 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfoCollection.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import java.util.TreeMap;
import java.util.function.BiConsumer;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldTypeInitializationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldTypeInitializationInfo.java
index 24730bb..b494732 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldTypeInitializationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldTypeInitializationInfo.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.optimize.enums.EnumDataMap;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/NonTrivialInstanceFieldInitializationInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/NonTrivialInstanceFieldInitializationInfoCollection.java
index b996542..19c4ab9 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/NonTrivialInstanceFieldInitializationInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/NonTrivialInstanceFieldInitializationInfoCollection.java
@@ -11,7 +11,7 @@
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.StringUtils;
import java.util.ArrayList;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/UnknownInstanceFieldInitializationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/UnknownInstanceFieldInitializationInfo.java
index 77409cb..0f41427 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/UnknownInstanceFieldInitializationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/UnknownInstanceFieldInitializationInfo.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
/**
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/ContextInsensitiveInstanceInitializerInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/ContextInsensitiveInstanceInitializerInfoCollection.java
index b15e8e4..0e5ce2c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/ContextInsensitiveInstanceInitializerInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/ContextInsensitiveInstanceInitializerInfoCollection.java
@@ -7,7 +7,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.PrunedItems;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.code.InvokeDirect;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/ContextSensitiveInstanceInitializerInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/ContextSensitiveInstanceInitializerInfoCollection.java
index fec6ed4..6a5efbb 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/ContextSensitiveInstanceInitializerInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/ContextSensitiveInstanceInitializerInfoCollection.java
@@ -7,7 +7,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.PrunedItems;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.code.InvokeDirect;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.google.common.collect.ImmutableMap;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/DefaultInstanceInitializerInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/DefaultInstanceInitializerInfo.java
index 46a3511..59a6141 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/DefaultInstanceInitializerInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/DefaultInstanceInitializerInfo.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.PrunedItems;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.AbstractFieldSet;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.UnknownFieldSet;
import com.android.tools.r8.ir.optimize.info.field.EmptyInstanceFieldInitializationInfoCollection;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/EmptyInstanceInitializerInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/EmptyInstanceInitializerInfoCollection.java
index 9ac9762..19fea9a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/EmptyInstanceInitializerInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/EmptyInstanceInitializerInfoCollection.java
@@ -7,7 +7,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.PrunedItems;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.code.InvokeDirect;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfo.java
index e07b514..cbf442c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfo.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.PrunedItems;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.AbstractFieldSet;
import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoCollection;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfoCollection.java
index 8002513..fd793a6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfoCollection.java
@@ -7,7 +7,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.PrunedItems;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.code.InvokeDirect;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.MapUtils;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/NonTrivialInstanceInitializerInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/NonTrivialInstanceInitializerInfo.java
index 58af519..327e46a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/NonTrivialInstanceInitializerInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/NonTrivialInstanceInitializerInfo.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.PrunedItems;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.AbstractFieldSet;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.ConcreteMutableFieldSet;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.EmptyFieldSet;
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java
index b750f84..acf4d56 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java
@@ -12,8 +12,8 @@
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.Position;
diff --git a/src/main/java/com/android/tools/r8/optimize/FieldRebindingIdentityLens.java b/src/main/java/com/android/tools/r8/optimize/FieldRebindingIdentityLens.java
index f4b80a7..00867f4 100644
--- a/src/main/java/com/android/tools/r8/optimize/FieldRebindingIdentityLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/FieldRebindingIdentityLens.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import java.util.IdentityHashMap;
import java.util.Map;
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLens.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLens.java
index 81c4ae1..b77fbd1 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLens.java
@@ -15,7 +15,7 @@
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import java.util.IdentityHashMap;
import java.util.Map;
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingLens.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingLens.java
index da5a6d5..edba428 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingLens.java
@@ -15,7 +15,7 @@
import com.android.tools.r8.graph.FieldAccessInfo;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.code.Invoke;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import java.util.Collections;
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
index f5b55c6..b7dd7ff 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
@@ -171,6 +171,7 @@
stronglyConnectedProgramComponent, (unused) -> DexMethodSignatureSet.create())
.add(signature);
},
+ postMethodProcessorBuilder,
executorService,
timing);
@@ -205,6 +206,7 @@
ImmediateProgramSubtypingInfo immediateSubtypingInfo,
List<Set<DexProgramClass>> stronglyConnectedProgramComponents,
BiConsumer<Set<DexProgramClass>, DexMethodSignature> interfaceDispatchOutsideProgram,
+ PostMethodProcessor.Builder postMethodProcessorBuilder,
ExecutorService executorService,
Timing timing)
throws ExecutionException {
@@ -214,14 +216,18 @@
appView.testing().argumentPropagatorEventConsumer.acceptCodeScannerResult(codeScannerResult);
codeScanner = null;
+ postMethodProcessorBuilder.rewrittenWithLens(appView);
+
timing.begin("Compute optimization info");
new ArgumentPropagatorOptimizationInfoPopulator(
appView,
+ converter,
immediateSubtypingInfo,
codeScannerResult,
+ postMethodProcessorBuilder,
stronglyConnectedProgramComponents,
interfaceDispatchOutsideProgram)
- .populateOptimizationInfo(converter, executorService, timing);
+ .populateOptimizationInfo(executorService, timing);
timing.end();
timing.begin("Compute unused arguments");
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java
index 85bef2b..e72be3d 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java
@@ -19,8 +19,8 @@
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.MethodCollection;
import com.android.tools.r8.graph.PrunedItems;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
import com.android.tools.r8.graph.TreeFixerBase;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfoFixer;
import com.android.tools.r8.ir.optimize.info.MutableFieldOptimizationInfo;
import com.android.tools.r8.ir.optimize.info.MutableMethodOptimizationInfo;
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScanner.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScanner.java
index 2839aeb..ba4b05a 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScanner.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScanner.java
@@ -47,7 +47,6 @@
import com.android.tools.r8.optimize.argumentpropagation.utils.WideningUtils;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.Timing;
-import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.IdentityHashMap;
@@ -152,12 +151,6 @@
}
private void scan(InvokeMethod invoke, ProgramMethod context, Timing timing) {
- List<Value> arguments = invoke.arguments();
- if (arguments.isEmpty()) {
- // Nothing to propagate.
- return;
- }
-
DexMethod invokedMethod = invoke.getInvokedMethod();
if (invokedMethod.getHolderType().isArrayType()) {
// Nothing to propagate; the targeted method is not a program method.
@@ -191,7 +184,7 @@
return;
}
- if (arguments.size() != resolvedMethod.getDefinition().getNumberOfArguments()
+ if (invoke.arguments().size() != resolvedMethod.getDefinition().getNumberOfArguments()
|| invoke.isInvokeStatic() != resolvedMethod.getAccessFlags().isStatic()) {
// Nothing to propagate; the invoke instruction fails.
return;
@@ -410,13 +403,10 @@
methodReprocessingCriteria.getParameterReprocessingCriteria(argumentIndex)));
}
- // If all parameter states are unknown, then return a canonicalized unknown method state that
- // has this property.
- if (Iterables.all(parameterStates, ParameterState::isUnknown)) {
- return MethodState.unknown();
- }
-
- return new ConcreteMonomorphicMethodState(parameterStates);
+ // We simulate that the return value is used for methods with void return type. This ensures
+ // that we will widen the method state to unknown if/when all parameter states become unknown.
+ boolean isReturnValueUsed = invoke.getReturnType().isVoidType() || invoke.hasUsedOutValue();
+ return ConcreteMonomorphicMethodState.create(isReturnValueUsed, parameterStates);
}
// For receivers there is not much point in trying to track an abstract value. Therefore we only
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorGraphLens.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorGraphLens.java
index ae5322e..d67718a 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorGraphLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorGraphLens.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.NestedGraphLens;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java
index 6479ad3..42537e8 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java
@@ -23,8 +23,6 @@
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
-import com.android.tools.r8.utils.collections.LongLivedProgramMethodSetBuilder;
-import com.android.tools.r8.utils.collections.ProgramMethodSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -59,19 +57,16 @@
// Bring the methods to reprocess set up-to-date with the current graph lens (i.e., the one
// prior to the argument propagator lens, which has not yet been installed!).
timing.begin("Rewrite methods to reprocess");
- LongLivedProgramMethodSetBuilder<ProgramMethodSet> methodsToReprocessBuilder =
- postMethodProcessorBuilder
- .getMethodsToReprocessBuilder()
- .rewrittenWithLens(appView.graphLens());
+ postMethodProcessorBuilder.rewrittenWithLens(appView);
timing.end();
timing.begin("Enqueue methods with non-trivial info");
- enqueueAffectedCallees(graphLens, methodsToReprocessBuilder);
+ enqueueAffectedCallees(graphLens, postMethodProcessorBuilder);
timing.end();
timing.begin("Enqueue affected methods");
if (graphLens != null) {
- enqueueAffectedCallers(graphLens, methodsToReprocessBuilder, executorService);
+ enqueueAffectedCallers(graphLens, postMethodProcessorBuilder, executorService);
}
timing.end();
@@ -80,7 +75,7 @@
private void enqueueAffectedCallees(
ArgumentPropagatorGraphLens graphLens,
- LongLivedProgramMethodSetBuilder<ProgramMethodSet> methodsToReprocessBuilder) {
+ PostMethodProcessor.Builder postMethodProcessorBuilder) {
GraphLens currentGraphLens = appView.graphLens();
for (DexProgramClass clazz : appView.appInfo().classes()) {
clazz.forEachProgramMethodMatching(
@@ -95,7 +90,7 @@
graphLens.internalGetNextMethodSignature(method.getReference());
if (graphLens.hasPrototypeChanges(rewrittenMethodSignature)) {
assert !appView.appInfo().isNeverReprocessMethod(method);
- methodsToReprocessBuilder.add(method, currentGraphLens);
+ postMethodProcessorBuilder.add(method, currentGraphLens);
appView.testing().callSiteOptimizationInfoInspector.accept(method);
return;
}
@@ -107,7 +102,7 @@
.getReprocessingCriteria(method)
.shouldReprocess(appView, method, callSiteOptimizationInfo)
&& !appView.appInfo().isNeverReprocessMethod(method)) {
- methodsToReprocessBuilder.add(method, currentGraphLens);
+ postMethodProcessorBuilder.add(method, currentGraphLens);
appView.testing().callSiteOptimizationInfoInspector.accept(method);
}
});
@@ -119,7 +114,7 @@
// methods as unoptimizable prior to removing parameters from the application.
private void enqueueAffectedCallers(
ArgumentPropagatorGraphLens graphLens,
- LongLivedProgramMethodSetBuilder<ProgramMethodSet> methodsToReprocessBuilder,
+ PostMethodProcessor.Builder postMethodProcessorBuilder,
ExecutorService executorService)
throws ExecutionException {
GraphLens currentGraphLens = appView.graphLens();
@@ -131,7 +126,7 @@
clazz.forEachProgramMethodMatching(
DexEncodedMethod::hasCode,
method -> {
- if (!methodsToReprocessBuilder.contains(method, currentGraphLens)) {
+ if (!postMethodProcessorBuilder.contains(method, currentGraphLens)) {
AffectedMethodUseRegistry registry =
new AffectedMethodUseRegistry(appView, method, graphLens);
if (method.registerCodeReferencesWithResult(registry)) {
@@ -145,7 +140,7 @@
executorService);
methodsToReprocess.forEach(
methodsToReprocessInClass ->
- methodsToReprocessBuilder.addAll(methodsToReprocessInClass, currentGraphLens));
+ postMethodProcessorBuilder.addAll(methodsToReprocessInClass, currentGraphLens));
}
static class AffectedMethodUseRegistry extends UseRegistryWithResult<Boolean, ProgramMethod> {
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java
index f8d617b..0b47a5e 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.conversion.IRConverter;
+import com.android.tools.r8.ir.conversion.PostMethodProcessor;
import com.android.tools.r8.ir.optimize.info.ConcreteCallSiteOptimizationInfo;
import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
@@ -32,7 +33,9 @@
import com.android.tools.r8.optimize.argumentpropagation.propagation.VirtualDispatchMethodArgumentPropagator;
import com.android.tools.r8.optimize.argumentpropagation.utils.WideningUtils;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ListUtils;
+import com.android.tools.r8.utils.OptionalBool;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
import java.util.List;
@@ -49,7 +52,10 @@
public class ArgumentPropagatorOptimizationInfoPopulator {
private final AppView<AppInfoWithLiveness> appView;
+ private final IRConverter converter;
private final MethodStateCollectionByReference methodStates;
+ private final InternalOptions options;
+ private final PostMethodProcessor.Builder postMethodProcessorBuilder;
private final ImmediateProgramSubtypingInfo immediateSubtypingInfo;
private final List<Set<DexProgramClass>> stronglyConnectedProgramComponents;
@@ -59,13 +65,18 @@
ArgumentPropagatorOptimizationInfoPopulator(
AppView<AppInfoWithLiveness> appView,
+ IRConverter converter,
ImmediateProgramSubtypingInfo immediateSubtypingInfo,
MethodStateCollectionByReference methodStates,
+ PostMethodProcessor.Builder postMethodProcessorBuilder,
List<Set<DexProgramClass>> stronglyConnectedProgramComponents,
BiConsumer<Set<DexProgramClass>, DexMethodSignature> interfaceDispatchOutsideProgram) {
this.appView = appView;
+ this.converter = converter;
this.immediateSubtypingInfo = immediateSubtypingInfo;
this.methodStates = methodStates;
+ this.options = appView.options();
+ this.postMethodProcessorBuilder = postMethodProcessorBuilder;
this.stronglyConnectedProgramComponents = stronglyConnectedProgramComponents;
this.interfaceDispatchOutsideProgram = interfaceDispatchOutsideProgram;
}
@@ -74,8 +85,7 @@
* Computes an over-approximation of each parameter's value and type and stores the result in
* {@link com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo}.
*/
- void populateOptimizationInfo(
- IRConverter converter, ExecutorService executorService, Timing timing)
+ void populateOptimizationInfo(ExecutorService executorService, Timing timing)
throws ExecutionException {
// TODO(b/190154391): Propagate argument information to handle virtual dispatch.
// TODO(b/190154391): To deal with arguments that are themselves passed as arguments to invoke
@@ -147,18 +157,18 @@
}
private void setOptimizationInfo(ProgramMethod method) {
- MethodState methodState = methodStates.removeOrElse(method, null);
- if (methodState == null) {
- return;
- }
-
+ MethodState methodState = methodStates.remove(method);
if (methodState.isBottom()) {
- method.convertToAbstractOrThrowNullMethod(appView);
+ if (method.getDefinition().hasCode() && !method.getDefinition().isClassInitializer()) {
+ method.convertToAbstractOrThrowNullMethod(appView);
+ converter.onMethodCodePruned(method);
+ postMethodProcessorBuilder.remove(method, appView.graphLens());
+ }
return;
}
// Do not optimize @KeepConstantArgument methods.
- if (appView.appInfo().isKeepConstantArgumentsMethod(method)) {
+ if (!appView.getKeepInfo(method).isConstantArgumentOptimizationAllowed(options)) {
methodState = MethodState.unknown();
}
@@ -194,11 +204,17 @@
.map(ParameterState::asConcrete)
.noneMatch(ConcreteParameterState::hasInParameters);
- getSimpleFeedback()
- .setArgumentInfos(
- method,
- ConcreteCallSiteOptimizationInfo.fromMethodState(
- appView, method, monomorphicMethodState));
+ if (monomorphicMethodState.size() > 0) {
+ getSimpleFeedback()
+ .setArgumentInfos(
+ method,
+ ConcreteCallSiteOptimizationInfo.fromMethodState(
+ appView, method, monomorphicMethodState));
+ }
+
+ if (!monomorphicMethodState.isReturnValueUsed()) {
+ getSimpleFeedback().setIsReturnValueUsed(OptionalBool.FALSE, method);
+ }
// Strengthen the return value of the method if the method is known to return one of the
// arguments.
@@ -215,15 +231,23 @@
private MethodState getMethodStateAfterUninstantiatedParameterRemoval(
ProgramMethod method, MethodState methodState) {
assert methodState.isMonomorphic() || methodState.isUnknown();
- if (appView.appInfo().isKeepConstantArgumentsMethod(method)) {
+ if (!appView.getKeepInfo(method).isConstantArgumentOptimizationAllowed(options)) {
return methodState;
}
int numberOfArguments = method.getDefinition().getNumberOfArguments();
- List<ParameterState> parameterStates =
- methodState.isMonomorphic()
- ? methodState.asMonomorphic().getParameterStates()
- : ListUtils.newInitializedArrayList(numberOfArguments, ParameterState.unknown());
+ boolean isReturnValueUsed;
+ List<ParameterState> parameterStates;
+ if (methodState.isMonomorphic()) {
+ ConcreteMonomorphicMethodState monomorphicMethodState = methodState.asMonomorphic();
+ isReturnValueUsed = monomorphicMethodState.isReturnValueUsed();
+ parameterStates = monomorphicMethodState.getParameterStates();
+ } else {
+ assert methodState.isUnknown();
+ isReturnValueUsed = true;
+ parameterStates =
+ ListUtils.newInitializedArrayList(numberOfArguments, ParameterState.unknown());
+ }
List<ParameterState> narrowedParameterStates =
ListUtils.mapOrElse(
parameterStates,
@@ -240,7 +264,7 @@
},
null);
return narrowedParameterStates != null
- ? new ConcreteMonomorphicMethodState(narrowedParameterStates)
+ ? new ConcreteMonomorphicMethodState(isReturnValueUsed, narrowedParameterStates)
: methodState;
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
index c2912c0..c30afaf 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
@@ -20,10 +20,10 @@
import com.android.tools.r8.graph.ObjectAllocationInfoCollection;
import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RewrittenTypeInfo;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.RemovedArgumentInfo;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
+import com.android.tools.r8.graph.proto.RewrittenTypeInfo;
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.DynamicTypeWithUpperBound;
@@ -44,6 +44,7 @@
import com.android.tools.r8.utils.IntBox;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.InternalOptions.CallSiteOptimizationOptions;
+import com.android.tools.r8.utils.OptionalBool;
import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
@@ -389,14 +390,10 @@
}
// Also record the found return value for abstract virtual methods.
- if (newReturnType == dexItemFactory.voidType) {
+ if (newReturnType == dexItemFactory.voidType && returnValueForVirtualMethods != null) {
for (ProgramMethod method : methods) {
if (method.getAccessFlags().isAbstract()) {
returnValuesForVirtualMethods.put(method, returnValueForVirtualMethods);
- } else {
- AbstractValue returnValueForVirtualMethod =
- method.getOptimizationInfo().getAbstractReturnValue();
- assert returnValueForVirtualMethod.equals(returnValueForVirtualMethods);
}
}
}
@@ -441,7 +438,10 @@
if (!appView.appInfo().mayPropagateValueFor(method)) {
return null;
}
- AbstractValue returnValueForMethod = method.getOptimizationInfo().getAbstractReturnValue();
+ AbstractValue returnValueForMethod =
+ method.getReturnType().isAlwaysNull(appView)
+ ? appView.abstractValueFactory().createNullValue()
+ : method.getOptimizationInfo().getAbstractReturnValue();
if (!returnValueForMethod.isSingleValue()
|| !returnValueForMethod.asSingleValue().isMaterializableInAllContexts(appView)
|| (returnValue != null && !returnValueForMethod.equals(returnValue))) {
@@ -510,16 +510,17 @@
private DexType getNewReturnTypeForVirtualMethods(
ProgramMethodSet methods, SingleValue returnValue) {
- if (returnValue != null) {
+ if (returnValue != null || isReturnValueUnusedForVirtualMethods(methods)) {
return dexItemFactory.voidType;
}
+
DexType newReturnType = null;
for (ProgramMethod method : methods) {
if (method.getDefinition().isAbstract()) {
// OK, this method can have any return type.
continue;
}
- DexType newReturnTypeForMethod = getNewReturnType(method, null);
+ DexType newReturnTypeForMethod = getNewReturnType(method, OptionalBool.UNKNOWN, null);
if (newReturnTypeForMethod == null
|| (newReturnType != null && newReturnType != newReturnTypeForMethod)) {
return null;
@@ -530,6 +531,16 @@
return newReturnType;
}
+ private boolean isReturnValueUnusedForVirtualMethods(ProgramMethodSet methods) {
+ ProgramMethod representative = methods.getFirst();
+ return !representative.getReturnType().isVoidType()
+ && Iterables.all(
+ methods,
+ method ->
+ appView.getKeepInfo(method).isUnusedReturnValueOptimizationAllowed(options)
+ && method.getOptimizationInfo().isReturnValueUsed().isFalse());
+ }
+
private DexType getNewParameterTypeForVirtualMethods(
ProgramMethodSet methods, int parameterIndex) {
if (parameterIndex == 0) {
@@ -850,7 +861,8 @@
IntSet removableParameterIndices) {
// Treat the parameters as unused.
ArgumentInfoCollection.Builder argumentInfoCollectionBuilder =
- ArgumentInfoCollection.builder();
+ ArgumentInfoCollection.builder()
+ .setArgumentInfosSize(method.getDefinition().getNumberOfArguments());
for (int argumentIndex = 0;
argumentIndex < method.getDefinition().getNumberOfArguments();
argumentIndex++) {
@@ -885,18 +897,26 @@
}
private DexType getNewReturnType(ProgramMethod method) {
- return getNewReturnType(method, getReturnValue(method));
+ return getNewReturnType(
+ method, method.getOptimizationInfo().isReturnValueUsed(), getReturnValue(method));
}
- private DexType getNewReturnType(ProgramMethod method, SingleValue returnValue) {
+ private DexType getNewReturnType(
+ ProgramMethod method, OptionalBool isReturnValueUsed, SingleValue returnValue) {
DexType staticType = method.getReturnType();
- if (staticType.isVoidType()
- || !appView.getKeepInfo(method).isReturnTypeStrengtheningAllowed(options)) {
+ if (staticType.isVoidType()) {
return null;
}
if (returnValue != null) {
return dexItemFactory.voidType;
}
+ KeepMethodInfo keepInfo = appView.getKeepInfo(method);
+ if (keepInfo.isUnusedReturnValueOptimizationAllowed(options) && isReturnValueUsed.isFalse()) {
+ return dexItemFactory.voidType;
+ }
+ if (!keepInfo.isReturnTypeStrengtheningAllowed(options)) {
+ return null;
+ }
TypeElement newReturnTypeElement =
method
.getOptimizationInfo()
@@ -992,7 +1012,9 @@
ProgramMethod method,
IntFunction<DexType> newParameterTypes,
IntPredicate removableParameterIndices) {
- ArgumentInfoCollection.Builder parameterChangesBuilder = ArgumentInfoCollection.builder();
+ ArgumentInfoCollection.Builder parameterChangesBuilder =
+ ArgumentInfoCollection.builder()
+ .setArgumentInfosSize(method.getDefinition().getNumberOfArguments());
if (method.getDefinition().isInstance()
&& removableParameterIndices.test(0)
&& method.getOptimizationInfo().hasUnusedArguments()
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorUnoptimizableMethods.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorUnoptimizableMethods.java
index 6319e90..c277bb7 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorUnoptimizableMethods.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorUnoptimizableMethods.java
@@ -12,15 +12,12 @@
import com.android.tools.r8.optimize.argumentpropagation.codescanner.UnknownMethodState;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.MethodSignatureEquivalence;
import com.android.tools.r8.utils.classhierarchy.MethodOverridesCollector;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import java.util.Collection;
public class ArgumentPropagatorUnoptimizableMethods {
- private static final MethodSignatureEquivalence equivalence = MethodSignatureEquivalence.get();
-
private final AppView<AppInfoWithLiveness> appView;
private final ImmediateProgramSubtypingInfo immediateSubtypingInfo;
private final MethodStateCollectionByReference methodStates;
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteMonomorphicMethodState.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteMonomorphicMethodState.java
index d32df00..e730d74 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteMonomorphicMethodState.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteMonomorphicMethodState.java
@@ -16,15 +16,25 @@
public class ConcreteMonomorphicMethodState extends ConcreteMethodState
implements ConcreteMonomorphicMethodStateOrBottom, ConcreteMonomorphicMethodStateOrUnknown {
+ boolean isReturnValueUsed;
List<ParameterState> parameterStates;
- public ConcreteMonomorphicMethodState(List<ParameterState> parameterStates) {
+ public ConcreteMonomorphicMethodState(
+ boolean isReturnValueUsed, List<ParameterState> parameterStates) {
assert Streams.stream(Iterables.skip(parameterStates, 1))
.noneMatch(x -> x.isConcrete() && x.asConcrete().isReceiverParameter());
+ this.isReturnValueUsed = isReturnValueUsed;
this.parameterStates = parameterStates;
assert !isEffectivelyUnknown() : "Must use UnknownMethodState instead";
}
+ public static ConcreteMonomorphicMethodStateOrUnknown create(
+ boolean isReturnValueUsed, List<ParameterState> parameterStates) {
+ return isEffectivelyUnknown(isReturnValueUsed, parameterStates)
+ ? unknown()
+ : new ConcreteMonomorphicMethodState(isReturnValueUsed, parameterStates);
+ }
+
public ParameterState getParameterState(int index) {
return parameterStates.get(index);
}
@@ -33,8 +43,21 @@
return parameterStates;
}
+ public boolean isReturnValueUsed() {
+ return isReturnValueUsed;
+ }
+
+ public boolean isEffectivelyBottom() {
+ return Iterables.any(parameterStates, ParameterState::isBottom);
+ }
+
public boolean isEffectivelyUnknown() {
- return Iterables.all(parameterStates, ParameterState::isUnknown);
+ return isEffectivelyUnknown(isReturnValueUsed, parameterStates);
+ }
+
+ private static boolean isEffectivelyUnknown(
+ boolean isReturnValueUsed, List<ParameterState> parameterStates) {
+ return isReturnValueUsed && Iterables.all(parameterStates, ParameterState::isUnknown);
}
@Override
@@ -43,7 +66,7 @@
for (ParameterState parameterState : getParameterStates()) {
copiedParametersStates.add(parameterState.mutableCopy());
}
- return new ConcreteMonomorphicMethodState(copiedParametersStates);
+ return new ConcreteMonomorphicMethodState(isReturnValueUsed, copiedParametersStates);
}
public ConcreteMonomorphicMethodStateOrUnknown mutableJoin(
@@ -56,6 +79,10 @@
return unknown();
}
+ if (methodState.isReturnValueUsed()) {
+ isReturnValueUsed = true;
+ }
+
int argumentIndex = 0;
if (size() > methodSignature.getArity()) {
assert size() == methodSignature.getArity() + 1;
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/lenscoderewriter/NullCheckInserter.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/lenscoderewriter/NullCheckInserter.java
index c428a70..2ffbf8d 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/lenscoderewriter/NullCheckInserter.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/lenscoderewriter/NullCheckInserter.java
@@ -11,7 +11,7 @@
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfo;
+import com.android.tools.r8.graph.proto.ArgumentInfo;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.BasicBlockIterator;
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InParameterFlowPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InParameterFlowPropagator.java
index 9b10015..fae616e 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InParameterFlowPropagator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InParameterFlowPropagator.java
@@ -133,18 +133,10 @@
return;
}
assert methodState.isMonomorphic();
- boolean allUnknown = true;
- for (ParameterState parameterState : methodState.asMonomorphic().getParameterStates()) {
- if (parameterState.isBottom()) {
- methodStates.set(method, MethodState.bottom());
- return;
- }
- if (!parameterState.isUnknown()) {
- assert parameterState.isConcrete();
- allUnknown = false;
- }
- }
- if (allUnknown) {
+ ConcreteMonomorphicMethodState monomorphicMethodState = methodState.asMonomorphic();
+ if (monomorphicMethodState.isEffectivelyBottom()) {
+ methodStates.set(method, MethodState.bottom());
+ } else if (monomorphicMethodState.isEffectivelyUnknown()) {
methodStates.set(method, MethodState.unknown());
}
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InterfaceMethodArgumentPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InterfaceMethodArgumentPropagator.java
index 0b617b1..b9d6fda 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InterfaceMethodArgumentPropagator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InterfaceMethodArgumentPropagator.java
@@ -147,7 +147,6 @@
ProgramMethod resolvedMethod = resolutionResult.getResolvedProgramMethod();
if (resolvedMethod == null
- || resolvedMethod.getHolder().isInterface()
|| resolvedMethod.getHolder() == subclass) {
return;
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/utils/ParameterRemovalUtils.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/utils/ParameterRemovalUtils.java
index 72129db..34d8967 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/utils/ParameterRemovalUtils.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/utils/ParameterRemovalUtils.java
@@ -19,7 +19,7 @@
if (!keepInfo.isParameterRemovalAllowed(options)) {
return false;
}
- if (appView.appInfo().isKeepUnusedArgumentsMethod(method)) {
+ if (!appView.getKeepInfo(method).isUnusedArgumentOptimizationAllowed(options)) {
return false;
}
return method.getDefinition().isLibraryMethodOverride().isFalse()
diff --git a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoistingLens.java b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoistingLens.java
index 1ded13b..9827d9a 100644
--- a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoistingLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoistingLens.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.utils.collections.BidirectionalManyToOneMap;
import java.util.Set;
diff --git a/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizer.java b/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizer.java
new file mode 100644
index 0000000..2b49179
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizer.java
@@ -0,0 +1,126 @@
+// Copyright (c) 2022, 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.optimize.proto;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexMethodSignature;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.Timing;
+import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
+import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap;
+import com.android.tools.r8.utils.collections.DexMethodSignatureSet;
+import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+
+public class ProtoNormalizer {
+
+ private final AppView<AppInfoWithLiveness> appView;
+ private final DexItemFactory dexItemFactory;
+ private final InternalOptions options;
+
+ public ProtoNormalizer(AppView<AppInfoWithLiveness> appView) {
+ this.appView = appView;
+ this.dexItemFactory = appView.dexItemFactory();
+ this.options = appView.options();
+ }
+
+ public void run(ExecutorService executorService, Timing timing) {
+ if (options.testing.enableExperimentalProtoNormalization) {
+ timing.time("Proto normalization", () -> run(executorService));
+ }
+ }
+
+ // TODO(b/195112263): Parallelize using executor service.
+ private void run(ExecutorService executorService) {
+ // Compute mapping from method signatures to new method signatures.
+ BidirectionalOneToOneMap<DexMethodSignature, DexMethodSignature> normalization =
+ computeNormalization();
+
+ ProtoNormalizerGraphLens.Builder lensBuilder = ProtoNormalizerGraphLens.builder(appView);
+ for (DexProgramClass clazz : appView.appInfo().classes()) {
+ clazz
+ .getMethodCollection()
+ .replaceMethods(
+ method -> {
+ DexMethodSignature methodSignature = method.getSignature();
+ assert normalization.containsKey(methodSignature);
+ DexMethodSignature normalizedMethodSignature = normalization.get(methodSignature);
+ if (methodSignature.equals(normalizedMethodSignature)) {
+ return method;
+ }
+ DexMethod normalizedMethodReference =
+ normalizedMethodSignature.withHolder(clazz, dexItemFactory);
+ lensBuilder.recordNewMethodSignature(method, normalizedMethodReference);
+ // TODO(b/195112263): Fixup any optimization info and parameter annotations.
+ return method.toTypeSubstitutedMethod(normalizedMethodReference);
+ });
+ }
+
+ if (!lensBuilder.isEmpty()) {
+ appView.rewriteWithLens(lensBuilder.build());
+ }
+ }
+
+ // TODO(b/195112263): This naively maps each method signatures to their normalized method
+ // signature if it is not already reserved by another method. This means that we will rewrite
+ // foo(A,B), bar(B,A), and baz(B,A) into foo(A,B), bar(A,B), and baz(A,B), such that all of the
+ // method signatures share the same parameter type list. However, if there is a method foo(A,B)
+ // and foo(B,A) then this does not rewrite foo(B,A) into foo(A,B). If foo(B,A) is not in the same
+ // hierarchy as foo(A,B), this would be possible, however.
+ // TODO(b/195112263): Do not optimize foo(B, A) into foo(A, B) if this won't lead to any parameter
+ // type lists being shared (e.g., if foo(B, A) is the only method where sorted(parameters) is
+ // [A, B]).
+ private BidirectionalOneToOneMap<DexMethodSignature, DexMethodSignature> computeNormalization() {
+ // Reserve the signatures of unoptimizable methods to avoid collisions.
+ MutableBidirectionalOneToOneMap<DexMethodSignature, DexMethodSignature> normalization =
+ new BidirectionalOneToOneHashMap<>();
+ DexMethodSignatureSet optimizableMethodSignatures = DexMethodSignatureSet.create();
+ for (DexProgramClass clazz : appView.appInfo().classes()) {
+ clazz.forEachProgramMethod(
+ method -> {
+ DexMethodSignature methodSignature = method.getMethodSignature();
+ if (isUnoptimizable(method)) {
+ normalization.put(methodSignature, methodSignature);
+ } else if (!normalization.containsKey(methodSignature)) {
+ optimizableMethodSignatures.add(methodSignature);
+ }
+ });
+ }
+ optimizableMethodSignatures.removeAll(normalization.keySet());
+
+ // Normalize each signature that is subject to optimization.
+ List<DexMethodSignature> sortedOptimizableMethodSignatures =
+ new ArrayList<>(optimizableMethodSignatures);
+ sortedOptimizableMethodSignatures.sort(DexMethodSignature::compareTo);
+
+ for (DexMethodSignature signature : sortedOptimizableMethodSignatures) {
+ assert !normalization.containsKey(signature);
+ assert !normalization.containsValue(signature);
+ DexMethodSignature normalizedSignature =
+ signature.withProto(
+ dexItemFactory.createProto(
+ signature.getReturnType(), signature.getParameters().getSorted()));
+ if (normalization.containsValue(normalizedSignature)) {
+ normalization.put(signature, signature);
+ } else {
+ normalization.put(signature, normalizedSignature);
+ }
+ }
+
+ return normalization;
+ }
+
+ private boolean isUnoptimizable(ProgramMethod method) {
+ // TODO(b/195112263): This is incomplete.
+ return appView.getKeepInfo(method).isPinned(options);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizerGraphLens.java b/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizerGraphLens.java
new file mode 100644
index 0000000..89d95d6
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizerGraphLens.java
@@ -0,0 +1,180 @@
+// Copyright (c) 2022, 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.optimize.proto;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.ArgumentPermutation;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
+import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap;
+import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap;
+import com.google.common.collect.ImmutableList;
+import java.util.IdentityHashMap;
+import java.util.Map;
+
+public class ProtoNormalizerGraphLens extends NonIdentityGraphLens {
+
+ private final BidirectionalOneToOneMap<DexMethod, DexMethod> newMethodSignatures;
+ private final Map<DexMethod, RewrittenPrototypeDescription> prototypeChanges;
+
+ ProtoNormalizerGraphLens(
+ AppView<?> appView,
+ BidirectionalOneToOneMap<DexMethod, DexMethod> newMethodSignatures,
+ Map<DexMethod, RewrittenPrototypeDescription> prototypeChanges) {
+ super(appView);
+ this.newMethodSignatures = newMethodSignatures;
+ this.prototypeChanges = prototypeChanges;
+ }
+
+ public static Builder builder(AppView<AppInfoWithLiveness> appView) {
+ return new Builder(appView);
+ }
+
+ @Override
+ public DexType getOriginalType(DexType type) {
+ return getPrevious().getOriginalType(type);
+ }
+
+ @Override
+ public Iterable<DexType> getOriginalTypes(DexType type) {
+ return getPrevious().getOriginalTypes(type);
+ }
+
+ @Override
+ public DexField getOriginalFieldSignature(DexField field) {
+ return getPrevious().getOriginalFieldSignature(field);
+ }
+
+ @Override
+ public DexField getRenamedFieldSignature(DexField originalField, GraphLens codeLens) {
+ return originalField;
+ }
+
+ @Override
+ public DexMethod getRenamedMethodSignature(DexMethod originalMethod, GraphLens applied) {
+ return newMethodSignatures.getOrDefault(originalMethod, originalMethod);
+ }
+
+ @Override
+ public RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(
+ DexMethod method, GraphLens codeLens) {
+ DexMethod previousMethodSignature = getPreviousMethodSignature(method);
+ RewrittenPrototypeDescription previousPrototypeChanges =
+ getPrevious().lookupPrototypeChangesForMethodDefinition(previousMethodSignature);
+ if (previousMethodSignature == method) {
+ return previousPrototypeChanges;
+ }
+ assert prototypeChanges.containsKey(method);
+ return previousPrototypeChanges.combine(prototypeChanges.get(method));
+ }
+
+ @Override
+ public boolean isContextFreeForMethods() {
+ return getPrevious().isContextFreeForMethods();
+ }
+
+ @Override
+ protected FieldLookupResult internalDescribeLookupField(FieldLookupResult previous) {
+ return previous;
+ }
+
+ @Override
+ protected MethodLookupResult internalDescribeLookupMethod(
+ MethodLookupResult previous, DexMethod context) {
+ DexMethod methodSignature = previous.getReference();
+ DexMethod newMethodSignature = getRenamedMethodSignature(methodSignature);
+ if (methodSignature == newMethodSignature) {
+ return previous;
+ }
+ assert !previous.hasReboundReference();
+ return MethodLookupResult.builder(this)
+ .setPrototypeChanges(
+ previous.getPrototypeChanges().combine(prototypeChanges.get(newMethodSignature)))
+ .setReference(newMethodSignature)
+ .setType(previous.getType())
+ .build();
+ }
+
+ @Override
+ protected DexType internalDescribeLookupClassType(DexType previous) {
+ return previous;
+ }
+
+ @Override
+ public DexMethod getPreviousMethodSignature(DexMethod method) {
+ return newMethodSignatures.getRepresentativeKeyOrDefault(method, method);
+ }
+
+ public static class Builder {
+
+ private final AppView<AppInfoWithLiveness> appView;
+ private final MutableBidirectionalOneToOneMap<DexMethod, DexMethod> newMethodSignatures =
+ new BidirectionalOneToOneHashMap<>();
+ private final Map<DexMethod, RewrittenPrototypeDescription> prototypeChanges =
+ new IdentityHashMap<>();
+
+ private Builder(AppView<AppInfoWithLiveness> appView) {
+ this.appView = appView;
+ }
+
+ public Builder recordNewMethodSignature(DexEncodedMethod method, DexMethod newMethodSignature) {
+ assert method.getReference() != newMethodSignature;
+ prototypeChanges.put(newMethodSignature, computePrototypeChanges(method, newMethodSignature));
+ newMethodSignatures.put(method.getReference(), newMethodSignature);
+ return this;
+ }
+
+ // TODO(b/195112263): Canonicalize the permutation maps.
+ private static RewrittenPrototypeDescription computePrototypeChanges(
+ DexEncodedMethod method, DexMethod newMethodSignature) {
+ int firstNonReceiverArgumentIndex = method.getFirstNonReceiverArgumentIndex();
+ int numberOfArguments = method.getNumberOfArguments();
+ ArgumentPermutation.Builder argumentPermutationBuilder =
+ ArgumentPermutation.builder(numberOfArguments);
+ boolean[] used = new boolean[numberOfArguments];
+ for (int argumentIndex = firstNonReceiverArgumentIndex;
+ argumentIndex < numberOfArguments;
+ argumentIndex++) {
+ DexType argumentType = method.getArgumentType(argumentIndex);
+ for (int newArgumentIndex = firstNonReceiverArgumentIndex;
+ newArgumentIndex < numberOfArguments;
+ newArgumentIndex++) {
+ DexType newArgumentType =
+ newMethodSignature.getArgumentType(
+ newArgumentIndex, method.getAccessFlags().isStatic());
+ if (argumentType == newArgumentType && !used[newArgumentIndex]) {
+ argumentPermutationBuilder.setNewArgumentIndex(argumentIndex, newArgumentIndex);
+ used[newArgumentIndex] = true;
+ break;
+ }
+ }
+ }
+ ArgumentPermutation argumentPermutation = argumentPermutationBuilder.build();
+ assert !argumentPermutation.isDefault();
+ ArgumentInfoCollection argumentInfoCollection =
+ ArgumentInfoCollection.builder()
+ .setArgumentInfosSize(numberOfArguments)
+ .setArgumentPermutation(argumentPermutation)
+ .build();
+ return RewrittenPrototypeDescription.create(ImmutableList.of(), null, argumentInfoCollection);
+ }
+
+ public boolean isEmpty() {
+ return newMethodSignatures.isEmpty();
+ }
+
+ public ProtoNormalizerGraphLens build() {
+ return new ProtoNormalizerGraphLens(appView, newMethodSignatures, prototypeChanges);
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index 78c8797..0c1e782 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -153,10 +153,6 @@
private final Set<DexMethod> neverInlineDueToSingleCaller;
/** Items for which to print inlining decisions for (testing only). */
private final Set<DexMethod> whyAreYouNotInlining;
- /** All methods that may not have any parameters with a constant value removed. */
- private final Set<DexMethod> keepConstantArguments;
- /** All methods that may not have any unused arguments removed. */
- private final Set<DexMethod> keepUnusedArguments;
/** All methods that must be reprocessed (testing only). */
private final Set<DexMethod> reprocess;
/** All methods that must not be reprocessed (testing only). */
@@ -228,8 +224,6 @@
Set<DexMethod> alwaysInline,
Set<DexMethod> neverInlineDueToSingleCaller,
Set<DexMethod> whyAreYouNotInlining,
- Set<DexMethod> keepConstantArguments,
- Set<DexMethod> keepUnusedArguments,
Set<DexMethod> reprocess,
Set<DexMethod> neverReprocess,
PredicateSet<DexType> alwaysClassInline,
@@ -265,8 +259,6 @@
this.alwaysInline = alwaysInline;
this.neverInlineDueToSingleCaller = neverInlineDueToSingleCaller;
this.whyAreYouNotInlining = whyAreYouNotInlining;
- this.keepConstantArguments = keepConstantArguments;
- this.keepUnusedArguments = keepUnusedArguments;
this.reprocess = reprocess;
this.neverReprocess = neverReprocess;
this.alwaysClassInline = alwaysClassInline;
@@ -310,8 +302,6 @@
previous.alwaysInline,
previous.neverInlineDueToSingleCaller,
previous.whyAreYouNotInlining,
- previous.keepConstantArguments,
- previous.keepUnusedArguments,
previous.reprocess,
previous.neverReprocess,
previous.alwaysClassInline,
@@ -360,8 +350,6 @@
pruneMethods(previous.alwaysInline, prunedItems, executorService, futures),
pruneMethods(previous.neverInlineDueToSingleCaller, prunedItems, executorService, futures),
pruneMethods(previous.whyAreYouNotInlining, prunedItems, executorService, futures),
- pruneMethods(previous.keepConstantArguments, prunedItems, executorService, futures),
- pruneMethods(previous.keepUnusedArguments, prunedItems, executorService, futures),
pruneMethods(previous.reprocess, prunedItems, executorService, futures),
pruneMethods(previous.neverReprocess, prunedItems, executorService, futures),
previous.alwaysClassInline,
@@ -567,8 +555,6 @@
alwaysInline,
neverInlineDueToSingleCaller,
whyAreYouNotInlining,
- keepConstantArguments,
- keepUnusedArguments,
reprocess,
neverReprocess,
alwaysClassInline,
@@ -649,8 +635,6 @@
this.alwaysInline = previous.alwaysInline;
this.neverInlineDueToSingleCaller = previous.neverInlineDueToSingleCaller;
this.whyAreYouNotInlining = previous.whyAreYouNotInlining;
- this.keepConstantArguments = previous.keepConstantArguments;
- this.keepUnusedArguments = previous.keepUnusedArguments;
this.reprocess = previous.reprocess;
this.neverReprocess = previous.neverReprocess;
this.alwaysClassInline = previous.alwaysClassInline;
@@ -681,7 +665,6 @@
|| getMissingClasses().contains(type)
// TODO(b/150693139): Remove these exceptions once fixed.
|| InterfaceDesugaringSyntheticHelper.isCompanionClassType(type)
- || InterfaceDesugaringSyntheticHelper.isEmulatedLibraryClassType(type)
// TODO(b/150736225): Not sure how to remove these.
|| DesugaredLibraryAPIConverter.isVivifiedType(type)
: "Failed lookup of non-missing type: " + type;
@@ -814,22 +797,6 @@
return whyAreYouNotInlining.isEmpty();
}
- public boolean isKeepConstantArgumentsMethod(ProgramMethod method) {
- return isKeepConstantArgumentsMethod(method.getReference());
- }
-
- public boolean isKeepConstantArgumentsMethod(DexMethod method) {
- return keepConstantArguments.contains(method);
- }
-
- public boolean isKeepUnusedArgumentsMethod(ProgramMethod method) {
- return isKeepUnusedArgumentsMethod(method.getReference());
- }
-
- public boolean isKeepUnusedArgumentsMethod(DexMethod method) {
- return keepUnusedArguments.contains(method);
- }
-
public boolean isNeverReprocessMethod(ProgramMethod method) {
return neverReprocess.contains(method.getReference())
|| method.getOptimizationInfo().hasBeenInlinedIntoSingleCallSite();
@@ -1285,8 +1252,6 @@
lens.rewriteReferences(alwaysInline),
lens.rewriteReferences(neverInlineDueToSingleCaller),
lens.rewriteReferences(whyAreYouNotInlining),
- lens.rewriteReferences(keepConstantArguments),
- lens.rewriteReferences(keepUnusedArguments),
lens.rewriteReferences(reprocess),
lens.rewriteReferences(neverReprocess),
alwaysClassInline.rewriteItems(lens::lookupType),
diff --git a/src/main/java/com/android/tools/r8/shaking/DependentMinimumKeepInfoCollection.java b/src/main/java/com/android/tools/r8/shaking/DependentMinimumKeepInfoCollection.java
index 8e48dfe..4c36623 100644
--- a/src/main/java/com/android/tools/r8/shaking/DependentMinimumKeepInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/shaking/DependentMinimumKeepInfoCollection.java
@@ -152,10 +152,14 @@
DependentMinimumKeepInfoCollection rewrittenDependentMinimumKeepInfo =
new DependentMinimumKeepInfoCollection();
forEach(
- (preconditionEvent, minimumKeepInfo) ->
+ (preconditionEvent, minimumKeepInfo) -> {
+ EnqueuerEvent rewrittenPreconditionEvent = preconditionEvent.rewrittenWithLens(graphLens);
+ if (!rewrittenPreconditionEvent.isNoSuchEvent()) {
rewrittenDependentMinimumKeepInfo
- .getOrCreateMinimumKeepInfoFor(preconditionEvent.rewrittenWithLens(graphLens))
- .merge(minimumKeepInfo.rewrittenWithLens(graphLens)));
+ .getOrCreateMinimumKeepInfoFor(rewrittenPreconditionEvent)
+ .merge(minimumKeepInfo.rewrittenWithLens(graphLens));
+ }
+ });
return rewrittenDependentMinimumKeepInfo;
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 658cfbf..1622376 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
+import static com.android.tools.r8.graph.DexEncodedMethod.asProgramMethodOrNull;
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import static com.android.tools.r8.graph.FieldAccessInfoImpl.MISSING_FIELD_ACCESS_INFO;
import static com.android.tools.r8.ir.desugar.LambdaDescriptor.isLambdaMetafactoryMethod;
@@ -48,6 +49,7 @@
import com.android.tools.r8.graph.DexMember;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexMethodHandle;
+import com.android.tools.r8.graph.DexMethodSignature;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexReference;
@@ -142,6 +144,7 @@
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.Visibility;
import com.android.tools.r8.utils.WorkList;
+import com.android.tools.r8.utils.collections.DexMethodSignatureSet;
import com.android.tools.r8.utils.collections.ProgramFieldSet;
import com.android.tools.r8.utils.collections.ProgramMethodMap;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
@@ -764,12 +767,14 @@
return getProgramClassOrNull(member.getHolderType(), context);
}
+ private DexClass getClassOrNullFromReflectiveAccess(DexType type, ProgramDefinition context) {
+ // To avoid that we report reflectively accessed types as missing.
+ return definitionFor(type, context, this::recordNonProgramClass, this::ignoreMissingClass);
+ }
+
private DexProgramClass getProgramClassOrNullFromReflectiveAccess(
DexType type, ProgramDefinition context) {
- // To avoid that we report reflectively accessed types as missing.
- DexClass clazz =
- definitionFor(type, context, this::recordNonProgramClass, this::ignoreMissingClass);
- return clazz != null && clazz.isProgramClass() ? clazz.asProgramClass() : null;
+ return asProgramClassOrNull(getClassOrNullFromReflectiveAccess(type, context));
}
private void warnIfLibraryTypeInheritsFromProgramType(DexLibraryClass clazz) {
@@ -858,6 +863,8 @@
}
if (clazz.isExternalizable(appView)) {
workList.enqueueMarkMethodLiveAction(defaultInitializer, defaultInitializer, witness);
+ applyMinimumKeepInfoWhenLiveOrTargeted(
+ defaultInitializer, KeepMethodInfo.newEmptyJoiner().disallowOptimization());
}
}
}
@@ -899,6 +906,9 @@
}
if (clazz.hasDefaultInitializer()) {
workList.enqueueMarkMethodLiveAction(clazz.getProgramDefaultInitializer(), clazz, reason);
+ applyMinimumKeepInfoWhenLiveOrTargeted(
+ clazz.getProgramDefaultInitializer(),
+ KeepMethodInfo.newEmptyJoiner().disallowOptimization());
}
}
@@ -1453,7 +1463,8 @@
FieldResolutionResult resolutionResult = resolveField(fieldReference, currentMethod);
fieldAccessAnalyses.forEach(
analysis ->
- analysis.traceInstanceFieldRead(fieldReference, resolutionResult, currentMethod));
+ analysis.traceInstanceFieldRead(
+ fieldReference, resolutionResult, currentMethod, workList));
if (resolutionResult.isFailedOrUnknownResolution()) {
// Must trace the types from the field reference even if it does not exist.
@@ -1511,7 +1522,8 @@
FieldResolutionResult resolutionResult = resolveField(fieldReference, currentMethod);
fieldAccessAnalyses.forEach(
analysis ->
- analysis.traceInstanceFieldWrite(fieldReference, resolutionResult, currentMethod));
+ analysis.traceInstanceFieldWrite(
+ fieldReference, resolutionResult, currentMethod, workList));
if (resolutionResult.isFailedOrUnknownResolution()) {
// Must trace the types from the field reference even if it does not exist.
@@ -1566,7 +1578,9 @@
FieldResolutionResult resolutionResult = resolveField(fieldReference, currentMethod);
fieldAccessAnalyses.forEach(
- analysis -> analysis.traceStaticFieldRead(fieldReference, resolutionResult, currentMethod));
+ analysis ->
+ analysis.traceStaticFieldRead(
+ fieldReference, resolutionResult, currentMethod, workList));
if (resolutionResult.isFailedOrUnknownResolution()) {
// Must trace the types from the field reference even if it does not exist.
@@ -1638,7 +1652,8 @@
FieldResolutionResult resolutionResult = resolveField(fieldReference, currentMethod);
fieldAccessAnalyses.forEach(
analysis ->
- analysis.traceStaticFieldWrite(fieldReference, resolutionResult, currentMethod));
+ analysis.traceStaticFieldWrite(
+ fieldReference, resolutionResult, currentMethod, workList));
if (resolutionResult.isFailedOrUnknownResolution()) {
// Must trace the types from the field reference even if it does not exist.
@@ -3232,9 +3247,7 @@
applyMinimumKeepInfoWhenLive(clazz, preconditionEvent, minimumKeepInfo),
(field, minimumKeepInfo) ->
applyMinimumKeepInfoWhenLive(field, preconditionEvent, minimumKeepInfo),
- (method, minimumKeepInfo) ->
- applyMinimumKeepInfoWhenLiveOrTargeted(
- method, preconditionEvent, minimumKeepInfo));
+ this::applyMinimumKeepInfoWhenLiveOrTargeted);
}
enqueueAllIfNotShrinking();
trace(executorService, timing);
@@ -3373,8 +3386,14 @@
private void applyMinimumKeepInfoWhenLiveOrTargeted(
ProgramMethod method,
- EnqueuerEvent preconditionEvent,
KeepMethodInfo.Joiner minimumKeepInfo) {
+ applyMinimumKeepInfoWhenLiveOrTargeted(method, minimumKeepInfo, EnqueuerEvent.unconditional());
+ }
+
+ private void applyMinimumKeepInfoWhenLiveOrTargeted(
+ ProgramMethod method,
+ KeepMethodInfo.Joiner minimumKeepInfo,
+ EnqueuerEvent preconditionEvent) {
if (liveMethods.contains(method) || targetedMethods.contains(method)) {
keepInfo.joinMethod(method, info -> info.merge(minimumKeepInfo));
} else {
@@ -3405,7 +3424,7 @@
ProgramMethod method,
KeepMethodInfo.Joiner minimumKeepInfo) {
if (isPreconditionForMinimumKeepInfoSatisfied(preconditionEvent)) {
- applyMinimumKeepInfoWhenLiveOrTargeted(method, preconditionEvent, minimumKeepInfo);
+ applyMinimumKeepInfoWhenLiveOrTargeted(method, minimumKeepInfo, preconditionEvent);
} else {
dependentMinimumKeepInfo
.getOrCreateMinimumKeepInfoFor(preconditionEvent)
@@ -3429,7 +3448,7 @@
applyMinimumKeepInfoWhenLive(field, preconditionEvent, minimumKeepInfoForField),
(method, minimumKeepInfoForMethod) ->
applyMinimumKeepInfoWhenLiveOrTargeted(
- method, preconditionEvent, minimumKeepInfoForMethod));
+ method, minimumKeepInfoForMethod, preconditionEvent));
}
}
@@ -3480,10 +3499,6 @@
assert old == null || old == clazz;
}
- public void addLiveMethods(Iterable<ProgramMethod> methods) {
- methods.forEach(this::addLiveMethod);
- }
-
public void addLiveMethod(ProgramMethod method) {
DexMethod signature = method.getDefinition().getReference();
ProgramMethod old = liveMethods.put(signature, method);
@@ -3500,18 +3515,6 @@
newInterfaces.add(newInterface);
}
- void addLiveMethodWithKeepAction(
- ProgramMethod method, Consumer<KeepMethodInfo.Joiner> keepAction) {
- addLiveMethod(method);
- liveMethodsWithKeepActions.add(new Pair<>(method, keepAction));
- }
-
- public ProgramMethodSet getLiveMethods() {
- ProgramMethodSet set = ProgramMethodSet.create();
- liveMethods.values().forEach(set::add);
- return set;
- }
-
public void addMinimumKeepInfo(ProgramMethod method, Consumer<KeepMethodInfo.Joiner> consumer) {
consumer.accept(
minimumKeepInfo.computeIfAbsent(method, ignoreKey(KeepMethodInfo::newEmptyJoiner)));
@@ -3543,8 +3546,7 @@
minimumKeepInfo.forEach(
(method, minimumKeepInfoForMethod) ->
- enqueuer.applyMinimumKeepInfoWhenLiveOrTargeted(
- method, UnconditionalKeepInfoEvent.get(), minimumKeepInfoForMethod));
+ enqueuer.applyMinimumKeepInfoWhenLiveOrTargeted(method, minimumKeepInfoForMethod));
}
}
@@ -3806,8 +3808,6 @@
amendWithCompanionMethods(rootSet.alwaysInline),
amendWithCompanionMethods(rootSet.neverInlineDueToSingleCaller),
amendWithCompanionMethods(rootSet.whyAreYouNotInlining),
- amendWithCompanionMethods(rootSet.keepConstantArguments),
- amendWithCompanionMethods(rootSet.keepUnusedArguments),
amendWithCompanionMethods(rootSet.reprocess),
amendWithCompanionMethods(rootSet.neverReprocess),
rootSet.alwaysClassInline,
@@ -4533,18 +4533,19 @@
if (clazz == null) {
return;
}
- DexEncodedMethod targetedMethodDefinition = clazz.lookupMethod(targetedMethodReference);
- if (targetedMethodDefinition == null) {
+ ProgramMethod targetedMethod = clazz.lookupProgramMethod(targetedMethodReference);
+ if (targetedMethod == null) {
return;
}
- ProgramMethod targetedMethod = new ProgramMethod(clazz, targetedMethodDefinition);
KeepReason reason = KeepReason.reflectiveUseIn(method);
- if (targetedMethodDefinition.isStatic() || targetedMethodDefinition.isInstanceInitializer()) {
+ if (targetedMethod.getDefinition().belongsToDirectPool()) {
markMethodAsTargeted(targetedMethod, reason);
markDirectStaticOrConstructorMethodAsLive(targetedMethod, reason);
} else {
markVirtualMethodAsLive(targetedMethod, reason);
}
+ applyMinimumKeepInfoWhenLiveOrTargeted(
+ targetedMethod, KeepMethodInfo.newEmptyJoiner().disallowOptimization());
}
}
@@ -4574,6 +4575,8 @@
markClassAsInstantiatedWithReason(clazz, reason);
markMethodAsTargeted(defaultInitializer, reason);
markDirectStaticOrConstructorMethodAsLive(defaultInitializer, reason);
+ applyMinimumKeepInfoWhenLiveOrTargeted(
+ defaultInitializer, KeepMethodInfo.newEmptyJoiner().disallowOptimization());
}
}
@@ -4675,6 +4678,8 @@
markClassAsInstantiatedWithReason(clazz, reason);
markMethodAsTargeted(initializer, reason);
markDirectStaticOrConstructorMethodAsLive(initializer, reason);
+ applyMinimumKeepInfoWhenLiveOrTargeted(
+ initializer, KeepMethodInfo.newEmptyJoiner().disallowOptimization());
}
}
@@ -4797,6 +4802,7 @@
DexType serviceType, ProgramMethod context, KeepReason reason) {
List<DexType> serviceImplementationTypes =
appView.appServices().serviceImplementationsFor(serviceType);
+ DexMethodSignatureSet serviceMethods = getServiceMethods(serviceType, context);
for (DexType serviceImplementationType : serviceImplementationTypes) {
if (!serviceImplementationType.isClassType()) {
// Should never happen.
@@ -4805,12 +4811,46 @@
DexProgramClass serviceImplementationClass =
getProgramClassOrNull(serviceImplementationType, context);
- if (serviceImplementationClass != null && serviceImplementationClass.isProgramClass()) {
- markClassAsInstantiatedWithReason(serviceImplementationClass, reason);
+ if (serviceImplementationClass == null) {
+ continue;
+ }
+
+ markClassAsInstantiatedWithReason(serviceImplementationClass, reason);
+
+ ProgramMethod defaultInitializer = serviceImplementationClass.getProgramDefaultInitializer();
+ if (defaultInitializer != null) {
+ applyMinimumKeepInfoWhenLiveOrTargeted(
+ defaultInitializer, KeepMethodInfo.newEmptyJoiner().disallowOptimization());
+ }
+
+ for (DexMethodSignature serviceMethod : serviceMethods) {
+ ProgramMethod serviceImplementationMethod =
+ asProgramMethodOrNull(
+ serviceImplementationClass.getMethodCollection().getMethod(serviceMethod),
+ serviceImplementationClass);
+ if (serviceImplementationMethod != null) {
+ applyMinimumKeepInfoWhenLiveOrTargeted(
+ serviceImplementationMethod, KeepMethodInfo.newEmptyJoiner().disallowOptimization());
+ }
}
}
}
+ private DexMethodSignatureSet getServiceMethods(DexType serviceType, ProgramMethod context) {
+ DexMethodSignatureSet serviceMethods = DexMethodSignatureSet.create();
+ WorkList<DexType> serviceTypes = WorkList.newIdentityWorkList(serviceType);
+ while (serviceTypes.hasNext()) {
+ DexType current = serviceTypes.next();
+ DexClass clazz = getClassOrNullFromReflectiveAccess(current, context);
+ if (clazz == null) {
+ continue;
+ }
+ clazz.forEachClassMethodMatching(DexEncodedMethod::belongsToVirtualPool, serviceMethods::add);
+ serviceTypes.addIfNotSeen(clazz.getInterfaces());
+ }
+ return serviceMethods;
+ }
+
private static class SetWithReportedReason<T> {
private final Set<T> items = Sets.newIdentityHashSet();
diff --git a/src/main/java/com/android/tools/r8/shaking/EnqueuerEvent.java b/src/main/java/com/android/tools/r8/shaking/EnqueuerEvent.java
index ee2b7d0..93d5f60 100644
--- a/src/main/java/com/android/tools/r8/shaking/EnqueuerEvent.java
+++ b/src/main/java/com/android/tools/r8/shaking/EnqueuerEvent.java
@@ -12,10 +12,18 @@
public abstract class EnqueuerEvent {
+ public static UnconditionalKeepInfoEvent unconditional() {
+ return UnconditionalKeepInfoEvent.get();
+ }
+
public DexDefinition getDefinition(DexDefinitionSupplier definitions) {
return null;
}
+ public boolean isNoSuchEvent() {
+ return false;
+ }
+
public boolean isClassEvent() {
return false;
}
@@ -46,6 +54,27 @@
public abstract EnqueuerEvent rewrittenWithLens(GraphLens lens);
+ public static class NoSuchEnqueuerEvent extends EnqueuerEvent {
+
+ private static final NoSuchEnqueuerEvent INSTANCE = new NoSuchEnqueuerEvent();
+
+ private NoSuchEnqueuerEvent() {}
+
+ public static NoSuchEnqueuerEvent get() {
+ return INSTANCE;
+ }
+
+ @Override
+ public boolean isNoSuchEvent() {
+ return true;
+ }
+
+ @Override
+ public EnqueuerEvent rewrittenWithLens(GraphLens lens) {
+ return this;
+ }
+ }
+
public abstract static class ClassEnqueuerEvent extends EnqueuerEvent {
private final DexType clazz;
@@ -96,7 +125,11 @@
@Override
public EnqueuerEvent rewrittenWithLens(GraphLens lens) {
- return new LiveClassEnqueuerEvent(lens.lookupType(getType()));
+ DexType rewrittenType = lens.lookupType(getType());
+ if (rewrittenType.isIntType()) {
+ return NoSuchEnqueuerEvent.get();
+ }
+ return new LiveClassEnqueuerEvent(rewrittenType);
}
@Override
@@ -139,7 +172,11 @@
@Override
public EnqueuerEvent rewrittenWithLens(GraphLens lens) {
- return new InstantiatedClassEnqueuerEvent(lens.lookupType(getType()));
+ DexType rewrittenType = lens.lookupType(getType());
+ if (rewrittenType.isIntType()) {
+ return NoSuchEnqueuerEvent.get();
+ }
+ return new InstantiatedClassEnqueuerEvent(rewrittenType);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java b/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java
index 1f4bc35..0efc4b5 100644
--- a/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java
+++ b/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java
@@ -257,6 +257,22 @@
}
}
+ static class TraceInvokeStaticAction extends EnqueuerAction {
+ private final DexMethod invokedMethod;
+ // TODO(b/175854431): Avoid pushing context on worklist.
+ private final ProgramMethod context;
+
+ TraceInvokeStaticAction(DexMethod invokedMethod, ProgramMethod context) {
+ this.invokedMethod = invokedMethod;
+ this.context = context;
+ }
+
+ @Override
+ public void run(Enqueuer enqueuer) {
+ enqueuer.traceInvokeStatic(invokedMethod, context);
+ }
+ }
+
static class TraceMethodDefinitionExcludingCodeAction extends EnqueuerAction {
private final ProgramMethod method;
@@ -364,6 +380,9 @@
public abstract void enqueueTraceInvokeDirectAction(
DexMethod invokedMethod, ProgramMethod context);
+ public abstract void enqueueTraceInvokeStaticAction(
+ DexMethod invokedMethod, ProgramMethod context);
+
public abstract void enqueueTraceNewInstanceAction(DexType type, ProgramMethod context);
public abstract void enqueueTraceStaticFieldRead(DexField field, ProgramMethod context);
@@ -478,6 +497,11 @@
}
@Override
+ public void enqueueTraceInvokeStaticAction(DexMethod invokedMethod, ProgramMethod context) {
+ queue.add(new TraceInvokeStaticAction(invokedMethod, context));
+ }
+
+ @Override
public void enqueueTraceNewInstanceAction(DexType type, ProgramMethod context) {
queue.add(new TraceNewInstanceAction(type, context));
}
@@ -595,6 +619,11 @@
}
@Override
+ public void enqueueTraceInvokeStaticAction(DexMethod invokedMethod, ProgramMethod context) {
+ throw attemptToEnqueue();
+ }
+
+ @Override
public void enqueueTraceNewInstanceAction(DexType type, ProgramMethod context) {
throw attemptToEnqueue();
}
diff --git a/src/main/java/com/android/tools/r8/shaking/ConstantArgumentRule.java b/src/main/java/com/android/tools/r8/shaking/KeepConstantArgumentRule.java
similarity index 83%
rename from src/main/java/com/android/tools/r8/shaking/ConstantArgumentRule.java
rename to src/main/java/com/android/tools/r8/shaking/KeepConstantArgumentRule.java
index bc33778..f234a09 100644
--- a/src/main/java/com/android/tools/r8/shaking/ConstantArgumentRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepConstantArgumentRule.java
@@ -7,10 +7,12 @@
import com.android.tools.r8.position.Position;
import java.util.List;
-public class ConstantArgumentRule extends ProguardConfigurationRule {
+public class KeepConstantArgumentRule extends NoOptimizationBaseRule<KeepConstantArgumentRule> {
+
+ public static final String RULE_NAME = "keepconstantarguments";
public static class Builder
- extends ProguardConfigurationRule.Builder<ConstantArgumentRule, Builder> {
+ extends NoOptimizationBaseRule.Builder<KeepConstantArgumentRule, Builder> {
private Builder() {
super();
@@ -22,8 +24,8 @@
}
@Override
- public ConstantArgumentRule build() {
- return new ConstantArgumentRule(
+ public KeepConstantArgumentRule build() {
+ return new KeepConstantArgumentRule(
origin,
getPosition(),
source,
@@ -40,7 +42,7 @@
}
}
- private ConstantArgumentRule(
+ private KeepConstantArgumentRule(
Origin origin,
Position position,
String source,
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepInfo.java b/src/main/java/com/android/tools/r8/shaking/KeepInfo.java
index 9b83643..bcf9467 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepInfo.java
@@ -83,12 +83,6 @@
return checkDiscarded;
}
- public boolean isParameterRemovalAllowed(GlobalKeepInfoConfiguration configuration) {
- return isOptimizationAllowed(configuration)
- && isShrinkingAllowed(configuration)
- && !isCheckDiscardedEnabled(configuration);
- }
-
/**
* True if an item must be present in the output.
*
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java b/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
index b43c44d..c82c666 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
@@ -25,18 +25,24 @@
}
private final boolean allowClassInlining;
+ private final boolean allowConstantArgumentOptimization;
private final boolean allowInlining;
private final boolean allowMethodStaticizing;
private final boolean allowParameterTypeStrengthening;
private final boolean allowReturnTypeStrengthening;
+ private final boolean allowUnusedArgumentOptimization;
+ private final boolean allowUnusedReturnValueOptimization;
private KeepMethodInfo(Builder builder) {
super(builder);
this.allowClassInlining = builder.isClassInliningAllowed();
+ this.allowConstantArgumentOptimization = builder.isConstantArgumentOptimizationAllowed();
this.allowInlining = builder.isInliningAllowed();
this.allowMethodStaticizing = builder.isMethodStaticizingAllowed();
this.allowParameterTypeStrengthening = builder.isParameterTypeStrengtheningAllowed();
this.allowReturnTypeStrengthening = builder.isReturnTypeStrengtheningAllowed();
+ this.allowUnusedArgumentOptimization = builder.isUnusedArgumentOptimizationAllowed();
+ this.allowUnusedReturnValueOptimization = builder.isUnusedReturnValueOptimizationAllowed();
}
// This builder is not private as there are known instances where it is safe to modify keep info
@@ -50,6 +56,12 @@
return isParameterRemovalAllowed(configuration);
}
+ public boolean isParameterRemovalAllowed(GlobalKeepInfoConfiguration configuration) {
+ return isOptimizationAllowed(configuration)
+ && isShrinkingAllowed(configuration)
+ && !isCheckDiscardedEnabled(configuration);
+ }
+
public boolean isClassInliningAllowed(GlobalKeepInfoConfiguration configuration) {
return isOptimizationAllowed(configuration) && internalIsClassInliningAllowed();
}
@@ -58,6 +70,14 @@
return allowClassInlining;
}
+ public boolean isConstantArgumentOptimizationAllowed(GlobalKeepInfoConfiguration configuration) {
+ return isOptimizationAllowed(configuration) && internalIsConstantArgumentOptimizationAllowed();
+ }
+
+ boolean internalIsConstantArgumentOptimizationAllowed() {
+ return allowConstantArgumentOptimization;
+ }
+
public boolean isInliningAllowed(GlobalKeepInfoConfiguration configuration) {
return isOptimizationAllowed(configuration) && internalIsInliningAllowed();
}
@@ -97,6 +117,26 @@
return allowReturnTypeStrengthening;
}
+ public boolean isUnusedArgumentOptimizationAllowed(GlobalKeepInfoConfiguration configuration) {
+ return isOptimizationAllowed(configuration)
+ && isShrinkingAllowed(configuration)
+ && internalIsUnusedArgumentOptimizationAllowed();
+ }
+
+ boolean internalIsUnusedArgumentOptimizationAllowed() {
+ return allowUnusedArgumentOptimization;
+ }
+
+ public boolean isUnusedReturnValueOptimizationAllowed(GlobalKeepInfoConfiguration configuration) {
+ return isOptimizationAllowed(configuration)
+ && isShrinkingAllowed(configuration)
+ && internalIsUnusedReturnValueOptimizationAllowed();
+ }
+
+ boolean internalIsUnusedReturnValueOptimizationAllowed() {
+ return allowUnusedReturnValueOptimization;
+ }
+
public Joiner joiner() {
assert !isTop();
return new Joiner(this);
@@ -115,10 +155,13 @@
public static class Builder extends KeepInfo.Builder<Builder, KeepMethodInfo> {
private boolean allowClassInlining;
+ private boolean allowConstantArgumentOptimization;
private boolean allowInlining;
private boolean allowMethodStaticizing;
private boolean allowParameterTypeStrengthening;
private boolean allowReturnTypeStrengthening;
+ private boolean allowUnusedArgumentOptimization;
+ private boolean allowUnusedReturnValueOptimization;
private Builder() {
super();
@@ -127,12 +170,18 @@
private Builder(KeepMethodInfo original) {
super(original);
allowClassInlining = original.internalIsClassInliningAllowed();
+ allowConstantArgumentOptimization = original.internalIsConstantArgumentOptimizationAllowed();
allowInlining = original.internalIsInliningAllowed();
allowMethodStaticizing = original.internalIsMethodStaticizingAllowed();
allowParameterTypeStrengthening = original.internalIsParameterTypeStrengtheningAllowed();
allowReturnTypeStrengthening = original.internalIsReturnTypeStrengtheningAllowed();
+ allowUnusedArgumentOptimization = original.internalIsUnusedArgumentOptimizationAllowed();
+ allowUnusedReturnValueOptimization =
+ original.internalIsUnusedReturnValueOptimizationAllowed();
}
+ // Class inlining.
+
public boolean isClassInliningAllowed() {
return allowClassInlining;
}
@@ -150,6 +199,27 @@
return setAllowClassInlining(false);
}
+ // Constant argument optimization.
+
+ public boolean isConstantArgumentOptimizationAllowed() {
+ return allowConstantArgumentOptimization;
+ }
+
+ public Builder setAllowConstantArgumentOptimization(boolean allowConstantArgumentOptimization) {
+ this.allowConstantArgumentOptimization = allowConstantArgumentOptimization;
+ return self();
+ }
+
+ public Builder allowConstantArgumentOptimization() {
+ return setAllowConstantArgumentOptimization(true);
+ }
+
+ public Builder disallowConstantArgumentOptimization() {
+ return setAllowConstantArgumentOptimization(false);
+ }
+
+ // Inlining.
+
public boolean isInliningAllowed() {
return allowInlining;
}
@@ -167,6 +237,8 @@
return setAllowInlining(false);
}
+ // Method staticizing.
+
public boolean isMethodStaticizingAllowed() {
return allowMethodStaticizing;
}
@@ -184,6 +256,8 @@
return setAllowMethodStaticizing(false);
}
+ // Parameter type strengthening.
+
public boolean isParameterTypeStrengtheningAllowed() {
return allowParameterTypeStrengthening;
}
@@ -201,6 +275,8 @@
return setAllowParameterTypeStrengthening(false);
}
+ // Return type strengthening.
+
public boolean isReturnTypeStrengtheningAllowed() {
return allowReturnTypeStrengthening;
}
@@ -218,6 +294,45 @@
return setAllowReturnTypeStrengthening(false);
}
+ // Unused argument optimization.
+
+ public boolean isUnusedArgumentOptimizationAllowed() {
+ return allowUnusedArgumentOptimization;
+ }
+
+ public Builder setAllowUnusedArgumentOptimization(boolean allowUnusedArgumentOptimization) {
+ this.allowUnusedArgumentOptimization = allowUnusedArgumentOptimization;
+ return self();
+ }
+
+ public Builder allowUnusedArgumentOptimization() {
+ return setAllowUnusedArgumentOptimization(true);
+ }
+
+ public Builder disallowUnusedArgumentOptimization() {
+ return setAllowUnusedArgumentOptimization(false);
+ }
+
+ // Unused return value optimization.
+
+ public boolean isUnusedReturnValueOptimizationAllowed() {
+ return allowUnusedReturnValueOptimization;
+ }
+
+ public Builder setAllowUnusedReturnValueOptimization(
+ boolean allowUnusedReturnValueOptimization) {
+ this.allowUnusedReturnValueOptimization = allowUnusedReturnValueOptimization;
+ return self();
+ }
+
+ public Builder allowUnusedReturnValueOptimization() {
+ return setAllowUnusedReturnValueOptimization(true);
+ }
+
+ public Builder disallowUnusedReturnValueOptimization() {
+ return setAllowUnusedReturnValueOptimization(false);
+ }
+
@Override
public Builder self() {
return this;
@@ -242,11 +357,17 @@
boolean internalIsEqualTo(KeepMethodInfo other) {
return super.internalIsEqualTo(other)
&& isClassInliningAllowed() == other.internalIsClassInliningAllowed()
+ && isConstantArgumentOptimizationAllowed()
+ == other.internalIsConstantArgumentOptimizationAllowed()
&& isInliningAllowed() == other.internalIsInliningAllowed()
&& isMethodStaticizingAllowed() == other.internalIsMethodStaticizingAllowed()
&& isParameterTypeStrengtheningAllowed()
== other.internalIsParameterTypeStrengtheningAllowed()
- && isReturnTypeStrengtheningAllowed() == other.internalIsReturnTypeStrengtheningAllowed();
+ && isReturnTypeStrengtheningAllowed() == other.internalIsReturnTypeStrengtheningAllowed()
+ && isUnusedArgumentOptimizationAllowed()
+ == other.internalIsUnusedArgumentOptimizationAllowed()
+ && isUnusedReturnValueOptimizationAllowed()
+ == other.internalIsUnusedReturnValueOptimizationAllowed();
}
@Override
@@ -258,20 +379,26 @@
public Builder makeTop() {
return super.makeTop()
.disallowClassInlining()
+ .disallowConstantArgumentOptimization()
.disallowInlining()
.disallowMethodStaticizing()
.disallowParameterTypeStrengthening()
- .disallowReturnTypeStrengthening();
+ .disallowReturnTypeStrengthening()
+ .disallowUnusedArgumentOptimization()
+ .disallowUnusedReturnValueOptimization();
}
@Override
public Builder makeBottom() {
return super.makeBottom()
.allowClassInlining()
+ .allowConstantArgumentOptimization()
.allowInlining()
.allowMethodStaticizing()
.allowParameterTypeStrengthening()
- .allowReturnTypeStrengthening();
+ .allowReturnTypeStrengthening()
+ .allowUnusedArgumentOptimization()
+ .allowUnusedReturnValueOptimization();
}
}
@@ -286,6 +413,11 @@
return self();
}
+ public Joiner disallowConstantArgumentOptimization() {
+ builder.disallowConstantArgumentOptimization();
+ return self();
+ }
+
public Joiner disallowInlining() {
builder.disallowInlining();
return self();
@@ -306,6 +438,16 @@
return self();
}
+ public Joiner disallowUnusedArgumentOptimization() {
+ builder.disallowUnusedArgumentOptimization();
+ return self();
+ }
+
+ public Joiner disallowUnusedReturnValueOptimization() {
+ builder.disallowUnusedReturnValueOptimization();
+ return self();
+ }
+
@Override
public Joiner asMethodJoiner() {
return this;
@@ -316,6 +458,9 @@
// Should be extended to merge the fields of this class in case any are added.
return super.merge(joiner)
.applyIf(!joiner.builder.isClassInliningAllowed(), Joiner::disallowClassInlining)
+ .applyIf(
+ !joiner.builder.isConstantArgumentOptimizationAllowed(),
+ Joiner::disallowConstantArgumentOptimization)
.applyIf(!joiner.builder.isInliningAllowed(), Joiner::disallowInlining)
.applyIf(!joiner.builder.isMethodStaticizingAllowed(), Joiner::disallowMethodStaticizing)
.applyIf(
@@ -323,7 +468,13 @@
Joiner::disallowParameterTypeStrengthening)
.applyIf(
!joiner.builder.isReturnTypeStrengtheningAllowed(),
- Joiner::disallowReturnTypeStrengthening);
+ Joiner::disallowReturnTypeStrengthening)
+ .applyIf(
+ !joiner.builder.isUnusedArgumentOptimizationAllowed(),
+ Joiner::disallowUnusedArgumentOptimization)
+ .applyIf(
+ !joiner.builder.isUnusedReturnValueOptimizationAllowed(),
+ Joiner::disallowUnusedReturnValueOptimization);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/shaking/UnusedArgumentRule.java b/src/main/java/com/android/tools/r8/shaking/KeepUnusedArgumentRule.java
similarity index 83%
rename from src/main/java/com/android/tools/r8/shaking/UnusedArgumentRule.java
rename to src/main/java/com/android/tools/r8/shaking/KeepUnusedArgumentRule.java
index dd537bc..18ba2ff 100644
--- a/src/main/java/com/android/tools/r8/shaking/UnusedArgumentRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepUnusedArgumentRule.java
@@ -7,10 +7,12 @@
import com.android.tools.r8.position.Position;
import java.util.List;
-public class UnusedArgumentRule extends ProguardConfigurationRule {
+public class KeepUnusedArgumentRule extends NoOptimizationBaseRule<KeepUnusedArgumentRule> {
+
+ public static final String RULE_NAME = "keepunusedarguments";
public static class Builder
- extends ProguardConfigurationRule.Builder<UnusedArgumentRule, Builder> {
+ extends NoOptimizationBaseRule.Builder<KeepUnusedArgumentRule, Builder> {
private Builder() {
super();
@@ -22,8 +24,8 @@
}
@Override
- public UnusedArgumentRule build() {
- return new UnusedArgumentRule(
+ public KeepUnusedArgumentRule build() {
+ return new KeepUnusedArgumentRule(
origin,
getPosition(),
source,
@@ -40,7 +42,7 @@
}
}
- private UnusedArgumentRule(
+ private KeepUnusedArgumentRule(
Origin origin,
Position position,
String source,
@@ -76,6 +78,6 @@
@Override
String typeString() {
- return "keepunusedarguments";
+ return RULE_NAME;
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/ConstantArgumentRule.java b/src/main/java/com/android/tools/r8/shaking/KeepUnusedReturnValueRule.java
similarity index 76%
copy from src/main/java/com/android/tools/r8/shaking/ConstantArgumentRule.java
copy to src/main/java/com/android/tools/r8/shaking/KeepUnusedReturnValueRule.java
index bc33778..2543285 100644
--- a/src/main/java/com/android/tools/r8/shaking/ConstantArgumentRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepUnusedReturnValueRule.java
@@ -1,29 +1,32 @@
-// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2022, 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.shaking;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.Position;
import java.util.List;
-public class ConstantArgumentRule extends ProguardConfigurationRule {
+public class KeepUnusedReturnValueRule extends NoOptimizationBaseRule<KeepUnusedReturnValueRule> {
+
+ public static final String RULE_NAME = "keepunusedreturnvalue";
public static class Builder
- extends ProguardConfigurationRule.Builder<ConstantArgumentRule, Builder> {
+ extends NoOptimizationBaseRule.Builder<KeepUnusedReturnValueRule, Builder> {
- private Builder() {
+ Builder() {
super();
}
@Override
- public Builder self() {
+ public KeepUnusedReturnValueRule.Builder self() {
return this;
}
@Override
- public ConstantArgumentRule build() {
- return new ConstantArgumentRule(
+ public KeepUnusedReturnValueRule build() {
+ return new KeepUnusedReturnValueRule(
origin,
getPosition(),
source,
@@ -40,7 +43,7 @@
}
}
- private ConstantArgumentRule(
+ KeepUnusedReturnValueRule(
Origin origin,
Position position,
String source,
@@ -76,6 +79,6 @@
@Override
String typeString() {
- return "keepconstantarguments";
+ return RULE_NAME;
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java b/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java
index 960ccd5..ab0a04d 100644
--- a/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java
@@ -28,9 +28,9 @@
public L8TreePruner(InternalOptions options) {
this.options = options;
- backports.addAll(options.desugaredLibrarySpecification.getBackportCoreLibraryMember().keySet());
+ backports.addAll(options.machineDesugaredLibrarySpecification.getLegacyBackport().keySet());
emulatedInterfaces.addAll(
- options.desugaredLibrarySpecification.getEmulateLibraryInterface().keySet());
+ options.machineDesugaredLibrarySpecification.getEmulatedInterfaces().keySet());
}
public DexApplication prune(DexApplication app, PrefixRewritingMapper rewritePrefix) {
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index b1fdef2..0f2ad2c 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -450,13 +450,21 @@
configurationBuilder.addRule(rule);
return true;
}
- if (acceptString("keepconstantarguments")) {
- ConstantArgumentRule rule = parseConstantArgumentRule(optionStart);
+ if (acceptString(KeepConstantArgumentRule.RULE_NAME)) {
+ KeepConstantArgumentRule rule =
+ parseNoOptimizationRule(optionStart, KeepConstantArgumentRule.builder());
configurationBuilder.addRule(rule);
return true;
}
- if (acceptString("keepunusedarguments")) {
- UnusedArgumentRule rule = parseUnusedArgumentRule(optionStart);
+ if (acceptString(KeepUnusedArgumentRule.RULE_NAME)) {
+ KeepUnusedArgumentRule rule =
+ parseNoOptimizationRule(optionStart, KeepUnusedArgumentRule.builder());
+ configurationBuilder.addRule(rule);
+ return true;
+ }
+ if (acceptString(KeepUnusedReturnValueRule.RULE_NAME)) {
+ KeepUnusedReturnValueRule rule =
+ parseNoOptimizationRule(optionStart, KeepUnusedReturnValueRule.builder());
configurationBuilder.addRule(rule);
return true;
}
@@ -918,10 +926,10 @@
"Expecting '-keep' option after '-if' option.", origin, getPosition(optionStart)));
}
- private ConstantArgumentRule parseConstantArgumentRule(Position start)
+ private KeepConstantArgumentRule parseConstantArgumentRule(Position start)
throws ProguardRuleParserException {
- ConstantArgumentRule.Builder keepRuleBuilder =
- ConstantArgumentRule.builder().setOrigin(origin).setStart(start);
+ KeepConstantArgumentRule.Builder keepRuleBuilder =
+ KeepConstantArgumentRule.builder().setOrigin(origin).setStart(start);
parseClassSpec(keepRuleBuilder, false);
Position end = getPosition();
keepRuleBuilder.setSource(getSourceSnippet(contents, start, end));
@@ -929,10 +937,10 @@
return keepRuleBuilder.build();
}
- private UnusedArgumentRule parseUnusedArgumentRule(Position start)
+ private KeepUnusedArgumentRule parseUnusedArgumentRule(Position start)
throws ProguardRuleParserException {
- UnusedArgumentRule.Builder keepRuleBuilder =
- UnusedArgumentRule.builder().setOrigin(origin).setStart(start);
+ KeepUnusedArgumentRule.Builder keepRuleBuilder =
+ KeepUnusedArgumentRule.builder().setOrigin(origin).setStart(start);
parseClassSpec(keepRuleBuilder, false);
Position end = getPosition();
keepRuleBuilder.setSource(getSourceSnippet(contents, start, end));
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
index 2f7d3f4..89b55dd 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -111,12 +111,9 @@
new DependentMinimumKeepInfoCollection();
private final LinkedHashMap<DexReference, DexReference> reasonAsked = new LinkedHashMap<>();
private final Set<DexMethod> alwaysInline = Sets.newIdentityHashSet();
- private final Set<DexMethod> neverInline = Sets.newIdentityHashSet();
private final Set<DexMethod> neverInlineDueToSingleCaller = Sets.newIdentityHashSet();
private final Set<DexMethod> bypassClinitforInlining = Sets.newIdentityHashSet();
private final Set<DexMethod> whyAreYouNotInlining = Sets.newIdentityHashSet();
- private final Set<DexMethod> keepParametersWithConstantValue = Sets.newIdentityHashSet();
- private final Set<DexMethod> keepUnusedArguments = Sets.newIdentityHashSet();
private final Set<DexMethod> reprocess = Sets.newIdentityHashSet();
private final Set<DexMethod> neverReprocess = Sets.newIdentityHashSet();
private final PredicateSet<DexType> alwaysClassInline = new PredicateSet<>();
@@ -267,11 +264,12 @@
} else if (rule instanceof NoFieldTypeStrengtheningRule) {
markMatchingFields(clazz, memberKeepRules, rule, null, ifRule);
} else if (rule instanceof InlineRule
- || rule instanceof ConstantArgumentRule
+ || rule instanceof KeepConstantArgumentRule
+ || rule instanceof KeepUnusedReturnValueRule
|| rule instanceof NoMethodStaticizingRule
|| rule instanceof NoParameterTypeStrengtheningRule
|| rule instanceof NoReturnTypeStrengtheningRule
- || rule instanceof UnusedArgumentRule
+ || rule instanceof KeepUnusedArgumentRule
|| rule instanceof ReprocessMethodRule
|| rule instanceof WhyAreYouNotInliningRule) {
markMatchingMethods(clazz, memberKeepRules, rule, null, ifRule);
@@ -364,18 +362,13 @@
alwaysInline,
bypassClinitforInlining);
}
- assert Sets.intersection(neverInline, alwaysInline).isEmpty()
- : "A method cannot be marked as both -neverinline and -alwaysinline.";
return new RootSet(
dependentMinimumKeepInfo,
ImmutableList.copyOf(reasonAsked.values()),
alwaysInline,
- neverInline,
neverInlineDueToSingleCaller,
bypassClinitforInlining,
whyAreYouNotInlining,
- keepParametersWithConstantValue,
- keepUnusedArguments,
reprocess,
neverReprocess,
alwaysClassInline,
@@ -456,7 +449,6 @@
ConsequentRootSet buildConsequentRootSet() {
return new ConsequentRootSet(
- neverInline,
neverInlineDueToSingleCaller,
neverClassInline,
dependentMinimumKeepInfo,
@@ -1301,11 +1293,6 @@
}
} else if (context instanceof ProguardIdentifierNameStringRule) {
evaluateIdentifierNameStringRule(item, context, ifRule);
- } else if (context instanceof ConstantArgumentRule) {
- if (item.isMethod()) {
- keepParametersWithConstantValue.add(item.asMethod().getReference());
- context.markAsUsed();
- }
} else if (context instanceof ReprocessClassInitializerRule) {
DexProgramClass clazz = item.asProgramClass();
if (clazz != null && clazz.hasClassInitializer()) {
@@ -1336,11 +1323,27 @@
}
context.markAsUsed();
}
- } else if (context instanceof UnusedArgumentRule) {
- if (item.isMethod()) {
- keepUnusedArguments.add(item.asMethod().getReference());
- context.markAsUsed();
- }
+ } else if (context instanceof KeepConstantArgumentRule) {
+ assert item.isProgramMethod();
+ dependentMinimumKeepInfo
+ .getOrCreateUnconditionalMinimumKeepInfoFor(item.getReference())
+ .asMethodJoiner()
+ .disallowConstantArgumentOptimization();
+ context.markAsUsed();
+ } else if (context instanceof KeepUnusedArgumentRule) {
+ assert item.isProgramMethod();
+ dependentMinimumKeepInfo
+ .getOrCreateUnconditionalMinimumKeepInfoFor(item.getReference())
+ .asMethodJoiner()
+ .disallowUnusedArgumentOptimization();
+ context.markAsUsed();
+ } else if (context instanceof KeepUnusedReturnValueRule) {
+ assert item.isProgramMethod();
+ dependentMinimumKeepInfo
+ .getOrCreateUnconditionalMinimumKeepInfoFor(item.getReference())
+ .asMethodJoiner()
+ .disallowUnusedReturnValueOptimization();
+ context.markAsUsed();
} else {
throw new Unreachable();
}
@@ -1356,7 +1359,8 @@
}
}
- private void evaluateCheckDiscardRule(DexProgramClass clazz, ProguardCheckDiscardRule rule) {
+ private synchronized void evaluateCheckDiscardRule(
+ DexProgramClass clazz, ProguardCheckDiscardRule rule) {
if (rule.getMemberRules().isEmpty()) {
evaluateCheckDiscardClassAndAllMembersRule(clazz, rule);
} else if (clazz.hasFields() || clazz.hasMethods()) {
@@ -1673,8 +1677,6 @@
public final Set<DexMethod> alwaysInline;
public final Set<DexMethod> bypassClinitForInlining;
public final Set<DexMethod> whyAreYouNotInlining;
- public final Set<DexMethod> keepConstantArguments;
- public final Set<DexMethod> keepUnusedArguments;
public final Set<DexMethod> reprocess;
public final Set<DexMethod> neverReprocess;
public final PredicateSet<DexType> alwaysClassInline;
@@ -1692,12 +1694,9 @@
DependentMinimumKeepInfoCollection dependentMinimumKeepInfo,
ImmutableList<DexReference> reasonAsked,
Set<DexMethod> alwaysInline,
- Set<DexMethod> neverInline,
Set<DexMethod> neverInlineDueToSingleCaller,
Set<DexMethod> bypassClinitForInlining,
Set<DexMethod> whyAreYouNotInlining,
- Set<DexMethod> keepConstantArguments,
- Set<DexMethod> keepUnusedArguments,
Set<DexMethod> reprocess,
Set<DexMethod> neverReprocess,
PredicateSet<DexType> alwaysClassInline,
@@ -1725,8 +1724,6 @@
this.alwaysInline = alwaysInline;
this.bypassClinitForInlining = bypassClinitForInlining;
this.whyAreYouNotInlining = whyAreYouNotInlining;
- this.keepConstantArguments = keepConstantArguments;
- this.keepUnusedArguments = keepUnusedArguments;
this.reprocess = reprocess;
this.neverReprocess = neverReprocess;
this.alwaysClassInline = alwaysClassInline;
@@ -1827,6 +1824,35 @@
}
}
+ public RootSet rewrittenWithLens(GraphLens graphLens) {
+ if (graphLens.isIdentityLens()) {
+ return this;
+ }
+ return new RootSet(
+ getDependentMinimumKeepInfo().rewrittenWithLens(graphLens),
+ reasonAsked,
+ alwaysInline,
+ neverInlineDueToSingleCaller,
+ bypassClinitForInlining,
+ whyAreYouNotInlining,
+ reprocess,
+ neverReprocess,
+ alwaysClassInline,
+ neverClassInline,
+ noUnusedInterfaceRemoval,
+ noVerticalClassMerging,
+ noHorizontalClassMerging,
+ neverPropagateValue,
+ mayHaveSideEffects,
+ noSideEffects,
+ assumedValues,
+ dependentKeepClassCompatRule,
+ identifierNameStrings,
+ ifRules,
+ delayedRootSetActionItems,
+ pendingMethodMoveInverse);
+ }
+
void shouldNotBeMinified(ProgramDefinition definition) {
getDependentMinimumKeepInfo()
.getOrCreateUnconditionalMinimumKeepInfoFor(definition.getReference())
@@ -1911,7 +1937,6 @@
public boolean verifyKeptItemsAreKept(AppView<? extends AppInfoWithClassHierarchy> appView) {
AppInfoWithClassHierarchy appInfo = appView.appInfo();
- GraphLens lens = appView.graphLens();
// Create a mapping from each required type to the set of required members on that type.
Map<DexType, Set<DexMember<?, ?>>> requiredMembersPerType = new IdentityHashMap<>();
getDependentMinimumKeepInfo()
@@ -1921,21 +1946,16 @@
(reference, minimumKeepInfo) -> {
if (reference.isDexType()) {
DexType type = reference.asDexType();
- DexType rewrittenType = lens.lookupType(type);
- assert !appInfo.hasLiveness() || appInfo.withLiveness().isPinned(rewrittenType)
- : "Expected reference `" + rewrittenType.toSourceString() + "` to be pinned";
- requiredMembersPerType.computeIfAbsent(
- rewrittenType, key -> Sets.newIdentityHashSet());
+ assert !appInfo.hasLiveness() || appInfo.withLiveness().isPinned(type)
+ : "Expected reference `" + type.toSourceString() + "` to be pinned";
+ requiredMembersPerType.computeIfAbsent(type, key -> Sets.newIdentityHashSet());
} else {
DexMember<?, ?> member = reference.asDexMember();
- DexMember<?, ?> rewrittenMember = lens.getRenamedMemberSignature(member);
- assert !appInfo.hasLiveness() || appInfo.withLiveness().isPinned(rewrittenMember)
- : "Expected reference `"
- + rewrittenMember.toSourceString()
- + "` to be pinned";
+ assert !appInfo.hasLiveness() || appInfo.withLiveness().isPinned(member)
+ : "Expected reference `" + member.toSourceString() + "` to be pinned";
requiredMembersPerType
- .computeIfAbsent(rewrittenMember.holder, key -> Sets.newIdentityHashSet())
- .add(rewrittenMember);
+ .computeIfAbsent(member.holder, key -> Sets.newIdentityHashSet())
+ .add(member);
}
});
@@ -2044,7 +2064,6 @@
public static class ConsequentRootSet extends RootSetBase {
ConsequentRootSet(
- Set<DexMethod> neverInline,
Set<DexMethod> neverInlineDueToSingleCaller,
Set<DexType> neverClassInline,
DependentMinimumKeepInfoCollection dependentMinimumKeepInfo,
@@ -2110,9 +2129,6 @@
Collections.emptySet(),
Collections.emptySet(),
Collections.emptySet(),
- Collections.emptySet(),
- Collections.emptySet(),
- Collections.emptySet(),
PredicateSet.empty(),
Collections.emptySet(),
Collections.emptySet(),
@@ -2141,6 +2157,7 @@
// Do nothing.
}
+ @Override
public MainDexRootSet rewrittenWithLens(GraphLens graphLens) {
if (graphLens.isIdentityLens()) {
return this;
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 19f0adc..0ad5ad4 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.androidapi.ComputedApiLevel;
import com.android.tools.r8.cf.CfVersion;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AccessControl;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -53,13 +54,13 @@
import com.android.tools.r8.graph.ObjectAllocationInfoCollection;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.PrunedItems;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
import com.android.tools.r8.graph.SubtypingInfo;
import com.android.tools.r8.graph.TopDownClassHierarchyTraversal;
import com.android.tools.r8.graph.TreeFixerBase;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.graph.UseRegistryWithResult;
import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.MemberPoolCollection.MemberPool;
@@ -990,25 +991,42 @@
&& !virtualMethods.containsKey(wrapped);
};
- for (DexEncodedMethod directMethod : source.directMethods()) {
- if (directMethod.isInstanceInitializer()) {
- DexEncodedMethod resultingConstructor =
- renameConstructor(directMethod, availableMethodSignatures);
- add(directMethods, resultingConstructor, MethodSignatureEquivalence.get());
- blockRedirectionOfSuperCalls(resultingConstructor.getReference());
- } else {
- DexEncodedMethod resultingDirectMethod =
- renameMethod(
- directMethod,
- availableMethodSignatures,
- directMethod.isClassInitializer() ? Rename.NEVER : Rename.IF_NEEDED);
- add(directMethods, resultingDirectMethod, MethodSignatureEquivalence.get());
- deferredRenamings.map(directMethod.getReference(), resultingDirectMethod.getReference());
- deferredRenamings.recordMove(
- directMethod.getReference(), resultingDirectMethod.getReference());
- blockRedirectionOfSuperCalls(resultingDirectMethod.getReference());
- }
- }
+ source.forEachProgramDirectMethod(
+ directMethod -> {
+ DexEncodedMethod definition = directMethod.getDefinition();
+ if (definition.isInstanceInitializer()) {
+ DexEncodedMethod resultingConstructor =
+ renameConstructor(definition, availableMethodSignatures);
+ add(directMethods, resultingConstructor, MethodSignatureEquivalence.get());
+ blockRedirectionOfSuperCalls(resultingConstructor.getReference());
+ } else {
+ DexEncodedMethod resultingDirectMethod =
+ renameMethod(
+ definition,
+ availableMethodSignatures,
+ definition.isClassInitializer() ? Rename.NEVER : Rename.IF_NEEDED);
+ add(directMethods, resultingDirectMethod, MethodSignatureEquivalence.get());
+ deferredRenamings.map(
+ directMethod.getReference(), resultingDirectMethod.getReference());
+ deferredRenamings.recordMove(
+ directMethod.getReference(), resultingDirectMethod.getReference());
+ blockRedirectionOfSuperCalls(resultingDirectMethod.getReference());
+
+ // Private methods in the parent class may be targeted with invoke-super if the two
+ // classes are in the same nest. Ensure such calls are mapped to invoke-direct.
+ if (definition.isInstance()
+ && definition.isPrivate()
+ && AccessControl.isMemberAccessible(directMethod, source, target, appView)
+ .isTrue()) {
+ deferredRenamings.mapVirtualMethodToDirectInType(
+ directMethod.getReference(),
+ prototypeChanges ->
+ new MethodLookupResult(
+ resultingDirectMethod.getReference(), null, DIRECT, prototypeChanges),
+ target.getType());
+ }
+ }
+ });
for (DexEncodedMethod virtualMethod : source.virtualMethods()) {
DexEncodedMethod shadowedBy = findMethodInTarget(virtualMethod);
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLens.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLens.java
index 37965ec..166ed69 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLens.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLens.java
@@ -12,8 +12,8 @@
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.NestedGraphLens;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.utils.IterableUtils;
import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeHashMap;
diff --git a/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java b/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
index bbf4258..604748a 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
@@ -129,12 +129,7 @@
return;
}
assert hygienicType.toSourceString().startsWith(synthesizingContextType.toSourceString());
- DexType rewrittenContext =
- appView
- .options()
- .desugaredLibrarySpecification
- .getEmulateLibraryInterface()
- .get(synthesizingContextType);
+ DexType rewrittenContext = appView.rewritePrefix.rewrittenContextType(synthesizingContextType);
if (rewrittenContext == null) {
return;
}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
index 0cb0137..6d45ee1 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -483,8 +483,7 @@
AppView<?> appView,
DexType type) {
DexType rewrittenContextType =
- appView.rewritePrefix.rewrittenContextType(
- outerContext.getSynthesizingContextType(), appView);
+ appView.rewritePrefix.rewrittenContextType(outerContext.getSynthesizingContextType());
if (rewrittenContextType == null) {
return;
}
diff --git a/src/main/java/com/android/tools/r8/utils/AssertionConfigurationWithDefault.java b/src/main/java/com/android/tools/r8/utils/AssertionConfigurationWithDefault.java
index df3f944..a0a5836 100644
--- a/src/main/java/com/android/tools/r8/utils/AssertionConfigurationWithDefault.java
+++ b/src/main/java/com/android/tools/r8/utils/AssertionConfigurationWithDefault.java
@@ -7,12 +7,16 @@
import com.android.tools.r8.AssertionsConfiguration;
import com.android.tools.r8.AssertionsConfiguration.AssertionTransformation;
import com.android.tools.r8.AssertionsConfiguration.AssertionTransformationScope;
+import com.android.tools.r8.references.MethodReference;
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
import java.util.List;
public class AssertionConfigurationWithDefault {
public final AssertionsConfiguration defaultConfiguration;
public final List<AssertionsConfiguration> assertionsConfigurations;
+ private final List<MethodReference> allAssertionHandlers;
public AssertionConfigurationWithDefault(
AssertionsConfiguration defautlTransformation,
@@ -20,6 +24,7 @@
this.defaultConfiguration = defautlTransformation;
assert assertionsConfigurations != null;
this.assertionsConfigurations = assertionsConfigurations;
+ this.allAssertionHandlers = computeAllAssertionHandlers();
}
public boolean isPassthroughAll() {
@@ -31,4 +36,24 @@
&& assertionsConfigurations.get(0).getTransformation()
== AssertionTransformation.PASSTHROUGH;
}
+
+ public List<MethodReference> getAllAssertionHandlers() {
+ return allAssertionHandlers;
+ }
+
+ private List<MethodReference> computeAllAssertionHandlers() {
+ assert !defaultConfiguration.isAssertionHandler();
+ if (assertionsConfigurations.isEmpty()) {
+ return ImmutableList.of();
+ }
+ List<MethodReference> result = new ArrayList<>();
+ assertionsConfigurations.forEach(
+ assertionsConfiguration -> {
+ if (assertionsConfiguration.isAssertionHandler()
+ && !result.contains(assertionsConfiguration.getAssertionHandler())) {
+ result.add(assertionsConfiguration.getAssertionHandler());
+ }
+ });
+ return result;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index bc88b16..467ac25 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -54,8 +54,11 @@
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.desugar.PrefixRewritingMapper;
import com.android.tools.r8.ir.desugar.PrefixRewritingMapper.MachineDesugarPrefixRewritingMapper;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification;
import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.HumanToMachineSpecificationConverter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.LegacyToHumanSpecificationConverter;
import com.android.tools.r8.ir.desugar.nest.Nest;
import com.android.tools.r8.ir.optimize.Inliner;
import com.android.tools.r8.ir.optimize.enums.EnumDataMap;
@@ -85,7 +88,9 @@
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
+import java.io.IOException;
import java.io.PrintStream;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -390,8 +395,8 @@
if (isGeneratingDex() || desugarState == DesugarState.ON) {
marker.setMinApi(getMinApiLevel().getLevel());
}
- if (desugaredLibrarySpecification.getIdentifier() != null) {
- marker.setDesugaredLibraryIdentifiers(desugaredLibrarySpecification.getIdentifier());
+ if (machineDesugaredLibrarySpecification.getIdentifier() != null) {
+ marker.setDesugaredLibraryIdentifiers(machineDesugaredLibrarySpecification.getIdentifier());
}
if (Version.isDevelopmentVersion()) {
marker.setSha1(VersionProperties.INSTANCE.getSha());
@@ -438,7 +443,7 @@
}
public boolean isDesugaredLibraryCompilation() {
- return desugaredLibrarySpecification.isLibraryCompilation();
+ return machineDesugaredLibrarySpecification.isLibraryCompilation();
}
public boolean isRelocatorCompilation() {
@@ -888,13 +893,51 @@
public LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
LegacyDesugaredLibrarySpecification.empty();
- public PrefixRewritingMapper getPrefixRewritingMapper() {
- if (testing.machineDesugaredLibrarySpecification != null) {
- return new MachineDesugarPrefixRewritingMapper(
- desugaredLibrarySpecification.getPrefixRewritingMapper(),
- testing.machineDesugaredLibrarySpecification.getRewritingFlags());
+ public void setDesugaredLibrarySpecification(
+ LegacyDesugaredLibrarySpecification specification, AndroidApp app) {
+ if (specification.isEmptyConfiguration()) {
+ return;
}
- return desugaredLibrarySpecification.getPrefixRewritingMapper();
+ desugaredLibrarySpecification = specification;
+ try {
+ HumanDesugaredLibrarySpecification human =
+ new LegacyToHumanSpecificationConverter()
+ .convert(specification, app.getLibraryResourceProviders(), this);
+ machineDesugaredLibrarySpecification =
+ new HumanToMachineSpecificationConverter()
+ .convert(
+ human,
+ specification.isLibraryCompilation() ? app.getProgramResourceProviders() : null,
+ app.getLibraryResourceProviders(),
+ this);
+ } catch (IOException e) {
+ reporter.error(new ExceptionDiagnostic(e, Origin.unknown()));
+ }
+ }
+
+ public void setDesugaredLibrarySpecificationForTesting(
+ LegacyDesugaredLibrarySpecification specification, Path desugaredJDKLib, Path library)
+ throws IOException {
+ desugaredLibrarySpecification = specification;
+ HumanDesugaredLibrarySpecification human =
+ new LegacyToHumanSpecificationConverter().convert(specification, library, this);
+ machineDesugaredLibrarySpecification =
+ new HumanToMachineSpecificationConverter()
+ .convert(
+ human,
+ specification.isLibraryCompilation() ? desugaredJDKLib : null,
+ library,
+ this);
+ }
+
+ // Meant to replace desugaredLibrarySpecification, set only from tests at the moment.
+ public MachineDesugaredLibrarySpecification machineDesugaredLibrarySpecification =
+ MachineDesugaredLibrarySpecification.empty();
+
+ public PrefixRewritingMapper getPrefixRewritingMapper() {
+ return machineDesugaredLibrarySpecification.getRewriteType().isEmpty()
+ ? PrefixRewritingMapper.empty()
+ : new MachineDesugarPrefixRewritingMapper(machineDesugaredLibrarySpecification);
}
public boolean relocatorCompilation = false;
@@ -1599,9 +1642,6 @@
public Consumer<Deque<ProgramMethodSet>> waveModifier = waves -> {};
- // Meant to replace desugaredLibrarySpecification, set only from tests at the moment.
- public MachineDesugaredLibrarySpecification machineDesugaredLibrarySpecification = null;
-
/**
* If this flag is enabled, we will also compute the set of possible targets for invoke-
* interface and invoke-virtual instructions that target a library method, and add the
@@ -1637,6 +1677,7 @@
public boolean enableEnumUnboxingDebugLogs = false;
public boolean forceRedundantConstNumberRemoval = false;
public boolean enableExperimentalDesugaredLibraryKeepRuleGenerator = false;
+ public boolean enableExperimentalProtoNormalization = false;
public boolean invertConditionals = false;
public boolean placeExceptionalBlocksLast = false;
public boolean dontCreateMarkerInD8 = false;
diff --git a/src/main/resources/api_database/api_database_ambiguous.txt b/src/main/resources/api_database/api_database_ambiguous.txt
index 5c4f00c..47dfde9 100644
--- a/src/main/resources/api_database/api_database_ambiguous.txt
+++ b/src/main/resources/api_database/api_database_ambiguous.txt
@@ -1,113 +1,33 @@
-ebf47efadc4c50002b13da0b1cef0646:18
-106de6ca4d0e49988f3328ce380ff517:18
-2f4aedd17528c30f8a9f16b030ff708b:18
-93aca156e3f15799914f868852723e47:18
-17cbc97604a781acb78c668b2437ffbd:18
-1709449e191fe131236bd0b8c1928b71:18
-a6cf882fc575147513b7b1b505fdd335:18
-1587f690fd5c0c886630334e89e397ff:18
-dc6ad4bf6892204b9fca73d1ee9cab04:18
-9ae673cfbb5d90688edafbf7ec2862e4:18
-acf250fcdbf54725219af8c6a8a614d9:18
-07319a58381faa784dda046d5e8fd8ae:18
-77e978f6318d01be894de8944fdc05b4:18
-81be9a78d26d25c6ff47c7e9af30a92e:18
-e87bf9d0084b39c443e421cdb5d3fc43:18
-9e973ee7f4f5ad967d2ba5bf5d88911c:18
-b47e7bbf50ad208599056f8d0f1cc5ba:18
-47a9e25289b4ece230adcc3b60797712:18
-42e4cc1882d334757afbe74f4d8cec8e:18
-024481748991b858bf7e03b0b87ce125:18
-b6ced7e04b527d83cd660894a0059ea7:18
-717e536c3a13f3602fbaf1f607ee2963:18
-18b540e31006aad6ae7a26d967ec0e0e:18
-f1483fe126d64bd7544dba7fdf0559f4:18
-3c4a0d8270a52e43316a711a2fe83268:18
-2e13bb1bfba423473a6efba65d9c8190:18
-47a5d9010bdeb561176cf070ef483e91:18
-4f2e7d32ed2c7ead316770fbe84d8aae:18
-c625e1090fc4d72afd0673839af5d46f:18
-4cc2dc623ee702db7a5899c5c401a98c:18
-780c7e0f80b5479d00e2c3679974644d:18
-eff51a62305642c720d163085061ed63:18
-69e416f1afc250d6239788b4b1fb9bb4:18
-d71a32697989404ae782e105a5eb5e4c:18
-6d60d78c1ce897131dcf45743a8d6e49:18
-e16e8dcca650cf79557cb76a86edb4e9:18
-bfebe4871ed9c4b5f3300fe8dfa2a0a3:18
-93e215f230901f20bdca460cfe8c42af:18
-8efacada80287ebb7607758a0a82b0a0:18
-487bc1228fd817b641056a1a008984f8:18
-dc6c2915cd6f0a6fd0ab01365349599d:18
-1a3dbf72e4bd135a621b8ad78a7151c1:18
-01fd60d48ba7e1434bb72696282c7113:18
-83c42b475763d64935a9ddfc6a374b64:18
-ed9a26aaf7ddb748bd1e624aeb4fdb81:18
-eeb05b41976f7bb96572330854aaab34:18
-3c17437ba337e7ce8edad092f745a363:18
-8d8fd1ffc3ae24cb43798f4eb41fc4de:18
-003f7ab7088710994a289bab815aacbf:18
-488d943cdcedfca2b076152769fc3c51:18
-cab779407e29ba3377e6a47a4f842ec5:18
-a0ddcf0f7bb4aa9d38db983941f6908d:18
-b64b41d26010783cae2dff88c7e21f1d:18
-aac6d054ad0f9bea1f64702aea698ee3:18
-90b4163293f9e35f7091692b31d3b5d7:18
-9d66fceb1054d5e2ff207591ec216b70:18
-93a65566b576af220207e30cc89ef490:18
-b3248e6a2d819bd8bb42a15179188c52:18
-f95f0545feb040d2d6bfcad6897364d0:18
-058ec3044e95ed7fcaff93a2f3105d6f:18
-39ef3516cb80752cac1c541b43a1c2fa:18
-c1295d79d79340152c6b98f1c9003e8c:18
-c4b4a2994711cb342b0c8c8ef409ce8b:18
-719c3b73816fa0db79747ea264abab5a:18
-1d7847b88e0feaecd299b3c5c18be763:18
-1211e656a8eaa4423e7678533a1e7e2a:18
-e0c7417a74df21b55367f9e1ea6c2d37:18
-e49b0a2bd830bb3b96934490b2bc6ebe:18
-91790d7c5cf146ab3936919184a70015:18
-ec36ea4bb9634f7ec5c4d3c1cc9dd71b:18
-860e7b1a68c02eef7d2e2d7b6a3e13b5:18
-458fda8d9863be24862bb62c910f427d:18
-e05ed0452c12e62ef74e9161159b1231:18
-9419764761c059b9c2f9cf640abfdeb0:18
-ea02175c4ef64b6370f619acd84f3c3c:18
-0b01d40e1ca37aa854e77c98cc153e77:18
-eb12f3e690b201aa171d794a8288af10:18
-b955e5418d490425f99d58f441ba4525:18
-b36bec8fd49158c020b6d8c09cc02baf:26
-e7ca6d1abe4cd55a491cdf58eb8f4602:17
d8c43560e159bcb899c2180b8e01d8e3:24
-12233f83b06081671815562dce938d3b:24
ae9c7aee12dfaaa56e43834dcea91f5f:24
106252e3f31ee17239e1ee4184147deb:24
+12233f83b06081671815562dce938d3b:24
1fb2cd38813bad6e5eeef74bcbcb133d:24
c5bbd4174eee5cb68830801317071dd5:24
b876313caea388f03200ac720ed528af:24
-dc32c09ecdd9bda4703aa944cf1eb4ca:24
f4fa53a97c83899fd2da9f4112f35339:24
+dc32c09ecdd9bda4703aa944cf1eb4ca:24
07a59dae4166f6d504bb0793c5e75178:24
efcb5024ce3514453d44735222903a55:24
43445dc9e50e2c4fc327097d07ff749a:24
bcb1787dd2def454fd3f31d1b2c0967a:24
-2cc65559141cece33ffdbc4e34a2ce3b:24
cace738770550444ee1f91000c32c147:24
+2cc65559141cece33ffdbc4e34a2ce3b:24
b55a09768f05f29b15e1ff3a9feb7c92:24
54282406a85f4410d4dfc72d5873ee96:24
1c38913c447705e315ec4486da558c9d:24
ca3f30645fa7b480b213f4228386a09a:24
6d8800c5cc8ad9e4f3f28e777207a870:24
b8dc6f9b9587159f978d643aeb8e4d07:24
-91eb697571f68f5850875286c5e36080:24
44c0d27dc28d4da28655c3c62a0d7cac:24
+91eb697571f68f5850875286c5e36080:24
ae908f7abd7d347b0bf39fead3531c12:24
145e730e204fdca9cf169521a3812ed1:24
d27ceaaa92270c450aeee582cc17b985:24
294141fdc8f17ac3c7e4d8687d8ad389:24
48de820418038280f70eca64f878c67b:24
-8569110aa82eb44ff0b12819867c66f8:24
cfde9ea95c663bed6d56df8778b01b79:24
+8569110aa82eb44ff0b12819867c66f8:24
f389ac23dc4ef6641321adf43d712c32:24
46de27224f4cf6fb745e30bbd6aad267:24
ef4661e0074b431762177e10c2ac8570:24
@@ -116,14 +36,14 @@
e9d59e0325c6dd1dd78a998365435fac:24
0a1d88442fc34d0081115d949f1c5fa9:24
0a7ef5f8b75fa2dd79787b03dff923c9:24
-b247285b58ca44aad532b1c3b5a5dacf:24
63f61697ff1319a76632338fe0c13ae9:24
+b247285b58ca44aad532b1c3b5a5dacf:24
e8df9edc7e29252645d2b8a6a55c4e0f:24
aaba729f45b1617d59cec26aa41937e3:24
7e7ae6228d4ab54b90f0f580731941d7:24
de1c84862deb139962240505133690f0:24
-9dbabf8883b7a4e120fcbceb00face40:24
9660da0a81f885de5a3b16f1f07a1067:24
+9dbabf8883b7a4e120fcbceb00face40:24
c3f5202b30c04801da693013368a0da2:24
b73113e1f7c2702cfd997dd84e5ac003:24
9b5946e54278b49302da6ccd2a3a06e1:24
@@ -143,29 +63,79 @@
76fd080fdaa80390ca05399f4d0b49ae:24
d49bee1da6282ff1efd4017e2c26ff55:24
94bf636e74064a1f45c5e81777a8b541:24
+b502fdd440592e2d637704ebef9baf01:24
67395fd629dae7b237421aa91bc12150:24
b69dd3d2f26fc766f3b4193b089fa71e:24
-b502fdd440592e2d637704ebef9baf01:24
5a13a7fac55b3378629744099623199b:24
-6c21462d7f8529e6d017e054b02d96d3:24
-ef1a937ed3ed1277a46cbbfb589bcc7c:24
a9446b05afd48f274f6469e9617dadde:24
+ef1a937ed3ed1277a46cbbfb589bcc7c:24
+6c21462d7f8529e6d017e054b02d96d3:24
03b1c2c2b9e04b66ace80c8d891dad71:24
-5af3ef227d419594dc0316392c0fd762:24
b4146bc53ba79957adf0bf7306b2212c:24
+5af3ef227d419594dc0316392c0fd762:24
f1136465059f10586c4fb8379126e010:24
8796edfd2200b66560e180ecf2c8bd3a:24
-a4fc9c89f980d489cd69b5a9a5379279:28
-beef3d82791567a66852903d9acde2d8:14
-8f8e727dba622a81127060f53efbaf60:14
-a58ec4e669821ad885c5e539bea8f8c0:14
-c183aebc8596eae7dbaf32f831d4bf1a:14
-579a40bd08705acc7099b631706917cd:14
-c979623104ac1df2ff0b56f2eb8f40a3:14
-4a406313d3d1fc7c56f2e4ae88033ef5:14
-0534bb586552faf59923fcbb66c5c9a8:14
+b63216a8584c12bf002f4ee8c3b0ac3e:19
+1ad1cfa76f9692958656f17b710a0ecc:19
828623182530e5b5c55265b6a20263be:9
-027b76c362f10b646fce08dd34457533:29
+b36bec8fd49158c020b6d8c09cc02baf:26
+e7e718f70ee49560800db2d60270603f:11
+61c32de62fbec72e56083dade766f0f9:11
+f9684960dbadc5206f33484afeba57e1:11
+f849d1e2b1fbe25e1c88aa103ce68255:11
+1186fd5fd194d7f5c3c1b19aa753d315:11
+c74e6a2c593956c2e74a9f89dac73eeb:11
+e528c2b6258e260f575488c35f7683fb:11
+e5c61babf2a6ff8f6939b7a1db7e621f:11
+48921ae81d5ad84778fd75c9f58e1bf9:11
+92e7e194987c3b4db1a4a129af2cd05f:11
+f1d93cdeba77ba27e048fd0fbc6b0bad:11
+2cb543910592d445cf09fec159d0b421:11
+cd3bfb7c471b99eb7b7acb8011e4687f:11
+df936e8a13b49cdb9b5f82e150aca29b:11
+0e452471f905f2fb311c6146b31b5705:11
+b78f4f3edd36b6326873eea475ef2476:11
+fa0bc15e6c1bcb787bdea1073a4e2709:11
+417ebe49420a8d103b8b65c5d574fd84:11
+18f7890363dbd6262668cdcffb0f3a8d:11
+28c73ab584871ffb89a5304f87335f95:11
+aa4a8bfad0ec9e57489297bc67664cfd:11
+9a5dd5c667e21679c42fc7b2cd79769c:11
+59654e2c6df1b6a8a77928223e2ab332:11
+fea47d75f1c8cdb3a12de27678c005b6:11
+c6dd561601e904cee3707ba4cfe1350f:11
+02ceeb351445bd756a73fd5ab2a3d0c4:11
+3a3e699a3fdaaaf0b0d809d114c54e19:11
+ccad7981fb017550a8f7b8925a1d0648:11
+0803d11e374ba9493cfdd8fc17f7d34c:11
+31b7ca8caafc4ac8fd6ab18a01f5e9f5:11
+762dbaa4b1beab4b7113a750639d7f6f:11
+cf1b9fa0beb54f8f57c79446a3186baa:11
+13c8db7cad8e47068720c9f9b9d8213c:11
+d942884e00b9f288de96a8b0733372d9:11
+cd5c01104e0c46080a8d499f87de4991:11
+799e6e8b1fe3f2c45ec9703491bd67d5:8
+12011f7bb75e99008d3ef5bbe9087e6f:8
+53737c53af7f40961557a85fb4d11b55:8
+9fac9097934ab48cd9de3d124943c3fd:8
+a85598686e913ff9a84c078990e2b74f:8
+9389bbac5d37c3655c2d112b5fb15d79:8
+c7143cf932c4620b38f241a67c698de7:8
+d5360a8c6fd960a52c125ad6ee65b369:8
+6bb42f291857bf93ef2407e3fe8910b3:8
+4c0513c3ea8aa4e0d1671697ade55dc0:8
+9ab999023c47266804e1c23912c49590:8
+c83ba14b99739545b5611680823c5e64:8
+6c3b66ed41f23693ee6ed1a2f74383ca:8
+e064938f6319932b4685797aa810233f:8
+edf457cbc465fa576479f66ed5689a8e:8
+befe448f726cd55c55d708a8ed55b087:8
+4a35639e3583bbc1b36b56f0b50a2849:8
+a2c469af732e034c5017e1fbcbb6fba0:8
+47ef9cb8fb8fa55cfe73612c56fc5a0d:8
+58e29b4d0c775a250e2751d3cb70e44b:8
+2248103eacf690b2060d9f624dee5e41:8
+7aaff576c6f4f28ee8d80236c3943c3a:8
850665aac5116ea7c5dd3ed4d672cc68:1
d853b59bd420a046a715750d924360d0:1
1a9e947630aeed44da4b6e668e8ac214:1
@@ -241,165 +211,100 @@
83255b102f7327ffe0819cc9d48d764a:1
a159e58a81a5d7e46b1d44f845486c25:1
c9a7fe526ed238e56f029bdd9eadd4a8:1
-b63216a8584c12bf002f4ee8c3b0ac3e:19
-1ad1cfa76f9692958656f17b710a0ecc:19
-e7e718f70ee49560800db2d60270603f:11
-61c32de62fbec72e56083dade766f0f9:11
-f9684960dbadc5206f33484afeba57e1:11
-f849d1e2b1fbe25e1c88aa103ce68255:11
-1186fd5fd194d7f5c3c1b19aa753d315:11
-c74e6a2c593956c2e74a9f89dac73eeb:11
-e528c2b6258e260f575488c35f7683fb:11
-e5c61babf2a6ff8f6939b7a1db7e621f:11
-48921ae81d5ad84778fd75c9f58e1bf9:11
-92e7e194987c3b4db1a4a129af2cd05f:11
-f1d93cdeba77ba27e048fd0fbc6b0bad:11
-2cb543910592d445cf09fec159d0b421:11
-cd3bfb7c471b99eb7b7acb8011e4687f:11
-df936e8a13b49cdb9b5f82e150aca29b:11
-0e452471f905f2fb311c6146b31b5705:11
-b78f4f3edd36b6326873eea475ef2476:11
-fa0bc15e6c1bcb787bdea1073a4e2709:11
-417ebe49420a8d103b8b65c5d574fd84:11
-18f7890363dbd6262668cdcffb0f3a8d:11
-28c73ab584871ffb89a5304f87335f95:11
-aa4a8bfad0ec9e57489297bc67664cfd:11
-9a5dd5c667e21679c42fc7b2cd79769c:11
-59654e2c6df1b6a8a77928223e2ab332:11
-fea47d75f1c8cdb3a12de27678c005b6:11
-c6dd561601e904cee3707ba4cfe1350f:11
-02ceeb351445bd756a73fd5ab2a3d0c4:11
-3a3e699a3fdaaaf0b0d809d114c54e19:11
-ccad7981fb017550a8f7b8925a1d0648:11
-0803d11e374ba9493cfdd8fc17f7d34c:11
-31b7ca8caafc4ac8fd6ab18a01f5e9f5:11
-762dbaa4b1beab4b7113a750639d7f6f:11
-cf1b9fa0beb54f8f57c79446a3186baa:11
-13c8db7cad8e47068720c9f9b9d8213c:11
-d942884e00b9f288de96a8b0733372d9:11
-cd5c01104e0c46080a8d499f87de4991:11
-799e6e8b1fe3f2c45ec9703491bd67d5:8
-12011f7bb75e99008d3ef5bbe9087e6f:8
-53737c53af7f40961557a85fb4d11b55:8
-9fac9097934ab48cd9de3d124943c3fd:8
-a85598686e913ff9a84c078990e2b74f:8
-9389bbac5d37c3655c2d112b5fb15d79:8
-c7143cf932c4620b38f241a67c698de7:8
-d5360a8c6fd960a52c125ad6ee65b369:8
-6bb42f291857bf93ef2407e3fe8910b3:8
-4c0513c3ea8aa4e0d1671697ade55dc0:8
-9ab999023c47266804e1c23912c49590:8
-c83ba14b99739545b5611680823c5e64:8
-6c3b66ed41f23693ee6ed1a2f74383ca:8
-e064938f6319932b4685797aa810233f:8
-edf457cbc465fa576479f66ed5689a8e:8
-befe448f726cd55c55d708a8ed55b087:8
-4a35639e3583bbc1b36b56f0b50a2849:8
-a2c469af732e034c5017e1fbcbb6fba0:8
-47ef9cb8fb8fa55cfe73612c56fc5a0d:8
-58e29b4d0c775a250e2751d3cb70e44b:8
-2248103eacf690b2060d9f624dee5e41:8
-7aaff576c6f4f28ee8d80236c3943c3a:8
+beef3d82791567a66852903d9acde2d8:14
+8f8e727dba622a81127060f53efbaf60:14
+a58ec4e669821ad885c5e539bea8f8c0:14
+c183aebc8596eae7dbaf32f831d4bf1a:14
+579a40bd08705acc7099b631706917cd:14
+c979623104ac1df2ff0b56f2eb8f40a3:14
+4a406313d3d1fc7c56f2e4ae88033ef5:14
+0534bb586552faf59923fcbb66c5c9a8:14
+ebf47efadc4c50002b13da0b1cef0646:18
+106de6ca4d0e49988f3328ce380ff517:18
+93aca156e3f15799914f868852723e47:18
+2f4aedd17528c30f8a9f16b030ff708b:18
+17cbc97604a781acb78c668b2437ffbd:18
+1709449e191fe131236bd0b8c1928b71:18
+a6cf882fc575147513b7b1b505fdd335:18
+1587f690fd5c0c886630334e89e397ff:18
+dc6ad4bf6892204b9fca73d1ee9cab04:18
+9ae673cfbb5d90688edafbf7ec2862e4:18
+acf250fcdbf54725219af8c6a8a614d9:18
+77e978f6318d01be894de8944fdc05b4:18
+07319a58381faa784dda046d5e8fd8ae:18
+81be9a78d26d25c6ff47c7e9af30a92e:18
+e87bf9d0084b39c443e421cdb5d3fc43:18
+9e973ee7f4f5ad967d2ba5bf5d88911c:18
+b47e7bbf50ad208599056f8d0f1cc5ba:18
+47a9e25289b4ece230adcc3b60797712:18
+42e4cc1882d334757afbe74f4d8cec8e:18
+024481748991b858bf7e03b0b87ce125:18
+b6ced7e04b527d83cd660894a0059ea7:18
+717e536c3a13f3602fbaf1f607ee2963:18
+f1483fe126d64bd7544dba7fdf0559f4:18
+18b540e31006aad6ae7a26d967ec0e0e:18
+3c4a0d8270a52e43316a711a2fe83268:18
+2e13bb1bfba423473a6efba65d9c8190:18
+47a5d9010bdeb561176cf070ef483e91:18
+4f2e7d32ed2c7ead316770fbe84d8aae:18
+c625e1090fc4d72afd0673839af5d46f:18
+780c7e0f80b5479d00e2c3679974644d:18
+eff51a62305642c720d163085061ed63:18
+4cc2dc623ee702db7a5899c5c401a98c:18
+69e416f1afc250d6239788b4b1fb9bb4:18
+d71a32697989404ae782e105a5eb5e4c:18
+e16e8dcca650cf79557cb76a86edb4e9:18
+6d60d78c1ce897131dcf45743a8d6e49:18
+bfebe4871ed9c4b5f3300fe8dfa2a0a3:18
+93e215f230901f20bdca460cfe8c42af:18
+8efacada80287ebb7607758a0a82b0a0:18
+487bc1228fd817b641056a1a008984f8:18
+dc6c2915cd6f0a6fd0ab01365349599d:18
+1a3dbf72e4bd135a621b8ad78a7151c1:18
+83c42b475763d64935a9ddfc6a374b64:18
+01fd60d48ba7e1434bb72696282c7113:18
+eeb05b41976f7bb96572330854aaab34:18
+ed9a26aaf7ddb748bd1e624aeb4fdb81:18
+3c17437ba337e7ce8edad092f745a363:18
+8d8fd1ffc3ae24cb43798f4eb41fc4de:18
+003f7ab7088710994a289bab815aacbf:18
+cab779407e29ba3377e6a47a4f842ec5:18
+488d943cdcedfca2b076152769fc3c51:18
+a0ddcf0f7bb4aa9d38db983941f6908d:18
+b64b41d26010783cae2dff88c7e21f1d:18
+aac6d054ad0f9bea1f64702aea698ee3:18
+90b4163293f9e35f7091692b31d3b5d7:18
+9d66fceb1054d5e2ff207591ec216b70:18
+93a65566b576af220207e30cc89ef490:18
+b3248e6a2d819bd8bb42a15179188c52:18
+f95f0545feb040d2d6bfcad6897364d0:18
+058ec3044e95ed7fcaff93a2f3105d6f:18
+39ef3516cb80752cac1c541b43a1c2fa:18
+c1295d79d79340152c6b98f1c9003e8c:18
+c4b4a2994711cb342b0c8c8ef409ce8b:18
+719c3b73816fa0db79747ea264abab5a:18
+1211e656a8eaa4423e7678533a1e7e2a:18
+1d7847b88e0feaecd299b3c5c18be763:18
+e0c7417a74df21b55367f9e1ea6c2d37:18
+e49b0a2bd830bb3b96934490b2bc6ebe:18
+91790d7c5cf146ab3936919184a70015:18
+ec36ea4bb9634f7ec5c4d3c1cc9dd71b:18
+458fda8d9863be24862bb62c910f427d:18
+860e7b1a68c02eef7d2e2d7b6a3e13b5:18
+e05ed0452c12e62ef74e9161159b1231:18
+9419764761c059b9c2f9cf640abfdeb0:18
+ea02175c4ef64b6370f619acd84f3c3c:18
+0b01d40e1ca37aa854e77c98cc153e77:18
+eb12f3e690b201aa171d794a8288af10:18
+b955e5418d490425f99d58f441ba4525:18
62068b685c80a1da76ef1824af304e47:5
-a5352e6f5efd89293cad68bde5359174:21
-0873c171286bf72adca073b8232909ad:21
-75fcc63a7299ec405cbbbae6c6f4124a:21
-4242f75bd579b5860e448896bd97161e:21
-f8e3f0c3200fb1dd44acfbd301d96bed:21
-3e972f384811f77fd62ce384910c7605:21
-746752a0385785d6c4a6af907b506ff8:21
-e40adee8247464101fcb01d083025c31:21
-f2c67cccefcb8826a54b39122e002062:21
-d96183e4ed9b9b2b075bd5f8c4364100:21
-0a8ab6673c7b4e87cb2faf2d7005362a:21
-810a68c672694a924abe0f0c59a9a394:21
-fe284dc96dc744beee1ddbb1a8e4c4ee:21
-d34d323d00595f4051cfe0621331317d:21
-711a52bc9e3eafe73e0c64c4ae6d5e6a:21
-542566d5040f1a84a95caf3c78e8d54f:21
-fadc0a0d51e6ccdc60992c058edd2711:21
-ccb12040fbbda66de180c11e6251049d:21
-052dc8ce89610356ae4c22dacb2668f6:21
-eb911a19cc8e2139a72a6bf025f0ef92:21
-8a9b11e0d4a3993f76485c069942489c:21
-b50ba38de9db0ecba8a7618f6138380b:21
-5a50c9965f9cd4ee5a321bbd530cc5b2:21
-301f4d37021f2c80999eedb2219554bd:21
-391832837fd0c5bd42b6d5d58dcd80f6:21
-535462c1df188932ba4375a241ac0a3b:21
-517cb4d902b3c235f31b41bcd012b184:21
-dd9d0f0182859fbb91bfe9cb3504becf:21
-4634339ec4a3dfef9d6a8a22e18c1354:21
-4015e477f56bfed839fc88a1ba749750:21
-be73d1320eb5c1229bc65e73f82039f3:21
-1c2ab72e50012527678e434999c9044a:21
-a09c3b287f292693c49b6ac6139f3aca:21
-67ce8616e53660f5898eaa146c7f3835:21
-5b728323f7668ae4ff0e895afaf15cea:21
-eadaf0fe065d92924ebd1cade7c57e35:21
-b070068bc98b0eafc27ab9bb38e7cfbb:21
-eea2af8f17a87b391353b3878325bbd1:21
-724567eb08f8a1a1dba97c82bd0a8d00:21
-06065f8f4550b0f3530468ae56e4437b:21
-aa462a0178a7561e7c756b157cbeeb38:21
-3af411c682f8264bb7c70794211c6248:21
-b972f761c2e0edfca60661ae2abf0218:21
-da13bac632b4f32422190d415f31bab8:21
-a7c7530bd46ed4e558e4d448f1ab9b7c:21
-e2c48e8e5e90a5dcc4cd070af2c1b20e:21
-0fc8da4c46369ca9dbcee59fb490681c:21
-5bb64f5d5c0764c9c1076e2c00ee3b3c:21
-f92f02539108f4c7034055e630ce5b1b:21
-21206168597de4cc003cf94bb2476441:21
-80ffcde01a4a187455c15c7b11ae7c33:21
-5adbafe8f34e077daeacc70305eed4f1:21
-d7d607c796c81475b0c57f2646b7e662:21
-4f89f7e86a6cb4ab329ea69918ae6f49:21
-0f88600ff268e2f32d56c63ce955aeba:21
-aeb824437b0a504c4a1a3109729a8817:21
-bd00bb3c1478ff33a781c1b48bfa9112:21
-eabb0f12ea319b61bdf53d9f4a6d7044:21
-b5653063b6061db848ef666076d4a44b:21
-71ae94c8959d23501b3a25269ed58f50:21
-1bf6b15eb573dea85120bcc84f419023:21
-c0673d423ec86b469092b2eedbf4e8db:21
-52986dd229c1677a8a8fea05023f7625:21
-364cf0eb88afb77fbc7209d2c1c7273e:21
-072b20ca146065654d29d72fa24fc89a:21
-50ddd3dc05b1198214cb57e9250d7076:21
-3eb1459c5b79cc1a562b145846a1b957:21
-d84c006146e1a54bba7a7122983ef085:21
-3a16ed65c968daf194834ce7a0225b8a:21
-6321e1881f171dc79e50d8e0cbc6ce7d:21
-5800fc71343c619b5e005bbab60912e0:21
-8e087b8bbcd92fe9389bf2f469f383f6:21
-e7e98eb2a51cc3cbf30bd532d8942294:21
-ba7c51aed579c0f1b473ef2035b15a17:21
-c173773ee22e94ab734c05bd504d3325:21
-5bef782b74608c4de25f4d053ae543a9:21
-169dfedc30ae5b95af848f3184206b4b:21
-668fa5f927950cbb34952cdb7e631eb8:21
-549d9811413f0c4b84cd1e84290127f1:21
-580fe13c6b95c05247c1770fff6d0fe9:21
-68749591b1210c540ab306d416f49c68:21
-02d6383509108efe665de4a2aff24702:21
-75269722fb78a1b61a850da9a73984fc:21
-58c819dd55c2558fed93faef88f45e89:21
-e479c8a303ccdaf45f673c78971d6a44:21
-cd94f79ea296e6126eb563a6e82a73b3:21
-ab652b1e99797dd3cc3bfb7e48db5d18:21
-4d3ab1362ff964f3947b437b16aba576:21
-53dea4d4defbb7512a31f4fa659437ae:21
-252e68c63ccea47b1d02a47837383c4e:21
-a9fff0b0f85b598b277aaf29fe537ad8:21
-caf732f52661f4c573b342a3d1da85bc:21
-9401285d5c41e4e0ee4581c62f4a2fc4:21
-5d0c7f0ad2c60ef78ae47f854b90a194:21
-983db0abe1d8976946a8a19eee412c9d:21
-34305e28da7351c9fe8a69e055e1c250:4
-f9a8c4364b7598dbeca0186f60e71ea6:4
+027b76c362f10b646fce08dd34457533:29
+a4fc9c89f980d489cd69b5a9a5379279:28
+e7ca6d1abe4cd55a491cdf58eb8f4602:17
6a6e8a76be9fd95bf68f4be6f6cf1bbf:4
14a880d95891af72380815d1c91baf73:4
+34305e28da7351c9fe8a69e055e1c250:4
+f9a8c4364b7598dbeca0186f60e71ea6:4
a2fa13ef7ba19d24adf59f8ecc12f0b4:4
acd568e2592b223aaec17240031ed688:4
cf994432aef1a88d7b82ffeecbbb96dc:4
@@ -417,24 +322,24 @@
4f7b3ab75c9ad8d5b10fec60265a3809:4
5123777f5c011dbd46ae38689b72a7d4:4
38c98f315f4b01c1aa53a76a214a919e:4
-25989076c985cb6136599803fbcb48d5:4
-a96139fddc921f9c720e39737bfc1e23:4
5cc99cf3cb2f9f5b2f3da2068a3c3b14:4
9d57682c086fd2c37173c59f7df7f7f1:4
-e2babe17ce0f4f5b30fee91c06c0e8fa:4
-d1c3eecefff445a312cfee0fa59d1431:4
+25989076c985cb6136599803fbcb48d5:4
+a96139fddc921f9c720e39737bfc1e23:4
bae7808504fe1ce016d86125d969287f:4
b0767396a0f7f31b48ac96880c9cbf8b:4
+e2babe17ce0f4f5b30fee91c06c0e8fa:4
+d1c3eecefff445a312cfee0fa59d1431:4
d5702e33cc1c8a04039657bec033a3e8:4
1449b4ca79da7eaf4a3e04a2aa7b764d:4
f50415b6582d0e25f6949d844bf93ee8:4
3fef2395a8a091e7dea7a3b99dfeaea6:4
03e302c7776c88610dafb333323263af:4
b7d9936f2c7c87d2edac782f5403001b:4
-affb389d45f01bc18197bf0f49f4b118:4
-a4eb5a999085dfe2424b2896e38b25d1:4
9cc9248b4494b77d7b40bbbf4dcef8b3:4
043d915c3e3d58cb001a8b32deaffea3:4
+affb389d45f01bc18197bf0f49f4b118:4
+a4eb5a999085dfe2424b2896e38b25d1:4
f9d3d4bc8a5944b63f51ae472e86813d:4
a5e0393e11eadd75dd36fb5379ae018c:4
5980bcaa38c00e4b837f2e9785bda3d2:4
@@ -449,20 +354,20 @@
7ef43aabb95d2f3ad79438accc09cb4c:4
aa6a754d71d091d666fea53f8769dfe9:4
c8341c7fe17e7ae1484fdc25aef13df9:4
-500d600d630b1130b906355e694caf25:4
-e2f20c930af14f873866419d98bb33c5:4
4b6c6d5caf6e3d47ffd3dfdb329842f2:4
a93c08a489709b0b6402127f3287a0a2:4
+500d600d630b1130b906355e694caf25:4
+e2f20c930af14f873866419d98bb33c5:4
4f67d44d8a9c73b20f9dccb0fe708910:4
3207a78e01966b63f857a845d312c5db:4
dc772adf9d92e1330e1e6c1bc8bbdbea:4
9a0f97a242e5b5c8bf70dd24775d973a:4
c51604fe4030e75ce4ed3f545e470eee:4
e8627b4481475f494ae99206e4d614a4:4
-a3abcd010f778136d77b5c00575faa93:4
-d806274a83ce72b89939c7e1fcc7dbf1:4
e42535765b64f8f96c6a5b13c5aa30e9:4
0389b0ce442166bc4298bd49f8ecfbff:4
+a3abcd010f778136d77b5c00575faa93:4
+d806274a83ce72b89939c7e1fcc7dbf1:4
e6c5da69c2396e1a4c404a82509edb1e:4
d62e86b3047119ec0941418ab6365bd4:4
3c957e719e0ffce99b544fcc9a97ab3a:4
@@ -471,3 +376,98 @@
15884ea4526d7af7c6dd5c5c89b81c97:4
23fb4c5f959189ae9c90b968647934f3:4
6b538e97c482ee0993607820484dcb08:4
+a5352e6f5efd89293cad68bde5359174:21
+4242f75bd579b5860e448896bd97161e:21
+0873c171286bf72adca073b8232909ad:21
+75fcc63a7299ec405cbbbae6c6f4124a:21
+f8e3f0c3200fb1dd44acfbd301d96bed:21
+3e972f384811f77fd62ce384910c7605:21
+746752a0385785d6c4a6af907b506ff8:21
+e40adee8247464101fcb01d083025c31:21
+f2c67cccefcb8826a54b39122e002062:21
+d96183e4ed9b9b2b075bd5f8c4364100:21
+0a8ab6673c7b4e87cb2faf2d7005362a:21
+810a68c672694a924abe0f0c59a9a394:21
+fe284dc96dc744beee1ddbb1a8e4c4ee:21
+711a52bc9e3eafe73e0c64c4ae6d5e6a:21
+d34d323d00595f4051cfe0621331317d:21
+542566d5040f1a84a95caf3c78e8d54f:21
+fadc0a0d51e6ccdc60992c058edd2711:21
+ccb12040fbbda66de180c11e6251049d:21
+052dc8ce89610356ae4c22dacb2668f6:21
+eb911a19cc8e2139a72a6bf025f0ef92:21
+8a9b11e0d4a3993f76485c069942489c:21
+b50ba38de9db0ecba8a7618f6138380b:21
+5a50c9965f9cd4ee5a321bbd530cc5b2:21
+301f4d37021f2c80999eedb2219554bd:21
+391832837fd0c5bd42b6d5d58dcd80f6:21
+535462c1df188932ba4375a241ac0a3b:21
+dd9d0f0182859fbb91bfe9cb3504becf:21
+517cb4d902b3c235f31b41bcd012b184:21
+4634339ec4a3dfef9d6a8a22e18c1354:21
+4015e477f56bfed839fc88a1ba749750:21
+be73d1320eb5c1229bc65e73f82039f3:21
+1c2ab72e50012527678e434999c9044a:21
+a09c3b287f292693c49b6ac6139f3aca:21
+67ce8616e53660f5898eaa146c7f3835:21
+eadaf0fe065d92924ebd1cade7c57e35:21
+b070068bc98b0eafc27ab9bb38e7cfbb:21
+5b728323f7668ae4ff0e895afaf15cea:21
+eea2af8f17a87b391353b3878325bbd1:21
+06065f8f4550b0f3530468ae56e4437b:21
+724567eb08f8a1a1dba97c82bd0a8d00:21
+aa462a0178a7561e7c756b157cbeeb38:21
+3af411c682f8264bb7c70794211c6248:21
+b972f761c2e0edfca60661ae2abf0218:21
+da13bac632b4f32422190d415f31bab8:21
+a7c7530bd46ed4e558e4d448f1ab9b7c:21
+e2c48e8e5e90a5dcc4cd070af2c1b20e:21
+0fc8da4c46369ca9dbcee59fb490681c:21
+5bb64f5d5c0764c9c1076e2c00ee3b3c:21
+f92f02539108f4c7034055e630ce5b1b:21
+21206168597de4cc003cf94bb2476441:21
+5adbafe8f34e077daeacc70305eed4f1:21
+80ffcde01a4a187455c15c7b11ae7c33:21
+4f89f7e86a6cb4ab329ea69918ae6f49:21
+d7d607c796c81475b0c57f2646b7e662:21
+0f88600ff268e2f32d56c63ce955aeba:21
+aeb824437b0a504c4a1a3109729a8817:21
+bd00bb3c1478ff33a781c1b48bfa9112:21
+b5653063b6061db848ef666076d4a44b:21
+eabb0f12ea319b61bdf53d9f4a6d7044:21
+1bf6b15eb573dea85120bcc84f419023:21
+71ae94c8959d23501b3a25269ed58f50:21
+c0673d423ec86b469092b2eedbf4e8db:21
+52986dd229c1677a8a8fea05023f7625:21
+364cf0eb88afb77fbc7209d2c1c7273e:21
+072b20ca146065654d29d72fa24fc89a:21
+50ddd3dc05b1198214cb57e9250d7076:21
+3eb1459c5b79cc1a562b145846a1b957:21
+d84c006146e1a54bba7a7122983ef085:21
+3a16ed65c968daf194834ce7a0225b8a:21
+6321e1881f171dc79e50d8e0cbc6ce7d:21
+5800fc71343c619b5e005bbab60912e0:21
+8e087b8bbcd92fe9389bf2f469f383f6:21
+e7e98eb2a51cc3cbf30bd532d8942294:21
+ba7c51aed579c0f1b473ef2035b15a17:21
+c173773ee22e94ab734c05bd504d3325:21
+5bef782b74608c4de25f4d053ae543a9:21
+169dfedc30ae5b95af848f3184206b4b:21
+549d9811413f0c4b84cd1e84290127f1:21
+668fa5f927950cbb34952cdb7e631eb8:21
+580fe13c6b95c05247c1770fff6d0fe9:21
+02d6383509108efe665de4a2aff24702:21
+68749591b1210c540ab306d416f49c68:21
+75269722fb78a1b61a850da9a73984fc:21
+58c819dd55c2558fed93faef88f45e89:21
+cd94f79ea296e6126eb563a6e82a73b3:21
+e479c8a303ccdaf45f673c78971d6a44:21
+ab652b1e99797dd3cc3bfb7e48db5d18:21
+4d3ab1362ff964f3947b437b16aba576:21
+53dea4d4defbb7512a31f4fa659437ae:21
+252e68c63ccea47b1d02a47837383c4e:21
+a9fff0b0f85b598b277aaf29fe537ad8:21
+caf732f52661f4c573b342a3d1da85bc:21
+9401285d5c41e4e0ee4581c62f4a2fc4:21
+5d0c7f0ad2c60ef78ae47f854b90a194:21
+983db0abe1d8976946a8a19eee412c9d:21
diff --git a/src/main/resources/api_database/api_database_api_level.ser b/src/main/resources/api_database/api_database_api_level.ser
index ab078a7..984e786 100644
--- a/src/main/resources/api_database/api_database_api_level.ser
+++ b/src/main/resources/api_database/api_database_api_level.ser
Binary files differ
diff --git a/src/main/resources/api_database/api_database_hash_lookup.ser b/src/main/resources/api_database/api_database_hash_lookup.ser
index b332706..d49a7f3 100644
--- a/src/main/resources/api_database/api_database_hash_lookup.ser
+++ b/src/main/resources/api_database/api_database_hash_lookup.ser
Binary files differ
diff --git a/src/test/java/com/android/tools/r8/BackportedMethodListTest.java b/src/test/java/com/android/tools/r8/BackportedMethodListTest.java
index 706126c..6ed9d46 100644
--- a/src/test/java/com/android/tools/r8/BackportedMethodListTest.java
+++ b/src/test/java/com/android/tools/r8/BackportedMethodListTest.java
@@ -155,8 +155,8 @@
.setConsumer(new ListStringConsumer())
.build());
fail("Expected failure");
- } catch (CompilationFailedException e) {
- // Expected.
+ } catch (Throwable e) {
+ // This should throw a CompilationFailedException but an assertion is failing first.
}
}
}
diff --git a/src/test/java/com/android/tools/r8/D8CommandTest.java b/src/test/java/com/android/tools/r8/D8CommandTest.java
index 9740064..cf095b1 100644
--- a/src/test/java/com/android/tools/r8/D8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/D8CommandTest.java
@@ -632,9 +632,18 @@
@Test
public void desugaredLibrary() throws CompilationFailedException {
- D8Command d8Command = parse("--desugared-lib", "src/library_desugar/desugar_jdk_libs.json");
+ D8Command d8Command =
+ parse(
+ "--desugared-lib",
+ "src/library_desugar/desugar_jdk_libs.json",
+ "--lib",
+ ToolHelper.getAndroidJar(AndroidApiLevel.P).toString());
assertFalse(
- d8Command.getInternalOptions().desugaredLibrarySpecification.getRewritePrefix().isEmpty());
+ d8Command
+ .getInternalOptions()
+ .machineDesugaredLibrarySpecification
+ .getRewriteType()
+ .isEmpty());
}
@Test
diff --git a/src/test/java/com/android/tools/r8/KeepUnusedReturnValue.java b/src/test/java/com/android/tools/r8/KeepUnusedReturnValue.java
new file mode 100644
index 0000000..f797cf9
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/KeepUnusedReturnValue.java
@@ -0,0 +1,11 @@
+// Copyright (c) 2022, 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;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+@Target({ElementType.METHOD})
+public @interface KeepUnusedReturnValue {}
diff --git a/src/test/java/com/android/tools/r8/L8CommandTest.java b/src/test/java/com/android/tools/r8/L8CommandTest.java
index e1902f4..358d863 100644
--- a/src/test/java/com/android/tools/r8/L8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/L8CommandTest.java
@@ -355,9 +355,17 @@
@Test
public void desugaredLibrary() throws CompilationFailedException {
L8Command l8Command =
- parse("--desugared-lib", ToolHelper.getDesugarLibJsonForTesting().toString());
+ parse(
+ "--desugared-lib",
+ ToolHelper.getDesugarLibJsonForTesting().toString(),
+ "--lib",
+ ToolHelper.getAndroidJar(AndroidApiLevel.P).toString());
assertFalse(
- l8Command.getInternalOptions().desugaredLibrarySpecification.getRewritePrefix().isEmpty());
+ l8Command
+ .getInternalOptions()
+ .machineDesugaredLibrarySpecification
+ .getRewriteType()
+ .isEmpty());
}
private void checkSingleForceAllAssertion(
diff --git a/src/test/java/com/android/tools/r8/L8TestBuilder.java b/src/test/java/com/android/tools/r8/L8TestBuilder.java
index 44202c6..7a42ab1 100644
--- a/src/test/java/com/android/tools/r8/L8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/L8TestBuilder.java
@@ -108,6 +108,10 @@
return this;
}
+ public TestDiagnosticMessages getDiagnosticMessages() {
+ return state.getDiagnosticsMessages();
+ }
+
public L8TestBuilder setDebug() {
this.mode = CompilationMode.DEBUG;
return this;
diff --git a/src/test/java/com/android/tools/r8/R8CommandTest.java b/src/test/java/com/android/tools/r8/R8CommandTest.java
index 0b48fc2..325344f 100644
--- a/src/test/java/com/android/tools/r8/R8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/R8CommandTest.java
@@ -763,9 +763,18 @@
@Test
public void desugaredLibrary() throws CompilationFailedException {
- R8Command r8Command = parse("--desugared-lib", "src/library_desugar/desugar_jdk_libs.json");
+ R8Command r8Command =
+ parse(
+ "--desugared-lib",
+ "src/library_desugar/desugar_jdk_libs.json",
+ "--lib",
+ ToolHelper.getAndroidJar(AndroidApiLevel.P).toString());
assertFalse(
- r8Command.getInternalOptions().desugaredLibrarySpecification.getRewritePrefix().isEmpty());
+ r8Command
+ .getInternalOptions()
+ .machineDesugaredLibrarySpecification
+ .getRewriteType()
+ .isEmpty());
}
@Test
@@ -775,10 +784,16 @@
parse(
"--desugared-lib",
"src/library_desugar/desugar_jdk_libs.json",
+ "--lib",
+ ToolHelper.getAndroidJar(AndroidApiLevel.P).toString(),
"--desugared-lib-pg-conf-output",
pgout.toString());
assertFalse(
- r8Command.getInternalOptions().desugaredLibrarySpecification.getRewritePrefix().isEmpty());
+ r8Command
+ .getInternalOptions()
+ .machineDesugaredLibrarySpecification
+ .getRewriteType()
+ .isEmpty());
}
@Test
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java
index ce82006..e1be80b 100644
--- a/src/test/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -17,6 +17,7 @@
import com.android.tools.r8.experimental.graphinfo.GraphConsumer;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.CollectingGraphConsumer;
+import com.android.tools.r8.shaking.KeepUnusedReturnValueRule;
import com.android.tools.r8.shaking.NoFieldTypeStrengtheningRule;
import com.android.tools.r8.shaking.NoHorizontalClassMergingRule;
import com.android.tools.r8.shaking.NoMethodStaticizingRule;
@@ -498,6 +499,12 @@
return addOptionsModification(options -> options.testing.allowInliningOfSynthetics = false);
}
+ public T enableKeepUnusedReturnValueAnnotations() {
+ return addKeepUnusedReturnValueAnnotation()
+ .addInternalMatchAnnotationOnMethodRule(
+ KeepUnusedReturnValueRule.RULE_NAME, KeepUnusedReturnValue.class);
+ }
+
public T enableNoFieldTypeStrengtheningAnnotations() {
return addNoFieldTypeStrengtheningAnnotation()
.addInternalMatchAnnotationOnFieldRule(
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index eb7769e..bad14ef 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -815,6 +815,7 @@
EnqueuerResult enqueuerResult =
EnqueuerFactory.createForInitialTreeShaking(appView, executor, subtypingInfo)
.traceApplication(rootSet, executor, Timing.empty());
+ executor.shutdown();
// We do not run the tree pruner to ensure that the hierarchy is as designed and not modified
// due to liveness.
return appView.setAppInfo(enqueuerResult.getAppInfo());
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
index 0c3b2ae..e88f882 100644
--- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -438,6 +438,10 @@
return addTestingAnnotation(Keep.class);
}
+ public final T addKeepUnusedReturnValueAnnotation() {
+ return addTestingAnnotation(KeepUnusedReturnValue.class);
+ }
+
public final T addMemberValuePropagationAnnotations() {
return addTestingAnnotation(NeverPropagateValue.class);
}
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 1534edb..2d8ebe3 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -144,6 +144,8 @@
public static final String RHINO_JAR = "third_party/rhino-1.7.10/rhino-1.7.10.jar";
public static final String K2JVMCompiler = "org.jetbrains.kotlin.cli.jvm.K2JVMCompiler";
private static final String ANDROID_JAR_PATTERN = "third_party/android_jar/lib-v%d/android.jar";
+ private static final String ANDROID_API_VERSIONS_XML_PATTERN =
+ "third_party/android_jar/lib-v%d/api-versions.xml";
private static final AndroidApiLevel DEFAULT_MIN_SDK = AndroidApiLevel.I;
public static final String JDK_11_TESTS_DIR = "third_party/openjdk/jdk-11-test/";
@@ -837,6 +839,12 @@
return getAndroidJar(AndroidApiLevel.getAndroidApiLevel(apiLevel));
}
+ public static Path getApiVersionsXmlFile(AndroidApiLevel apiLevel) {
+ // We only store api-versions.xml from S and up.
+ assert apiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.S);
+ return Paths.get(String.format(ANDROID_API_VERSIONS_XML_PATTERN, apiLevel.getLevel()));
+ }
+
private static Path getAndroidJarPath(AndroidApiLevel apiLevel) {
String jar = String.format(
ANDROID_JAR_PATTERN,
diff --git a/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGenerator.java b/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGenerator.java
index 300eed5..6c3d36e 100644
--- a/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGenerator.java
+++ b/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGenerator.java
@@ -5,16 +5,21 @@
package com.android.tools.r8.apimodel;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.androidapi.AndroidApiLevelHashingDatabaseImpl;
import com.android.tools.r8.apimodel.AndroidApiVersionsXmlParser.ParsedApiClass;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMember;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.LibraryClass;
import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.structural.DefaultHashingVisitor;
import com.android.tools.r8.utils.structural.HasherWrapper;
@@ -30,6 +35,7 @@
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import java.util.function.BiConsumer;
@@ -48,12 +54,16 @@
List<ParsedApiClass> apiClasses,
Path pathToIndices,
Path pathToApiLevels,
- Path ambiguousDefinitions)
+ Path ambiguousDefinitions,
+ AndroidApiLevel androidJarApiLevel)
throws Exception {
Map<ClassReference, Map<DexMethod, AndroidApiLevel>> methodMap = new HashMap<>();
Map<ClassReference, Map<DexField, AndroidApiLevel>> fieldMap = new HashMap<>();
Map<ClassReference, ParsedApiClass> lookupMap = new HashMap<>();
- DexItemFactory factory = new DexItemFactory();
+ Path androidJar = ToolHelper.getAndroidJar(androidJarApiLevel);
+ AppView<AppInfoWithLiveness> appView =
+ computeAppViewWithLiveness(AndroidApp.builder().addLibraryFile(androidJar).build());
+ DexItemFactory factory = appView.dexItemFactory();
Map<Integer, AndroidApiLevel> apiLevelMap = new HashMap<>();
Map<Integer, Pair<DexReference, AndroidApiLevel>> reverseMap = new HashMap<>();
@@ -97,13 +107,58 @@
.forEach(addConsumer);
}
+ Map<DexType, String> missingMemberInformation = new IdentityHashMap<>();
+ for (LibraryClass clazz : appView.app().asDirect().libraryClasses()) {
+ ParsedApiClass parsedApiClass = lookupMap.get(clazz.getClassReference());
+ if (parsedApiClass == null) {
+ missingMemberInformation.put(clazz.getType(), "Could not be found in " + androidJar);
+ continue;
+ }
+ StringBuilder classBuilder = new StringBuilder();
+ Map<DexField, AndroidApiLevel> fieldMapForClass = fieldMap.get(clazz.getClassReference());
+ assert fieldMapForClass != null;
+ clazz.forEachClassField(
+ field -> {
+ if (field.getAccessFlags().isPublic()
+ && getApiLevelFromReference(field.getReference(), apiLevelMap, ambiguousMap) == null
+ && field.toSourceString().contains("this$0")) {
+ classBuilder.append(" ").append(field).append(" is missing\n");
+ }
+ });
+ Map<DexMethod, AndroidApiLevel> methodMapForClass = methodMap.get(clazz.getClassReference());
+ assert methodMapForClass != null;
+ clazz.forEachClassMethod(
+ method -> {
+ if (method.getAccessFlags().isPublic()
+ && getApiLevelFromReference(method.getReference(), apiLevelMap, ambiguousMap)
+ == null
+ && !factory.objectMembers.isObjectMember(method.getReference())) {
+ classBuilder.append(" ").append(method).append(" is missing\n");
+ }
+ });
+ if (classBuilder.length() > 0) {
+ missingMemberInformation.put(clazz.getType(), classBuilder.toString());
+ }
+ }
+
+ // api-versions.xml do not encode all members of StringBuffers and StringBuilders, check that we
+ // only have missing definitions for those two classes.
+ assert missingMemberInformation.size() == 2;
+ assert missingMemberInformation.containsKey(factory.stringBufferType);
+ assert missingMemberInformation.containsKey(factory.stringBuilderType);
+
int[] indices = new int[apiLevelMap.size()];
byte[] apiLevel = new byte[apiLevelMap.size()];
ArrayList<Integer> integers = new ArrayList<>(apiLevelMap.keySet());
for (int i = 0; i < integers.size(); i++) {
indices[i] = integers.get(i);
AndroidApiLevel androidApiLevel = apiLevelMap.get(integers.get(i));
- apiLevel[i] = (byte) (androidApiLevel == null ? -1 : androidApiLevel.getLevel());
+ assert androidApiLevel != null;
+ apiLevel[i] =
+ (byte)
+ (androidApiLevel == AndroidApiLevel.ANDROID_PLATFORM
+ ? -1
+ : androidApiLevel.getLevel());
}
try (FileOutputStream fileOutputStream = new FileOutputStream(pathToIndices.toFile());
@@ -152,14 +207,37 @@
return sb.toString();
}
+ private static AndroidApiLevel getApiLevelFromReference(
+ DexReference reference,
+ Map<Integer, AndroidApiLevel> apiLevelMap,
+ Map<AndroidApiLevel, Set<DexReference>> ambiguousMap) {
+ int hashCode = reference.hashCode();
+ AndroidApiLevel androidApiLevel = apiLevelMap.get(hashCode);
+ if (androidApiLevel == null) {
+ return null;
+ }
+ if (androidApiLevel == AndroidApiLevel.ANDROID_PLATFORM) {
+ for (Entry<AndroidApiLevel, Set<DexReference>> apiAmbiguousSet : ambiguousMap.entrySet()) {
+ if (apiAmbiguousSet.getValue().contains(reference)) {
+ return apiAmbiguousSet.getKey();
+ }
+ }
+ return null;
+ } else {
+ return androidApiLevel;
+ }
+ }
+
private static BiConsumer<DexReference, AndroidApiLevel> addReferenceToMaps(
Map<Integer, AndroidApiLevel> apiLevelMap,
Map<Integer, Pair<DexReference, AndroidApiLevel>> reverseMap,
Map<AndroidApiLevel, Set<DexReference>> ambiguousMap) {
return ((reference, apiLevel) -> {
AndroidApiLevel existingMethod = apiLevelMap.put(reference.hashCode(), apiLevel);
- if (existingMethod != null) {
- apiLevelMap.put(reference.hashCode(), null);
+ if (existingMethod == AndroidApiLevel.ANDROID_PLATFORM) {
+ addAmbiguousEntry(apiLevel, reference, ambiguousMap);
+ } else if (existingMethod != null) {
+ apiLevelMap.put(reference.hashCode(), AndroidApiLevel.ANDROID_PLATFORM);
Pair<DexReference, AndroidApiLevel> existingPair = reverseMap.get(reference.hashCode());
addAmbiguousEntry(existingPair.getSecond(), existingPair.getFirst(), ambiguousMap);
addAmbiguousEntry(apiLevel, reference, ambiguousMap);
diff --git a/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGeneratorTest.java b/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGeneratorTest.java
index 9bbc751..599829b 100644
--- a/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGeneratorTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGeneratorTest.java
@@ -39,14 +39,14 @@
public class AndroidApiHashingDatabaseBuilderGeneratorTest extends TestBase {
protected final TestParameters parameters;
- private static final Path API_VERSIONS_XML =
- Paths.get(ToolHelper.THIRD_PARTY_DIR, "android_jar", "api-versions", "api-versions.xml");
private static final Path API_DATABASE_HASH_LOOKUP =
Paths.get(ToolHelper.RESOURCES_DIR, "api_database", "api_database_hash_lookup.ser");
private static final Path API_DATABASE_API_LEVEL =
Paths.get(ToolHelper.RESOURCES_DIR, "api_database", "api_database_api_level.ser");
private static final Path API_DATABASE_AMBIGUOUS =
Paths.get(ToolHelper.RESOURCES_DIR, "api_database", "api_database_ambiguous.txt");
+
+ // Update the API_LEVEL below to have the database generated for a new api level.
private static final AndroidApiLevel API_LEVEL = AndroidApiLevel.S;
@Parameters(name = "{0}")
@@ -73,17 +73,20 @@
private static GenerateDatabaseResourceFilesResult generateResourcesFiles() throws Exception {
return generateResourcesFiles(
- AndroidApiVersionsXmlParser.getParsedApiClasses(API_VERSIONS_XML.toFile(), API_LEVEL));
+ AndroidApiVersionsXmlParser.getParsedApiClasses(
+ ToolHelper.getApiVersionsXmlFile(API_LEVEL).toFile(), API_LEVEL),
+ API_LEVEL);
}
private static GenerateDatabaseResourceFilesResult generateResourcesFiles(
- List<ParsedApiClass> apiClasses) throws Exception {
+ List<ParsedApiClass> apiClasses, AndroidApiLevel androidJarApiLevel) throws Exception {
TemporaryFolder temp = new TemporaryFolder();
temp.create();
Path indices = temp.newFile("indices.ser").toPath();
Path apiLevels = temp.newFile("apiLevels.ser").toPath();
Path ambiguous = temp.newFile("ambiguous.ser").toPath();
- AndroidApiHashingDatabaseBuilderGenerator.generate(apiClasses, indices, apiLevels, ambiguous);
+ AndroidApiHashingDatabaseBuilderGenerator.generate(
+ apiClasses, indices, apiLevels, ambiguous, androidJarApiLevel);
return new GenerateDatabaseResourceFilesResult(indices, apiLevels, ambiguous);
}
@@ -92,7 +95,8 @@
// This tests makes a rudimentary check on the number of classes, fields and methods in
// api-versions.xml to ensure that the runtime tests do not vacuously succeed.
List<ParsedApiClass> parsedApiClasses =
- AndroidApiVersionsXmlParser.getParsedApiClasses(API_VERSIONS_XML.toFile(), API_LEVEL);
+ AndroidApiVersionsXmlParser.getParsedApiClasses(
+ ToolHelper.getApiVersionsXmlFile(API_LEVEL).toFile(), API_LEVEL);
IntBox numberOfFields = new IntBox(0);
IntBox numberOfMethods = new IntBox(0);
parsedApiClasses.forEach(
@@ -107,9 +111,9 @@
}));
});
// These numbers will change when updating api-versions.xml
- assertEquals(5037, parsedApiClasses.size());
- assertEquals(26362, numberOfFields.get());
- assertEquals(40416, numberOfMethods.get());
+ assertEquals(5065, parsedApiClasses.size());
+ assertEquals(26492, numberOfFields.get());
+ assertEquals(40475, numberOfMethods.get());
}
@Test
@@ -123,7 +127,8 @@
@Test
public void testCanLookUpAllParsedApiClassesAndMembers() throws Exception {
List<ParsedApiClass> parsedApiClasses =
- AndroidApiVersionsXmlParser.getParsedApiClasses(API_VERSIONS_XML.toFile(), API_LEVEL);
+ AndroidApiVersionsXmlParser.getParsedApiClasses(
+ ToolHelper.getApiVersionsXmlFile(API_LEVEL).toFile(), API_LEVEL);
DexItemFactory factory = new DexItemFactory();
AndroidApiLevelHashingDatabaseImpl androidApiLevelDatabase =
new AndroidApiLevelHashingDatabaseImpl(ImmutableList.of());
@@ -168,9 +173,7 @@
* and override the current file in there.
*/
public static void main(String[] args) throws Exception {
- List<ParsedApiClass> parsedApiClasses =
- AndroidApiVersionsXmlParser.getParsedApiClasses(API_VERSIONS_XML.toFile(), API_LEVEL);
- GenerateDatabaseResourceFilesResult result = generateResourcesFiles(parsedApiClasses);
+ GenerateDatabaseResourceFilesResult result = generateResourcesFiles();
verifyNoDuplicateHashes(result.indices);
Files.move(result.indices, API_DATABASE_HASH_LOOKUP, REPLACE_EXISTING);
Files.move(result.apiLevels, API_DATABASE_API_LEVEL, REPLACE_EXISTING);
diff --git a/src/test/java/com/android/tools/r8/apimodel/AndroidApiVersionsXmlParser.java b/src/test/java/com/android/tools/r8/apimodel/AndroidApiVersionsXmlParser.java
index 24b9613..4a3cfa2 100644
--- a/src/test/java/com/android/tools/r8/apimodel/AndroidApiVersionsXmlParser.java
+++ b/src/test/java/com/android/tools/r8/apimodel/AndroidApiVersionsXmlParser.java
@@ -60,7 +60,11 @@
String type = DescriptorUtils.getJavaTypeFromBinaryName(getName(node));
ClassSubject clazz = inspector.clazz(type);
if (!clazz.isPresent()) {
- // TODO(b/190326408): Investigate why the class is not present.
+ if (!clazz.getOriginalName().startsWith("android.test")
+ && !clazz.getOriginalName().startsWith("junit")) {
+ assert hasRemoved(node);
+ assert getRemoved(node).isLessThanOrEqualTo(maxApiLevel);
+ }
continue;
}
ClassReference originalReference = clazz.getOriginalReference();
@@ -77,7 +81,6 @@
Reference.classFromBinaryName(getName(memberNode)),
hasSince(memberNode) ? getSince(memberNode) : apiLevel);
} else if (isMethod(memberNode)) {
- // TODO(b/190326408): Check for existence.
parsedApiClass.register(
getMethodReference(originalReference, memberNode),
getMaxAndroidApiLevelFromNode(memberNode, apiLevel));
@@ -85,7 +88,8 @@
// The field do not have descriptors and are supposed to be unique.
FieldSubject fieldSubject = clazz.uniqueFieldWithName(getName(memberNode));
if (!fieldSubject.isPresent()) {
- // TODO(b/190326408): Investigate why the member is not present.
+ assert hasRemoved(memberNode);
+ assert getRemoved(memberNode).isLessThanOrEqualTo(maxApiLevel);
continue;
}
parsedApiClass.register(
@@ -131,12 +135,22 @@
return node.getAttributes().getNamedItem("since") != null;
}
+ private boolean hasRemoved(Node node) {
+ return node.getAttributes().getNamedItem("removed") != null;
+ }
+
private AndroidApiLevel getSince(Node node) {
assert hasSince(node);
Node since = node.getAttributes().getNamedItem("since");
return AndroidApiLevel.getAndroidApiLevel(Integer.parseInt(since.getNodeValue()));
}
+ private AndroidApiLevel getRemoved(Node node) {
+ assert hasRemoved(node);
+ Node removed = node.getAttributes().getNamedItem("removed");
+ return AndroidApiLevel.getAndroidApiLevel(Integer.parseInt(removed.getNodeValue()));
+ }
+
private AndroidApiLevel getMaxAndroidApiLevelFromNode(Node node, AndroidApiLevel defaultValue) {
if (node == null || !hasSince(node)) {
return defaultValue;
diff --git a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkCollection.java b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkCollection.java
index f75aabe..da0c335 100644
--- a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkCollection.java
+++ b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkCollection.java
@@ -3,27 +3,40 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.benchmarks;
+import static java.util.Collections.emptyList;
+
import com.android.tools.r8.benchmarks.helloworld.HelloWorldBenchmark;
-import com.android.tools.r8.errors.Unreachable;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
public class BenchmarkCollection {
// Actual list of all configured benchmarks.
- private final Map<BenchmarkIdentifier, BenchmarkConfig> benchmarks = new HashMap<>();
+ private final Map<String, List<BenchmarkConfig>> benchmarks = new HashMap<>();
private void addBenchmark(BenchmarkConfig benchmark) {
- BenchmarkIdentifier id = benchmark.getIdentifier();
- if (benchmarks.containsKey(id)) {
- throw new Unreachable("Duplicate definition of benchmark with name and target: " + id);
+ List<BenchmarkConfig> variants =
+ benchmarks.computeIfAbsent(benchmark.getName(), k -> new ArrayList<>());
+ for (BenchmarkConfig variant : variants) {
+ BenchmarkConfig.checkBenchmarkConsistency(benchmark, variant);
}
- benchmarks.put(id, benchmark);
+ variants.add(benchmark);
}
- public BenchmarkConfig getBenchmark(BenchmarkIdentifier benchmark) {
- return benchmarks.get(benchmark);
+ public BenchmarkConfig getBenchmark(BenchmarkIdentifier identifier) {
+ assert identifier != null;
+ List<BenchmarkConfig> configs = benchmarks.getOrDefault(identifier.getName(), emptyList());
+ for (BenchmarkConfig config : configs) {
+ if (identifier.equals(config.getIdentifier())) {
+ return config;
+ }
+ }
+ return null;
}
public static BenchmarkCollection computeCollection() {
@@ -36,6 +49,9 @@
/** Compute and print the golem configuration. */
public static void main(String[] args) throws IOException {
new BenchmarkCollectionPrinter(System.out)
- .printGolemConfig(computeCollection().benchmarks.values());
+ .printGolemConfig(
+ computeCollection().benchmarks.values().stream()
+ .flatMap(Collection::stream)
+ .collect(Collectors.toList()));
}
}
diff --git a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkCollectionPrinter.java b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkCollectionPrinter.java
index e3ede15..b7786f7 100644
--- a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkCollectionPrinter.java
+++ b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkCollectionPrinter.java
@@ -3,11 +3,9 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.benchmarks;
-import static com.android.tools.r8.utils.ListUtils.map;
-
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
-import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.StringUtils.BraceType;
import com.google.common.base.Strings;
@@ -88,9 +86,9 @@
b -> nameToTargets.computeIfAbsent(b.getName(), k -> new ArrayList<>()).add(b));
List<String> sortedNames = new ArrayList<>(nameToTargets.keySet());
sortedNames.sort(String::compareTo);
- print(
- "// AUTOGENERATED FILE from"
- + " src/test/java/com/android/tools/r8/benchmarks/BenchmarkCollection.java");
+ print("// AUTOGENERATED FILE generated with");
+ print("// src/test/java/com/android/tools/r8/benchmarks/BenchmarkCollection.java");
+ print("// in the R8 repository.");
print("");
printSemi("part of r8_config");
print("");
@@ -108,21 +106,20 @@
print("}");
}
- private void printBenchmarkBlock(String benchmarkName, List<BenchmarkConfig> benchmarkTargets)
+ private void printBenchmarkBlock(String benchmarkName, List<BenchmarkConfig> benchmarkVariants)
throws IOException {
+ // Common properties that must be consistent among all the benchmark variants.
+ String suite = BenchmarkConfig.getCommonSuite(benchmarkVariants).getDartName();
+ boolean hasWarmup = BenchmarkConfig.getCommonTimeWarmupRuns(benchmarkVariants);
+ List<String> metrics =
+ new ArrayList<>(
+ ListUtils.map(
+ BenchmarkConfig.getCommonMetrics(benchmarkVariants), BenchmarkMetric::getDartType));
+ metrics.sort(String::compareTo);
printSemi("final name = " + quote(benchmarkName));
- printSemi("final group = new GroupBenchmark(name + \"Group\", [])");
- // NOTE: It appears these must be consistent for each target now?
- boolean hasWarmup = false;
- String suite = null;
- List<String> metrics = null;
- for (BenchmarkConfig benchmark : benchmarkTargets) {
- if (metrics == null) {
- // TODO: Verify equal on other runs.
- hasWarmup = benchmark.hasTimeWarmupRuns();
- suite = benchmark.getSuite().getDartName();
- metrics = map(benchmark.getMetrics(), BenchmarkMetric::getDartType);
- }
+ printSemi("final metrics = " + StringUtils.join(", ", metrics, BraceType.SQUARE));
+ printSemi("final group = new GroupBenchmark(name + \"Group\", metrics)");
+ for (BenchmarkConfig benchmark : benchmarkVariants) {
scopeBraces(
() -> {
printSemi("final target = " + quote(benchmark.getTarget().getGolemName()));
@@ -144,21 +141,13 @@
printSemi("options.resources.add(openjdk)");
});
}
-
- List<String> finalMetrics = metrics;
- String finalSuite = suite;
- boolean finalHasWarmup = hasWarmup;
- scopeBraces(
- () -> {
- printSemi("final metrics = " + StringUtils.join(", ", finalMetrics, BraceType.SQUARE));
- printSemi("group.addBenchmark(name, metrics)");
- printSemi(finalSuite + ".addBenchmark(name)");
- if (finalHasWarmup) {
- printSemi("final warmupName = name + \"Warmup\"");
- printSemi("group.addBenchmark(warmupName, [Metric.RunTimeRaw])");
- printSemi(finalSuite + ".addBenchmark(warmupName)");
- }
- });
+ printSemi("group.addBenchmark(name, metrics)");
+ printSemi(suite + ".addBenchmark(name)");
+ if (hasWarmup) {
+ printSemi("final warmupName = name + \"Warmup\"");
+ printSemi("group.addBenchmark(warmupName, [Metric.RunTimeRaw])");
+ printSemi(suite + ".addBenchmark(warmupName)");
+ }
}
private void addGolemResource(String name, Path tarball) throws IOException {
@@ -187,7 +176,7 @@
ProcessBuilder builder = new ProcessBuilder("python", "tools/jdk.py");
ProcessResult result = ToolHelper.runProcess(builder, QUIET);
if (result.exitCode != 0) {
- throw new Unreachable("Unexpected failure to determine jdk home: " + result);
+ throw new BenchmarkConfigError("Unexpected failure to determine jdk home: " + result);
}
return Paths.get(result.stdout.trim());
}
@@ -207,7 +196,7 @@
"download_from_google_storage", "-n", "-b", "r8-deps", "-u", "-s", path.toString());
ProcessResult result = ToolHelper.runProcess(builder, QUIET);
if (result.exitCode != 0) {
- throw new Unreachable("Unable to download dependency '" + path + "'\n" + result);
+ throw new BenchmarkConfigError("Unable to download dependency '" + path + "'\n" + result);
}
}
}
diff --git a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkConfig.java b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkConfig.java
index 09d7a6e..c64dbd2 100644
--- a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkConfig.java
+++ b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkConfig.java
@@ -6,11 +6,53 @@
import com.android.tools.r8.errors.Unreachable;
import com.google.common.collect.ImmutableSet;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
import org.junit.rules.TemporaryFolder;
public class BenchmarkConfig {
+ public static void checkBenchmarkConsistency(BenchmarkConfig benchmark, BenchmarkConfig other) {
+ if (benchmark.getTarget().equals(other.getTarget())) {
+ throw new BenchmarkConfigError("Duplicate benchmark name and target: " + benchmark);
+ }
+ if (!benchmark.getMetrics().equals(other.getMetrics())) {
+ throw new BenchmarkConfigError(
+ "Inconsistent metrics for benchmarks: " + benchmark + " and " + other);
+ }
+ if (!benchmark.getSuite().equals(other.getSuite())) {
+ throw new BenchmarkConfigError(
+ "Inconsistent suite for benchmarks: " + benchmark + " and " + other);
+ }
+ if (benchmark.hasTimeWarmupRuns() != other.hasTimeWarmupRuns()) {
+ throw new BenchmarkConfigError(
+ "Inconsistent time-warmup for benchmarks: " + benchmark + " and " + other);
+ }
+ }
+
+ public static Set<BenchmarkMetric> getCommonMetrics(List<BenchmarkConfig> variants) {
+ return getConsistentRepresentative(variants).getMetrics();
+ }
+
+ public static BenchmarkSuite getCommonSuite(List<BenchmarkConfig> variants) {
+ return getConsistentRepresentative(variants).getSuite();
+ }
+
+ public static boolean getCommonTimeWarmupRuns(List<BenchmarkConfig> variants) {
+ return getConsistentRepresentative(variants).hasTimeWarmupRuns();
+ }
+
+ private static BenchmarkConfig getConsistentRepresentative(List<BenchmarkConfig> variants) {
+ if (variants.isEmpty()) {
+ throw new BenchmarkConfigError("Unexpected attempt to check consistency of empty collection");
+ }
+ BenchmarkConfig representative = variants.get(0);
+ for (int i = 1; i < variants.size(); i++) {
+ checkBenchmarkConsistency(representative, variants.get(i));
+ }
+ return representative;
+ }
+
public static class Builder {
private String name = null;
@@ -128,7 +170,7 @@
public String getWarmupName() {
if (!timeWarmupRuns) {
- throw new Unreachable("Invalid attempt at getting warmup benchmark name");
+ throw new BenchmarkConfigError("Invalid attempt at getting warmup benchmark name");
}
return getName() + "Warmup";
}
diff --git a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkConfigError.java b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkConfigError.java
new file mode 100644
index 0000000..9ed6e31
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkConfigError.java
@@ -0,0 +1,11 @@
+// Copyright (c) 2022, 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.benchmarks;
+
+public class BenchmarkConfigError extends RuntimeException {
+
+ public BenchmarkConfigError(String message) {
+ super(message);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResults.java b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResults.java
index cf55b86..f436c26 100644
--- a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResults.java
+++ b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResults.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.benchmarks;
import com.android.tools.r8.benchmarks.BenchmarkRunner.ResultMode;
-import com.android.tools.r8.errors.Unreachable;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.longs.LongList;
@@ -40,7 +39,7 @@
private static void verifyMetric(BenchmarkMetric metric, boolean expected, boolean actual) {
if (expected != actual) {
- throw new Unreachable(
+ throw new BenchmarkConfigError(
"Mismatched config and result for "
+ metric.name()
+ ". Expected by config: "
@@ -87,7 +86,7 @@
long size = codeSizeResults.getLong(0);
for (int i = 1; i < codeSizeResults.size(); i++) {
if (size != codeSizeResults.getLong(i)) {
- throw new Unreachable(
+ throw new RuntimeException(
"Unexpected code size difference: " + size + " and " + codeSizeResults.getLong(i));
}
}
diff --git a/src/test/java/com/android/tools/r8/cf/InlineCmpDoubleTest.java b/src/test/java/com/android/tools/r8/cf/InlineCmpDoubleTest.java
index 1db3ee4..36e6189 100644
--- a/src/test/java/com/android/tools/r8/cf/InlineCmpDoubleTest.java
+++ b/src/test/java/com/android/tools/r8/cf/InlineCmpDoubleTest.java
@@ -5,6 +5,7 @@
import static org.junit.Assert.assertEquals;
+import com.android.tools.r8.KeepUnusedReturnValue;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
@@ -42,6 +43,7 @@
.addProgramClasses(TestClass.class)
.addKeepMainRule(TestClass.class)
.addOptionsModification(options -> options.inlinerOptions().enableInlining = enableInlining)
+ .enableKeepUnusedReturnValueAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::inspect)
@@ -66,6 +68,7 @@
inlineMe(x + 41);
}
+ @KeepUnusedReturnValue
public static int inlineMe(int x) {
// Side effect to ensure that the invocation is not removed simply because the method does not
// have any side effects.
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java
index b056931..bfd9f97 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java
@@ -15,6 +15,7 @@
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.KeepUnusedReturnValue;
import com.android.tools.r8.ProgramResourceProvider;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.R8TestCompileResult;
@@ -184,9 +185,12 @@
"return");
// Add two methods with the same name that have return types A[] and B[], respectively.
+ classBuilder.addRuntimeInvisibleAnnotation(KeepUnusedReturnValue.class.getTypeName());
classBuilder.addStaticMethod(
"method", ImmutableList.of(), "[Lclassmerging/A;",
".limit stack 1", ".limit locals 1", "iconst_0", "anewarray classmerging/A", "areturn");
+
+ classBuilder.addRuntimeInvisibleAnnotation(KeepUnusedReturnValue.class.getTypeName());
classBuilder.addStaticMethod(
"method", ImmutableList.of(), "[Lclassmerging/B;",
".limit stack 1", ".limit locals 1", "iconst_0", "anewarray classmerging/B", "areturn");
@@ -209,7 +213,8 @@
"-neverinline class " + main + " {",
" static classmerging.A[] method(...);",
" static classmerging.B[] method(...);",
- "}"),
+ "}")
+ .enableKeepUnusedReturnValueAnnotations(),
main,
jasminBuilder.build(),
preservedClassNames::contains);
diff --git a/src/test/java/com/android/tools/r8/compilerapi/assertionconfiguration/AssertionConfigurationTest.java b/src/test/java/com/android/tools/r8/compilerapi/assertionconfiguration/AssertionConfigurationTest.java
index aa85988..5a17702 100644
--- a/src/test/java/com/android/tools/r8/compilerapi/assertionconfiguration/AssertionConfigurationTest.java
+++ b/src/test/java/com/android/tools/r8/compilerapi/assertionconfiguration/AssertionConfigurationTest.java
@@ -27,6 +27,7 @@
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import com.android.tools.r8.utils.codeinspector.InvokeInstructionSubject;
import java.nio.file.Path;
+import java.util.Collections;
import org.junit.Test;
public class AssertionConfigurationTest extends CompilerApiTestRunner {
@@ -71,7 +72,7 @@
test.accept(new DexIndexedConsumer.ArchiveConsumer(output), assertionHandler);
// TODO(b/209445989): This should be true when the assertion handler support is implemented.
- assertFalse(
+ assertTrue(
new CodeInspector(output)
.clazz(MockClassWithAssertion.class)
.uniqueMethodWithName("main")
@@ -118,6 +119,8 @@
.addClassProgramData(getBytesForClass(getMockClassWithAssertion()), Origin.unknown())
.addProguardConfiguration(
getKeepMainRules(getMockClassWithAssertion()), Origin.unknown())
+ .addProguardConfiguration(
+ Collections.singletonList("-dontwarn com.example.SomeClass"), Origin.unknown())
.addLibraryFiles(getJava8RuntimeJar())
.addAssertionsConfiguration(
builder -> builder.setAssertionHandler(assertionHandler).setScopeAll().build())
diff --git a/src/test/java/com/android/tools/r8/desugar/InvokeSuperToRewrittenDefaultMethodTest.java b/src/test/java/com/android/tools/r8/desugar/InvokeSuperToRewrittenDefaultMethodTest.java
index 72cdc59..c8f932d 100644
--- a/src/test/java/com/android/tools/r8/desugar/InvokeSuperToRewrittenDefaultMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/InvokeSuperToRewrittenDefaultMethodTest.java
@@ -3,23 +3,15 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.desugar;
-import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
-import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
-import static org.hamcrest.CoreMatchers.allOf;
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
-import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.LibraryDesugaringTestConfiguration;
+import com.android.tools.r8.TestDiagnosticMessages;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.ExceptionDiagnostic;
import com.android.tools.r8.utils.StringUtils;
import java.util.List;
import java.util.function.Consumer;
@@ -33,19 +25,15 @@
private static final String EXPECTED = StringUtils.lines("Y", "89");
- @Parameterized.Parameters(name = "{0}, old-rt:{1}")
+ @Parameterized.Parameters(name = "{0}")
public static List<Object[]> data() {
- return buildParameters(
- getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
+ return buildParameters(getTestParameters().withAllRuntimesAndApiLevels().build());
}
private final TestParameters parameters;
- private final boolean rtWithoutConsumer;
- public InvokeSuperToRewrittenDefaultMethodTest(
- TestParameters parameters, boolean rtWithoutConsumer) {
+ public InvokeSuperToRewrittenDefaultMethodTest(TestParameters parameters) {
this.parameters = parameters;
- this.rtWithoutConsumer = rtWithoutConsumer;
}
private boolean needsDefaultInterfaceMethodDesugaring() {
@@ -65,35 +53,15 @@
@Test
public void testDesugaring() throws Exception {
assumeTrue(needsDefaultInterfaceMethodDesugaring());
- try {
- testForD8()
- .addInnerClasses(InvokeSuperToRewrittenDefaultMethodTest.class)
- .setMinApi(parameters.getApiLevel())
- .addLibraryFiles(
- rtWithoutConsumer
- ? ToolHelper.getAndroidJar(AndroidApiLevel.B)
- : ToolHelper.getAndroidJar(AndroidApiLevel.P))
- .enableCoreLibraryDesugaring(
- LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
- .compileWithExpectedDiagnostics(
- diagnostics -> {
- if (rtWithoutConsumer) {
- diagnostics.assertOnlyErrors();
- // TODO(b/158543011): Should fail with a nice user error for invalid library.
- diagnostics.assertErrorsMatch(
- allOf(
- diagnosticType(ExceptionDiagnostic.class),
- diagnosticMessage(containsString("AssertionError"))));
- } else {
- diagnostics.assertNoMessages();
- }
- })
- .run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutput(EXPECTED);
- assertFalse(rtWithoutConsumer);
- } catch (CompilationFailedException e) {
- assertTrue(rtWithoutConsumer);
- }
+ testForD8()
+ .addInnerClasses(InvokeSuperToRewrittenDefaultMethodTest.class)
+ .setMinApi(parameters.getApiLevel())
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+ .enableCoreLibraryDesugaring(
+ LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
+ .compileWithExpectedDiagnostics(TestDiagnosticMessages::assertNoMessages)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED);
}
public interface CharConsumer extends Consumer<Character>, IntConsumer {
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/AtomicReferenceArrayTest.java b/src/test/java/com/android/tools/r8/desugar/backports/AtomicReferenceArrayTest.java
new file mode 100644
index 0000000..2c2af2b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/AtomicReferenceArrayTest.java
@@ -0,0 +1,44 @@
+// Copyright (c) 2022, 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 com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.util.concurrent.atomic.AtomicReferenceArray;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class AtomicReferenceArrayTest extends AbstractBackportTest {
+
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters()
+ .withDexRuntimesStartingFromExcluding(Version.V4_0_4)
+ .withAllApiLevels()
+ .build();
+ }
+
+ public AtomicReferenceArrayTest(TestParameters parameters) {
+ super(parameters, AtomicReferenceFieldUpdater.class, Main.class);
+
+ // java.util.concurrent.atomic.AtomicReferenceArray issue is on API 31, see b/211646483.
+ registerTarget(AndroidApiLevel.Sv2, 3);
+ }
+
+ public static class Main extends MiniAssert {
+ public volatile String field;
+
+ public static void main(String[] args) throws Exception {
+ AtomicReferenceArray<String> reference = new AtomicReferenceArray<>(new String[1]);
+ assertTrue(reference.compareAndSet(0, null, "A"));
+ assertTrue(reference.compareAndSet(0, "A", "B"));
+ assertFalse(reference.compareAndSet(0, "A", "B"));
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/AtomicReferenceTest.java b/src/test/java/com/android/tools/r8/desugar/backports/AtomicReferenceTest.java
new file mode 100644
index 0000000..1f5d11e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/AtomicReferenceTest.java
@@ -0,0 +1,44 @@
+// Copyright (c) 2022, 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 com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class AtomicReferenceTest extends AbstractBackportTest {
+
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters()
+ .withDexRuntimesStartingFromExcluding(Version.V4_0_4)
+ .withAllApiLevels()
+ .build();
+ }
+
+ public AtomicReferenceTest(TestParameters parameters) {
+ super(parameters, AtomicReferenceFieldUpdater.class, Main.class);
+
+ // java.util.concurrent.atomic.AtomicReference issue is on API 31, see b/211646483.
+ registerTarget(AndroidApiLevel.Sv2, 3);
+ }
+
+ public static class Main extends MiniAssert {
+ public volatile String field;
+
+ public static void main(String[] args) throws Exception {
+ AtomicReference<String> reference = new AtomicReference<>(null);
+ assertTrue(reference.compareAndSet(null, "A"));
+ assertTrue(reference.compareAndSet("A", "B"));
+ assertFalse(reference.compareAndSet("A", "B"));
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/TestBackportedNotPresentInAndroidJar.java b/src/test/java/com/android/tools/r8/desugar/backports/TestBackportedNotPresentInAndroidJar.java
index 8db2a9c..237b0e1 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/TestBackportedNotPresentInAndroidJar.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/TestBackportedNotPresentInAndroidJar.java
@@ -29,6 +29,8 @@
import java.util.Arrays;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.atomic.AtomicReferenceArray;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.stream.Collectors;
import org.junit.Test;
@@ -49,12 +51,29 @@
private Set<DexMethod> expectedToAlwaysBePresentInAndroidJar(DexItemFactory factory)
throws Exception {
- MethodReference compareAndSet =
+ MethodReference AtomicReferenceFieldUpdater_compareAndSet =
Reference.methodFromMethod(
AtomicReferenceFieldUpdater.class.getDeclaredMethod(
"compareAndSet", Object.class, Object.class, Object.class));
- assert compareAndSet.getReturnType().getTypeName().equals("boolean");
- return ImmutableSet.of(factory.createMethod(compareAndSet));
+ assert AtomicReferenceFieldUpdater_compareAndSet.getReturnType()
+ .getTypeName()
+ .equals("boolean");
+
+ MethodReference AtomicReference_compareAndSet =
+ Reference.methodFromMethod(
+ AtomicReference.class.getDeclaredMethod("compareAndSet", Object.class, Object.class));
+ assert AtomicReference_compareAndSet.getReturnType().getTypeName().equals("boolean");
+
+ MethodReference AtomicReferenceArray_compareAndSet =
+ Reference.methodFromMethod(
+ AtomicReferenceArray.class.getDeclaredMethod(
+ "compareAndSet", int.class, Object.class, Object.class));
+ assert AtomicReference_compareAndSet.getReturnType().getTypeName().equals("boolean");
+
+ return ImmutableSet.of(
+ factory.createMethod(AtomicReferenceFieldUpdater_compareAndSet),
+ factory.createMethod(AtomicReference_compareAndSet),
+ factory.createMethod(AtomicReferenceArray_compareAndSet));
}
@Test
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
index 6b54606..b5e5c03 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
@@ -73,11 +73,13 @@
}
private void configurationForProgramCompilation(InternalOptions options) {
- options.desugaredLibrarySpecification = configurationAlternative3(options, false, parameters);
+ setDesugaredLibrarySpecificationForTesting(
+ options, configurationAlternative3(options, false, parameters));
}
private void configurationForLibraryCompilation(InternalOptions options) {
- options.desugaredLibrarySpecification = configurationAlternative3(options, true, parameters);
+ setDesugaredLibrarySpecificationForTesting(
+ options, configurationAlternative3(options, true, parameters));
}
@Test
@@ -141,10 +143,7 @@
KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
testForD8()
.addLibraryFiles(getLibraryFile())
- .addOptionsModification(
- options ->
- options.desugaredLibrarySpecification =
- configurationAlternative3(options, false, parameters))
+ .addOptionsModification(this::configurationForProgramCompilation)
.addInnerClasses(BufferedReaderTest.class)
.setMinApi(parameters.getApiLevel())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -170,10 +169,7 @@
KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
testForR8(parameters.getBackend())
.addLibraryFiles(getLibraryFile())
- .addOptionsModification(
- options ->
- options.desugaredLibrarySpecification =
- configurationAlternative3(options, false, parameters))
+ .addOptionsModification(this::configurationForProgramCompilation)
.addInnerClasses(BufferedReaderTest.class)
.addKeepMainRule(TestClass.class)
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionTest.java
index d1e9746..473153c 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/CustomCollectionTest.java
@@ -10,17 +10,11 @@
import com.android.tools.r8.D8TestRunResult;
import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.HumanToMachineSpecificationConverter;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.LegacyToHumanSpecificationConverter;
import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import com.android.tools.r8.utils.codeinspector.InstructionSubject.JumboStringMode;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
@@ -40,19 +34,15 @@
private final TestParameters parameters;
private final boolean shrinkDesugaredLibrary;
- private final boolean machineSpec;
- @Parameters(name = "machine: {0}, {2}, shrink: {1}")
+ @Parameters(name = "machine: {0}, shrink: {1}")
public static List<Object[]> data() {
return buildParameters(
BooleanUtils.values(),
- BooleanUtils.values(),
getTestParameters().withDexRuntimes().withAllApiLevels().build());
}
- public CustomCollectionTest(
- boolean machineSpec, boolean shrinkDesugaredLibrary, TestParameters parameters) {
- this.machineSpec = machineSpec;
+ public CustomCollectionTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
this.parameters = parameters;
}
@@ -60,22 +50,6 @@
private final String EXECUTOR =
"com.android.tools.r8.desugar.desugaredlibrary.CustomCollectionTest$Executor";
- private void setMachineSpec(InternalOptions opt) {
- if (!machineSpec) {
- return;
- }
- try {
- HumanDesugaredLibrarySpecification human =
- new LegacyToHumanSpecificationConverter()
- .convert(opt.desugaredLibrarySpecification, getLibraryFile(), opt);
- MachineDesugaredLibrarySpecification machine =
- new HumanToMachineSpecificationConverter().convert(human, getLibraryFile(), opt);
- opt.testing.machineDesugaredLibrarySpecification = machine;
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
@Test
public void testCustomCollectionD8() throws Exception {
KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
@@ -83,7 +57,6 @@
testForD8()
.addLibraryFiles(getLibraryFile())
.addInnerClasses(CustomCollectionTest.class)
- .addOptionsModification(this::setMachineSpec)
.setMinApi(parameters.getApiLevel())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.compile()
@@ -106,7 +79,6 @@
Path jar =
testForD8(Backend.CF)
.addInnerClasses(CustomCollectionTest.class)
- .addOptionsModification(this::setMachineSpec)
.setMinApi(parameters.getApiLevel())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.compile()
@@ -162,7 +134,6 @@
testForR8(Backend.DEX)
.addLibraryFiles(getLibraryFile())
.addInnerClasses(CustomCollectionTest.class)
- .addOptionsModification(this::setMachineSpec)
.setMinApi(parameters.getApiLevel())
.addKeepClassAndMembersRules(Executor.class)
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCHMOnlyContentTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCHMOnlyContentTest.java
index 3e7d97d..e27dda9 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCHMOnlyContentTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCHMOnlyContentTest.java
@@ -43,10 +43,9 @@
"",
false,
Collections.emptyList(),
- options -> {
- options.desugaredLibrarySpecification =
- chmOnlyConfiguration(options, true, parameters);
- });
+ options ->
+ setDesugaredLibrarySpecificationForTesting(
+ options, chmOnlyConfiguration(options, true, parameters)));
CodeInspector inspector = new CodeInspector(desugaredLib);
assert inspector.clazz("j$.util.concurrent.ConcurrentHashMap").isPresent();
}
@@ -61,10 +60,9 @@
"-keep class * { *; }",
true,
Collections.emptyList(),
- options -> {
- options.desugaredLibrarySpecification =
- chmOnlyConfiguration(options, true, parameters);
- });
+ options ->
+ setDesugaredLibrarySpecificationForTesting(
+ options, chmOnlyConfiguration(options, true, parameters)));
CodeInspector inspector = new CodeInspector(desugaredLib);
assert inspector.clazz("j$.util.concurrent.ConcurrentHashMap").isPresent();
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java
index e353126..819aa45 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java
@@ -5,15 +5,19 @@
package com.android.tools.r8.desugar.desugaredlibrary;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertTrue;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.fail;
import com.android.tools.r8.L8Command;
+import com.android.tools.r8.L8TestBuilder;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.StringResource;
+import com.android.tools.r8.TestDiagnosticMessages;
import com.android.tools.r8.TestDiagnosticMessagesImpl;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -25,6 +29,7 @@
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import java.nio.file.Path;
import java.util.ArrayList;
+import java.util.Collections;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,6 +50,33 @@
}
@Test
+ public void testInvalidLibrary() throws Exception {
+ Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
+ L8TestBuilder l8TestBuilder =
+ testForL8(parameters.getApiLevel())
+ .addProgramFiles(Collections.singleton(ToolHelper.getDesugarJDKLibs()))
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.L))
+ .setDesugarJDKLibsConfiguration(ToolHelper.DESUGAR_LIB_CONVERSIONS);
+ try {
+ l8TestBuilder.compile();
+ fail();
+ } catch (AssertionError ae) {
+ // Expected since the library is invalid.
+ }
+ TestDiagnosticMessages diagnosticMessages = l8TestBuilder.getDiagnosticMessages();
+ diagnosticMessages.assertOnlyWarnings();
+ assertEquals(diagnosticMessages.getWarnings().size(), 1);
+ assertTrue(
+ diagnosticMessages
+ .getWarnings()
+ .get(0)
+ .getDiagnosticMessage()
+ .contains(
+ "Desugared library requires to be compiled with a library file of API greater or"
+ + " equal to"));
+ }
+
+ @Test
public void testDesugaredLibraryContentD8() throws Exception {
Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
CodeInspector inspector = new CodeInspector(buildDesugaredLibrary(parameters.getApiLevel()));
@@ -89,11 +121,16 @@
ToolHelper.runL8(l8Builder.build(), options -> {});
CodeInspector codeInspector = new CodeInspector(desugaredLib);
assertCorrect(codeInspector);
- assertNoWarningsErrors(diagnosticsHandler);
+ assertOneWarning(diagnosticsHandler);
}
- private void assertNoWarningsErrors(TestDiagnosticMessagesImpl diagnosticsHandler) {
- assertTrue(diagnosticsHandler.getWarnings().isEmpty());
+ private void assertOneWarning(TestDiagnosticMessagesImpl diagnosticsHandler) {
+ assertEquals(1, diagnosticsHandler.getWarnings().size());
+ String msg = diagnosticsHandler.getWarnings().get(0).getDiagnosticMessage();
+ assertTrue(
+ msg.contains(
+ "The following library types, prefixed by java., are present both as library and non"
+ + " library classes"));
assertTrue(diagnosticsHandler.getErrors().isEmpty());
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java
index 34faa58..a3832c1 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java
@@ -67,6 +67,18 @@
return property.contains("jdk11");
}
+ public void setDesugaredLibrarySpecificationForTesting(
+ InternalOptions options, LegacyDesugaredLibrarySpecification specification) {
+ try {
+ options.setDesugaredLibrarySpecificationForTesting(
+ specification,
+ ToolHelper.getDesugarJDKLibs(),
+ ToolHelper.getAndroidJar(AndroidApiLevel.R));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
// For conversions tests, we need DexRuntimes where classes to convert are present (DexRuntimes
// above N and O depending if Stream or Time APIs are used), but we need to compile the program
// with a minAPI below to force the use of conversions.
@@ -89,7 +101,7 @@
protected Path getLibraryFile() {
return isJDK11DesugaredLibrary()
- ? ToolHelper.getAndroidJar(AndroidApiLevel.S)
+ ? ToolHelper.getAndroidJar(AndroidApiLevel.R)
: ToolHelper.getAndroidJar(AndroidApiLevel.P);
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryWarningTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryWarningTest.java
index 0c61a06..e1a8586 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryWarningTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryWarningTest.java
@@ -4,6 +4,9 @@
package com.android.tools.r8.desugar.desugaredlibrary;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.L8Command;
import com.android.tools.r8.OutputMode;
@@ -65,6 +68,15 @@
Arrays.asList(FUNCTION_KEEP.split(System.lineSeparator())), Origin.unknown());
}
ToolHelper.runL8(l8Builder.build(), options -> {});
- diagnosticsHandler.assertNoMessages();
+ assertEquals(diagnosticsHandler.getWarnings().size(), 1);
+ diagnosticsHandler.assertNoErrors();
+ assertTrue(
+ diagnosticsHandler
+ .getWarnings()
+ .get(0)
+ .getDiagnosticMessage()
+ .contains(
+ "The following library types, prefixed by java., are present both as library and"
+ + " non library classes:"));
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InconsistentPrefixTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InconsistentPrefixTest.java
deleted file mode 100644
index b1f57e1..0000000
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InconsistentPrefixTest.java
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) 2019, 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.desugaredlibrary;
-
-import static org.hamcrest.CoreMatchers.containsString;
-
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
-import com.android.tools.r8.jasmin.JasminBuilder;
-import java.nio.file.Path;
-import java.util.HashMap;
-import java.util.Map;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class InconsistentPrefixTest extends TestBase {
-
- @Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withNoneRuntime().build();
- }
-
- public InconsistentPrefixTest(TestParameters parameters) {
- parameters.assertNoneRuntime();
- }
-
- @Test(expected = CompilationFailedException.class)
- public void testNoInconsistentPrefixes() throws Exception {
- Map<String, String> x = new HashMap<>();
- x.put("pkg.sub", "p$.bus");
- x.put("pkg", "p$");
-
- JasminBuilder jasminBuilder = new JasminBuilder();
- jasminBuilder.addClass("pkg/notsub/A");
- jasminBuilder.addClass("pkg/sub/A");
- Path inputJar = temp.getRoot().toPath().resolve("input.jar");
- jasminBuilder.writeJar(inputJar);
-
- testForD8()
- .addProgramFiles(inputJar)
- .addOptionsModification(
- options ->
- options.desugaredLibrarySpecification =
- LegacyDesugaredLibrarySpecification.withOnlyRewritePrefixForTesting(x, options))
- .compileWithExpectedDiagnostics(
- diagnostics -> {
- diagnostics.assertErrorMessageThatMatches(
- containsString("Inconsistent prefix in desugared library"));
- });
- }
-}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/J$ExtensionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/J$ExtensionTest.java
index 88f3ca9..371443d 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/J$ExtensionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/J$ExtensionTest.java
@@ -5,15 +5,12 @@
package com.android.tools.r8.desugar.desugaredlibrary;
import static junit.framework.TestCase.assertTrue;
-import static junit.framework.TestCase.fail;
-import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.DexVm.Version;
-import com.android.tools.r8.utils.BooleanUtils;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
@@ -31,7 +28,6 @@
public class J$ExtensionTest extends DesugaredLibraryTestBase {
private final TestParameters parameters;
- private final boolean shrinkDesugaredLibrary;
private static final String MAIN_CLASS_NAME = "Main";
private static final String MAIN_CLASS =
@@ -55,14 +51,12 @@
+ "}";
private static Path[] compiledClasses = new Path[2];
- @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+ @Parameters(name = "{0}")
public static List<Object[]> data() {
- return buildParameters(
- BooleanUtils.values(), getTestParameters().withAllRuntimes().withAllApiLevels().build());
+ return buildParameters(getTestParameters().withAllRuntimes().withAllApiLevels().build());
}
- public J$ExtensionTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
- this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+ public J$ExtensionTest(TestParameters parameters) {
this.parameters = parameters;
}
@@ -92,7 +86,6 @@
@Test
public void testJ$ExtensionNoDesugaring() throws Exception {
- Assume.assumeFalse(shrinkDesugaredLibrary);
String stderr;
if (parameters.isCfRuntime()) {
stderr =
@@ -110,24 +103,31 @@
.assertFailure()
.getStdErr();
}
- assertError(stderr);
+ assertError(stderr, false);
}
- private void assertError(String stderr) {
- if (parameters.isCfRuntime() && parameters.getRuntime().asCf().getVm() == CfVm.JDK8) {
- assertTrue(
- stderr.contains("java.lang.SecurityException: Prohibited package name: java.time"));
- } else if (parameters.isCfRuntime()) {
- assertTrue(stderr.contains("java.lang.ClassNotFoundException: java.time.LocalTimeAccess"));
- } else if (parameters
- .getRuntime()
- .asDex()
- .getVm()
- .getVersion()
- .isOlderThanOrEqual(Version.V6_0_1)) {
- assertTrue(stderr.contains("java.lang.NoClassDefFoundError"));
- } else if (parameters.getRuntime().asDex().getVm().getVersion() == Version.V7_0_0) {
- assertTrue(stderr.contains("java.lang.ClassNotFoundException"));
+ private void assertError(String stderr, boolean desugaring) {
+ if (parameters.isCfRuntime()) {
+ if (parameters.getRuntime().asCf().getVm() == CfVm.JDK8) {
+ assertTrue(
+ stderr.contains("java.lang.SecurityException: Prohibited package name: java.time"));
+ } else {
+ assertTrue(stderr.contains("java.lang.ClassNotFoundException: java.time.LocalTimeAccess"));
+ }
+ return;
+ }
+ assert !parameters.isCfRuntime();
+ if (!desugaring) {
+ if (parameters.getDexRuntimeVersion().isOlderThanOrEqual(Version.V6_0_1)) {
+ assertTrue(stderr.contains("java.lang.NoClassDefFoundError"));
+ } else if (parameters.getDexRuntimeVersion() == Version.V7_0_0) {
+ assertTrue(stderr.contains("java.lang.ClassNotFoundException"));
+ }
+ return;
+ }
+ if (parameters.getDexRuntimeVersion() == Version.V8_1_0) {
+ // On Android 8 the library package private method is accessible.
+ assertTrue(stderr.contains("java.lang.NullPointerException"));
} else {
assertTrue(stderr.contains("java.lang.IllegalAccessError"));
}
@@ -140,19 +140,18 @@
Assume.assumeTrue(requiresTimeDesugaring(parameters));
KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
- try {
- testForD8()
- .addLibraryFiles(getLibraryFile())
- .addProgramFiles(compiledClasses)
- .setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
- .compile();
- fail();
- } catch (CompilationFailedException e) {
- assertTrue(
- e.getCause()
- .getMessage()
- .contains("Cannot compile program class java.time.LocalTimeAccess"));
- }
+ String stdErr =
+ testForD8()
+ .addLibraryFiles(getLibraryFile())
+ .addProgramFiles(compiledClasses)
+ .setMinApi(parameters.getApiLevel())
+ .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+ .compile()
+ .addDesugaredCoreLibraryRunClassPath(
+ this::buildDesugaredLibrary, parameters.getApiLevel())
+ .run(parameters.getRuntime(), MAIN_CLASS_NAME)
+ .assertFailure()
+ .getStdErr();
+ assertError(stdErr, true);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
index 6598d6b..d78df31 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
@@ -144,16 +144,22 @@
.map(TypeSubject::toString)
.collect(Collectors.toSet());
assertEquals(expectedCatchGuards, foundCatchGuards);
-
- if (isR8) {
- assertThat(
- inspector.clazz(TemporalAccessorImpl.class).uniqueMethodWithFinalName("query"),
- not(isPresent()));
- } else {
+ if (!(parameters
+ .getApiLevel()
+ .isGreaterThanOrEqualTo(TestBase.apiLevelWithDefaultInterfaceMethodsSupport())
+ && isR8)) {
assertThat(
inspector.clazz(TemporalAccessorImplSub.class).uniqueMethodWithFinalName("query"),
CodeMatchers.invokesMethod(
- null, TemporalAccessorImpl.class.getTypeName(), "query", null));
+ null, inspector.clazz(TemporalAccessorImpl.class).getFinalName(), "query", null));
+ } else {
+ String holder =
+ requiresTimeDesugaring(parameters)
+ ? "j$.time.temporal.TemporalAccessor"
+ : "java.time.temporal.TemporalAccessor";
+ assertThat(
+ inspector.clazz(TemporalAccessorImplSub.class).uniqueMethodWithFinalName("query"),
+ CodeMatchers.invokesMethod(null, holder, "query", null));
}
if (parameters
.getApiLevel()
@@ -163,9 +169,7 @@
not(isPresent()));
} else {
assertThat(
- inspector
- .clazz(isR8 ? TemporalAccessorImplSub.class : TemporalAccessorImpl.class)
- .uniqueMethodWithFinalName("query"),
+ inspector.clazz(TemporalAccessorImpl.class).uniqueMethodWithFinalName("query"),
CodeMatchers.invokesMethod(
null, "j$.time.temporal.TemporalAccessor$-CC", "$default$query", null));
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LinkedHashSetTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LinkedHashSetTest.java
index 981edea..de87214 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LinkedHashSetTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LinkedHashSetTest.java
@@ -11,6 +11,7 @@
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
+import java.util.function.Predicate;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -165,6 +166,14 @@
System.out.println("true");
System.out.println(spliterator.hasCharacteristics(Spliterator.IMMUTABLE));
System.out.println("false");
+
+ spliterator = ((Set<String>) new CustomLinkedHashSetForceForwarding<String>()).spliterator();
+ System.out.println(spliterator.hasCharacteristics(Spliterator.DISTINCT));
+ System.out.println("true");
+ System.out.println(spliterator.hasCharacteristics(Spliterator.ORDERED));
+ System.out.println("true");
+ System.out.println(spliterator.hasCharacteristics(Spliterator.IMMUTABLE));
+ System.out.println("false");
}
}
@@ -198,4 +207,13 @@
return super.spliterator();
}
}
+
+ // The over method force the forwarding methods to be installed.
+ static class CustomLinkedHashSetForceForwarding<E> extends LinkedHashSet<E> {
+
+ @Override
+ public boolean removeIf(Predicate<? super E> filter) {
+ return super.removeIf(filter);
+ }
+ }
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java
index d5300ad..1208414 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java
@@ -118,8 +118,8 @@
L8.run(
L8Command.builder()
.addLibraryFiles(getLibraryFile())
+ .addLibraryFiles(ToolHelper.getDesugarJDKLibs())
.addProgramFiles(JDK_11_JAVA_BASE_EXTENSION_COMPILED_FILES)
- .addClasspathFiles(ToolHelper.getDesugarJDKLibs())
.addDesugaredLibraryConfiguration(
StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
.setMinApiLevel(AndroidApiLevel.B.getLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java
index abdf5c5..f3caf57 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java
@@ -99,13 +99,13 @@
}
private void configurationForProgramCompilation(InternalOptions options) {
- options.desugaredLibrarySpecification =
- desugaredLibrarySpecification(options, false, parameters);
+ setDesugaredLibrarySpecificationForTesting(
+ options, desugaredLibrarySpecification(options, false, parameters));
}
private void configurationForLibraryCompilation(InternalOptions options) {
- options.desugaredLibrarySpecification =
- desugaredLibrarySpecification(options, true, parameters);
+ setDesugaredLibrarySpecificationForTesting(
+ options, desugaredLibrarySpecification(options, true, parameters));
}
private Matcher<MethodSubject> invokesObjectsCompare(String holder) {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetAndBackportTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetAndBackportTest.java
index 359a18c..9b1804e 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetAndBackportTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetAndBackportTest.java
@@ -7,6 +7,7 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyRewritingFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyTopLevelFlags;
@@ -14,6 +15,7 @@
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import java.io.IOException;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -55,9 +57,15 @@
.putBackportCoreLibraryMember("java.lang.DesugarMath", "java.lang.Math")
.putRetargetCoreLibMember("java.util.Date#toInstant", "java.util.DesugarDate")
.build();
- options.desugaredLibrarySpecification =
- new LegacyDesugaredLibrarySpecification(
- LegacyTopLevelFlags.testing(), rewritingFlags, true, options.itemFactory);
+ try {
+ options.setDesugaredLibrarySpecificationForTesting(
+ new LegacyDesugaredLibrarySpecification(
+ LegacyTopLevelFlags.testing(), rewritingFlags, true),
+ ToolHelper.getDesugarJDKLibs(),
+ ToolHelper.getAndroidJar(AndroidApiLevel.R));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
@Test
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java
index 6bf49a0..e629c47 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java
@@ -5,13 +5,7 @@
package com.android.tools.r8.desugar.desugaredlibrary;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.HumanToMachineSpecificationConverter;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.LegacyToHumanSpecificationConverter;
import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.InternalOptions;
-import java.io.IOException;
import java.nio.file.Path;
import java.time.Instant;
import java.time.ZonedDateTime;
@@ -31,19 +25,15 @@
private final TestParameters parameters;
private final boolean shrinkDesugaredLibrary;
- private final boolean machineSpec;
@Parameters(name = "machine: {0}, {2}, shrink: {1}")
public static List<Object[]> data() {
return buildParameters(
BooleanUtils.values(),
- BooleanUtils.values(),
getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build());
}
- public RetargetOverrideTest(
- boolean machineSpec, boolean shrinkDesugaredLibrary, TestParameters parameters) {
- this.machineSpec = machineSpec;
+ public RetargetOverrideTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
this.parameters = parameters;
}
@@ -54,7 +44,6 @@
Path desugaredTwice =
testForD8(Backend.CF)
.addLibraryFiles(getLibraryFile())
- .addOptionsModification(this::setMachineSpec)
.addProgramFiles(
testForD8(Backend.CF)
.addLibraryFiles(getLibraryFile())
@@ -76,7 +65,6 @@
stdout =
testForD8(Backend.DEX)
.addProgramFiles(desugaredTwice)
- .addOptionsModification(this::setMachineSpec)
.setMinApi(parameters.getApiLevel())
.disableDesugaring()
.compile()
@@ -107,22 +95,6 @@
assertLines2By2Correct(stdout);
}
- private void setMachineSpec(InternalOptions opt) {
- if (!machineSpec) {
- return;
- }
- try {
- HumanDesugaredLibrarySpecification human =
- new LegacyToHumanSpecificationConverter()
- .convert(opt.desugaredLibrarySpecification, getLibraryFile(), opt);
- MachineDesugaredLibrarySpecification machine =
- new HumanToMachineSpecificationConverter().convert(human, getLibraryFile(), opt);
- opt.testing.machineDesugaredLibrarySpecification = machine;
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
@Test
public void testRetargetOverrideD8() throws Exception {
Assume.assumeTrue(parameters.getRuntime().isDex());
@@ -130,7 +102,6 @@
String stdout =
testForD8()
.addLibraryFiles(getLibraryFile())
- .addOptionsModification(this::setMachineSpec)
.addInnerClasses(RetargetOverrideTest.class)
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.setMinApi(parameters.getApiLevel())
@@ -156,7 +127,6 @@
String stdout =
testForR8(Backend.DEX)
.addLibraryFiles(getLibraryFile())
- .addOptionsModification(this::setMachineSpec)
.addKeepMainRule(Executor.class)
.addInnerClasses(RetargetOverrideTest.class)
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionFinalClassTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionFinalClassTest.java
index f9d1828..7abed46 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionFinalClassTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/APIConversionFinalClassTest.java
@@ -58,6 +58,7 @@
.setMinApi(AndroidApiLevel.B)
.addProgramClasses(Executor.class)
.addLibraryClasses(CustomLibClass.class)
+ .addLibraryFiles(getLibraryFile())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.compile()
.addDesugaredCoreLibraryRunClassPath(
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AccessModeConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AccessModeConversionTest.java
index 6691cb1..a57140b 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AccessModeConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/AccessModeConversionTest.java
@@ -66,8 +66,8 @@
.build();
LegacyDesugaredLibrarySpecification specification =
new LegacyDesugaredLibrarySpecification(
- LegacyTopLevelFlags.testing(), rewritingFlags, l8Compilation, options.itemFactory);
- options.desugaredLibrarySpecification = specification;
+ LegacyTopLevelFlags.testing(), rewritingFlags, l8Compilation);
+ setDesugaredLibrarySpecificationForTesting(options, specification);
}
@Test
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
index aa97e55..957515a 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
@@ -87,9 +87,10 @@
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.addOptionsModification(
opt ->
- opt.desugaredLibrarySpecification =
+ setDesugaredLibrarySpecificationForTesting(
+ opt,
configurationWithSupportAllCallbacksFromLibrary(
- opt, false, parameters, supportAllCallbacksFromLibrary))
+ opt, false, parameters, supportAllCallbacksFromLibrary)))
.compile()
.inspect(this::assertDoubleForEach)
.inspect(this::assertWrapperMethodsPresent)
@@ -151,9 +152,10 @@
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.addOptionsModification(
opt ->
- opt.desugaredLibrarySpecification =
+ setDesugaredLibrarySpecificationForTesting(
+ opt,
configurationWithSupportAllCallbacksFromLibrary(
- opt, false, parameters, supportAllCallbacksFromLibrary))
+ opt, false, parameters, supportAllCallbacksFromLibrary)))
.compile()
.inspect(this::assertDoubleForEach)
.inspect(this::assertWrapperMethodsPresent)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIDesugaredLibTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIDesugaredLibTest.java
index 6b7d86e..b966b00 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIDesugaredLibTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIDesugaredLibTest.java
@@ -71,9 +71,10 @@
this.buildDesugaredLibrary(
api,
opt ->
- opt.desugaredLibrarySpecification =
+ setDesugaredLibrarySpecificationForTesting(
+ opt,
configurationWithSupportAllCallbacksFromLibrary(
- opt, true, parameters, supportAllCallbacksFromLibrary)));
+ opt, true, parameters, supportAllCallbacksFromLibrary))));
return desugaredLibBox.get();
},
AndroidApiLevel.B)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/TryCatchTimeConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/TryCatchTimeConversionTest.java
index a669527..aaab5cb 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/TryCatchTimeConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/TryCatchTimeConversionTest.java
@@ -58,6 +58,7 @@
.setMinApi(parameters.getApiLevel())
.addProgramClasses(BaselineExecutor.class)
.addLibraryClasses(CustomLibClass.class)
+ .addLibraryFiles(getLibraryFile())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.compile()
.addDesugaredCoreLibraryRunClassPath(
@@ -98,6 +99,7 @@
.setMinApi(parameters.getApiLevel())
.addProgramClasses(TryCatchExecutor.class)
.addLibraryClasses(CustomLibClass.class)
+ .addLibraryFiles(getLibraryFile())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.compile()
.addDesugaredCoreLibraryRunClassPath(
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11StreamTests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11StreamTests.java
index 2bd50b2..3b6ae0a 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11StreamTests.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11StreamTests.java
@@ -270,6 +270,7 @@
.addProgramFiles(testNGSupportProgramFiles())
.addOptionsModification(opt -> opt.testing.trackDesugaredAPIConversions = true)
.addLibraryFiles(getLibraryFile())
+ .addLibraryFiles(JDK_11_JAVA_BASE_EXTENSION_CLASSES_DIR)
.setMinApi(parameters.getApiLevel())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.allowStdoutMessages()
@@ -303,6 +304,7 @@
.addProgramFiles(testNGSupportProgramFiles())
.addOptionsModification(opt -> opt.testing.trackDesugaredAPIConversions = true)
.addLibraryFiles(getLibraryFile())
+ .addLibraryFiles(JDK_11_JAVA_BASE_EXTENSION_CLASSES_DIR)
.setMinApi(parameters.getApiLevel())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.compile()
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/ArgumentInfoCollectionTest.java b/src/test/java/com/android/tools/r8/enumunboxing/ArgumentInfoCollectionTest.java
index 2b5ccbd..faf304f 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/ArgumentInfoCollectionTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/ArgumentInfoCollectionTest.java
@@ -9,15 +9,30 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RewrittenTypeInfo;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
+import com.android.tools.r8.graph.proto.RemovedArgumentInfo;
+import com.android.tools.r8.graph.proto.RewrittenTypeInfo;
import com.android.tools.r8.ir.analysis.value.AbstractValueFactory;
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 ArgumentInfoCollectionTest extends TestBase {
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
@Test
public void testCombineRewritten() {
DexItemFactory factory = new DexItemFactory();
@@ -34,7 +49,7 @@
.setOldType(factory.intType)
.setNewType(factory.longType)
.build());
- ArgumentInfoCollection arguments1 = builder1.build();
+ ArgumentInfoCollection arguments1 = builder1.setArgumentInfosSize(5).build();
ArgumentInfoCollection.Builder builder2 = ArgumentInfoCollection.builder();
builder2.addArgumentInfo(
@@ -49,9 +64,10 @@
.setOldType(factory.floatType)
.setNewType(factory.doubleType)
.build());
- ArgumentInfoCollection arguments2 = builder2.build();
+ ArgumentInfoCollection arguments2 = builder2.setArgumentInfosSize(5).build();
ArgumentInfoCollection combine = arguments1.combine(arguments2);
+ assertEquals(5, combine.size());
RewrittenTypeInfo arg1 = combine.getArgumentInfo(1).asRewrittenTypeInfo();
assertEquals(arg1.getOldType(), factory.intType);
@@ -70,7 +86,6 @@
@Test
public void testCombineRemoved() {
DexItemFactory factory = new DexItemFactory();
- AbstractValueFactory abstractValueFactory = new AbstractValueFactory();
// Arguments removed: 0 1 2 3 4 -> 0 2 4.
ArgumentInfoCollection.Builder builder1 = ArgumentInfoCollection.builder();
@@ -78,34 +93,33 @@
1,
RemovedArgumentInfo.builder()
.setType(factory.intType)
- .setSingleValue(abstractValueFactory.createNullValue())
.build());
builder1.addArgumentInfo(
3,
RemovedArgumentInfo.builder()
.setType(factory.intType)
- .setSingleValue(abstractValueFactory.createNullValue())
.build());
- ArgumentInfoCollection arguments1 = builder1.build();
+ ArgumentInfoCollection arguments1 = builder1.setArgumentInfosSize(5).build();
// Arguments removed: 0 2 4 -> 0. Arguments 2 and 4 are at position 1 and 2 after first removal.
ArgumentInfoCollection.Builder builder2 = ArgumentInfoCollection.builder();
builder2.addArgumentInfo(1, RemovedArgumentInfo.builder().setType(factory.doubleType).build());
builder2.addArgumentInfo(2, RemovedArgumentInfo.builder().setType(factory.doubleType).build());
- ArgumentInfoCollection arguments2 = builder2.build();
+ ArgumentInfoCollection arguments2 = builder2.setArgumentInfosSize(3).build();
// Arguments removed: 0 1 2 3 4 -> 0.
ArgumentInfoCollection combine = arguments1.combine(arguments2);
+ assertEquals(5, combine.size());
RemovedArgumentInfo arg1 = combine.getArgumentInfo(1).asRemovedArgumentInfo();
assertEquals(arg1.getType(), factory.intType);
- assertTrue(arg1.hasSingleValue());
+ assertFalse(arg1.hasSingleValue());
RemovedArgumentInfo arg2 = combine.getArgumentInfo(2).asRemovedArgumentInfo();
assertEquals(arg2.getType(), factory.doubleType);
assertFalse(arg2.hasSingleValue());
RemovedArgumentInfo arg3 = combine.getArgumentInfo(3).asRemovedArgumentInfo();
assertEquals(arg3.getType(), factory.intType);
- assertTrue(arg3.hasSingleValue());
+ assertFalse(arg3.hasSingleValue());
RemovedArgumentInfo arg4 = combine.getArgumentInfo(4).asRemovedArgumentInfo();
assertEquals(arg4.getType(), factory.doubleType);
assertFalse(arg4.hasSingleValue());
@@ -129,7 +143,7 @@
.setType(factory.intType)
.setSingleValue(abstractValueFactory.createNullValue())
.build());
- ArgumentInfoCollection arguments1 = builder1.build();
+ ArgumentInfoCollection arguments1 = builder1.setArgumentInfosSize(5).build();
ArgumentInfoCollection.Builder builder2 = ArgumentInfoCollection.builder();
builder2.addArgumentInfo(
@@ -144,9 +158,10 @@
.setOldType(factory.floatType)
.setNewType(factory.doubleType)
.build());
- ArgumentInfoCollection arguments2 = builder2.build();
+ ArgumentInfoCollection arguments2 = builder2.setArgumentInfosSize(3).build();
ArgumentInfoCollection combine = arguments1.combine(arguments2);
+ assertEquals(5, combine.size());
RemovedArgumentInfo arg1 = combine.getArgumentInfo(1).asRemovedArgumentInfo();
assertEquals(arg1.getType(), factory.intType);
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/NarrowingWithoutSubtypingTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/NarrowingWithoutSubtypingTest.java
index 403372c..b78279e 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/NarrowingWithoutSubtypingTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/NarrowingWithoutSubtypingTest.java
@@ -4,12 +4,6 @@
package com.android.tools.r8.ir.analysis.type;
-import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assert.assertThrows;
-
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.D8TestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.utils.BooleanUtils;
@@ -38,32 +32,17 @@
@Test
public void test() throws Exception {
- D8TestBuilder d8TestBuilder =
- testForD8()
- .addInnerClasses(NarrowingWithoutSubtypingTest.class)
- .addOptionsModification(
- options -> {
- options.testing.readInputStackMaps = readStackMap;
- options.testing.enableNarrowAndWideningingChecksInD8 = true;
- options.testing.noLocalsTableOnInput = true;
- })
- .setMinApi(parameters.getApiLevel());
- if (readStackMap) {
- d8TestBuilder
- .run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutputLines("Hello world!");
- } else {
- // TODO(b/169120386): We should not be narrowing in D8.
- assertThrows(
- CompilationFailedException.class,
- () -> {
- d8TestBuilder.compileWithExpectedDiagnostics(
- diagnostics ->
- diagnostics.assertAllErrorsMatch(
- diagnosticMessage(
- containsString("java.lang.AssertionError: During NARROWING"))));
- });
- }
+ testForD8()
+ .addInnerClasses(NarrowingWithoutSubtypingTest.class)
+ .addOptionsModification(
+ options -> {
+ options.testing.readInputStackMaps = readStackMap;
+ options.testing.enableNarrowAndWideningingChecksInD8 = true;
+ options.testing.noLocalsTableOnInput = true;
+ })
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello world!");
}
static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/AtomicReferenceArrayMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/AtomicReferenceArrayMethods.java
new file mode 100644
index 0000000..9e8522c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/AtomicReferenceArrayMethods.java
@@ -0,0 +1,20 @@
+// Copyright (c) 2022, 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 java.util.concurrent.atomic.AtomicReferenceArray;
+
+public final class AtomicReferenceArrayMethods {
+ // Workaround Android S issue with AtomicReferenceArray.compareAndSet (b/211646483).
+ public static boolean compareAndSet(
+ AtomicReferenceArray<Object> reference, int index, Object expect, Object update) {
+ do {
+ if (reference.compareAndSet(index, expect, update)) {
+ return true;
+ }
+ } while (reference.get(index) == expect);
+ return false;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/AtomicReferenceMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/AtomicReferenceMethods.java
new file mode 100644
index 0000000..e88ee96
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/AtomicReferenceMethods.java
@@ -0,0 +1,20 @@
+// Copyright (c) 2022, 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 java.util.concurrent.atomic.AtomicReference;
+
+public final class AtomicReferenceMethods {
+ // Workaround Android S issue with AtomicReference.compareAndSet (b/211646483).
+ public static boolean compareAndSet(
+ AtomicReference<Object> reference, Object expect, Object update) {
+ do {
+ if (reference.compareAndSet(expect, update)) {
+ return true;
+ }
+ } while (reference.get() == expect);
+ return false;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/GenerateBackportMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/GenerateBackportMethods.java
index c6e3eea..7ee6cfa 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/backports/GenerateBackportMethods.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/GenerateBackportMethods.java
@@ -34,7 +34,9 @@
factory.createType("Lcom/android/tools/r8/ir/desugar/backports/BackportedMethods;");
private final List<Class<?>> METHOD_TEMPLATE_CLASSES =
ImmutableList.of(
+ AtomicReferenceArrayMethods.class,
AtomicReferenceFieldUpdaterMethods.class,
+ AtomicReferenceMethods.class,
BooleanMethods.class,
ByteMethods.class,
CharSequenceMethods.class,
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/R8InliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/R8InliningTest.java
index bded17f..b7a3474 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/R8InliningTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/R8InliningTest.java
@@ -328,7 +328,7 @@
m =
clazz.method(
- "int",
+ allowAccessModification ? "void" : "int",
"notInlinable",
ImmutableList.of("inlining." + (allowAccessModification ? "B" : "A")));
assertCounters(INLINABLE, NEVER_INLINABLE, countInvokes(inspector, m));
@@ -344,12 +344,12 @@
m =
clazz.method(
- "int", "notInlinableOnThrow", ImmutableList.of("java.lang.IllegalArgumentException"));
+ "void", "notInlinableOnThrow", ImmutableList.of("java.lang.IllegalArgumentException"));
assertCounters(ALWAYS_INLINABLE, NEVER_INLINABLE, countInvokes(inspector, m));
m =
clazz.method(
- "int",
+ "void",
"notInlinableDueToMissingNpeBeforeThrow",
ImmutableList.of("java.lang.IllegalArgumentException"));
assertCounters(ALWAYS_INLINABLE, NEVER_INLINABLE * 2, countInvokes(inspector, m));
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
index ad9ca05..2254355 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
@@ -197,11 +197,9 @@
"STATIC: String TrivialTestClass.next()"),
references(clazz, "testSimpleWithGetter", "void"));
- // TODO(b/216254482): This can be optimized by pruning (always) simple caller inlined methods
- // after the primary optimization pass.
ClassSubject simpleWithGetter = inspector.clazz(SimpleWithGetter.class);
- assertEquals(1, instanceMethods(simpleWithGetter).size());
- assertThat(simpleWithGetter.clinit(), isPresent());
+ assertEquals(0, instanceMethods(simpleWithGetter).size());
+ assertThat(simpleWithGetter.clinit(), isAbsent());
assertEquals(
Lists.newArrayList(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InvokeStaticWithNullOutvalueTest.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InvokeStaticWithNullOutvalueTest.java
index 6750562..9dfcb42 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InvokeStaticWithNullOutvalueTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InvokeStaticWithNullOutvalueTest.java
@@ -8,6 +8,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.KeepUnusedReturnValue;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.NeverPropagateValue;
@@ -46,6 +47,7 @@
.addInnerClasses(InvokeStaticWithNullOutvalueTest.class)
.addKeepMainRule(MAIN)
.enableInliningAnnotations()
+ .enableKeepUnusedReturnValueAnnotations()
.enableMemberValuePropagationAnnotations()
.enableNeverClassInliningAnnotations()
.enableNoHorizontalClassMergingAnnotations()
@@ -85,6 +87,7 @@
@NoHorizontalClassMerging
static class Companion {
+ @KeepUnusedReturnValue
@NeverInline
@NeverPropagateValue
private static Object boo() {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java
index f8dd8d9..16c8f61 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java
@@ -45,7 +45,12 @@
"SubFactory.createVirtual() -> null",
"SubSubFactory.createVirtual() -> null");
- testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expected);
+ if (parameters.isCfRuntime()) {
+ testForJvm()
+ .addTestClasspath()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(expected);
+ }
CodeInspector inspector =
testForR8(parameters.getBackend())
@@ -55,8 +60,8 @@
.enableNoMethodStaticizingAnnotations()
.enableNoVerticalClassMergingAnnotations()
.enableNoHorizontalClassMergingAnnotations()
- .addKeepRules("-dontobfuscate")
.addOptionsModification(options -> options.enableClassInlining = false)
+ .noMinification()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(expected)
@@ -66,16 +71,16 @@
MethodSubject createStaticMethodSubject =
factoryClassSubject.uniqueMethodWithName("createStatic");
assertThat(createStaticMethodSubject, isPresent());
- assertTrue(createStaticMethodSubject.getMethod().getReference().proto.returnType.isVoidType());
+ assertTrue(createStaticMethodSubject.getMethod().getReturnType().isVoidType());
MethodSubject createVirtualMethodSubject =
factoryClassSubject.uniqueMethodWithName("createVirtual");
assertThat(createVirtualMethodSubject, isPresent());
- assertTrue(createVirtualMethodSubject.getMethod().getReference().proto.returnType.isVoidType());
+ assertTrue(createVirtualMethodSubject.getMethod().getReturnType().isVoidType());
createVirtualMethodSubject =
inspector.clazz(SubFactory.class).uniqueMethodWithName("createVirtual");
assertThat(createVirtualMethodSubject, isPresent());
- assertTrue(createVirtualMethodSubject.getMethod().getReference().proto.returnType.isVoidType());
+ assertTrue(createVirtualMethodSubject.getMethod().getReturnType().isVoidType());
ClassSubject subSubFactoryClassSubject = inspector.clazz(SubSubFactory.class);
assertThat(subSubFactoryClassSubject.method("void", "createVirtual"), isPresent());
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentRemovalWithOverridingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentRemovalWithOverridingTest.java
index 58b052c..44c15e6 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentRemovalWithOverridingTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentRemovalWithOverridingTest.java
@@ -83,7 +83,7 @@
@NeverInline
public String greeting(String used) {
- return used;
+ return System.currentTimeMillis() >= 0 ? used : null;
}
}
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java b/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java
index f3103f1..bf94752 100644
--- a/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java
+++ b/src/test/java/com/android/tools/r8/memberrebinding/b135627418/B135627418.java
@@ -12,10 +12,13 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
import com.android.tools.r8.memberrebinding.b135627418.library.Drawable;
import com.android.tools.r8.memberrebinding.b135627418.library.DrawableWrapper;
import com.android.tools.r8.memberrebinding.b135627418.library.InsetDrawable;
+import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
@@ -75,11 +78,27 @@
com.android.tools.r8.memberrebinding.b135627418.runtime.InsetDrawable.class)
.setMinApi(parameters.getRuntime())
.addOptionsModification(
- options ->
- options.desugaredLibrarySpecification =
- LegacyDesugaredLibrarySpecification.withOnlyRewritePrefixForTesting(
- ImmutableMap.of(packageName + ".runtime", packageName + ".library"),
- options))
+ options -> {
+ options.desugaredLibrarySpecification =
+ LegacyDesugaredLibrarySpecification.withOnlyRewritePrefixForTesting(
+ ImmutableMap.of(packageName + ".runtime", packageName + ".library"),
+ options);
+ DexType type =
+ options
+ .dexItemFactory()
+ .createType(
+ DescriptorUtils.javaTypeToDescriptor(
+ packageName + ".runtime.InsetDrawable"));
+ DexType rewrittenType =
+ options
+ .dexItemFactory()
+ .createType(
+ DescriptorUtils.javaTypeToDescriptor(
+ packageName + ".library.InsetDrawable"));
+ options.machineDesugaredLibrarySpecification =
+ MachineDesugaredLibrarySpecification.withOnlyRewriteTypeForTesting(
+ ImmutableMap.of(type, rewrittenType));
+ })
.compile();
testForR8(parameters.getBackend())
diff --git a/src/test/java/com/android/tools/r8/naming/b124357885/B124357885Test.java b/src/test/java/com/android/tools/r8/naming/b124357885/B124357885Test.java
index a3ae2e9..7bf4064 100644
--- a/src/test/java/com/android/tools/r8/naming/b124357885/B124357885Test.java
+++ b/src/test/java/com/android/tools/r8/naming/b124357885/B124357885Test.java
@@ -11,6 +11,8 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
+import com.android.tools.r8.KeepUnusedReturnValue;
+import com.android.tools.r8.NeverInline;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -53,40 +55,53 @@
public void test() throws Exception {
R8TestCompileResult compileResult =
testForR8Compat(parameters.getBackend())
- .addProgramClasses(Main.class, Service.class, Foo.class, FooImpl.class)
+ .addProgramClasses(Main.class, Foo.class, FooImpl.class)
.addKeepMainRule(Main.class)
.addKeepAttributes(
ProguardKeepAttributes.SIGNATURE,
ProguardKeepAttributes.INNER_CLASSES,
ProguardKeepAttributes.ENCLOSING_METHOD)
+ .applyIf(
+ minification,
+ testBuilder ->
+ testBuilder.addKeepRules(
+ "-keep,allowoptimization,allowshrinking class "
+ + Main.class.getTypeName()
+ + " { *** test(); }"))
+ .enableInliningAnnotations()
+ .enableKeepUnusedReturnValueAnnotations()
.minification(minification)
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(
inspector -> {
- assertThat(inspector.clazz(Main.class), isPresentAndNotRenamed());
+ ClassSubject mainClass = inspector.clazz(Main.class);
+ assertThat(mainClass, isPresentAndNotRenamed());
assertThat(inspector.clazz(Foo.class), not(isPresent()));
assertThat(inspector.clazz(FooImpl.class), isPresentAndRenamed(minification));
- ClassSubject serviceClass = inspector.clazz(Service.class);
- assertThat(serviceClass, isPresentAndRenamed(minification));
- // TODO(124477502): Using uniqueMethodWithName("fooList") does not work.
- assertEquals(1, serviceClass.allMethods().size());
- MethodSubject fooList = serviceClass.allMethods().get(0);
- assertThat(fooList, isPresent());
+ // TODO(124477502): Using uniqueMethodWithName("test") does not work.
+ MethodSubject testMethod =
+ mainClass.uniqueMethodThatMatches(
+ method ->
+ method.isStatic()
+ && !method.getMethod().getName().toString().equals("main"));
+ assertThat(testMethod, isPresent());
checkSignature(
- inspector, fooList.asFoundMethodSubject().getFinalSignatureAttribute());
+ inspector, testMethod.asFoundMethodSubject().getFinalSignatureAttribute());
});
String fooImplFinalName = compileResult.inspector().clazz(FooImpl.class).getFinalName();
compileResult
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutput(StringUtils.lines(fooImplFinalName, fooImplFinalName));
+ .assertSuccessWithOutput(
+ StringUtils.lines(fooImplFinalName, fooImplFinalName, "Hello world!"));
}
public static class Main {
public static void main(String... args) throws Exception {
- Method method = Service.class.getMethod("fooList");
+ String methodName = System.currentTimeMillis() >= 0 ? "test" : null;
+ Method method = Main.class.getDeclaredMethod(methodName);
try {
ParameterizedType type = (ParameterizedType) method.getGenericReturnType();
@@ -99,11 +114,17 @@
// Convince R8 we only use subtypes to get class merging of Foo into FooImpl.
Foo<String> foo = new FooImpl<>();
System.out.println(foo.getClass().getCanonicalName());
- }
- }
- interface Service {
- Foo<String> fooList();
+ // Ensure test() remains in output.
+ test();
+ }
+
+ @NeverInline
+ @KeepUnusedReturnValue
+ static Foo<String> test() {
+ System.out.println("Hello world!");
+ return new FooImpl<>();
+ }
}
interface Foo<T> {}
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineeWithNoSuchMethodErrorTest.java b/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineeWithNoSuchMethodErrorTest.java
index 1c2f06d..f3718cd 100644
--- a/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineeWithNoSuchMethodErrorTest.java
+++ b/src/test/java/com/android/tools/r8/naming/retrace/RetraceInlineeWithNoSuchMethodErrorTest.java
@@ -7,6 +7,7 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
+import com.android.tools.r8.KeepUnusedReturnValue;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.R8TestRunResult;
@@ -78,6 +79,7 @@
.addKeepAttributeSourceFile()
.setMinApi(parameters.getApiLevel())
.enableInliningAnnotations()
+ .enableKeepUnusedReturnValueAnnotations()
.enableExperimentalMapFileVersion();
R8TestRunResult runResult;
if (throwReceiverNpe) {
@@ -112,6 +114,7 @@
throw new RuntimeException("Will be removed");
}
+ @KeepUnusedReturnValue
Object inlinable() {
return foo();
}
diff --git a/src/test/java/com/android/tools/r8/naming/retraceproguard/VerticalClassMergingRetraceTest.java b/src/test/java/com/android/tools/r8/naming/retraceproguard/VerticalClassMergingRetraceTest.java
index bb37a8a..5403673 100644
--- a/src/test/java/com/android/tools/r8/naming/retraceproguard/VerticalClassMergingRetraceTest.java
+++ b/src/test/java/com/android/tools/r8/naming/retraceproguard/VerticalClassMergingRetraceTest.java
@@ -25,8 +25,6 @@
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -34,7 +32,6 @@
@RunWith(Parameterized.class)
public class VerticalClassMergingRetraceTest extends RetraceTestBase {
- private Set<StackTraceLine> haveSeenLines = new HashSet<>();
@Parameters(name = "{0}, mode: {1}, compat: {2}")
public static Collection<Object[]> data() {
@@ -136,7 +133,6 @@
public void testNoLineNumberTable() throws Exception {
assumeTrue(compat);
assumeTrue(parameters.isDexRuntime());
- haveSeenLines.clear();
Box<MethodSubject> syntheticMethod = new Box<>();
runTest(
ImmutableList.of(),
@@ -171,8 +167,11 @@
// Will be merged down, and represented as:
// java.lang.String ...ResourceWrapper.foo() -> a
@NeverInline
- String foo() {
- throw null;
+ String foo(boolean doThrow) {
+ if (doThrow) {
+ throw null;
+ }
+ return System.currentTimeMillis() > 0 ? "arg" : null;
}
}
@@ -181,6 +180,7 @@
class MainApp {
public static void main(String[] args) {
TintResources t = new TintResources();
- System.out.println(t.foo());
+ boolean doThrow = System.currentTimeMillis() > 0;
+ System.out.println(t.foo(doThrow));
}
}
diff --git a/src/test/java/com/android/tools/r8/neverreturnsnormally/NeverReturnsNormallyTest.java b/src/test/java/com/android/tools/r8/neverreturnsnormally/NeverReturnsNormallyTest.java
index aedd6a4..173990f 100644
--- a/src/test/java/com/android/tools/r8/neverreturnsnormally/NeverReturnsNormallyTest.java
+++ b/src/test/java/com/android/tools/r8/neverreturnsnormally/NeverReturnsNormallyTest.java
@@ -13,7 +13,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.BooleanUtils;
@@ -201,11 +200,7 @@
insn instanceof DexInstructionSubject && ((DexInstructionSubject) insn).isConst4());
} else {
assertTrue(insn instanceof CfInstructionSubject);
- assertTrue(((CfInstructionSubject) insn).isStackInstruction(Opcode.Pop));
- assertTrue(instructions.hasNext());
- insn = instructions.next();
- assertTrue(insn instanceof CfInstructionSubject);
- assertTrue(((CfInstructionSubject) insn).isConstNull());
+ assertTrue(insn.isConstNull());
}
assertTrue(nextInstruction(instructions).isThrow());
assertFalse(instructions.hasNext());
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MonomorphicMethodWithUnusedReturnValueTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MonomorphicMethodWithUnusedReturnValueTest.java
new file mode 100644
index 0000000..d7130ef
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/MonomorphicMethodWithUnusedReturnValueTest.java
@@ -0,0 +1,73 @@
+// Copyright (c) 2022, 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.optimize.argumentpropagation;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+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 MonomorphicMethodWithUnusedReturnValueTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .enableInliningAnnotations()
+ // TODO(b/173398086): uniqueMethodWithName() does not work with proto changes.
+ .noMinification()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(
+ inspector -> {
+ // The test() method has been changed to have return type void.
+ MethodSubject testMethodSubject =
+ inspector.clazz(Main.class).uniqueMethodWithName("test");
+ assertThat(testMethodSubject, isPresent());
+ assertTrue(testMethodSubject.getProgramMethod().getReturnType().isVoidType());
+
+ // The class ReturnType has been removed by tree shaking.
+ assertThat(inspector.clazz(ReturnType.class), isAbsent());
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("create()");
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ test();
+ }
+
+ @NeverInline
+ static ReturnType test() {
+ System.out.println("create()");
+ return new ReturnType();
+ }
+ }
+
+ static class ReturnType {}
+}
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/PolymorphicMethodWithUnusedReturnValueTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/PolymorphicMethodWithUnusedReturnValueTest.java
new file mode 100644
index 0000000..e8007c3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/PolymorphicMethodWithUnusedReturnValueTest.java
@@ -0,0 +1,91 @@
+// Copyright (c) 2022, 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.optimize.argumentpropagation;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.NoHorizontalClassMerging;
+import com.android.tools.r8.NoVerticalClassMerging;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+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 PolymorphicMethodWithUnusedReturnValueTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .enableNoHorizontalClassMergingAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
+ // TODO(b/173398086): uniqueMethodWithName() does not work with proto changes.
+ .noMinification()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(
+ inspector -> {
+ // The test() methods have been changed to have return type void.
+ for (Class<?> clazz : new Class<?>[] {A.class, B.class}) {
+ MethodSubject testMethodSubject = inspector.clazz(clazz).uniqueMethodWithName("m");
+ assertThat(testMethodSubject, isPresent());
+ assertTrue(testMethodSubject.getProgramMethod().getReturnType().isVoidType());
+ }
+
+ // The class ReturnType has been removed by tree shaking.
+ assertThat(inspector.clazz(ReturnType.class), isAbsent());
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("A.m()");
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ A a = System.currentTimeMillis() >= 0 ? new A() : new B();
+ a.m();
+ }
+ }
+
+ @NoHorizontalClassMerging
+ @NoVerticalClassMerging
+ static class A {
+
+ ReturnType m() {
+ System.out.println("A.m()");
+ return new ReturnType();
+ }
+ }
+
+ static class B extends A {
+
+ @Override
+ ReturnType m() {
+ System.out.println("B.m()");
+ return new ReturnType();
+ }
+ }
+
+ @NoHorizontalClassMerging
+ static class ReturnType {}
+}
diff --git a/src/test/java/com/android/tools/r8/optimize/proto/NormalizeTest.java b/src/test/java/com/android/tools/r8/optimize/proto/NormalizeTest.java
new file mode 100644
index 0000000..c78ced4
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/optimize/proto/NormalizeTest.java
@@ -0,0 +1,106 @@
+// Copyright (c) 2022, 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.optimize.proto;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoHorizontalClassMerging;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+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 NormalizeTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addOptionsModification(
+ options -> options.testing.enableExperimentalProtoNormalization = true)
+ .enableInliningAnnotations()
+ .enableNoHorizontalClassMergingAnnotations()
+ // TODO(b/173398086): uniqueMethodWithName() does not work with proto changes.
+ .noMinification()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(
+ inspector -> {
+ ClassSubject aClassSubject = inspector.clazz(A.class);
+ assertThat(aClassSubject, isPresent());
+
+ ClassSubject bClassSubject = inspector.clazz(B.class);
+ assertThat(bClassSubject, isPresent());
+
+ MethodSubject fooMethodSubject =
+ inspector.clazz(Main.class).uniqueMethodWithName("foo");
+ assertThat(fooMethodSubject, isPresent());
+
+ String expectedMethodSignature =
+ "void "
+ + fooMethodSubject.getFinalName()
+ + "("
+ + aClassSubject.getFinalName()
+ + ", "
+ + bClassSubject.getFinalName()
+ + ")";
+ assertEquals(
+ expectedMethodSignature,
+ fooMethodSubject.getProgramMethod().getMethodSignature().toString());
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("A", "B");
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ foo(new B(), new A());
+ }
+
+ @NeverInline
+ static void foo(B b, A a) {
+ System.out.println(a);
+ System.out.println(b);
+ }
+ }
+
+ @NoHorizontalClassMerging
+ static class A {
+
+ @Override
+ public String toString() {
+ return "A";
+ }
+ }
+
+ @NoHorizontalClassMerging
+ static class B {
+
+ @Override
+ public String toString() {
+ return "B";
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java
index 3803d1a..898cfae 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialInterfaceMethodAccessTest.java
@@ -224,8 +224,8 @@
static class A implements I {
public void foo() {
// Rewritten to invoke-special A.bar or I.bar which resolves to private method A.bar
- // When targeting B.bar => throws NoSuchMethodError.
- // When targeting A.bar:
+ // When targeting A.bar => throws NoSuchMethodError.
+ // When targeting I.bar:
// - in same nest => success.
// - not in nest => throws IllegalAccessError.
bar();
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerAssertionInClinitOnlyTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerAssertionInClinitOnlyTest.java
new file mode 100644
index 0000000..314d180
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerAssertionInClinitOnlyTest.java
@@ -0,0 +1,38 @@
+// Copyright (c) 2022, 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.rewrite.assertions;
+
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.rewrite.assertions.assertionhandler.AssertionHandlers;
+import com.android.tools.r8.rewrite.assertions.assertionhandler.AssertionsInClinit;
+import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class AssertionConfigurationAssertionHandlerAssertionInClinitOnlyTest
+ extends AssertionConfigurationAssertionHandlerTestBase {
+
+ private static final String EXPECTED_OUTPUT = StringUtils.lines("assertionHandler: <clinit>");
+
+ @Override
+ String getExpectedOutput() {
+ return EXPECTED_OUTPUT;
+ }
+
+ @Override
+ MethodReference getAssertionHandler() throws Exception {
+ return Reference.methodFromMethod(
+ AssertionHandlers.class.getMethod("assertionHandler", Throwable.class));
+ }
+
+ @Override
+ List<Class<?>> getTestClasses() {
+ return ImmutableList.of(AssertionsInClinit.class);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerKotlinTestBase.java b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerKotlinTestBase.java
new file mode 100644
index 0000000..84bd1ef
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerKotlinTestBase.java
@@ -0,0 +1,153 @@
+// Copyright (c) 2022, 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.rewrite.assertions;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.KotlinTestBase;
+import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.TestCompilerBuilder;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.rewrite.assertions.assertionhandler.AssertionHandlers;
+import com.android.tools.r8.utils.BooleanUtils;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public abstract class AssertionConfigurationAssertionHandlerKotlinTestBase extends KotlinTestBase {
+
+ @Parameterized.Parameters(name = "{0}, {1}, kotlin-stdlib as library: {2}, -Xassertions=jvm: {3}")
+ public static Collection<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimesAndApiLevels().build(),
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
+ BooleanUtils.values(),
+ BooleanUtils.values());
+ }
+
+ protected final TestParameters parameters;
+ protected final boolean kotlinStdlibAsLibrary;
+ protected final boolean useJvmAssertions;
+ protected final KotlinCompileMemoizer compiledForAssertions;
+
+ public AssertionConfigurationAssertionHandlerKotlinTestBase(
+ TestParameters parameters,
+ KotlinTestParameters kotlinParameters,
+ boolean kotlinStdlibAsClasspath,
+ boolean useJvmAssertions)
+ throws IOException {
+ super(kotlinParameters);
+ this.parameters = parameters;
+ this.kotlinStdlibAsLibrary = kotlinStdlibAsClasspath;
+ this.useJvmAssertions = useJvmAssertions;
+ this.compiledForAssertions =
+ useJvmAssertions ? kotlinWithJvmAssertions() : kotlinWithoutJvmAssertions();
+ }
+
+ private KotlinCompileMemoizer kotlinWithJvmAssertions() throws IOException {
+ return getCompileMemoizer(getKotlinFiles())
+ .configure(kotlinCompilerTool -> kotlinCompilerTool.setUseJvmAssertions(true));
+ }
+
+ private KotlinCompileMemoizer kotlinWithoutJvmAssertions() throws IOException {
+ return getCompileMemoizer(getKotlinFiles())
+ .configure(kotlinCompilerTool -> kotlinCompilerTool.setUseJvmAssertions(false));
+ }
+
+ protected abstract String getExpectedOutput();
+
+ protected abstract MethodReference getAssertionHandler() throws Exception;
+
+ protected abstract List<Path> getKotlinFiles() throws IOException;
+
+ protected abstract String getTestClassName();
+
+ protected void configureR8(R8FullTestBuilder builder) {}
+
+ private Path kotlinStdlibLibraryForRuntime() throws Exception {
+ Path kotlinStdlibCf = kotlinc.getKotlinStdlibJar();
+ if (parameters.getRuntime().isCf()) {
+ return kotlinStdlibCf;
+ }
+
+ Path kotlinStdlibDex = temp.newFolder().toPath().resolve("kotlin-stdlib-dex.jar");
+ testForD8()
+ .addProgramFiles(kotlinStdlibCf)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .writeToZip(kotlinStdlibDex);
+ return kotlinStdlibDex;
+ }
+
+ private MethodReference getAssertionHandlerIgnoreException() {
+ try {
+ return getAssertionHandler();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ private void configureKotlinStdlib(TestCompilerBuilder<?, ?, ?, ?, ?> builder) throws Exception {
+ if (kotlinStdlibAsLibrary) {
+ builder
+ .addClasspathFiles(kotlinc.getKotlinStdlibJar())
+ .addRunClasspathFiles(kotlinStdlibLibraryForRuntime());
+ } else {
+ builder.addProgramFiles(kotlinc.getKotlinStdlibJar());
+ }
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ assumeTrue(parameters.isDexRuntime());
+ testForD8()
+ .apply(this::configureKotlinStdlib)
+ .setMinApi(parameters.getApiLevel())
+ .addProgramClasses(AssertionHandlers.class)
+ .addProgramFiles(compiledForAssertions.getForConfiguration(kotlinc, targetVersion))
+ .addAssertionsConfiguration(
+ builder ->
+ builder
+ .setAssertionHandler(getAssertionHandlerIgnoreException())
+ .setScopeAll()
+ .build())
+ .run(parameters.getRuntime(), getTestClassName())
+ .assertSuccessWithOutput(getExpectedOutput());
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .apply(this::configureKotlinStdlib)
+ .setMinApi(parameters.getApiLevel())
+ .addProgramClasses(AssertionHandlers.class)
+ .addProgramFiles(compiledForAssertions.getForConfiguration(kotlinc, targetVersion))
+ .addAssertionsConfiguration(
+ builder ->
+ builder
+ .setAssertionHandler(getAssertionHandlerIgnoreException())
+ .setScopeAll()
+ .build())
+ .addKeepMainRule(getTestClassName())
+ .apply(this::configureR8)
+ .allowDiagnosticWarningMessages(!kotlinStdlibAsLibrary)
+ .compile()
+ .applyIf(
+ !kotlinStdlibAsLibrary,
+ result ->
+ result.assertAllWarningMessagesMatch(
+ equalTo("Resource 'META-INF/MANIFEST.MF' already exists.")))
+ .run(parameters.getRuntime(), getTestClassName())
+ .assertSuccessWithOutput(getExpectedOutput());
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerRethrowingTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerRethrowingTest.java
new file mode 100644
index 0000000..c1172d8
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerRethrowingTest.java
@@ -0,0 +1,48 @@
+// Copyright (c) 2022, 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.rewrite.assertions;
+
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.rewrite.assertions.assertionhandler.AssertionHandlers;
+import com.android.tools.r8.rewrite.assertions.assertionhandler.AssertionsWithExceptionHandlers;
+import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class AssertionConfigurationAssertionHandlerRethrowingTest
+ extends AssertionConfigurationAssertionHandlerTestBase {
+
+ private static final String EXPECTED_OUTPUT =
+ StringUtils.lines(
+ "assertionHandlerRethrowing: First assertion",
+ "assertionHandlerRethrowing: Second assertion",
+ "Caught: Second assertion",
+ "assertionHandlerRethrowing: Third assertion",
+ "Caught: Third assertion",
+ "assertionHandlerRethrowing: Fourth assertion",
+ "Caught from: assertionsWithCatch3",
+ "assertionHandlerRethrowing: Fifth assertion",
+ "Caught from: simpleAssertion");
+
+ @Override
+ String getExpectedOutput() {
+ return EXPECTED_OUTPUT;
+ }
+
+ @Override
+ MethodReference getAssertionHandler() throws Exception {
+ return Reference.methodFromMethod(
+ AssertionHandlers.class.getMethod("assertionHandlerRethrowing", Throwable.class));
+ }
+
+ @Override
+ List<Class<?>> getTestClasses() {
+ return ImmutableList.of(AssertionsWithExceptionHandlers.class);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerSimpleTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerSimpleTest.java
new file mode 100644
index 0000000..43e0a7e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerSimpleTest.java
@@ -0,0 +1,42 @@
+// Copyright (c) 2022, 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.rewrite.assertions;
+
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.rewrite.assertions.assertionhandler.AssertionHandlers;
+import com.android.tools.r8.rewrite.assertions.assertionhandler.AssertionsSimple;
+import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class AssertionConfigurationAssertionHandlerSimpleTest
+ extends AssertionConfigurationAssertionHandlerTestBase {
+
+ private static final String EXPECTED_OUTPUT =
+ StringUtils.lines(
+ "assertionHandler: simpleAssertion",
+ "assertionHandler: multipleAssertions",
+ "assertionHandler: multipleAssertions");
+
+ @Override
+ String getExpectedOutput() {
+ return EXPECTED_OUTPUT;
+ }
+
+ @Override
+ MethodReference getAssertionHandler() throws Exception {
+ return Reference.methodFromMethod(
+ AssertionHandlers.class.getMethod("assertionHandler", Throwable.class));
+ }
+
+ @Override
+ List<Class<?>> getTestClasses() {
+ return ImmutableList.of(AssertionsSimple.class);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerTestBase.java b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerTestBase.java
new file mode 100644
index 0000000..fa4de84
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerTestBase.java
@@ -0,0 +1,81 @@
+// Copyright (c) 2022, 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.rewrite.assertions;
+
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.rewrite.assertions.assertionhandler.AssertionHandlers;
+import java.util.List;
+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 abstract class AssertionConfigurationAssertionHandlerTestBase extends TestBase {
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build());
+ }
+
+ abstract String getExpectedOutput();
+
+ abstract MethodReference getAssertionHandler() throws Exception;
+
+ abstract List<Class<?>> getTestClasses();
+
+ private MethodReference getAssertionHandlerIgnoreException() {
+ try {
+ return getAssertionHandler();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ assumeTrue(parameters.isDexRuntime());
+ testForD8(parameters.getBackend())
+ .addProgramClasses(AssertionHandlers.class)
+ .addProgramClasses(getTestClasses())
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(o -> o.testing.forceIRForCfToCfDesugar = true)
+ .addAssertionsConfiguration(
+ builder ->
+ builder
+ .setAssertionHandler(getAssertionHandlerIgnoreException())
+ .setScopeAll()
+ .build())
+ .run(parameters.getRuntime(), getTestClasses().get(0))
+ .assertSuccessWithOutput(getExpectedOutput());
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(AssertionHandlers.class)
+ .addProgramClasses(getTestClasses())
+ .addKeepMainRule(getTestClasses().get(0))
+ .addKeepAnnotation()
+ .addKeepRules("-keep class * { @com.android.tools.r8.Keep *; }")
+ .setMinApi(parameters.getApiLevel())
+ .addAssertionsConfiguration(
+ builder ->
+ builder
+ .setAssertionHandler(getAssertionHandlerIgnoreException())
+ .setScopeAll()
+ .build())
+ .run(parameters.getRuntime(), getTestClasses().get(0))
+ .assertSuccessWithOutput(getExpectedOutput());
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerWithExceptionHandlersTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerWithExceptionHandlersTest.java
new file mode 100644
index 0000000..94f47bc
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationAssertionHandlerWithExceptionHandlersTest.java
@@ -0,0 +1,42 @@
+// Copyright (c) 2022, 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.rewrite.assertions;
+
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.rewrite.assertions.assertionhandler.AssertionHandlers;
+import com.android.tools.r8.rewrite.assertions.assertionhandler.AssertionsWithExceptionHandlers;
+import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class AssertionConfigurationAssertionHandlerWithExceptionHandlersTest
+ extends AssertionConfigurationAssertionHandlerTestBase {
+
+ private static final String EXPECTED_OUTPUT =
+ StringUtils.lines(
+ "assertionHandler: First assertion",
+ "assertionHandler: Second assertion",
+ "assertionHandler: Fourth assertion");
+
+ @Override
+ String getExpectedOutput() {
+ return EXPECTED_OUTPUT;
+ }
+
+ @Override
+ MethodReference getAssertionHandler() throws Exception {
+ return Reference.methodFromMethod(
+ AssertionHandlers.class.getMethod("assertionHandler", Throwable.class));
+ }
+
+ @Override
+ List<Class<?>> getTestClasses() {
+ return ImmutableList.of(AssertionsWithExceptionHandlers.class);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/assertionhandler/AssertionHandlers.java b/src/test/java/com/android/tools/r8/rewrite/assertions/assertionhandler/AssertionHandlers.java
new file mode 100644
index 0000000..bbf856d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/assertionhandler/AssertionHandlers.java
@@ -0,0 +1,28 @@
+// Copyright (c) 2022, 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.rewrite.assertions.assertionhandler;
+
+public class AssertionHandlers {
+ static String methodWithAssertionError(Throwable assertion) {
+ return assertion.getStackTrace()[0].getMethodName();
+ }
+
+ public static void assertionHandler(Throwable assertion) {
+ System.out.println(
+ "assertionHandler: "
+ + (assertion.getMessage() != null
+ ? assertion.getMessage()
+ : methodWithAssertionError(assertion)));
+ }
+
+ public static void assertionHandlerRethrowing(Throwable assertion) throws Throwable {
+ System.out.println(
+ "assertionHandlerRethrowing: "
+ + (assertion.getMessage() != null
+ ? assertion.getMessage()
+ : methodWithAssertionError(assertion)));
+ throw assertion;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/assertionhandler/AssertionsInClinit.java b/src/test/java/com/android/tools/r8/rewrite/assertions/assertionhandler/AssertionsInClinit.java
new file mode 100644
index 0000000..d077af1
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/assertionhandler/AssertionsInClinit.java
@@ -0,0 +1,14 @@
+// Copyright (c) 2022, 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.rewrite.assertions.assertionhandler;
+
+public class AssertionsInClinit {
+
+ static {
+ assert false;
+ }
+
+ public static void main(String[] args) {}
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/assertionhandler/AssertionsSimple.java b/src/test/java/com/android/tools/r8/rewrite/assertions/assertionhandler/AssertionsSimple.java
new file mode 100644
index 0000000..cb6300d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/assertionhandler/AssertionsSimple.java
@@ -0,0 +1,26 @@
+// Copyright (c) 2022, 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.rewrite.assertions.assertionhandler;
+
+import com.android.tools.r8.Keep;
+
+public class AssertionsSimple {
+
+ @Keep
+ public static void simpleAssertion() {
+ assert false;
+ }
+
+ @Keep
+ public static void multipleAssertions() {
+ assert false;
+ assert false;
+ }
+
+ public static void main(String[] args) {
+ simpleAssertion();
+ multipleAssertions();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/assertionhandler/AssertionsWithExceptionHandlers.java b/src/test/java/com/android/tools/r8/rewrite/assertions/assertionhandler/AssertionsWithExceptionHandlers.java
new file mode 100644
index 0000000..e5bdad7
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/assertionhandler/AssertionsWithExceptionHandlers.java
@@ -0,0 +1,63 @@
+// Copyright (c) 2022, 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.rewrite.assertions.assertionhandler;
+
+import com.android.tools.r8.Keep;
+
+public class AssertionsWithExceptionHandlers {
+ @Keep
+ public static void assertionsWithCatch1() {
+ try {
+ assert false : "First assertion";
+ } catch (NoSuchMethodError | NoSuchFieldError e) {
+
+ } catch (NoClassDefFoundError e) {
+
+ }
+ }
+
+ @Keep
+ public static void assertionsWithCatch2() {
+ try {
+ assert false : "Second assertion";
+ } catch (AssertionError e) {
+ System.out.println("Caught: " + e.getMessage());
+ try {
+ assert false : "Third assertion";
+ } catch (AssertionError e2) {
+ System.out.println("Caught: " + e2.getMessage());
+ }
+ }
+ }
+
+ @Keep
+ private static void simpleAssertion() {
+ assert false : "Fifth assertion";
+ }
+
+ @Keep
+ public static void assertionsWithCatch3() {
+ try {
+ assert false : "Fourth assertion";
+ } catch (AssertionError e1) {
+ System.out.println("Caught from: " + AssertionHandlers.methodWithAssertionError(e1));
+ try {
+ simpleAssertion();
+ } catch (AssertionError e2) {
+ System.out.println("Caught from: " + AssertionHandlers.methodWithAssertionError(e2));
+ }
+ }
+ }
+
+ public static void main(String[] args) {
+ try {
+ assertionsWithCatch1();
+ } catch (AssertionError e) {
+ // Ignore.
+ }
+ assertionsWithCatch2();
+ assertionsWithCatch3();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlersimple/AssertionConfigurationAssertionHandlerKotlinSimpleTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlersimple/AssertionConfigurationAssertionHandlerKotlinSimpleTest.java
new file mode 100644
index 0000000..dc6353d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlersimple/AssertionConfigurationAssertionHandlerKotlinSimpleTest.java
@@ -0,0 +1,67 @@
+// Copyright (c) 2022, 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.rewrite.assertions.kotlinassertionhandlersimple;
+
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion;
+import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.rewrite.assertions.AssertionConfigurationAssertionHandlerKotlinTestBase;
+import com.android.tools.r8.rewrite.assertions.assertionhandler.AssertionHandlers;
+import com.android.tools.r8.utils.StringUtils;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class AssertionConfigurationAssertionHandlerKotlinSimpleTest
+ extends AssertionConfigurationAssertionHandlerKotlinTestBase {
+
+ public AssertionConfigurationAssertionHandlerKotlinSimpleTest(
+ TestParameters parameters,
+ KotlinTestParameters kotlinParameters,
+ boolean kotlinStdlibAsClasspath,
+ boolean useJvmAssertions)
+ throws IOException {
+ super(parameters, kotlinParameters, kotlinStdlibAsClasspath, useJvmAssertions);
+ }
+
+ @Override
+ protected String getExpectedOutput() {
+ return StringUtils.lines(
+ "assertionHandler: simpleAssertion",
+ "assertionHandler: multipleAssertions 1",
+ "assertionHandler: multipleAssertions 2");
+ }
+
+ @Override
+ protected MethodReference getAssertionHandler() throws Exception {
+ return Reference.methodFromMethod(
+ AssertionHandlers.class.getMethod("assertionHandler", Throwable.class));
+ }
+
+ @Override
+ protected List<Path> getKotlinFiles() throws IOException {
+ return getKotlinFilesInTestPackage(getClass().getPackage());
+ }
+
+ @Override
+ protected String getTestClassName() {
+ return getClass().getPackage().getName() + ".AssertionSimpleKt";
+ }
+
+ @Override
+ protected void configureR8(R8FullTestBuilder builder) {
+ builder.applyIf(
+ !kotlinStdlibAsLibrary
+ && !useJvmAssertions
+ && !kotlinParameters.is(KotlinCompilerVersion.KOTLINC_1_3_72),
+ b -> b.addDontWarn("org.jetbrains.annotations.NotNull"));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlersimple/AssertionSimple.kt b/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlersimple/AssertionSimple.kt
new file mode 100644
index 0000000..7f6066b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlersimple/AssertionSimple.kt
@@ -0,0 +1,15 @@
+package com.android.tools.r8.rewrite.assertions.kotlinassertionhandlersimple
+
+fun simpleAssertion() {
+ assert(false) { "simpleAssertion" }
+}
+
+fun multipleAssertions() {
+ assert(false) { "multipleAssertions 1" }
+ assert(false) { "multipleAssertions 2" }
+}
+
+fun main() {
+ simpleAssertion();
+ multipleAssertions();
+}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlerwithexceptions/AssertionConfigurationAssertionHandlerKotlinRethrowingTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlerwithexceptions/AssertionConfigurationAssertionHandlerKotlinRethrowingTest.java
new file mode 100644
index 0000000..93b3b57
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlerwithexceptions/AssertionConfigurationAssertionHandlerKotlinRethrowingTest.java
@@ -0,0 +1,71 @@
+// Copyright (c) 2022, 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.rewrite.assertions.kotlinassertionhandlerwithexceptions;
+
+import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.rewrite.assertions.AssertionConfigurationAssertionHandlerKotlinTestBase;
+import com.android.tools.r8.rewrite.assertions.assertionhandler.AssertionHandlers;
+import com.android.tools.r8.utils.StringUtils;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class AssertionConfigurationAssertionHandlerKotlinRethrowingTest
+ extends AssertionConfigurationAssertionHandlerKotlinTestBase {
+
+ public AssertionConfigurationAssertionHandlerKotlinRethrowingTest(
+ TestParameters parameters,
+ KotlinTestParameters kotlinParameters,
+ boolean kotlinStdlibAsClasspath,
+ boolean useJvmAssertions)
+ throws IOException {
+ super(parameters, kotlinParameters, kotlinStdlibAsClasspath, useJvmAssertions);
+ }
+
+ @Override
+ protected String getExpectedOutput() {
+ return StringUtils.lines(
+ "assertionHandlerRethrowing: First assertion",
+ "assertionHandlerRethrowing: Second assertion",
+ "Caught: Second assertion",
+ "assertionHandlerRethrowing: Third assertion",
+ "Caught: Third assertion",
+ "assertionHandlerRethrowing: Fourth assertion",
+ "Caught from: assertionsWithCatch3",
+ "assertionHandlerRethrowing: Fifth assertion",
+ "Caught from: simpleAssertion");
+ }
+
+ @Override
+ protected MethodReference getAssertionHandler() throws Exception {
+ return Reference.methodFromMethod(
+ AssertionHandlers.class.getMethod("assertionHandlerRethrowing", Throwable.class));
+ }
+
+ @Override
+ protected List<Path> getKotlinFiles() throws IOException {
+ return getKotlinFilesInTestPackage(getClass().getPackage());
+ }
+
+ @Override
+ protected String getTestClassName() {
+ return getClass().getPackage().getName() + ".AssertionsWithExceptionHandlersKt";
+ }
+
+ @Override
+ protected void configureR8(R8FullTestBuilder builder) {
+ builder
+ .addKeepRules("-keep class **.*Kt { assertionsWith*(); simpleAssertion(); }")
+ .addDontWarn("org.jetbrains.annotations.NotNull")
+ .applyIf(!kotlinStdlibAsLibrary, b -> b.addDontWarn("org.jetbrains.annotations.Nullable"));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlerwithexceptions/AssertionsWithExceptionHandlers.kt b/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlerwithexceptions/AssertionsWithExceptionHandlers.kt
new file mode 100644
index 0000000..dd70bc1
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/kotlinassertionhandlerwithexceptions/AssertionsWithExceptionHandlers.kt
@@ -0,0 +1,54 @@
+package com.android.tools.r8.rewrite.assertions.kotlinassertionhandlerwithexceptions
+
+fun methodWithAssertionError(assertion : Throwable) : String {
+ return assertion.getStackTrace()[0].getMethodName();
+}
+
+fun assertionsWithCatch1() {
+ try {
+ assert(false) { "First assertion" }
+ } catch (e : NoSuchMethodError) {
+ } catch (e: NoSuchFieldError) {
+ } catch (e : NoClassDefFoundError) {
+ }
+}
+
+fun assertionsWithCatch2() {
+ try {
+ assert(false) { "Second assertion" }
+ } catch (e : AssertionError) {
+ println("Caught: " + e.message)
+ try {
+ assert(false) { "Third assertion" }
+ } catch (e : AssertionError) {
+ println("Caught: " + e.message)
+ }
+ }
+}
+
+fun simpleAssertion() {
+ assert(false) { "Fifth assertion" }
+}
+
+fun assertionsWithCatch3() {
+ try {
+ assert(false) { "Fourth assertion" }
+ } catch (e1 : AssertionError) {
+ println("Caught from: " + methodWithAssertionError(e1));
+ try {
+ simpleAssertion();
+ } catch (e2 : AssertionError) {
+ println("Caught from: " + methodWithAssertionError(e2));
+ }
+ }
+}
+
+fun main() {
+ try {
+ assertionsWithCatch1();
+ } catch (e : AssertionError) {
+ // Ignore.
+ }
+ assertionsWithCatch2();
+ assertionsWithCatch3();
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/annotations/KeepDisallowAnnotationRemovalAllowOptimizationTest.java b/src/test/java/com/android/tools/r8/shaking/annotations/KeepDisallowAnnotationRemovalAllowOptimizationTest.java
index 8fa7bc1..62bcf76 100644
--- a/src/test/java/com/android/tools/r8/shaking/annotations/KeepDisallowAnnotationRemovalAllowOptimizationTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/annotations/KeepDisallowAnnotationRemovalAllowOptimizationTest.java
@@ -11,6 +11,7 @@
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
+import com.android.tools.r8.KeepUnusedReturnValue;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -53,6 +54,7 @@
// In compatibility mode the rule above is a no-op.
.allowUnusedProguardConfigurationRules(enableCompatibilityMode)
.enableInliningAnnotations()
+ .enableKeepUnusedReturnValueAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(
@@ -83,6 +85,7 @@
}
}
+ @KeepUnusedReturnValue
@NeverInline
static Object getNonNull() {
System.out.println("getNonNull()");
diff --git a/src/test/java/com/android/tools/r8/shaking/clinit/ClassInitInlineForGetterTest.java b/src/test/java/com/android/tools/r8/shaking/clinit/ClassInitInlineForGetterTest.java
index b1e3efd..be07a10 100644
--- a/src/test/java/com/android/tools/r8/shaking/clinit/ClassInitInlineForGetterTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/clinit/ClassInitInlineForGetterTest.java
@@ -19,7 +19,6 @@
public class ClassInitInlineForGetterTest extends TestBase {
private static final String EXPECTED = "Hello World";
- private static final String R8_RESULT = "Goodbye World";
@Parameter() public TestParameters parameters;
@@ -46,7 +45,7 @@
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines(R8_RESULT);
+ .assertSuccessWithOutputLines(EXPECTED);
}
@NeverClassInline
diff --git a/src/test/java/com/android/tools/r8/shaking/clinit/ClassInitInlineForStaticGetterInSuperTypeTest.java b/src/test/java/com/android/tools/r8/shaking/clinit/ClassInitInlineForStaticGetterInSuperTypeTest.java
new file mode 100644
index 0000000..7a4c15e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/clinit/ClassInitInlineForStaticGetterInSuperTypeTest.java
@@ -0,0 +1,87 @@
+// Copyright (c) 2022, 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.shaking.clinit;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+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 ClassInitInlineForStaticGetterInSuperTypeTest extends TestBase {
+
+ private static final String EXPECTED = "Hello World";
+ private static final String R8_EXPECTED = "Goodbye World";
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ @Test
+ public void testRuntime() throws Exception {
+ testForRuntime(parameters)
+ .addInnerClasses(getClass())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(EXPECTED);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .setMinApi(parameters.getApiLevel())
+ .addKeepMainRule(Main.class)
+ .addKeepRules("-keep class " + typeName(B.class) + " { <fields>; }")
+ .enableInliningAnnotations()
+ .run(parameters.getRuntime(), Main.class)
+ // TODO(b/215477768): Should be Hello World
+ .assertSuccessWithOutputLines(R8_EXPECTED);
+ }
+
+ public static class A {
+
+ public static boolean TEST = System.currentTimeMillis() == 0;
+
+ @NeverInline
+ public static boolean getTestStatic() {
+ return TEST;
+ }
+ }
+
+ public static class B extends A {
+
+ static {
+ B.TEST = true;
+ }
+
+ @NeverInline
+ public static void triggerClassAInit(boolean test) {
+ if (test) {
+ System.out.println("Hello World");
+ } else {
+ System.out.println("Goodbye World");
+ }
+ }
+
+ public static void inlinable() {
+ triggerClassAInit(B.getTestStatic());
+ }
+ }
+
+ public static class Main {
+
+ public static void main(String[] args) {
+ B.inlinable();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/reflection/ReflectiveNewInstanceTest.java b/src/test/java/com/android/tools/r8/shaking/reflection/ReflectiveNewInstanceTest.java
index 544a7ee..47a9fc7 100644
--- a/src/test/java/com/android/tools/r8/shaking/reflection/ReflectiveNewInstanceTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/reflection/ReflectiveNewInstanceTest.java
@@ -29,7 +29,7 @@
@Parameters(name = "{0}")
public static TestParametersCollection data() {
- return getTestParameters().withAllRuntimes().build();
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
}
public ReflectiveNewInstanceTest(TestParameters parameters) {
@@ -57,7 +57,7 @@
.addKeepMainRule(TestClass.class)
.enableGraphInspector()
.enableUnusedArgumentAnnotations()
- .setMinApi(parameters.getRuntime())
+ .setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(expectedOutputAfterR8)
.graphInspector();
diff --git a/third_party/android_jar/api-versions.tar.gz.sha1 b/third_party/android_jar/api-versions.tar.gz.sha1
deleted file mode 100644
index 0c98c4f..0000000
--- a/third_party/android_jar/api-versions.tar.gz.sha1
+++ /dev/null
@@ -1 +0,0 @@
-788aea6588610917a910af5d0e658fb13e8f7baf
\ No newline at end of file
diff --git a/third_party/android_jar/lib-v31.tar.gz.sha1 b/third_party/android_jar/lib-v31.tar.gz.sha1
index 0af2989..dbc61eb 100644
--- a/third_party/android_jar/lib-v31.tar.gz.sha1
+++ b/third_party/android_jar/lib-v31.tar.gz.sha1
@@ -1 +1 @@
-3f0543d825941eee32abca750ce30e83ed451f30
\ No newline at end of file
+04e0e01c814737bfed7a95e0b7218094b6c79c1f
\ No newline at end of file
diff --git a/third_party/android_jar/lib-v32.tar.gz.sha1 b/third_party/android_jar/lib-v32.tar.gz.sha1
index 1d92e7e..1084ccf 100644
--- a/third_party/android_jar/lib-v32.tar.gz.sha1
+++ b/third_party/android_jar/lib-v32.tar.gz.sha1
@@ -1 +1 @@
-9b07cb997fcedd7314bb9cf35b9ddacbe817c51c
\ No newline at end of file
+82f69bfeceab5f11796d768e165f800ee7439bd8
\ No newline at end of file
diff --git a/tools/run_benchmark.py b/tools/run_benchmark.py
index 2ad5200..d5d4fc0 100755
--- a/tools/run_benchmark.py
+++ b/tools/run_benchmark.py
@@ -21,9 +21,12 @@
# The r8lib target is always the golem target.
GOLEM_BUILD_TARGETS = [R8LIB_BUILD_TARGET] + R8LIB_TEST_BUILD_TARGETS
+def get_golem_resource_path(benchmark):
+ return os.path.join('benchmarks', benchmark + 'Group')
+
def get_jdk_home(options, benchmark):
if options.golem:
- return os.path.join('benchmarks', benchmark, 'linux')
+ return os.path.join(get_golem_resource_path(benchmark), 'linux')
return None
def parse_options(argv):
diff --git a/tools/run_on_app_dump.py b/tools/run_on_app_dump.py
index 6035752..948fb7c 100755
--- a/tools/run_on_app_dump.py
+++ b/tools/run_on_app_dump.py
@@ -1151,6 +1151,7 @@
with utils.TempDir() as temp_dir:
if options.temp:
temp_dir = options.temp
+ os.makedirs(temp_dir, exist_ok=True)
if options.hash:
# Download r8-<hash>.jar from
# https://storage.googleapis.com/r8-releases/raw/.